@smartos-lib/components 1.7.0-beta.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. package/.eslintrc +12 -0
  2. package/.eslintrc-auto-import.json +332 -0
  3. package/Components.code-workspace +143 -0
  4. package/LICENSE +21 -0
  5. package/dist/smart-docx-editor/index.d.ts +2 -0
  6. package/dist/smart-docx-editor/index.js +68 -0
  7. package/dist/smart-file-preview/index.d.ts +18 -0
  8. package/dist/smart-file-preview/index.js +37 -0
  9. package/dist/smart-upload/index.d.ts +2 -0
  10. package/dist/smart-upload/index.js +800 -0
  11. package/index.html +16 -0
  12. package/package.json +23 -0
  13. package/public/favicon.svg +6 -0
  14. package/scripts/components.vite.config.ts +96 -0
  15. package/scripts/shared.ts +9 -0
  16. package/src/App.vue +28 -0
  17. package/src/components/Logo/index.vue +15 -0
  18. package/src/components-private/.gitkeep +0 -0
  19. package/src/composables/useElementStyle.ts +23 -0
  20. package/src/composables/useNaiveStyle.ts +43 -0
  21. package/src/composables/useNaiveTheme.ts +71 -0
  22. package/src/composables/useSmart.ts +36 -0
  23. package/src/layouts/default.vue +3 -0
  24. package/src/main.ts +33 -0
  25. package/src/modules/pinia/index.ts +8 -0
  26. package/src/modules/progress/index.ts +12 -0
  27. package/src/modules/router/install.ts +9 -0
  28. package/src/modules/router/routes.ts +40 -0
  29. package/src/pages/[...all].vue +21 -0
  30. package/src/pages/frame/component/[name].vue +14 -0
  31. package/src/pages/frame/index.vue +81 -0
  32. package/src/pages/index/composables/useTabsManage.ts +46 -0
  33. package/src/pages/index/index.vue +111 -0
  34. package/src/pages/index/type.ts +13 -0
  35. package/src/pages/index/utils/index.ts +41 -0
  36. package/src/settings.ts +9 -0
  37. package/src/shared/components.ts +52 -0
  38. package/src/shared/env.ts +11 -0
  39. package/src/shared/unocss.theme.ts +1600 -0
  40. package/src/stores/theme.ts +29 -0
  41. package/src/styles/element.scss +3 -0
  42. package/src/styles/styles.scss +21 -0
  43. package/src/types.ts +20 -0
  44. package/src/utils/callCustomElementExposed.ts +6 -0
  45. package/src/utils/deepCloneESModule.ts +10 -0
  46. package/src/utils/defineCustomElements.ts +18 -0
  47. package/src/utils/formatComponentsGlob.ts +16 -0
  48. package/src/utils/getFileMD5.ts +31 -0
  49. package/src/utils/getFileNameAndExt.ts +11 -0
  50. package/src/utils/isFileEqual.ts +13 -0
  51. package/src/utils/jsonToFormData.ts +8 -0
  52. package/src/web-components/smart-docx-drive-page/App.vue +37 -0
  53. package/src/web-components/smart-docx-drive-page/apis/doc.ts +85 -0
  54. package/src/web-components/smart-docx-drive-page/apis/file.ts +278 -0
  55. package/src/web-components/smart-docx-drive-page/apis/folder.ts +72 -0
  56. package/src/web-components/smart-docx-drive-page/children/Home.vue +8 -0
  57. package/src/web-components/smart-docx-drive-page/children/Me.vue +47 -0
  58. package/src/web-components/smart-docx-drive-page/components/CustomImage.vue +26 -0
  59. package/src/web-components/smart-docx-drive-page/components/CustomPopover.vue +62 -0
  60. package/src/web-components/smart-docx-drive-page/components/DocxDir.vue +99 -0
  61. package/src/web-components/smart-docx-drive-page/components/DocxDoc.vue +132 -0
  62. package/src/web-components/smart-docx-drive-page/components/DocxDownloadPopoverItem.vue +41 -0
  63. package/src/web-components/smart-docx-drive-page/components/DocxFileList.vue +156 -0
  64. package/src/web-components/smart-docx-drive-page/components/DocxPreview.vue +33 -0
  65. package/src/web-components/smart-docx-drive-page/components/DocxUpload.vue +164 -0
  66. package/src/web-components/smart-docx-drive-page/components/FileIcon.vue +62 -0
  67. package/src/web-components/smart-docx-drive-page/components-private/Header.vue +65 -0
  68. package/src/web-components/smart-docx-drive-page/components-private/Logo.vue +15 -0
  69. package/src/web-components/smart-docx-drive-page/components-private/Menu.vue +34 -0
  70. package/src/web-components/smart-docx-drive-page/components-private/Navbar.vue +36 -0
  71. package/src/web-components/smart-docx-drive-page/composables/useFullscreenElDialog.ts +41 -0
  72. package/src/web-components/smart-docx-drive-page/composables/usePrompt.ts +73 -0
  73. package/src/web-components/smart-docx-drive-page/data.ts +10 -0
  74. package/src/web-components/smart-docx-drive-page/external-style/custom-popover.sass +8 -0
  75. package/src/web-components/smart-docx-drive-page/external-style/index.sass +1 -0
  76. package/src/web-components/smart-docx-drive-page/index.ts +20 -0
  77. package/src/web-components/smart-docx-drive-page/index.vue +39 -0
  78. package/src/web-components/smart-docx-drive-page/info.ts +2 -0
  79. package/src/web-components/smart-docx-drive-page/stores/menu.ts +60 -0
  80. package/src/web-components/smart-docx-drive-page/types.ts +51 -0
  81. package/src/web-components/smart-docx-drive-page/utils/file-actions.ts +63 -0
  82. package/src/web-components/smart-docx-drive-page/utils/file.ts +31 -0
  83. package/src/web-components/smart-docx-editor/App.vue +32 -0
  84. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components/Markdown.vue +202 -0
  85. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components/Menu.vue +100 -0
  86. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components/types.ts +6 -0
  87. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/Markdown.tsx +71 -0
  88. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/MarkdownElement.tsx +81 -0
  89. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Blockquote/index.sass +6 -0
  90. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Blockquote/index.tsx +12 -0
  91. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Heading/index.sass +14 -0
  92. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Heading/index.tsx +17 -0
  93. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/List/index.scss +16 -0
  94. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/List/index.tsx +39 -0
  95. package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/types/custom-types.d.ts +69 -0
  96. package/src/web-components/smart-docx-editor/MarkdownShortcuts/composables/useTextSelection.ts +50 -0
  97. package/src/web-components/smart-docx-editor/MarkdownShortcuts/index.sass +19 -0
  98. package/src/web-components/smart-docx-editor/MarkdownShortcuts/index.vue +21 -0
  99. package/src/web-components/smart-docx-editor/MarkdownShortcuts/shared/const.ts +23 -0
  100. package/src/web-components/smart-docx-editor/MarkdownShortcuts/utils/slateHelpers.ts +23 -0
  101. package/src/web-components/smart-docx-editor/data.ts +38 -0
  102. package/src/web-components/smart-docx-editor/demo.vue +11 -0
  103. package/src/web-components/smart-docx-editor/index.md +3 -0
  104. package/src/web-components/smart-docx-editor/index.ts +5 -0
  105. package/src/web-components/smart-docx-editor/index.vue +12 -0
  106. package/src/web-components/smart-docx-editor/info.ts +2 -0
  107. package/src/web-components/smart-file-preview/category/Code.vue +171 -0
  108. package/src/web-components/smart-file-preview/category/Image.vue +49 -0
  109. package/src/web-components/smart-file-preview/category/Pdf.vue +14 -0
  110. package/src/web-components/smart-file-preview/category/Video.vue +27 -0
  111. package/src/web-components/smart-file-preview/demo.vue +34 -0
  112. package/src/web-components/smart-file-preview/index.md +5 -0
  113. package/src/web-components/smart-file-preview/index.ts +29 -0
  114. package/src/web-components/smart-file-preview/index.vue +56 -0
  115. package/src/web-components/smart-file-preview/info.ts +2 -0
  116. package/src/web-components/smart-file-preview/shared/const.ts +4 -0
  117. package/src/web-components/smart-file-preview/types.ts +38 -0
  118. package/src/web-components/smart-upload/index.ts +5 -0
  119. package/src/web-components/smart-upload/index.vue +101 -0
  120. package/src/web-components/smart-upload/info.ts +2 -0
  121. package/src/web-components/smart-upload/types.ts +28 -0
  122. package/tsconfig.json +15 -0
  123. package/types/auto-imports.d.ts +975 -0
  124. package/types/components.d.ts +14 -0
  125. package/types/env.d.ts +8 -0
  126. package/types/shims.d.ts +6 -0
  127. package/unocss.config.ts +23 -0
  128. package/vite.config.ts +60 -0
