@opengis/cms 0.0.50 → 0.0.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/{ArticlesPage-Cuit_90w.js → ArticlesPage-Cddv2qte.js} +5 -5
  2. package/dist/{BuilderPage-B79YHrmr.js → BuilderPage-BgcBJcw7.js} +139 -139
  3. package/dist/{CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-B6irHMzL.js → CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-C-k8QGA-.js} +19 -19
  4. package/dist/{CollectionsPage-JfmrHNR_.js → CollectionsPage-d5MLIIAG.js} +3 -3
  5. package/dist/{CreateForm-BMOBeP4G.js → CreateForm-B0srHu5e.js} +2 -2
  6. package/dist/{EditCollectionPage-B4p_iA6h.js → EditCollectionPage-NUVatLkY.js} +65 -59
  7. package/dist/{EmptyData-DaZt_nAm.js → EmptyData-BSW20VKP.js} +5 -5
  8. package/dist/{MenuAddPage-CmU4kAUM.js → MenuAddPage-Cn3JN04F.js} +3 -3
  9. package/dist/{MenuItemPage-UV8JlJvT.js → MenuItemPage-B0Th9EOe.js} +60 -60
  10. package/dist/{MenuPage-c4TPJgIN.js → MenuPage-DQpD3IXx.js} +4 -4
  11. package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-CTKNG0qR.js +84 -0
  12. package/dist/{UniversalTable.vue_vue_type_script_setup_true_lang-DR4PQwqR.js → UniversalTable.vue_vue_type_script_setup_true_lang-DW6O-xoY.js} +78 -78
  13. package/dist/{UniversalTablePagination.vue_vue_type_script_setup_true_lang-C8P9DCeX.js → UniversalTablePagination.vue_vue_type_script_setup_true_lang-DBIPBmpm.js} +46 -46
  14. package/dist/contentForm-C4Jp-FbQ.js +586 -0
  15. package/dist/{getField-C7EZs-YQ.js → getField-CKcz_b0t.js} +960 -933
  16. package/dist/index.js +10 -10
  17. package/dist/style.css +1 -1
  18. package/dist/{vuedraggable-CoAPPFYd.js → vuedraggable-mqqAYsch.js} +107 -107
  19. package/locales/en.json +6 -1
  20. package/locales/uk.json +4 -1
  21. package/package.json +68 -68
  22. package/server/functions/getContent.js +6 -15
  23. package/server/functions/getSearchData.js +3 -13
  24. package/server/functions/utils/mock.reply.js +56 -0
  25. package/server/routes/cms/controllers/listMedia.js +30 -3
  26. package/server/routes/cms/controllers/searchContent.js +12 -5
  27. package/server/routes/cms/utils/additionalData.js +1 -1
  28. package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-C8cip9Ci.js +0 -84
  29. package/dist/contentForm-S5mXr5B7.js +0 -553
package/locales/en.json CHANGED
@@ -126,7 +126,10 @@
126
126
  "dragToBuild": "Drag and drop content blocks here to build your collection structure",
127
127
  "collectionCreated": "Collection created successfully",
128
128
  "collectionCreationFailed": "Error creating collection",
129
- "pinPublication": "Pin Publication"
129
+ "pinPublication": "Pin Publication",
130
+ "enLocalization": "EN localization",
131
+ "translateContentSuccess": "Content translated successfully",
132
+ "translateContentError": "Error translating content"
130
133
  },
