@opengis/cms 0.0.2 → 0.0.3

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 (144) hide show
  1. package/.gitlab-ci.yml +36 -0
  2. package/config.example +21 -0
  3. package/docs/.vitepress/abbr.mjs +26 -0
  4. package/docs/.vitepress/config.mjs +119 -0
  5. package/docs/.vitepress/navigation.mjs +82 -0
  6. package/docs/.vitepress/theme/Layout.vue +17 -0
  7. package/docs/.vitepress/theme/components/NavigationLinks.vue +102 -0
  8. package/docs/.vitepress/theme/components/Panzoom.vue +169 -0
  9. package/docs/.vitepress/theme/index.mjs +15 -0
  10. package/docs/.vitepress/theme/style.scss +136 -0
  11. package/docs/abbr.json +4 -0
  12. package/docs/api/builder/cms.builder.delete.md +65 -0
  13. package/docs/api/builder/cms.builder.get.md +70 -0
  14. package/docs/api/builder/cms.builder.list.md +98 -0
  15. package/docs/api/builder/cms.builder.post.md +72 -0
  16. package/docs/api/builder/cms.builder.put.md +88 -0
  17. package/docs/api/category/cms.category.delete.md +60 -0
  18. package/docs/api/category/cms.category.get.md +61 -0
  19. package/docs/api/category/cms.category.list.md +77 -0
  20. package/docs/api/category/cms.category.post.md +62 -0
  21. package/docs/api/category/cms.category.put.md +78 -0
  22. package/docs/api/index.md +50 -0
  23. package/docs/api/manager/cms.manager.delete.md +64 -0
  24. package/docs/api/manager/cms.manager.get.md +72 -0
  25. package/docs/api/manager/cms.manager.list.md +96 -0
  26. package/docs/api/manager/cms.manager.post.md +70 -0
  27. package/docs/api/manager/cms.manager.put.md +86 -0
  28. package/docs/api/media/del.md +64 -0
  29. package/docs/api/media/edit.md +92 -0
  30. package/docs/api/media/list.md +70 -0
  31. package/docs/api/media/metadata.md +57 -0
  32. package/docs/api/media/preview.md +33 -0
  33. package/docs/api/media/upload.md +84 -0
  34. package/docs/db/erd.md +173 -0
  35. package/docs/db/index.md +7 -0
  36. package/docs/index.md +39 -0
  37. package/docs/public/logo-dark.svg +24 -0
  38. package/docs/public/logo-light.svg +24 -0
  39. package/docs/public/logo-short.svg +15 -0
  40. package/docs/public/logo.svg +19 -0
  41. package/docs/readme/index.md +6 -0
  42. package/docs/src/vs-button.vue +157 -0
  43. package/docs/vue/basic/button.md +144 -0
  44. package/docs/vue/index.md +9 -0
  45. package/index.html +14 -0
  46. package/package.json +2 -5
  47. package/server/app.js +25 -0
  48. package/server/config.js +5 -0
  49. package/server/index.js +23 -0
  50. package/server/migrations/media.sql +30 -0
  51. package/server/plugins/hook.js +91 -0
  52. package/server/plugins/vite.js +80 -0
  53. package/server/routes/builder/controllers/cms.builder.delete.js +21 -0
  54. package/server/routes/builder/controllers/cms.builder.get.js +17 -0
  55. package/server/routes/builder/controllers/cms.builder.list.js +16 -0
  56. package/server/routes/builder/controllers/cms.builder.post.js +21 -0
  57. package/server/routes/builder/controllers/cms.builder.put.js +23 -0
  58. package/server/routes/builder/index.mjs +22 -0
  59. package/server/routes/category/controllers/cms.category.delete.js +21 -0
  60. package/server/routes/category/controllers/cms.category.get.js +17 -0
  61. package/server/routes/category/controllers/cms.category.list.js +16 -0
  62. package/server/routes/category/controllers/cms.category.post.js +21 -0
  63. package/server/routes/category/controllers/cms.category.put.js +23 -0
  64. package/server/routes/category/index.mjs +22 -0
  65. package/server/routes/manager/controllers/cms.manager.delete.js +22 -0
  66. package/server/routes/manager/controllers/cms.manager.get.js +21 -0
  67. package/server/routes/manager/controllers/cms.manager.list.js +31 -0
  68. package/server/routes/manager/controllers/cms.manager.post.js +28 -0
  69. package/server/routes/manager/controllers/cms.manager.put.js +23 -0
  70. package/server/routes/manager/index.mjs +22 -0
  71. package/server/routes/media/controllers/delete.js +59 -0
  72. package/server/routes/media/controllers/edit.js +94 -0
  73. package/server/routes/media/controllers/list.js +74 -0
  74. package/server/routes/media/controllers/metadata.js +51 -0
  75. package/server/routes/media/controllers/preview.js +47 -0
  76. package/server/routes/media/controllers/upload.js +79 -0
  77. package/server/routes/media/index.mjs +16 -0
  78. package/server/routes/root.mjs +15 -0
  79. package/server/templates/cls/cms.category_type.json +10 -0
  80. package/server/templates/cls/cms.content_review_status.json +10 -0
  81. package/server/templates/cls/cms.content_status.json +10 -0
  82. package/server/templates/cls/cms.content_type.json +10 -0
  83. package/server/templates/cls/cms.lang.json +10 -0
  84. package/server/templates/page/login.html +59 -0
  85. package/server/templates/select/cms.category_id.sql +1 -0
  86. package/server/templates/select/cms.type_id.sql +1 -0
  87. package/src/App.vue +4 -0
  88. package/src/assets/tailwind/tailwind.js +62 -0
  89. package/src/assets/vue.svg +1 -0
  90. package/src/components/builder/vs-builder-content.vue +163 -0
  91. package/src/components/builder/vs-builder-menu.vue +142 -0
  92. package/src/components/formats/index.js +8 -0
  93. package/src/components/formats/vs-manager-table-date.vue +29 -0
  94. package/src/components/formats/vs-manager-table-switch.vue +16 -0
  95. package/src/components/icons/icon-actions.vue +24 -0
  96. package/src/components/icons/icon-arrow-left.vue +19 -0
  97. package/src/components/icons/icon-check.vue +23 -0
  98. package/src/components/icons/icon-chewron-right.vue +16 -0
  99. package/src/components/icons/icon-close.vue +22 -0
  100. package/src/components/icons/icon-edit.vue +22 -0
  101. package/src/components/icons/icon-folder.vue +18 -0
  102. package/src/components/icons/icon-folder2.vue +17 -0
  103. package/src/components/icons/icon-home.vue +16 -0
  104. package/src/components/icons/icon-image.vue +18 -0
  105. package/src/components/icons/icon-logo.vue +22 -0
  106. package/src/components/icons/icon-media.vue +22 -0
  107. package/src/components/icons/icon-point.vue +11 -0
  108. package/src/components/icons/icon-search.vue +22 -0
  109. package/src/components/icons/icon-table.vue +22 -0
  110. package/src/components/icons/icon-users.vue +18 -0
  111. package/src/components/icons/icon.plus.vue +18 -0
  112. package/src/components/manager/children/vs-manager-collection-content.vue +55 -0
  113. package/src/components/manager/children/vs-manager-collection-item-content.vue +116 -0
  114. package/src/components/manager/children/vs-manager-single-content.vue +112 -0
  115. package/src/components/manager/manager-table/vs-manager-colection-table-add.vue +84 -0
  116. package/src/components/manager/manager-table/vs-manager-collection-table.vue +59 -0
  117. package/src/components/manager/vs-manager-menu.vue +73 -0
  118. package/src/components/media/Breadcrumb.vue +73 -0
  119. package/src/components/shared-components/vs-not-data.vue +213 -0
  120. package/src/components/vs-main-menu.vue +53 -0
  121. package/src/helpers/debounce.js +10 -0
  122. package/src/helpers/translite.js +19 -0
  123. package/src/main.js +30 -0
  124. package/src/misc/import-file.js +32 -0
  125. package/src/pages/vs-builder.vue +22 -0
  126. package/src/pages/vs-layout.vue +17 -0
  127. package/src/pages/vs-manager.vue +30 -0
  128. package/src/pages/vs-media.vue +398 -0
  129. package/src/router/router.js +9 -0
  130. package/src/router/routes.config.js +40 -0
  131. package/src/style.css +0 -0
  132. package/src/templates/form-columns.js +70 -0
  133. package/src/templates/form-template.js +22 -0
  134. package/test/config.js +17 -0
  135. package/test/files/eye.svg +4 -0
  136. package/test/helper.js +30 -0
  137. package/test/routes/builder.test.js +99 -0
  138. package/test/routes/category.test.js +97 -0
  139. package/test/routes/manager.test.js +103 -0
  140. package/test/routes/media.test.js +252 -0
  141. package/vite.config.js +37 -0
  142. package/editor/dist/cms.js +0 -5900
  143. package/editor/dist/cms.umd.cjs +0 -19
  144. /package/{editor/dist → public}/vite.svg +0 -0