package/index.html ADDED
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta http-equiv="Expires" content="0">
7
+ <meta http-equiv="Pragma" content="no-cache">
8
+ <meta http-equiv="Cache-control" content="no-cache">
9
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
10
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml">
11
+ </head>
12
+ <body>
13
+ <div id="app"></div>
14
+ <script type="module" src="/src/main.ts"></script>
15
+ </body>
16
+ </html>
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@smartos-lib/components",
3
+ "type": "module",
4
+ "version": "1.7.0-beta.0",
5
+ "packageManager": "pnpm@8.14.3",
6
+ "author": "Wei Zhang <https://github.com/Zhang-Wei-666>",
7
+ "devDependencies": {
8
+ "@rollup/pluginutils": "^5.1.0",
9
+ "@types/prompts": "^2.4.9",
10
+ "pinia": "^2.1.7",
11
+ "prompts": "^2.4.2",
12
+ "vite-plugin-inspect": "^0.8.2",
13
+ "vite-plugin-pages": "^0.32.0",
14
+ "vite-plugin-vue-layouts": "^0.11.0",
15
+ "vue-router": "^4.2.5"
16
+ },
17
+ "scripts": {
18
+ "dev": "pnpm install && vite --host",
19
+ "build": "cd ../../ && pnpm build:components-prompts",
20
+ "build:editor": "pnpm install && vite build:components-prompts",
21
+ "preview": "pnpm install && vite build && vite preview --host"
22
+ }
23
+ }
@@ -0,0 +1,6 @@
1
+ <svg width="234" height="234" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M187.197 10h46.797L117.001 224.805.008 10h89.5L117 59.81 143.91 10h43.287Z" fill="#41B883"/>
3
+ <path d="M.008 10 117 224.805 233.994 10h-46.797l-70.196 128.883L46.221 10H.007Z" fill="#41B883"/>
4
+ <path d="M46.219 10 117 139.506 187.196 10h-43.288L117 59.81 89.506 10H46.22Z" fill="#35495E"/>
5
+ <path d="M210.562 138.833v14.557h-78.124v-14.557h78.124Zm0-7.278h-78.124c-2.073 0-4.06.767-5.525 2.131-1.465 1.365-2.288 3.217-2.288 5.147v14.557c0 1.93.823 3.781 2.288 5.146 1.465 1.365 3.452 2.132 5.525 2.132h78.124c2.073 0 4.06-.767 5.525-2.132 1.465-1.365 2.288-3.216 2.288-5.146v-14.557c0-1.93-.823-3.782-2.288-5.147-1.465-1.364-3.452-2.131-5.525-2.131Zm-62.5 43.67v36.391h-15.624v-36.391h15.624Zm0-7.279h-15.624c-2.073 0-4.06.767-5.525 2.132-1.465 1.365-2.288 3.216-2.288 5.147v36.391c0 1.93.823 3.782 2.288 5.147 1.465 1.365 3.452 2.131 5.525 2.131h15.624c2.073 0 4.06-.766 5.525-2.131 1.465-1.365 2.288-3.217 2.288-5.147v-36.391c0-1.931-.823-3.782-2.288-5.147-1.465-1.365-3.452-2.132-5.525-2.132Zm62.5 7.279v36.391H171.5v-36.391h39.062Zm0-7.279H171.5c-2.072 0-4.059.767-5.524 2.132-1.465 1.365-2.288 3.216-2.288 5.147v36.391c0 1.93.823 3.782 2.288 5.147 1.465 1.365 3.452 2.131 5.524 2.131h39.062c2.073 0 4.06-.766 5.525-2.131 1.465-1.365 2.288-3.217 2.288-5.147v-36.391c0-1.931-.823-3.782-2.288-5.147-1.465-1.365-3.452-2.132-5.525-2.132Z" fill="#000"/>
6
+ </svg>
@@ -0,0 +1,96 @@
1
+ import { dirname, resolve } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import type { UserConfig } from 'vite';
4
+ import { defineConfig } from 'vite';
5
+ import Vue from '@vitejs/plugin-vue';
6
+ import VueJsx from '@vitejs/plugin-vue-jsx';
7
+ import React from '@vitejs/plugin-react';
8
+ import Unocss from 'unocss/vite';
9
+ import Components from 'unplugin-vue-components/vite';
10
+ import IconsResolver from 'unplugin-icons/resolver';
11
+ import { ElementPlusResolver, NaiveUiResolver } from 'unplugin-vue-components/resolvers';
12
+ import { viteVueCESubStyle } from '@unplugin-vue-ce/sub-style';
13
+ import ViteCommonPlugins from '../../.vitepress/vite.common.plugins';
14
+ import { isCustomElementRE, viteCssConfig } from './shared';
15
+
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+
18
+ export default (options: CreateViteBaseConfigOptions = {}) => {
19
+ const plugins = options.plugins || [];
20
+
21
+ return defineConfig({
22
+ plugins: [
23
+ ...plugins,
24
+
25
+ // Vue 3 支持
26
+ Vue({
27
+ customElement: [isCustomElementRE],
28
+ script: {
29
+ defineModel: true,
30
+ },
31
+ template: {
32
+ compilerOptions: {
33
+ isCustomElement: tag => tag.startsWith('smart-'),
34
+ },
35
+ },
36
+ }),
37
+ // Vue JSX 支持
38
+ {
39
+ ...VueJsx({
40
+ exclude: [/[/\\]components-react[\\/$]+/],
41
+ }),
42
+ enforce: 'pre',
43
+ },
44
+ {
45
+ config: () => ({
46
+ esbuild: {
47
+ include: /\.[jt]sx*$/,
48
+ },
49
+ }),
50
+ },
51
+ // React 支持
52
+ React(),
53
+ // 子组件样式支持
54
+ viteVueCESubStyle(),
55
+ // 原子化 CSS 引擎 ( 供 Web Components 使用 )
56
+ Unocss({
57
+ configFile: resolve(__dirname, '../unocss.config.ts'),
58
+ mode: 'vue-scoped',
59
+ content: {
60
+ pipeline: {
61
+ include: [isCustomElementRE],
62
+ },
63
+ },
64
+ }),
65
+ // 自动导入使用到的组件
66
+ Components({
67
+ dts: resolve(__dirname, '../types/components.d.ts'),
68
+ dirs: [
69
+ resolve(__dirname, '../src/components'),
70
+ resolve(__dirname, '../src/components-private'),
71
+ ],
72
+ resolvers: [
73
+ // 自动导入图标组件
74
+ IconsResolver({ prefix: 'i' }),
75
+ // 自动导入 Naive UI 组件
76
+ NaiveUiResolver(),
77
+ // 自动导入 Element Plus 组件
78
+ ElementPlusResolver({ importStyle: false }),
79
+ ],
80
+ }),
81
+
82
+ ...ViteCommonPlugins({
83
+ autoImportDirs: [
84
+ resolve(__dirname, '../src/composables'),
85
+ resolve(__dirname, '../src/stores'),
86
+ ],
87
+ }),
88
+ ],
89
+ css: viteCssConfig,
90
+ });
91
+ };
92
+
93
+ interface CreateViteBaseConfigOptions {
94
+ /** 需要额外插入的 vite 插件 */
95
+ plugins?: UserConfig['plugins']
96
+ }
@@ -0,0 +1,9 @@
1
+ export const isCustomElementRE = /\/web-components\/.*\/.*\.vue$/;
2
+
3
+ export const viteCssConfig = {
4
+ preprocessorOptions: {
5
+ scss: {
6
+ additionalData: '@use "~/styles/element.scss" as *;',
7
+ },
8
+ },
9
+ };
package/src/App.vue ADDED
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <!-- 全局化配置 ( 主题 ) -->
3
+ <NConfigProvider :theme="theme" :theme-overrides="themeOverrides" :locale="zhCN" :date-locale="dateZhCN" abstract>
4
+ <!-- 加载条 ( 页面加载进度 ) -->
5
+ <NLoadingBarProvider>
6
+ <router-view />
7
+ <GetAppEnv />
8
+ </NLoadingBarProvider>
9
+ <!-- 全局样式 ( 写入一些样式至 body 层 ) -->
10
+ <NGlobalStyle />
11
+ </NConfigProvider>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import { useLoadingBar } from 'naive-ui';
16
+ import { app } from '@/shared/env';
17
+ import { settings } from '@/settings';
18
+
19
+ /** 主题相关 */
20
+ const { theme, themeOverrides, zhCN, dateZhCN } = useNaiveTheme();
21
+
22
+ /** 获取当前应用的一些环境变量 */
23
+ function GetAppEnv() {
24
+ app.loadingBar = useLoadingBar();
25
+ }
26
+
27
+ useTitle(settings.name);
28
+ </script>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <div class="relative" :class="props.size">
3
+ <i-logos-vue class="size-full" />
4
+ <i-carbon-template class="size-1/2 absolute right-0 bottom-0" />
5
+ </div>
6
+ </template>
7
+
8
+ <script lang="ts" setup>
9
+ const props = defineProps({
10
+ size: {
11
+ type: String,
12
+ default: 'size-12',
13
+ },
14
+ });
15
+ </script>
File without changes
@@ -0,0 +1,23 @@
1
+ /* eslint-disable @typescript-eslint/indent */
2
+
3
+ import elementPlusStyle from 'element-plus/theme-chalk/src/index.scss?inline';
4
+
5
+ /**
6
+ * 挂载 Element Plus UI 的样式到 web components 组件中
7
+ */
8
+ export function useElementStyle() {
9
+ const el = useCurrentElement();
10
+
11
+ onMounted(() => {
12
+ const shadowRoot = el.value!.parentNode!;
13
+ const style = document.createElement('style');
14
+ style.setAttribute('namespace', 'smart');
15
+
16
+ // 添加 element-plus 的样式到组件中
17
+ shadowRoot.appendChild(style).textContent = elementPlusStyle;
18
+
19
+ // 添加 element-plus 的样式到 document.head 中
20
+ // 因为 MessageBox、Notification 等组件是挂载在 document.body 上的, 否则样式不生效
21
+ document.querySelector('style[namespace="smart"]') || (document.head.appendChild(style.cloneNode()).textContent = elementPlusStyle);
22
+ });
23
+ }
@@ -0,0 +1,43 @@
1
+ import { uniqueKeyCustomizer } from 'mixte';
2
+
3
+ /**
4
+ * 挂载 Naive UI 的样式到 web components 组件中
5
+ * @param classPrefix 自定义组件的类的前缀, 默认为随机字符串
6
+ * @example
7
+ *
8
+ * // js
9
+ * const classPrefix = useNaiveStyle();
10
+ *
11
+ * // template
12
+ * <n-config-provider :cls-prefix="classPrefix">
13
+ * <n-select />
14
+ * </n-config-provider>
15
+ */
16
+ export function useNaiveStyle(classPrefix = uniqueKeyCustomizer()) {
17
+ const el = useCurrentElement();
18
+ const selectors = `style[cssr-id^="${classPrefix}-"]`;
19
+
20
+ onMounted(() => {
21
+ // Naive UI 的样式是动态插入到 document.head 中的
22
+ // 所以监听 document.head 中样式的变化, 并将同样前缀的样式其插入到组件中
23
+ function insertStyle() {
24
+ const shadowRoot = el.value!.parentNode!;
25
+
26
+ shadowRoot.querySelectorAll(selectors).forEach((style) => {
27
+ shadowRoot.removeChild(style);
28
+ });
29
+
30
+ Array.from(document.querySelectorAll(selectors)).forEach((style) => {
31
+ shadowRoot.appendChild(style.cloneNode()).textContent = style.textContent;
32
+ });
33
+ }
34
+
35
+ useMutationObserver(document.head, insertStyle, {
36
+ childList: true,
37
+ });
38
+
39
+ insertStyle();
40
+ });
41
+
42
+ return classPrefix;
43
+ }
@@ -0,0 +1,71 @@
1
+ import type { GlobalThemeOverrides } from 'naive-ui';
2
+ import { darkTheme, dateZhCN, zhCN } from 'naive-ui';
3
+ import { deepMerge } from 'mixte';
4
+ import { colors, fontFamily } from '@/shared/unocss.theme';
5
+
6
+ /** 通用主题变量覆盖 */
7
+ export const commonOverrides: GlobalThemeOverrides = {
8
+ common: {
9
+ // 默认字体
10
+ fontFamily: fontFamily.sans,
11
+ // 等宽字体
12
+ fontFamilyMono: fontFamily.mono,
13
+
14
+ // Primary 颜色
15
+ primaryColor: colors.primary,
16
+ primaryColorHover: colors['primary-hover'],
17
+ primaryColorPressed: colors['primary-active'],
18
+ primaryColorSuppl: colors.primary,
19
+ // Info 颜色
20
+ infoColor: colors.info,
21
+ infoColorHover: colors['info-hover'],
22
+ infoColorPressed: colors['info-active'],
23
+ infoColorSuppl: colors.info,
24
+ // Success 颜色
25
+ successColor: colors.success,
26
+ successColorHover: colors['success-hover'],
27
+ successColorPressed: colors['success-active'],
28
+ successColorSuppl: colors.success,
29
+ // Warning 颜色
30
+ warningColor: colors.warning,
31
+ warningColorHover: colors['warning-hover'],
32
+ warningColorPressed: colors['warning-active'],
33
+ warningColorSuppl: colors.warning,
34
+ // Error 颜色
35
+ errorColor: colors.error,
36
+ errorColorHover: colors['error-hover'],
37
+ errorColorPressed: colors['error-active'],
38
+ errorColorSuppl: colors.error,
39
+ },
40
+ };
41
+
42
+ /** 亮色主题变量覆盖 */
43
+ export const lightThemeOverrides: GlobalThemeOverrides = deepMerge({}, commonOverrides, {
44
+
45
+ });
46
+ /** 深色主题变量覆盖 */
47
+ export const darkThemeOverrides: GlobalThemeOverrides = deepMerge({}, commonOverrides, {
48
+ Button: {
49
+ textColorPrimary: '#FFF',
50
+ textColorHoverPrimary: '#FFF',
51
+ textColorPressedPrimary: '#FFF',
52
+ textColorFocusPrimary: '#FFF',
53
+ textColorDisabledPrimary: '#FFF',
54
+ },
55
+ });
56
+
57
+ export const useNaiveTheme = createSharedComposable(() => {
58
+ const themeStore = useThemeStore();
59
+
60
+ /** 当前 Naive UI 主题 */
61
+ const theme = computed(() => themeStore.dark ? darkTheme : null);
62
+ /** 对当前 NaiveUI 主题的变量覆盖 */
63
+ const themeOverrides = computed(() => themeStore.dark ? darkThemeOverrides : lightThemeOverrides);
64
+
65
+ return {
66
+ theme,
67
+ themeOverrides,
68
+ zhCN,
69
+ dateZhCN,
70
+ };
71
+ });
@@ -0,0 +1,36 @@
1
+ /* eslint-disable @typescript-eslint/indent */
2
+
3
+ import { version } from '@@/package.json';
4
+
5
+ /**
6
+ * SmartOS 相关组件的公用处理逻辑
7
+ */
8
+ export function useSmart() {
9
+ const el = useCurrentElement();
10
+
11
+ onMounted(() => {
12
+ const shadowRoot = el.value!.parentNode!; // @ts-expect-error
13
+ const { tailwindResetStyle, elementPlusStyle } = globalThis.SmartCore?.[version] ?? {};
14
+
15
+ // 挂载 Tailwind Reset 的样式
16
+ if (tailwindResetStyle)
17
+ shadowRoot.appendChild(document.createElement('style')).textContent = tailwindResetStyle;
18
+
19
+ // 挂载 Element Plus UI 的样式
20
+ if (elementPlusStyle) {
21
+ const style = document.createElement('style');
22
+ style.setAttribute('namespace', 'smart');
23
+
24
+ // 添加 element-plus 的样式到组件中
25
+ shadowRoot.appendChild(style).textContent = elementPlusStyle;
26
+
27
+ // 添加 element-plus 的样式到 document.head 中
28
+ // 因为 MessageBox、Notification 等组件是挂载在 document.body 上的, 否则样式不生效
29
+ document.querySelector('style[namespace="smart"]') || (document.head.appendChild(style.cloneNode()).textContent = elementPlusStyle);
30
+ }
31
+ });
32
+
33
+ return {
34
+ classPrefix: useNaiveStyle(),
35
+ };
36
+ }
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <router-view />
3
+ </template>
package/src/main.ts ADDED
@@ -0,0 +1,33 @@
1
+ import { isString } from 'mixte';
2
+ import App from './App.vue';
3
+ import type { UserModule } from './types';
4
+ import router from '@/modules/router/install';
5
+
6
+ import '@unocss/reset/tailwind.css';
7
+ import 'uno.css';
8
+ import '@/styles/styles.scss';
9
+
10
+ // 修复 Naive UI 和 Tailwind Reset 的样式冲突
11
+ document.head.insertAdjacentHTML('beforeend', '<meta name="naive-ui-style" />');
12
+
13
+ const app = createApp(App);
14
+
15
+ app.use(router);
16
+
17
+ Object.values(import.meta.glob<{ install: UserModule }>('./modules/**/index.ts', { eager: true })).forEach(m => m.install?.({ app, router }));
18
+
19
+ router.isReady().then(() => {
20
+ app.mount('#app');
21
+ });
22
+
23
+ const { warn, info } = console;
24
+
25
+ console.warn = (message?: any, ...optionalParams: any[]) => {
26
+ if (isString(message) && message.startsWith('[Vue warn]: Extraneous non-props attributes (data')) return;
27
+ warn.call(console, message, ...optionalParams);
28
+ };
29
+
30
+ console.info = (message?: any, ...optionalParams: any[]) => { // eslint-disable-line no-console
31
+ if (isString(message) && message.includes('Download the React DevTools')) return;
32
+ info.call(console, message, ...optionalParams);
33
+ };
@@ -0,0 +1,8 @@
1
+ import { createPinia } from 'pinia';
2
+ import type { UserModule } from '@/types';
3
+
4
+ export const install: UserModule = ({ app }) => {
5
+ const pinia = createPinia();
6
+
7
+ app.use(pinia);
8
+ };
@@ -0,0 +1,12 @@
1
+ import type { UserModule } from '@/types';
2
+ import { app } from '@/shared/env';
3
+
4
+ export const install: UserModule = ({ router }) => {
5
+ router.beforeEach(() => {
6
+ app.loadingBar?.start();
7
+ });
8
+
9
+ router.afterEach(() => {
10
+ app.loadingBar?.finish();
11
+ });
12
+ };
@@ -0,0 +1,9 @@
1
+ import { createRouter, createWebHistory } from 'vue-router';
2
+ import routes from './routes';
3
+
4
+ const router = createRouter({
5
+ history: createWebHistory(),
6
+ routes,
7
+ });
8
+
9
+ export default router;
@@ -0,0 +1,40 @@
1
+ import type { RouteComponent, RouteRecordRaw } from 'vue-router';
2
+ import { isESModule, isFunction, isPlainObject, leastRun } from 'mixte';
3
+ import { camelCase, upperFirst } from 'lodash-es';
4
+ import { setupLayouts } from 'virtual:generated-layouts';
5
+ import generatedRoutes from 'virtual:generated-pages';
6
+
7
+ /** 定义页面组件名称为路由名称 */
8
+ function defineComponentName(route: RouteRecordRaw, component: RouteComponent) {
9
+ if (component.name) return component;
10
+ return Object.assign({}, component, {
11
+ name: upperFirst(camelCase(route.name as string)),
12
+ });
13
+ }
14
+
15
+ /** 遍历路由 */
16
+ function eachRoutes(routes: RouteRecordRaw[]) {
17
+ routes.forEach((route) => {
18
+ const component = route.component;
19
+
20
+ // 对象形式的页面组件
21
+ if (isPlainObject(component)) {
22
+ route.component = defineComponentName(route, component);
23
+ }
24
+ // 页面组件是一个方法
25
+ else if (isFunction(component)) {
26
+ // @ts-expect-error
27
+ route.component = () => leastRun(0, component).then((m) => {
28
+ return defineComponentName(route, isESModule(m) ? m.default : m);
29
+ });
30
+ }
31
+
32
+ // 存在子路由
33
+ if (route.children)
34
+ eachRoutes(route.children);
35
+ });
36
+ }
37
+
38
+ eachRoutes(generatedRoutes);
39
+
40
+ export default setupLayouts(generatedRoutes);
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <div class="px-4 py-10 text-center">
3
+ <div class="text-5xl">
4
+ <i-bx-message-alt-x class="inline-block" />
5
+ </div>
6
+
7
+ <div class="mt-1">
8
+ 未找到页面
9
+ </div>
10
+
11
+ <div class="mt-6">
12
+ <NButton type="primary" @click="router.back()">
13
+ 返回
14
+ </NButton>
15
+ </div>
16
+ </div>
17
+ </template>
18
+
19
+ <script lang="ts" setup>
20
+ const router = useRouter();
21
+ </script>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <Index :component="name" />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ import Index from '../index.vue';
7
+
8
+ const route = useRoute();
9
+ const name = computed(() => route.params.name as string);
10
+ </script>
11
+
12
+ <route lang="yaml">
13
+ name: Frame/Component
14
+ </route>
@@ -0,0 +1,81 @@
1
+ <template>
2
+ <div class="min-h-screen flex">
3
+ <div class="w-full flex-grow">
4
+ <template v-if="tab && isReady">
5
+ <component :is="tab.component" v-bind="finalData" />
6
+ </template>
7
+ </div>
8
+ </div>
9
+ </template>
10
+
11
+ <script lang="ts" setup>
12
+ import { isFunction } from 'mixte';
13
+ import { setConfigProvider } from '@smartos-lib/core';
14
+ import type { Tab } from '../index/type';
15
+ import { LOGIN_AJAX_CONFIG, createAxiosInstance } from '../../../../apis/test-utils/env';
16
+ import { components } from '@/shared/components';
17
+
18
+ interface Props {
19
+ /** 指定渲染的组件名称 */
20
+ component?: string
21
+ }
22
+
23
+ const props = defineProps<Props>();
24
+
25
+ /** 组件是否加载完成 */
26
+ const isReady = ref(false);
27
+
28
+ /** 所有的选项卡信息 */
29
+ const tabs = useLocalStorage<Tab[]>('st-tabs', []);
30
+ /** 当前选项卡信息 */
31
+ const tab = computed(() => props.component ? ({ component: props.component } as Tab) : tabs.value.find(tab => tab.id === window.name));
32
+ /** 当前选项卡测试数据 */
33
+ const data = computed(() => components[tab.value?.component as string]?.data?.[tab.value?.data as string] || {});
34
+ /** 最终使用的选项卡数据 - 支持使用函数返回测试数据 */
35
+ const finalData = computed(() => {
36
+ return isFunction(data.value) ? data.value({ reloadCount: tab.value?.dataReloadCount ?? 0 }) : data.value;
37
+ });
38
+
39
+ /** Token */
40
+ const token = ref('');
41
+ /** 创建一个新的 axios 实例 */
42
+ const request = createAxiosInstance('/', token);
43
+
44
+ /** 发起登录请求 */
45
+ const login = useRequest(() => {
46
+ return request(LOGIN_AJAX_CONFIG);
47
+ });
48
+
49
+ login.onSuccess(() => {
50
+ token.value = login.data.value?.access_token;
51
+ });
52
+
53
+ // 加载组件
54
+ watchEffect(async () => {
55
+ const name = tab.value?.component;
56
+ const component = components[name as string];
57
+
58
+ if (component) {
59
+ // SmartOS 组件库, 需要先加载 '@smartos-lib/core/componentsProvider' 依赖
60
+ if (name!.startsWith('smart-')) {
61
+ setConfigProvider({ request });
62
+ login.execute();
63
+ await import('@smartos-lib/core/componentsProvider');
64
+ }
65
+
66
+ component?.index().then(() => {
67
+ isReady.value = true;
68
+
69
+ // 云文档云服务页, 依赖这几个组件, 所以也需要加载过来
70
+ if (name === 'smart-docx-drive-page') {
71
+ components['smart-file-preview']?.index();
72
+ components['smart-docx-editor']?.index();
73
+ }
74
+ });
75
+ }
76
+ });
77
+ </script>
78
+
79
+ <route lang="yaml">
80
+ name: Frame
81
+ </route>
@@ -0,0 +1,46 @@
1
+ import { uniqueKey } from 'mixte';
2
+ import type { Tab } from '../type';
3
+ import { components } from '@/shared/components';
4
+
5
+ /** 选项卡管理 */
6
+ export function useTabsManage() {
7
+ /** 所有的选项卡信息 */
8
+ const tabs = useLocalStorage<Tab[]>('st-tabs', []);
9
+ /** 当前激活的选项卡 ID */
10
+ const activeTabId = useLocalStorage<string>('st-active-tab-id', '');
11
+ /** 当前激活的选项卡 */
12
+ const activeTab = computed(() => tabs.value.find(tab => tab.id === activeTabId.value));
13
+ /** 当前激活的选项卡的测试数据 */
14
+ const activeTabData = computed(() => components[activeTab.value?.component as string]?.data);
15
+
16
+ /** 创建一个新选项卡 */
17
+ function createTab(component: string) {
18
+ const id = uniqueKey(tabs.value);
19
+
20
+ tabs.value.push({
21
+ id,
22
+ component,
23
+ });
24
+
25
+ activeTabId.value = id;
26
+ }
27
+
28
+ /** 关闭一个选项卡 */
29
+ function closeTab(id: string) {
30
+ const index = tabs.value.findIndex(tab => tab.id === id);
31
+
32
+ if (index > -1) {
33
+ tabs.value.splice(index, 1);
34
+ activeTabId.value === id && (activeTabId.value = tabs.value[Math.min(index, tabs.value.length - 1)]?.id);
35
+ }
36
+ }
37
+
38
+ return {
39
+ activeTab,
40
+ activeTabId,
41
+ activeTabData,
42
+ tabs,
43
+ createTab,
44
+ closeTab,
45
+ };
46
+ }