131
134
  "articles": {
132
135
  "title": "Articles",
@@ -478,6 +481,8 @@
478
481
  "configure": "Configure",
479
482
  "successTitle": "Success",
480
483
  "successMessage": "Settings saved successfully",
484
+ "translateContentSuccess": "Content translated successfully",
485
+ "translateContentError": "Error translating content",
481
486
  "errorTitle": "Error",
482
487
  "errorMessage": "Error saving settings",
483
488
  "generateNewKey": "Generate New Key",
package/locales/uk.json CHANGED
@@ -126,7 +126,10 @@
126
126
  "dragToBuild": "Перетягніть блоки контенту сюди, щоб створити структуру колекції",
127
127
  "collectionCreated": "Колекція успішно створена",
128
128
  "collectionCreationFailed": "Помилка при створенні колекції",
129
- "pinPublication": "Закріпити публікацію"
129
+ "pinPublication": "Закріпити публікацію",
130
+ "enLocalization": "EN локалізація",
131
+ "translateContentSuccess": "Контент успішно перекладений",
132
+ "translateContentError": "Помилка при перекладі контенту"
130
133
  },
131
134
  "articles": {
132
135
  "title": "Сторінки",
package/package.json CHANGED
@@ -1,68 +1,68 @@
1
- {
2
- "name": "@opengis/cms",
3
- "version": "0.0.50",
4
- "description": "cms",
5
- "type": "module",
6
- "author": "Softpro",
7
- "main": "./dist/index.js",
8
- "license": "EULA",
9
- "files": [
10
- "module",
11
- "locales",
12
- "dist",
13
- "server",
14
- "plugin.js",
15
- "utils.js",
16
- "utils.d.ts",
17
- "input-types.json"
18
- ],
19
- "scripts": {
20
- "patch": "npm version patch && git push && npm publish",
21
- "test": "node --test test/**/*.test.js",
22
- "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
23
- "dev": "NODE_ENV=dev bun --env-file=.env.ip server ",
24
- "admin": "vite admin",
25
- "build": "vite build && vite build admin",
26
- "build:lib": "vite build",
27
- "proxy": "vite dev admin",
28
- "start": "bun --env-file=.env.ip server",
29
- "prod": "NODE_ENV=production bun --env-file=.env.ip server ",
30
- "ip": "bun --env-file=.env.ip server",
31
- "demo": "node --env-file=.env.demo --env-file=.env server",
32
- "i18n:sync": "node i18n-sync.cjs",
33
- "prepublishOnly": "bun build:lib",
34
- "softpro": "bun --env-file=.env.softpro server",
35
- "softpro1": "NODE_ENV=production bun --env-file=.env.prod-softpro.local server"
36
- },
37
- "dependencies": {},
38
- "resolutions": {
39
- "rollup": "4.30.0"
40
- },
41
- "devDependencies": {
42
- "@fastify/compress": "^8.1.0",
43
- "@opengis/core": "^0.0.30",
44
- "@opengis/fastify-table": "^2.0.137",
45
- "@opengis/filter": "^0.1.31",
46
- "@opengis/form": "^0.0.109",
47
- "@opengis/richtext": "0.0.38",
48
- "@vueuse/head": "2.0.0",
49
- "js-yaml": "^4.1.0",
50
- "lucide-vue-next": "0.344.0",
51
- "vite": "5.1.4",
52
- "vue": "^3.5.17",
53
- "vue-i18n": "11.1.5",
54
- "vue-router": "4.4.3",
55
- "vuedraggable": "4.1.0",
56
- "@tailwindcss/typography": "0.5.10",
57
- "@tsconfig/node22": "^22.0.2",
58
- "@vitejs/plugin-vue": "5.0.4",
59
- "autoprefixer": "10.4.18",
60
- "eslint": "8.49.0",
61
- "postcss": "8.4.35",
62
- "sass": "^1.92.1",
63
- "tailwindcss": "3.4.1",
64
- "typescript": "~5.8.0",
65
- "vitest": "3.2.4",
66
- "vue-tsc": "^2.2.10"
67
- }
68
- }
1
+ {
2
+ "name": "@opengis/cms",
3
+ "version": "0.0.52",
4
+ "description": "cms",
5
+ "type": "module",
6
+ "author": "Softpro",
7
+ "main": "./dist/index.js",
8
+ "license": "EULA",
9
+ "files": [
10
+ "module",
11
+ "locales",
12
+ "dist",
13
+ "server",
14
+ "plugin.js",
15
+ "utils.js",
16
+ "utils.d.ts",
17
+ "input-types.json"
18
+ ],
19
+ "scripts": {
20
+ "patch": "npm version patch && git push && npm publish",
21
+ "test": "node --test test/**/*.test.js",
22
+ "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
23
+ "dev": "NODE_ENV=dev bun --env-file=.env.ip server ",
24
+ "admin": "vite admin",
25
+ "build": "vite build && vite build admin",
26
+ "build:lib": "vite build",
27
+ "proxy": "vite dev admin",
28
+ "start": "bun --env-file=.env.ip server",
29
+ "prod": "NODE_ENV=production bun --env-file=.env.ip server ",
30
+ "ip": "bun --env-file=.env.ip server",
31
+ "demo": "node --env-file=.env.demo --env-file=.env server",
32
+ "i18n:sync": "node i18n-sync.cjs",
33
+ "prepublishOnly": "bun build:lib",
34
+ "softpro": "bun --env-file=.env.softpro server",
35
+ "softpro1": "NODE_ENV=production bun --env-file=.env.prod-softpro.local server"
36
+ },
37
+ "dependencies": {},
38
+ "resolutions": {
39
+ "rollup": "4.30.0"
40
+ },
41
+ "devDependencies": {
42
+ "@fastify/compress": "^8.1.0",
43
+ "@opengis/core": "^0.0.30",
44
+ "@opengis/fastify-table": "^2.0.143",
45
+ "@opengis/filter": "^0.1.31",
46
+ "@opengis/form": "^0.0.109",
47
+ "@opengis/richtext": "0.0.45",
48
+ "@vueuse/head": "2.0.0",
49
+ "js-yaml": "^4.1.0",
50
+ "lucide-vue-next": "0.344.0",
51
+ "vite": "5.1.4",
52
+ "vue": "^3.5.17",
53
+ "vue-i18n": "11.1.5",
54
+ "vue-router": "4.4.3",
55
+ "vuedraggable": "4.1.0",
56
+ "@tailwindcss/typography": "0.5.10",
57
+ "@tsconfig/node22": "^22.0.2",
58
+ "@vitejs/plugin-vue": "5.0.4",
59
+ "autoprefixer": "10.4.18",
60
+ "eslint": "8.49.0",
61
+ "postcss": "8.4.35",
62
+ "sass": "^1.92.1",
63
+ "tailwindcss": "3.4.1",
64
+ "typescript": "~5.8.0",
65
+ "vitest": "3.2.4",
66
+ "vue-tsc": "^2.2.10"
67
+ }
68
+ }
@@ -1,25 +1,14 @@
1
1
  import { createHash } from 'node:crypto';
2
2
 
3
3
  import { config, getRedis, pgClients } from '@opengis/fastify-table/utils.js';
4
-
4
+ import { createMockReply } from './utils/mock.reply.js';
5
5
  import getContent from '../routes/cms/controllers/getContent.js';
6
6
 
7
7
  const pg = pgClients.client;
8
8
  const rclient = getRedis();
9
9
 
10
- const mockReply = {
11
- response: {},
12
- status: (statusCode) => {
13
- Object.assign(mockReply.response, { status: statusCode });
14
- return mockReply;
15
- },
16
- send: (result) => {
17
- Object.assign(mockReply.response, typeof result === 'object' ? result : { message: result });
18
- return { ...mockReply.response };
19
- },
20
- };
21
-
22
- export default async function getContentBySlug({ slug, filter, tags, state, locale, contextQuery, collection = 'pages', ttl = 3600, fields, limit = 12, page = 1 } = {}) {
10
+
11
+ export default async function getContentBySlug({ slug, filter, tags, state, locale, contextQuery, collection = 'pages', ttl = 3600, fields, limit = 12, page = 1, order, desc } = {}) {
23
12
  if (!slug) {
24
13
  // return { error: 'not enough params: slug', code: 400 };
25
14
  }
@@ -43,7 +32,9 @@ export default async function getContentBySlug({ slug, filter, tags, state, loca
43
32
  return { cache: true, ...cacheData };
44
33
  }
45
34
 
46
- const req = { pg: pgClients.client, params: { type: collection, id: slug }, query: { filter, tags, state, contextQuery, locale, fields, limit, page } };
35
+ const req = { pg: pgClients.client, params: { type: collection, id: slug }, query: { filter, tags, state, contextQuery, locale, fields, limit, page, order, desc } };
36
+
37
+ const mockReply = createMockReply();
47
38
  const result = await getContent(req, mockReply, true);
48
39
 
49
40
  if (ttl) {
@@ -1,29 +1,18 @@
1
1
  import { createHash } from 'node:crypto';
2
2
 
3
3
  import { config, getRedis, pgClients } from '@opengis/fastify-table/utils.js';
4
+ import { createMockReply } from './utils/mock.reply.js';
4
5
 
5
6
  import searchContent from '../routes/cms/controllers/searchContent.js';
6
7
 
7
8
  const pg = pgClients.client;
8
9
  const rclient = getRedis();
9
10
 
10
- const mockReply = {
11
- response: {},
12
- status: (statusCode) => {
13
- Object.assign(mockReply.response, { status: statusCode });
14
- return mockReply;
15
- },
16
- send: (result) => {
17
- Object.assign(mockReply.response, typeof result === 'object' ? result : { message: result });
18
- return { ...mockReply.response };
19
- },
20
- };
21
-
22
11
  export default async function getSearchData({ page = 1, limit = 12, ttl = 3600, search, locale, tags, filter, contentType, asc } = {}) {
23
12
  // check if any crud operations performed, if not - return cached response
24
13
  const crudInc = await rclient.get(`pg:site.contents:crud`) || 0;
25
14
 
26
- const cacheKey = createHash('md5').update([config.pg?.database, 'cms:search', crudInc, page, limit, ttl, locale, tags, filter, contentType, asc].join(':')).digest('hex');
15
+ const cacheKey = createHash('md5').update([config.pg?.database, 'cms:search', crudInc, page, limit, search, locale, tags, filter, contentType, asc].join(':')).digest('hex');
27
16
  const cacheData = ttl === 0 ? null : JSON.parse(await rclient.get(cacheKey));
28
17
 
29
18
  // return from cache
@@ -31,6 +20,7 @@ export default async function getSearchData({ page = 1, limit = 12, ttl = 3600,
31
20
  return { cache: true, ...cacheData };
32
21
  }
33
22
 
23
+ const mockReply = createMockReply();
34
24
  const result = await searchContent({ pg, query: { search, locale, page, limit, tags, filter, contentType } }, mockReply);
35
25
 
36
26
  if (ttl) {
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @template T
3
+ * @typedef {Object} MockReplyResponse
4
+ * @property {number} [status] - HTTP статус-код
5
+ * @property {T} [data] - Дані відповіді (якщо передано об'єкт)
6
+ * @property {string} [message] - Повідомлення (якщо передано рядок)
7
+ */
8
+
9
+ /**
10
+ * Створює ізольований mock-об'єкт reply для тестування Fastify-хендлерів.
11
+ * Імітує методи `status()` та `send()`.
12
+ *
13
+ * @template T
14
+ * @returns {{
15
+ * status: (statusCode: number) => any,
16
+ * send: (result: T | string) => MockReplyResponse<T>
17
+ * }}
18
+ */
19
+ export function createMockReply() {
20
+ /** @type {MockReplyResponse<any>} */
21
+
22
+ let response = {};
23
+
24
+ return {
25
+ /**
26
+ * Встановлює HTTP статус-код.
27
+ * Повертає той самий reply для чейнінгу.
28
+ *
29
+ * @param {number} statusCode
30
+ * @returns {any}
31
+ */
32
+ status(statusCode) {
33
+ response.status = statusCode;
34
+ return this;
35
+ },
36
+
37
+ /**
38
+ * Імітує Fastify reply.send().
39
+ * Якщо передано об'єкт — він додається як data.
40
+ * Якщо передано рядок — додається як message.
41
+ *
42
+ * @param {T | string} result
43
+ * @returns {MockReplyResponse<T>}
44
+ */
45
+ send(result) {
46
+ response = {
47
+ ...response,
48
+ ...(typeof result === 'object'
49
+ ? { data: result }
50
+ : { message: result }),
51
+ };
52
+
53
+ return response;
54
+ },
55
+ };
56
+ }
@@ -23,7 +23,7 @@ const rootDir = path.resolve(getFolder(config, 'local'));
23
23
  const dir = '/files';
24
24
 
25
25
  const filesizeCache = {};
26
- const previewWidth = 300;
26
+ const fileMtimeCache = {};
27
27
 
28
28
  mkdirSync(path.join(rootDir, dir), { recursive: true });
29
29
 
@@ -89,8 +89,33 @@ export default async function listMedia(req, reply) {
89
89
  const filepath = media ? media.url : ('/files/' + (el.path.split('/files/')[1] ? el.path.split('/files/')[1] + '/' : '') + el.name);
90
90
 
91
91
  if (!filesizeCache[filepath]) {
92
- const { size } = await stat(path.join(rootDir, filepath));
92
+ const { mtime, size } = await stat(path.join(rootDir, filepath));
93
93
  Object.assign(filesizeCache, { [filepath]: size });
94
+ mtime.setHours(0, 0, 0, 0); // strip hours from timestamp, leave only date
95
+ Object.assign(fileMtimeCache, { [filepath]: mtime });
96
+ }
97
+
98
+
99
+ const [, from, to] = q ? (q.match(/between\s+'(\d{4}-\d{2}-\d{2})'::date\s+and\s+'(\d{4}-\d{2}-\d{2})'::date/i) || []) : [];
100
+
101
+ // skip entirely if invalid dates passed to query.filter
102
+ if ((from && new Date(from).toString() === 'Invalid Date') || (to && new Date(to).toString() === 'Invalid Date')) {
103
+ return null;
104
+ }
105
+
106
+ // skip if file modification date does not match filter value
107
+ if (fileMtimeCache[filepath] && from && to && (new Date(from) > fileMtimeCache[filepath] || new Date(to) < fileMtimeCache[filepath])) {
108
+ return null;
109
+ }
110
+
111
+ const dt = q && !q.includes('between') ? query.filter.match(/\d{4}-\d{2}-\d{2}/)?.[0] : null;
112
+ const date = dt ? new Date(dt) : null;
113
+ // skip timezone offset
114
+ if (date) { date.setHours(0, 0, 0, 0); }
115
+
116
+ // filter by exact date
117
+ if (fileMtimeCache[filepath] && date && (new Date(date).getTime() !== fileMtimeCache[filepath].getTime())) {
118
+ return null;
94
119
  }
95
120
 
96
121
  const mime = getMimeType(el.name) || '';
@@ -116,10 +141,12 @@ export default async function listMedia(req, reply) {
116
141
  url: filepath,
117
142
  mime,
118
143
  preview,
144
+ updated_at: fileMtimeCache[filepath].toISOString(),
119
145
  }
120
146
  }));
121
147
 
122
- Object.assign(result, { data: subdirs.concat(files) });
148
+ // filter empty items, such as filtered out by query.filter=updated_at (not from db, but from fs.stat)
149
+ Object.assign(result, { data: subdirs.concat(files.filter(Boolean)) });
123
150
  return result;
124
151
 
125
152
  }
@@ -1,4 +1,6 @@
1
- import { config, pgClients, getFilterSQL } from '@opengis/fastify-table/utils.js';
1
+ import { pgClients, getFilterSQL } from '@opengis/fastify-table/utils.js';
2
+
3
+ import additionalData from '../utils/additionalData.js';
2
4
 
3
5
  const filterList = [
4
6
  {
@@ -55,11 +57,12 @@ export default async function searchContent({
55
57
  const limit = Math.min(query.limit || 16, maxLimit);
56
58
  const offset = (page - 1) * limit;
57
59
 
58
- const { q } = filter ? await getFilterSQL({
60
+ const { q } = filter || search ? await getFilterSQL({
59
61
  pg,
60
62
  table: 'site.contents',
61
63
  filter,
62
64
  search,
65
+ searchColumn: 'a.slug,a.title',
63
66
  query: `status='published'`,
64
67
  filterList,
65
68
  }) : { q: `status='published'` };
@@ -91,11 +94,11 @@ export default async function searchContent({
91
94
  const collections = contents.filter(el => el.content_type === 'collection' && el.table_name);
92
95
 
93
96
  // const totals = await pg.query(`select json_object_agg(oid::regclass, reltuples) from pg_class`).then(el => el.rows?.[0]?.json_object_agg || {});
94
- const allSingles = await pg.query(`select count(*)::int from site.contents where content_type_id in (select content_type_id from site.content_types where type = 'single' )`).then(el => el.rows?.[0]?.count || 0);
97
+ const allSingles = await pg.query(`select count(*)::int from site.contents where content_type_id in (select content_type_id from site.content_types where type = 'single') and status='published'`).then(el => el.rows?.[0]?.count || 0);
95
98
  const allCollectionTables = await pg.query(`select array_agg(table_name) from site.content_types where type = 'collection' and table_name is not null`).then(el => el.rows?.[0]?.array_agg || []);
96
99
 
97
100
  const allCollections = await Promise.all(allCollectionTables.map(async tablename => {
98
- const total = pg.queryCache ? await pg.queryCache(`select count(*)::int from data."${tablename}"`, { table: `data.${tablename}` }).then(el => el.rows?.[0]?.count || 0) : 0;
101
+ const total = pg.queryCache ? await pg.queryCache(`select count(*)::int from data."${tablename}" where status='published'`, { table: `data.${tablename}` }).then(el => el.rows?.[0]?.count || 0) : 0;
99
102
  return total;
100
103
  })).then(el => el.reduce((acc, curr) => acc + (curr || 0), 0) || 0);
101
104
 
@@ -121,10 +124,12 @@ export default async function searchContent({
121
124
  }[!!asc];
122
125
 
123
126
  const { optimizedSQL = `SELECT * FROM data."${table}" where status='published' ORDER BY ${order}` } =
124
- filter ? await getFilterSQL({
127
+ filter || search ? await getFilterSQL({
125
128
  pg,
126
129
  table: `data."${table}"`,
127
130
  filter,
131
+ search,
132
+ searchColumn: 'slug,title',
128
133
  query: `status='published'`,
129
134
  filterList: collectionFilters,
130
135
  order: 'published_at DESC NULLS LAST'
@@ -141,6 +146,8 @@ export default async function searchContent({
141
146
  return { rows: [], /*total: total // totals[`data.${table}`] || totals[`data."${table}"`] || 0*/ };
142
147
  });
143
148
 
149
+ // await additionalData(pg, items, locale);
150
+
144
151
  return {
145
152
  rows: items.map(el => ({
146
153
  ...row,
@@ -22,7 +22,7 @@ export default async function additionalData(pg, rows, locale, fields = '*') {
22
22
  const localization = localizations.find(el => el.object_id === row.id);
23
23
  const localizationKeys = Object.keys(localization?.json_object_agg || {}).filter(key => row[key.split(':').shift()]);
24
24
  const localizationObj1 = Object.entries(localization?.json_object_agg || {}).filter(([key]) => rows.length > 1 ? true : localizationKeys.includes(key)).reduce((acc, curr) => ({ ...acc, [curr[0]]: typeof curr[1] === 'string' && curr[1].startsWith('[') && curr[1].endsWith(']') ? JSON.parse(curr[1]) : curr[1] }), {});
25
- const localizationObj = fields?.length ? Object.fromEntries(Object.entries(localizationObj1).filter(([key]) => fields.split(',').includes(key.split(':').shift()))) : localizationObj1;
25
+ const localizationObj = fields?.length && fields !== '*' ? Object.fromEntries(Object.entries(localizationObj1).filter(([key]) => fields.split(',').includes(key.split(':').shift()))) : localizationObj1;
26
26
  if (locale && locale !== 'uk') {
27
27
  Object.assign(row, Object.keys(localizationObj).reduce((acc, curr) => ({ ...acc, [curr.replace(`:${locale}`, '')]: localizationObj[curr] }), {}));
28
28
  } else if (!locale) {
@@ -1,84 +0,0 @@
1
- import { defineComponent as s, mergeModels as m, useModel as c, ref as f, onMounted as h, watch as d, onBeforeUnmount as p, openBlock as g, createElementBlock as v, normalizeStyle as w } from "vue";
2
- async function M() {
3
- if (window.monaco)
4
- return window.monaco;
5
- const i = "https://cdn.jsdelivr.net/npm/monaco-editor@0.45.0/min";
6
- return window.require || (window.require = { paths: { vs: `${i}/vs` } }, await new Promise((t, l) => {
7
- const n = document.createElement("script");
8
- n.src = `${i}/vs/loader.min.js`, n.onload = () => t(), n.onerror = l, document.head.appendChild(n);
9
- })), new Promise((t) => {
10
- window.require(["vs/editor/editor.main"], () => t(window.monaco));
11
- });
12
- }
13
- const C = /* @__PURE__ */ s({
14
- __name: "MonacoEditor",
15
- props: /* @__PURE__ */ m({
16
- language: { default: "javascript" },
17
- theme: { default: "vs-dark" },
18
- width: { default: "100%" },
19
- height: { default: "100%" },
20
- options: { default: () => ({
21
- minimap: { enabled: !1 }
22
- }) }
23
- }, {
24
- modelValue: {
25
- required: !0
26
- },
27
- modelModifiers: {}
28
- }),
29
- emits: ["update:modelValue"],
30
- setup(i) {
31
- const t = i, l = c(i, "modelValue"), n = f(null);
32
- let o = null, r = null;
33
- return h(async () => {
34
- var e;
35
- if (n.value)
36
- try {
37
- r = await M();
38
- const a = ((e = l.value) == null ? void 0 : e.replace(/\\n/g, `
39
- `)) || "";
40
- o = r.editor.create(n.value, {
41
- value: a,
42
- language: t.language,
43
- theme: t.theme,
44
- automaticLayout: !0,
45
- ...t.options
46
- }), o.onDidChangeModelContent(() => {
47
- const u = (o == null ? void 0 : o.getValue()) || "";
48
- l.value = u;
49
- });
50
- } catch (a) {
51
- console.error("Failed to load Monaco Editor:", a);
52
- }
53
- }), d(
54
- () => l.value,
55
- (e) => {
56
- if (o) {
57
- const a = (e == null ? void 0 : e.replace(/\\n/g, `
58
- `)) || "";
59
- a !== o.getValue() && o.setValue(a);
60
- }
61
- },
62
- { immediate: !0 }
63
- ), d(
64
- () => t.language,
65
- (e) => {
66
- o && e && r && r.editor.setModelLanguage(o.getModel(), e);
67
- }
68
- ), d(
69
- () => t.theme,
70
- (e) => {
71
- o && e && r && r.editor.setTheme(e);
72
- }
73
- ), p(() => {
74
- o && (o.dispose(), o = null);
75
- }), (e, a) => (g(), v("div", {
76
- ref_key: "editorContainer",
77
- ref: n,
78
- style: w({ width: e.width, height: e.height })
79
- }, null, 4));
80
- }
81
- });
82
- export {
83
- C as _
84
- };