package/.gitlab-ci.yml ADDED
@@ -0,0 +1,36 @@
1
+ stages:
2
+ - build
3
+ - doc
4
+
5
+ build-dev:
6
+ tags:
7
+ - "1_140"
8
+ stage: build
9
+ variables:
10
+ GIT_STRATEGY: none
11
+ script:
12
+ - cd /data/server/local-cms && sudo git reset --hard HEAD
13
+ - cd /data/server/local-cms && sudo git pull
14
+ - sudo sed -i 's/3000/3004/g' /data/server/local-cms/server/index.js
15
+ - cd /data/server/local-cms && sudo npm i
16
+ - cd /data/server/local-cms && sudo npm run build
17
+ - cd /data/server/local-cms && pm2 restart 3004-local-cms
18
+ only:
19
+ - dev
20
+
21
+
22
+ docs-253:
23
+ stage: doc
24
+ tags:
25
+ - cdn
26
+ variables:
27
+ GIT_STRATEGY: none
28
+ script:
29
+ - cd /data/softpro/docs/$CI_PROJECT_NAME && git pull
30
+ - npm install
31
+ - npm run docs:build
32
+ - rm -rf /data/softpro/apidocs/$CI_PROJECT_NAME || true
33
+ - mkdir -p /data/softpro/apidocs/$CI_PROJECT_NAME
34
+ - cp -r /data/softpro/docs/$CI_PROJECT_NAME/docs/.vitepress/dist/* /data/softpro/apidocs/$CI_PROJECT_NAME
35
+ only:
36
+ - dev
package/config.example ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "folder": "site/ip_ukraine",
3
+ "pg": {
4
+ "host": "192.168.3.160",
5
+ "port": 5439,
6
+ "database": "ip_ukraine",
7
+ "user": "postgres",
8
+ "password": "postgres"
9
+ },
10
+ "redis": {
11
+ "host": "192.168.3.160",
12
+ "port": 6379,
13
+ "family": 4
14
+ },
15
+ "s3": {
16
+ "endpoint": "http://192.168.3.160:9000",
17
+ "user": "minioadmin",
18
+ "password": "minioadmin"
19
+ },
20
+ "convertServerAddress": "192.168.3.160:4003"
21
+ }
@@ -0,0 +1,26 @@
1
+ import abbr from '../abbr.json';
2
+
3
+ function handleAbbr(md) {
4
+ if (!abbr || typeof abbr !== 'object') {
5
+ return false;
6
+ }
7
+
8
+ const defaultRender = md.renderer.render.bind(md.renderer);
9
+
10
+ md.renderer.render = function(tokens, options, env) {
11
+ let result = defaultRender(tokens, options, env);
12
+
13
+ for (const key in abbr) {
14
+ const pattern = new RegExp(`${key}(?!\s*<\/abbr>)`, 'gm');
15
+ const replacement = `<abbr title="${abbr[key]}">${key}</abbr>`;
16
+
17
+ result = result.replace(pattern, replacement);
18
+ }
19
+
20
+ return result;
21
+ };
22
+
23
+ return true;
24
+ }
25
+
26
+ export default handleAbbr;
@@ -0,0 +1,119 @@
1
+ import { defineConfig } from 'vitepress';
2
+ import { withMermaid } from 'vitepress-plugin-mermaid';
3
+ import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs';
4
+ import markdownItAbbr from 'markdown-it-abbr';
5
+ import navigation from './navigation.mjs';
6
+ import handleAbbr from './abbr.mjs';
7
+
8
+ // Автоматична генерація одночасно nav (меню в хедері) і сайдбару для кожного пункту nav
9
+ const { nav, sidebar } = navigation(
10
+ /*
11
+ Перший параметр функції (обов'язковий) - масив об'єктів з ключами:
12
+ 1) text (обов'язковий) - назва пункта меню, яка буде відображатись в хедері
13
+ 2) folder (обов'язковий) - назва папки з документацією, яка повинна відкриватись по кліку на пункт меню з хедера
14
+ (на основі цієї папки буде автоматично сформований сайдбар)
15
+ 3) link (необов'язковий) - кастомне посилання, по стандарту веде на файл `docs/${forder}/index.md`
16
+ 4) інші необов'язкові ключі (activeMatch, target...) описані тут - https://vitepress.dev/reference/default-theme-nav#navigation-links
17
+ */
18
+ [
19
+ {
20
+ text: 'DB',
21
+ folder: 'db',
22
+ },
23
+ {
24
+ text: 'API',
25
+ folder: 'api',
26
+ },
27
+ {
28
+ text: 'Vue',
29
+ folder: 'vue',
30
+ },
31
+ {
32
+ text: 'Readme',
33
+ folder: 'readme',
34
+ },
35
+ ],
36
+ /*
37
+ Другий параметр функції (НЕобов'язковий) - об'єкт з двома ключами:
38
+ 1) nav - параметри для налаштування хедера, може містити наступні ключі:
39
+ * disableHome (Booleadn, default: false) - чи скрити пункт меню, який веде на головну
40
+ * homeTitle (String, default: 'Головна') - назва пункту меню, який веде на головну
41
+ 2) sidebar - параметри для налаштування сайдбару, може містити наступні ключі:
42
+ * ${назва_папки} (Object) - референс до кожного окремого сайдбару, який вказаний в першому параметрі функції. Ключем виступає те що вказано в folder. Перелік доступних ключів стандартний і описаний тут - https://github.com/jooy2/vitepress-sidebar#options
43
+ */
44
+ {
45
+ // nav: {
46
+ // disableHome: false,
47
+ // homeTitle: 'Головна',
48
+ // },
49
+ // sidebar: {
50
+ // 'api': {
51
+ // includeFolderIndexFile: true,
52
+ // }
53
+ // }
54
+ },
55
+ /*
56
+ Третій параметр функції (НЕобов'язковий, default: '/docs') - вказує папку, в якій знаходиться конфігураційна папка .vitepress:
57
+ - наприклад, якщо у вас в проєкті вже є інша документація і папка docs зайнята, то тут потрібно вказати нову назву папки
58
+ - детальніше тут - https://github.com/jooy2/vitepress-sidebar?tab=readme-ov-file#documentrootpath
59
+ */
60
+ // '/docs-dev',
61
+ );
62
+
63
+ export default withMermaid(
64
+ defineConfig({
65
+ base: '/cms/',
66
+
67
+ title: "Content Management System",
68
+ description: "Система Керування Контентом",
69
+
70
+ ignoreDeadLinks: true,
71
+
72
+ markdown: {
73
+ config(md) {
74
+ md.use(tabsMarkdownPlugin);
75
+ md.use(markdownItAbbr);
76
+ md.use(handleAbbr);
77
+ },
78
+ languageAlias: {
79
+ 'example': 'r',
80
+ 'schema-api': 'r',
81
+ 'scheme-api': 'r',
82
+ 'schema': 'r',
83
+ 'scheme': 'r'
84
+ },
85
+ },
86
+
87
+ head: [
88
+ ['script', { src: 'https://cdn.tailwindcss.com' }],
89
+ ['link', { rel: 'icon shortcut', href: './logo-short.svg' }],
90
+ ['link', { href: 'https://cdn.softpro.ua/vue/v3-core/dev/style.css' }],
91
+ ],
92
+
93
+ // https://vitepress.dev/reference/default-theme-config
94
+ themeConfig: {
95
+ nav,
96
+ sidebar,
97
+
98
+ logo: '/logo.svg',
99
+ siteTitle: false,
100
+
101
+ outline: 'deep',
102
+
103
+ search: {
104
+ provider: 'local',
105
+ },
106
+
107
+ socialLinks: [
108
+ { icon: 'github', link: 'https://git.softpro.ua/', },
109
+ ],
110
+
111
+ // Додаткові посилання в навігації - https://prnt.sc/5K70IDQh8J-f
112
+ // Виводиться на всіх сторінках
113
+ // Також можна оверрайдити/доповнювати на окремих сторінках, просто в потрібному .md файлі - https://prnt.sc/VAGE3r_RU389
114
+ navigationLinks: [
115
+ { icon: 'brand-gitlab', link: 'https://git.softpro.ua/', text: 'GitLab', },
116
+ ],
117
+ },
118
+ })
119
+ );
@@ -0,0 +1,82 @@
1
+ import { generateSidebar } from 'vitepress-sidebar';
2
+
3
+ function navigation(items = [], options = {}, documentRootPath = '/docs') {
4
+ const navHeader = [];
5
+ const navSidebar = [];
6
+
7
+ if (!options.nav) {
8
+ options.nav = {};
9
+ }
10
+
11
+ if (!options.sidebar) {
12
+ options.sidebar = {};
13
+ }
14
+
15
+ if (!options.nav.disableHome) {
16
+ navHeader.push(
17
+ {
18
+ text: options.nav.homeTitle || 'Головна',
19
+ link: '/',
20
+ }
21
+ );
22
+ }
23
+
24
+ items.forEach(item => {
25
+ if (item.text && item.items) {
26
+ navHeader.push(item);
27
+
28
+ return true;
29
+ }
30
+
31
+ if (!item.text || !item.folder) {
32
+ return false;
33
+ }
34
+
35
+ // FORMAT INCOME DATA
36
+ const itemFolder = item.folder.trim();
37
+ const itemFolderFormatted = `/${itemFolder}/`;
38
+
39
+ // NAVBAR
40
+ navHeader.push(
41
+ {
42
+ ...item,
43
+ link: item.link || itemFolderFormatted,
44
+ activeMatch: item.activeMatch || itemFolderFormatted,
45
+ }
46
+ );
47
+
48
+ // SIDEBAR
49
+ const sidebarOptions = options.sidebar[item.folder] || {};
50
+
51
+ navSidebar.push(
52
+ // https://github.com/jooy2/vitepress-sidebar#options
53
+ {
54
+ documentRootPath,
55
+ scanStartPath: itemFolder,
56
+ resolvePath: itemFolderFormatted,
57
+ useTitleFromFileHeading: true,
58
+ useTitleFromFrontmatter: true,
59
+ useFolderTitleFromIndexFile: true,
60
+ hyphenToSpace: true,
61
+ underscoreToSpace: true,
62
+ capitalizeFirst: true,
63
+ collapsed: true,
64
+ sortMenusByFrontmatterOrder: true,
65
+ frontmatterOrderDefaultValue: 1,
66
+ excludeFiles: [],
67
+ excludeFolders: [],
68
+ includeRootIndexFile: true,
69
+ includeFolderIndexFile: false,
70
+
71
+ ...sidebarOptions,
72
+ }
73
+ );
74
+ });
75
+
76
+ return {
77
+ nav: navHeader,
78
+ sidebar: generateSidebar(navSidebar),
79
+ };
80
+ }
81
+
82
+ export default navigation;
@@ -0,0 +1,17 @@
1
+ <script setup>
2
+ import DefaultTheme from 'vitepress/theme';
3
+ import Panzoom from './components/Panzoom.vue';
4
+ import NavigationLinks from './components/NavigationLinks.vue';
5
+
6
+ const { Layout } = DefaultTheme;
7
+ </script>
8
+
9
+ <template>
10
+ <Layout>
11
+ <template #aside-outline-after>
12
+ <NavigationLinks />
13
+ </template>
14
+ </Layout>
15
+
16
+ <Panzoom />
17
+ </template>
@@ -0,0 +1,102 @@
1
+ <script setup>
2
+ import { computed } from 'vue';
3
+ import { useData } from 'vitepress';
4
+
5
+ const { frontmatter, theme } = useData();
6
+
7
+ const headingLabel = computed(() => frontmatter.value.navigationLinksLabel || 'Resources');
8
+
9
+ const links = computed(() => {
10
+ const arr = [];
11
+
12
+ if (frontmatter.value.navigationLinks && Array.isArray(frontmatter.value.navigationLinks) && frontmatter.value.navigationLinks.length) {
13
+ frontmatter.value.navigationLinks.forEach(link => {
14
+ arr.push(formatLink(link));
15
+ });
16
+ }
17
+
18
+ if (theme.value.navigationLinks && Array.isArray(theme.value.navigationLinks) && theme.value.navigationLinks.length && !frontmatter.value.navigationLinksHideGlobal) {
19
+ theme.value.navigationLinks.forEach(link => {
20
+ arr.push(formatLink(link));
21
+ });
22
+ }
23
+
24
+ return arr;
25
+ });
26
+
27
+ function formatLink(linkObj) {
28
+ const { link } = linkObj;
29
+
30
+ return {
31
+ ...linkObj,
32
+ isTargetBlank: link.startsWith('http') || link.startsWith('www'),
33
+ }
34
+ }
35
+ </script>
36
+
37
+ <template>
38
+ <div v-if="links.length" class="nav-links">
39
+ <div v-if="headingLabel?.length" class="nav-links__item">
40
+ <span class="nav-links__heading">{{ headingLabel }}</span>
41
+ </div>
42
+
43
+ <a v-for="(link, idx) in links" :key="idx" :href="link.link" :target="link.isTargetBlank ? '_blank' : '_self'" class="nav-links__item">
44
+ <i v-if="link.icon" :class="`nav-links__icon ti ti-${link.icon}`"></i>
45
+
46
+ <span v-if="link.text" class="nav-links__text">{{ link.text }}</span>
47
+
48
+ <i v-if="link.isTargetBlank" class="nav-links__target ti ti-arrow-up-right"></i>
49
+ </a>
50
+ </div>
51
+ </template>
52
+
53
+ <style lang="scss" scoped>
54
+ .nav-links {
55
+ display: flex;
56
+ flex-direction: column;
57
+ margin: 30px 0 0;
58
+ padding-left: 16px;
59
+ border-left: 1px solid var(--vp-c-divider);
60
+
61
+ // .nav-links__item
62
+ &__item {
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 8px;
66
+ padding: 8px 0;
67
+ color: var(--vp-c-text-2);
68
+ transition: color 0.5s;
69
+
70
+ &:hover {
71
+ color: var(--vp-c-text);
72
+ }
73
+ }
74
+
75
+ // .nav-links__icon
76
+ &__icon {
77
+ font-size: 18px;
78
+ }
79
+
80
+ // .nav-links__heading
81
+ &__heading {
82
+ font-size: 14px;
83
+ font-weight: 600;
84
+ line-height: 1;
85
+ color: rgba(60, 60, 67);
86
+ }
87
+
88
+ // .nav-links__text
89
+ &__text {
90
+ font-size: 14px;
91
+ font-weight: 400;
92
+ line-height: 1;
93
+ }
94
+
95
+ // .nav-links__target
96
+ &__target {
97
+ align-self: flex-start;
98
+ font-size: 12px;
99
+ margin-left: -4px;
100
+ }
101
+ }
102
+ </style>
@@ -0,0 +1,169 @@
1
+ <script setup>
2
+ import { onMounted, nextTick, watch } from 'vue';
3
+ import { useRouter } from 'vitepress';
4
+ import Panzoom from '@panzoom/panzoom';
5
+
6
+ const { route } = useRouter();
7
+
8
+ onMounted(() => createPanzoom());
9
+
10
+ watch(
11
+ () => route.path,
12
+ async () => {
13
+ await nextTick();
14
+
15
+ createPanzoom();
16
+ },
17
+ );
18
+
19
+ function createPanzoom() {
20
+ document.querySelectorAll('img[alt = "zoom"], .mermaid').forEach(async (m) => {
21
+ if (m.panzoom) {
22
+ return false;
23
+ }
24
+
25
+ const wrapper = document.createElement('div');
26
+ wrapper.classList.add('mermaid-wrapper');
27
+
28
+ m.before(wrapper);
29
+
30
+ wrapper.appendChild(m);
31
+
32
+ await nextTick();
33
+
34
+ const pz = Panzoom(m, {
35
+ maxScale: 20,
36
+ minScale: 0.5,
37
+ canvas: true,
38
+ });
39
+
40
+ m.panzoom = pz;
41
+
42
+ wrapper.appendChild(createActions(pz, wrapper, m));
43
+ wrapper.addEventListener('wheel', pz.zoomWithWheel);
44
+ });
45
+ }
46
+
47
+ function createActions(panzoom, wrapper, mermaid) {
48
+ const actions = document.createElement('div');
49
+ actions.classList.add('mermaid-wrapper__actions');
50
+
51
+ actions.appendChild(createZoomIn(panzoom, wrapper, mermaid));
52
+ actions.appendChild(createZoomOut(panzoom, wrapper, mermaid));
53
+ actions.appendChild(createZoomRestore(panzoom, wrapper, mermaid));
54
+ actions.appendChild(createFullScreenToggler(panzoom, wrapper, mermaid));
55
+
56
+ return actions;
57
+ }
58
+
59
+ function createZoomIn(panzoom, wrapper, mermaid) {
60
+ const zoomIn = document.createElement('div');
61
+
62
+ zoomIn.classList.add('mermaid-wrapper__action');
63
+ zoomIn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
64
+ stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 5l0 14" /><path d="M5 12l14 0" /></svg>`;
65
+
66
+ zoomIn.onclick = () => {
67
+ panzoom.zoomIn();
68
+ };
69
+
70
+ return zoomIn;
71
+ }
72
+
73
+ function createZoomOut(panzoom, wrapper, mermaid) {
74
+ const zoomOut = document.createElement('div');
75
+
76
+ zoomOut.classList.add('mermaid-wrapper__action');
77
+ zoomOut.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
78
+ stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l14 0" /></svg>`;
79
+
80
+ zoomOut.onclick = () => {
81
+ panzoom.zoomOut();
82
+ };
83
+
84
+ return zoomOut;
85
+ }
86
+
87
+ function createZoomRestore(panzoom, wrapper, mermaid) {
88
+ const zoomRestore = document.createElement('div');
89
+
90
+ zoomRestore.classList.add('mermaid-wrapper__action');
91
+ zoomRestore.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
92
+ stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M21 21l-6 -6" />
93
+ <path d="M3.268 12.043a7.017 7.017 0 0 0 6.634 4.957a7.012 7.012 0 0 0 7.043 -6.131a7 7 0 0 0 -5.314 -7.672a7.021 7.021 0 0 0 -8.241 4.403" /><path d="M3 4v4h4" /></svg>`;
94
+
95
+ zoomRestore.onclick = () => {
96
+ panzoom.reset();
97
+ };
98
+
99
+ return zoomRestore;
100
+ }
101
+
102
+ function createFullScreenToggler(panzoom, wrapper, mermaid) {
103
+ const fullScreenToggler = document.createElement('div');
104
+
105
+ fullScreenToggler.classList.add('mermaid-wrapper__action');
106
+ fullScreenToggler.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
107
+ stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 8v-2a2 2 0 0 1 2 -2h2" />
108
+ <path d="M4 16v2a2 2 0 0 0 2 2h2" /><path d="M16 4h2a2 2 0 0 1 2 2v2" /><path d="M16 20h2a2 2 0 0 0 2 -2v-2" /></svg>`;
109
+
110
+ fullScreenToggler.onclick = () => {
111
+ panzoom.reset({ animate: false });
112
+ wrapper.classList.toggle('is-fullscreen');
113
+ };
114
+
115
+ return fullScreenToggler;
116
+ }
117
+ </script>
118
+
119
+ <template>
120
+ </template>
121
+
122
+ <style lang="scss">
123
+ .mermaid-wrapper {
124
+ display: block;
125
+ min-height: 168px;
126
+ overflow: hidden;
127
+ position: relative;
128
+ background: var(--vp-c-bg);
129
+
130
+ &__actions {
131
+ position: absolute;
132
+ z-index: 10;
133
+ right: 16px;
134
+ bottom: 16px;
135
+ display: flex;
136
+ flex-direction: column;
137
+ gap: 8px;
138
+ }
139
+
140
+ &__action {
141
+ display: inline-flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ text-align: center;
145
+ font-weight: 600;
146
+ color: var(--vp-button-alt-hover-text);
147
+ background-color: var(--vp-button-alt-hover-bg);
148
+ border-radius: 4px;
149
+ padding: 4px;
150
+ line-height: 1;
151
+ white-space: nowrap;
152
+ cursor: pointer;
153
+
154
+ & > * {
155
+ display: block;
156
+ width: 20px;
157
+ height: 20px;
158
+ font-size: 20px;
159
+ line-height: 1;
160
+ }
161
+ }
162
+
163
+ &.is-fullscreen {
164
+ position: fixed;
165
+ z-index: 1000;
166
+ inset: 0;
167
+ }
168
+ }
169
+ </style>
@@ -0,0 +1,15 @@
1
+ // https://vitepress.dev/guide/custom-theme
2
+ import DefaultTheme from 'vitepress/theme';
3
+ import { enhanceAppWithTabs } from 'vitepress-plugin-tabs/client';
4
+ import './style.scss';
5
+ //import "@tabler/icons-webfont/tabler-icons.css";
6
+ import Layout from './Layout.vue';
7
+
8
+ /** @type {import('vitepress').Theme} */
9
+ export default {
10
+ extends: DefaultTheme,
11
+ Layout: Layout,
12
+ enhanceApp({ app, router, siteData }) {
13
+ enhanceAppWithTabs(app);
14
+ }
15
+ };