@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.
- package/.gitlab-ci.yml +36 -0
- package/config.example +21 -0
- package/docs/.vitepress/abbr.mjs +26 -0
- package/docs/.vitepress/config.mjs +119 -0
- package/docs/.vitepress/navigation.mjs +82 -0
- package/docs/.vitepress/theme/Layout.vue +17 -0
- package/docs/.vitepress/theme/components/NavigationLinks.vue +102 -0
- package/docs/.vitepress/theme/components/Panzoom.vue +169 -0
- package/docs/.vitepress/theme/index.mjs +15 -0
- package/docs/.vitepress/theme/style.scss +136 -0
- package/docs/abbr.json +4 -0
- package/docs/api/builder/cms.builder.delete.md +65 -0
- package/docs/api/builder/cms.builder.get.md +70 -0
- package/docs/api/builder/cms.builder.list.md +98 -0
- package/docs/api/builder/cms.builder.post.md +72 -0
- package/docs/api/builder/cms.builder.put.md +88 -0
- package/docs/api/category/cms.category.delete.md +60 -0
- package/docs/api/category/cms.category.get.md +61 -0
- package/docs/api/category/cms.category.list.md +77 -0
- package/docs/api/category/cms.category.post.md +62 -0
- package/docs/api/category/cms.category.put.md +78 -0
- package/docs/api/index.md +50 -0
- package/docs/api/manager/cms.manager.delete.md +64 -0
- package/docs/api/manager/cms.manager.get.md +72 -0
- package/docs/api/manager/cms.manager.list.md +96 -0
- package/docs/api/manager/cms.manager.post.md +70 -0
- package/docs/api/manager/cms.manager.put.md +86 -0
- package/docs/api/media/del.md +64 -0
- package/docs/api/media/edit.md +92 -0
- package/docs/api/media/list.md +70 -0
- package/docs/api/media/metadata.md +57 -0
- package/docs/api/media/preview.md +33 -0
- package/docs/api/media/upload.md +84 -0
- package/docs/db/erd.md +173 -0
- package/docs/db/index.md +7 -0
- package/docs/index.md +39 -0
- package/docs/public/logo-dark.svg +24 -0
- package/docs/public/logo-light.svg +24 -0
- package/docs/public/logo-short.svg +15 -0
- package/docs/public/logo.svg +19 -0
- package/docs/readme/index.md +6 -0
- package/docs/src/vs-button.vue +157 -0
- package/docs/vue/basic/button.md +144 -0
- package/docs/vue/index.md +9 -0
- package/index.html +14 -0
- package/package.json +2 -5
- package/server/app.js +25 -0
- package/server/config.js +5 -0
- package/server/index.js +23 -0
- package/server/migrations/media.sql +30 -0
- package/server/plugins/hook.js +91 -0
- package/server/plugins/vite.js +80 -0
- package/server/routes/builder/controllers/cms.builder.delete.js +21 -0
- package/server/routes/builder/controllers/cms.builder.get.js +17 -0
- package/server/routes/builder/controllers/cms.builder.list.js +16 -0
- package/server/routes/builder/controllers/cms.builder.post.js +21 -0
- package/server/routes/builder/controllers/cms.builder.put.js +23 -0
- package/server/routes/builder/index.mjs +22 -0
- package/server/routes/category/controllers/cms.category.delete.js +21 -0
- package/server/routes/category/controllers/cms.category.get.js +17 -0
- package/server/routes/category/controllers/cms.category.list.js +16 -0
- package/server/routes/category/controllers/cms.category.post.js +21 -0
- package/server/routes/category/controllers/cms.category.put.js +23 -0
- package/server/routes/category/index.mjs +22 -0
- package/server/routes/manager/controllers/cms.manager.delete.js +22 -0
- package/server/routes/manager/controllers/cms.manager.get.js +21 -0
- package/server/routes/manager/controllers/cms.manager.list.js +31 -0
- package/server/routes/manager/controllers/cms.manager.post.js +28 -0
- package/server/routes/manager/controllers/cms.manager.put.js +23 -0
- package/server/routes/manager/index.mjs +22 -0
- package/server/routes/media/controllers/delete.js +59 -0
- package/server/routes/media/controllers/edit.js +94 -0
- package/server/routes/media/controllers/list.js +74 -0
- package/server/routes/media/controllers/metadata.js +51 -0
- package/server/routes/media/controllers/preview.js +47 -0
- package/server/routes/media/controllers/upload.js +79 -0
- package/server/routes/media/index.mjs +16 -0
- package/server/routes/root.mjs +15 -0
- package/server/templates/cls/cms.category_type.json +10 -0
- package/server/templates/cls/cms.content_review_status.json +10 -0
- package/server/templates/cls/cms.content_status.json +10 -0
- package/server/templates/cls/cms.content_type.json +10 -0
- package/server/templates/cls/cms.lang.json +10 -0
- package/server/templates/page/login.html +59 -0
- package/server/templates/select/cms.category_id.sql +1 -0
- package/server/templates/select/cms.type_id.sql +1 -0
- package/src/App.vue +4 -0
- package/src/assets/tailwind/tailwind.js +62 -0
- package/src/assets/vue.svg +1 -0
- package/src/components/builder/vs-builder-content.vue +163 -0
- package/src/components/builder/vs-builder-menu.vue +142 -0
- package/src/components/formats/index.js +8 -0
- package/src/components/formats/vs-manager-table-date.vue +29 -0
- package/src/components/formats/vs-manager-table-switch.vue +16 -0
- package/src/components/icons/icon-actions.vue +24 -0
- package/src/components/icons/icon-arrow-left.vue +19 -0
- package/src/components/icons/icon-check.vue +23 -0
- package/src/components/icons/icon-chewron-right.vue +16 -0
- package/src/components/icons/icon-close.vue +22 -0
- package/src/components/icons/icon-edit.vue +22 -0
- package/src/components/icons/icon-folder.vue +18 -0
- package/src/components/icons/icon-folder2.vue +17 -0
- package/src/components/icons/icon-home.vue +16 -0
- package/src/components/icons/icon-image.vue +18 -0
- package/src/components/icons/icon-logo.vue +22 -0
- package/src/components/icons/icon-media.vue +22 -0
- package/src/components/icons/icon-point.vue +11 -0
- package/src/components/icons/icon-search.vue +22 -0
- package/src/components/icons/icon-table.vue +22 -0
- package/src/components/icons/icon-users.vue +18 -0
- package/src/components/icons/icon.plus.vue +18 -0
- package/src/components/manager/children/vs-manager-collection-content.vue +55 -0
- package/src/components/manager/children/vs-manager-collection-item-content.vue +116 -0
- package/src/components/manager/children/vs-manager-single-content.vue +112 -0
- package/src/components/manager/manager-table/vs-manager-colection-table-add.vue +84 -0
- package/src/components/manager/manager-table/vs-manager-collection-table.vue +59 -0
- package/src/components/manager/vs-manager-menu.vue +73 -0
- package/src/components/media/Breadcrumb.vue +73 -0
- package/src/components/shared-components/vs-not-data.vue +213 -0
- package/src/components/vs-main-menu.vue +53 -0
- package/src/helpers/debounce.js +10 -0
- package/src/helpers/translite.js +19 -0
- package/src/main.js +30 -0
- package/src/misc/import-file.js +32 -0
- package/src/pages/vs-builder.vue +22 -0
- package/src/pages/vs-layout.vue +17 -0
- package/src/pages/vs-manager.vue +30 -0
- package/src/pages/vs-media.vue +398 -0
- package/src/router/router.js +9 -0
- package/src/router/routes.config.js +40 -0
- package/src/style.css +0 -0
- package/src/templates/form-columns.js +70 -0
- package/src/templates/form-template.js +22 -0
- package/test/config.js +17 -0
- package/test/files/eye.svg +4 -0
- package/test/helper.js +30 -0
- package/test/routes/builder.test.js +99 -0
- package/test/routes/category.test.js +97 -0
- package/test/routes/manager.test.js +103 -0
- package/test/routes/media.test.js +252 -0
- package/vite.config.js +37 -0
- package/editor/dist/cms.js +0 -5900
- package/editor/dist/cms.umd.cjs +0 -19
- /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
|
+
};
|