diff --git a/.gitignore b/.gitignore index b5ace4eb2f043911b03fbfa43aefa5bf28dc6c8f..dd5adcc5836224df88faf223b04fb0b62254241b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ yarn-error.log .history .vscode devui/vue-devui.ts +devui/theme/theme.scss diff --git a/devui-cli/commands/build.js b/devui-cli/commands/build.js index 1d2090d8e5f5cc8bb4694707d4cbf39813c1ef31..48c472f47b673f88f715fc4b738f97ea93d45a35 100644 --- a/devui-cli/commands/build.js +++ b/devui-cli/commands/build.js @@ -1,11 +1,12 @@ const path = require('path') const fs = require('fs') +const fsExtra = require('fs-extra') const { defineConfig, build } = require('vite') const vue = require('@vitejs/plugin-vue') const vueJsx = require('@vitejs/plugin-vue-jsx') -const entryDir = path.resolve(__dirname, '../devui') -const outputDir = path.resolve(__dirname, '../build') +const entryDir = path.resolve(__dirname, '../../devui') +const outputDir = path.resolve(__dirname, '../../build') const baseConfig = defineConfig({ configFile: false, @@ -54,6 +55,22 @@ const buildAll = async () => { })) } +const createPackageJson = (name) => { + const fileStr = `{ + "name": "${name}", + "version": "0.0.0", + "main": "index.umd.js", + "module": "index.es.js", + "style": "style.css" +}` + + fsExtra.outputFile( + path.resolve(outputDir, `${name}/package.json`), + fileStr, + 'utf-8' + ) +} + exports.build = async () => { await buildAll() @@ -65,5 +82,6 @@ exports.build = async () => { for(const name of components) { await buildSingle(name) + createPackageJson(name) } } diff --git a/devui-cli/commands/generate-theme.js b/devui-cli/commands/generate-theme.js new file mode 100644 index 0000000000000000000000000000000000000000..3acfa026b87d7bc467abdb1015a9d2cae6cc2d0b --- /dev/null +++ b/devui-cli/commands/generate-theme.js @@ -0,0 +1,16 @@ +require('esbuild-register') +const path = require('path') +const fs = require('fs-extra') +const theme = require('../../devui/theme/themes/light.ts').default + +const fileStr = Object.entries(theme) +.map(([key, value]) => `$${key}: var(--${key}, ${value})`) +.join(';\n') + +exports.generateTheme = async () => { + await fs.outputFile( + path.resolve(__dirname, '../../devui/theme/theme.scss'), + fileStr, + 'utf-8' + ) +} \ No newline at end of file diff --git a/devui-cli/index.js b/devui-cli/index.js index 24f11c31cce75277a294fa522ced1dee9cf571da..d4ed9906e6fe7e2f2b8c41cab1765391bdae6fd0 100755 --- a/devui-cli/index.js +++ b/devui-cli/index.js @@ -2,6 +2,7 @@ const { Command } = require('commander') const { create, validateCreateType } = require('./commands/create') const { build } = require('./commands/build') +const { generateTheme } = require('./commands/generate-theme') const { VERSION, CREATE_SUPPORT_TYPES } = require('./shared/constant') const program = new Command() @@ -19,4 +20,9 @@ program .description('打包组件库') .action(build) +program + .command('generate:theme') + .description('生成主题变量文件') + .action(generateTheme) + program.parse().version(VERSION) diff --git a/devui-cli/shared/constant.js b/devui-cli/shared/constant.js index da844a75cc26c20ea35491f9a2eb2b984f423f01..e71ce99a1d6b30a9e8e69cb78d6cc8a83dd6840c 100644 --- a/devui-cli/shared/constant.js +++ b/devui-cli/shared/constant.js @@ -29,7 +29,8 @@ exports.COMPONENT_PARTS_MAP = new Map([ exports.CREATE_SUPPORT_TYPE_MAP = Object.freeze({ component: 'component', 'vue-devui': 'vue-devui', - 'vitepress/sidebar': 'vitepress/sidebar' + 'vitepress/sidebar': 'vitepress/sidebar', + 'theme-variable': 'theme-variable', }) exports.CREATE_SUPPORT_TYPES = Object.keys(this.CREATE_SUPPORT_TYPE_MAP) exports.CREATE_UNFINISHED_TYPES = [] diff --git a/devui/anchor/src/anchor.scss b/devui/anchor/src/anchor.scss index f64724c16d44990d33fb32d49f68da4eada7c29c..0e6c03cd355c35d70914b15afa8f05837b7fa7f7 100644 --- a/devui/anchor/src/anchor.scss +++ b/devui/anchor/src/anchor.scss @@ -5,13 +5,15 @@ left: 0; height: auto; } + .scrollTarget { - height: 450px!important; + height: 450px !important; overflow-y: auto; } + .mycontainer { height: auto; - + // overflow-y: auto; } @@ -58,7 +60,7 @@ body > * ::-webkit-scrollbar-thumb:hover { body > * ::-webkit-scrollbar-corner { background-color: transparent; } - + .step-nav { padding-top: 8px; width: 240px; diff --git a/devui/styles-var/devui-var.scss b/devui/styles-var/devui-var.scss new file mode 100644 index 0000000000000000000000000000000000000000..32fd62bc0ae3f1bb15327044f2f09fc9856b5e0d --- /dev/null +++ b/devui/styles-var/devui-var.scss @@ -0,0 +1,6 @@ +@import '../style/theme/color'; +@import '../style/theme/font'; +@import '../style/theme/shadow'; +@import '../style/theme/corner'; +@import '../style/theme/animation'; +@import '../style/theme/z-index'; diff --git a/devui/theme/index.ts b/devui/theme/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..045f7781ecab2bb0cf055341d9fe8664214510a9 --- /dev/null +++ b/devui/theme/index.ts @@ -0,0 +1,10 @@ +import Theme from './theme' +import dark from './themes/dark' +import light from './themes/light' + +Theme.register('dark', dark) +Theme.register('light', light) + +export { dark, light } + +export default Theme diff --git a/devui/theme/theme.ts b/devui/theme/theme.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b37e404e64d34f6280ffdd976ef47b198dba96e --- /dev/null +++ b/devui/theme/theme.ts @@ -0,0 +1,43 @@ +class Theme { + static imports: any = {} + + static import(name: string): any { + return this.imports[name] + } + + static register(name: string, target: any): void { + this.imports[name] = target + } + + constructor(theme: string) { + this.applyTheme(theme) + } + + applyTheme(name: string): void { + const theme = Theme.imports[name] + if (!theme) { + console.error(`主题 ${theme} 未注册!`) + return + } + + const id = 'devui-theme-variable' + const themeVariable = `:root { ${stringify(theme)} }` + let styleElement = document.getElementById(id) + if (styleElement) { + styleElement.innerText = themeVariable + } else { + styleElement = document.createElement('style') + styleElement.id = id + styleElement.innerText = themeVariable + document.head.appendChild(styleElement) + } + } +} + +function stringify(theme: any) { + return Object.entries(theme) + .map(([key, value]) => `--${key}:${value}`) + .join(';') +} + +export default Theme diff --git a/devui/theme/themes/dark.ts b/devui/theme/themes/dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..f21377b65ffefa34e4ee92ac6d4521c7d796c311 --- /dev/null +++ b/devui/theme/themes/dark.ts @@ -0,0 +1,92 @@ +export default { + 'devui-global-bg': '#202124', + 'devui-global-bg-normal': '#202124', + 'devui-base-bg': '#2E2F31', + 'devui-base-bg-dark': '#2e2f31', + 'devui-brand': '#5e7ce0', + 'devui-brand-foil': '#313a61', + 'devui-brand-hover': '#425288', + 'devui-brand-active': '#526ecc', + 'devui-brand-active-focus': '#344899', + 'devui-contrast': '#C7000B', + 'devui-text': '#E8E8E8', + 'devui-text-weak': '#A0A0A0', + 'devui-aide-text': '#909090', + 'devui-aide-text-stress': '#A0A0A0', + 'devui-placeholder': '#8A8A8A', + 'devui-light-text': '#ffffff', + 'devui-dark-text': '#252b3a', + 'devui-link': '#526ECC', + 'devui-link-active': '#344899', + 'devui-link-light': '#96adfa', + 'devui-link-light-active': '#beccfa', + 'devui-line': '#505153', + 'devui-dividing-line': '#3D3E40', + 'devui-block': '#606061', + 'devui-area': '#34363A', + 'devui-danger': '#f66f6a', + 'devui-warning': '#fac20a', + 'devui-waiting': '#5e6580', + 'devui-success': '#50d4ab', + 'devui-info': '#5e7ce0', + 'devui-initial': '#64676e', + 'devui-unavailable': '#5b5b5c', + 'devui-shadow': 'rgba(17, 18, 19, 0.4)', + 'devui-light-shadow': 'rgba(17, 18, 19, 0.5)', + // 图标 + 'devui-icon-text': '#E8E8E8', + 'devui-icon-bg': '#2E2F31', + 'devui-icon-fill': '#606061', + 'devui-icon-fill-hover': '#73788a', + 'devui-icon-fill-active': '#5e7ce0', + 'devui-icon-fill-active-hover': '#526ecc', + // 表单 + 'devui-form-control-line': '#505153', + 'devui-form-control-line-hover': '#909090', + 'devui-form-control-line-active': '#5e7ce0', + 'devui-form-control-line-active-hover': '#344899', + 'devui-list-item-active-bg': '#5e7ce0', + 'devui-list-item-active-text': '#ffffff', + 'devui-list-item-active-hover-bg': '#526ecc', + 'devui-list-item-hover-bg': '#383838', + 'devui-list-item-hover-text': '#526ecc', + 'devui-list-item-selected-bg': '#454545', + 'devui-list-item-strip-bg': '#383838', + // 禁用 + 'devui-disabled-bg': '#3D3E44', + 'devui-disabled-line': '#505153', + 'devui-disabled-text': '#7D7D7D', + 'devui-primary-disabled': '#2B3458', + 'devui-icon-fill-active-disabled': '#2B3458', + // 特殊背景色 + 'devui-label-bg': '#46443F', + 'devui-connected-overlay-bg': '#2F2F2F', + 'devui-connected-overlay-line': '#526ecc', + 'devui-fullscreen-overlay-bg': '#2E2F31', + 'devui-feedback-overlay-bg': '#4C4C4C', + 'devui-feedback-overlay-text': '#DFE1E6', + 'devui-embed-search-bg': '#383838', + 'devui-embed-search-bg-hover': '#3D3E40', + 'devui-float-block-shadow': 'rgba(94, 124, 224, 0.3)', + 'devui-highlight-overlay': 'rgba(255, 255, 255, 0.1)', + 'devui-range-item-hover-bg': '#454545', + // 按钮 + 'devui-primary': '#5e7ce0', + 'devui-primary-hover': '#425288', + 'devui-primary-active': '#344899', + 'devui-contrast-hover': '#D64A52', + 'devui-contrast-active': '#B12220', + // 状态 + 'devui-danger-line': '#985C5A', + 'devui-danger-bg': '#4B3A39', + 'devui-warning-line': '#8D6138', + 'devui-warning-bg': '#554434', + 'devui-info-line': '#546BB7', + 'devui-info-bg': '#383D4F', + 'devui-success-line': '#5D887D', + 'devui-success-bg': '#304642', + 'devui-primary-line': '#546BB7', + 'devui-primary-bg': '#383D4F', + 'devui-default-line': '#5e7ce0', + 'devui-default-bg': '#383838', +} \ No newline at end of file diff --git a/devui/theme/themes/light.ts b/devui/theme/themes/light.ts new file mode 100644 index 0000000000000000000000000000000000000000..b86c08ca99498e3fa557b970e5f034329a4c8cfc --- /dev/null +++ b/devui/theme/themes/light.ts @@ -0,0 +1,135 @@ +export default { + // 基础变量 + 'devui-global-bg': '#f3f6f8', + 'devui-global-bg-normal': '#ffffff', + 'devui-base-bg': '#ffffff', + 'devui-base-bg-dark': '#333854', + 'devui-brand': '#5e7ce0', + 'devui-brand-foil': '#859bff', + 'devui-brand-hover': '#7693f5', + 'devui-brand-active': '#526ecc', + 'devui-brand-active-focus': '#344899', + 'devui-contrast': '#c7000b', + 'devui-text': '#252b3a', + 'devui-text-weak': '#575d6c', + 'devui-aide-text': '#8a8e99', + 'devui-aide-text-stress': '#575d6c', + 'devui-placeholder': '#8a8e99', + 'devui-light-text': '#ffffff', + 'devui-dark-text': '#252b3a', + 'devui-link': '#526ecc', + 'devui-link-active': '#526ecc', + 'devui-link-light': '#96adfa', + 'devui-link-light-active': '#beccfa', + 'devui-line': '#adb0b8', + 'devui-dividing-line': '#dfe1e6', + 'devui-block': '#ffffff', + 'devui-area': '#f8f8f8', + 'devui-danger': '#f66f6a', + 'devui-warning': '#fac20a', + 'devui-waiting': '#9faad7', + 'devui-success': '#50d4ab', + 'devui-info': '#5e7ce0', + 'devui-initial': '#e9edfa', + 'devui-unavailable': '#f5f5f6', + 'devui-shadow': 'rgba(0, 0, 0, 0.2)', + 'devui-light-shadow': 'rgba(0, 0, 0, 0.1)', + // 图标 + 'devui-icon-text': '#252b3a', + 'devui-icon-bg': '#ffffff', + 'devui-icon-fill': '#d3d5d9', + 'devui-icon-fill-hover': '#adb5ce', + 'devui-icon-fill-active': '#5e7ce0', + 'devui-icon-fill-active-hover': '#526ecc', + // 表单 + 'devui-form-control-line': '#adb0b8', + 'devui-form-control-line-hover': '#575d6c', + 'devui-form-control-line-active': '#5e7ce0', + 'devui-form-control-line-active-hover': '#344899', + 'devui-list-item-active-bg': '#5e7ce0', + 'devui-list-item-active-text': '#ffffff', + 'devui-list-item-active-hover-bg': '#526ecc', + 'devui-list-item-hover-bg': '#f2f5fc', + 'devui-list-item-hover-text': '#526ecc', + 'devui-list-item-selected-bg': '#e9edfa', + 'devui-list-item-strip-bg': '#f2f5fc', + // 禁用 + 'devui-disabled-bg': '#f5f5f6', + 'devui-disabled-line': '#dfe1e6', + 'devui-disabled-text': '#adb0b8', + 'devui-primary-disabled': '#beccfa', + 'devui-icon-fill-active-disabled': '#beccfa', + // 特殊背景色 + 'devui-label-bg': '#eef0f5', + 'devui-connected-overlay-bg': '#ffffff', + 'devui-connected-overlay-line': '#526ecc', + 'devui-fullscreen-overlay-bg': '#ffffff', + 'devui-feedback-overlay-bg': '#464d6e', + 'devui-feedback-overlay-text': '#dfe1e6', + 'devui-embed-search-bg': '#f2f5fc', + 'devui-embed-search-bg-hover': '#eef0f5', + 'devui-float-block-shadow': 'rgba(94, 124, 224, 0.3)', + 'devui-highlight-overlay': 'rgba(255, 255, 255, 0.8)', + 'devui-range-item-hover-bg': '#e9edfa', + // 按钮 + 'devui-primary': '#5e7ce0', + 'devui-primary-hover': '#7693f5', + 'devui-primary-active': '#344899', + 'devui-contrast-hover': '#d64a52', + 'devui-contrast-active': '#b12220', + // 状态 + 'devui-danger-line': '#f66f6a', + 'devui-danger-bg': '#ffeeed', + 'devui-warning-line': '#fa9841', + 'devui-warning-bg': '#fff3e8', + 'devui-info-line': '#5e7ce0', + 'devui-info-bg': '#f2f5fc', + 'devui-success-line': '#50d4ab', + 'devui-success-bg': '#edfff9', + 'devui-primary-line': '#5e7ce0', + 'devui-primary-bg': '#f2f5fc', + 'devui-default-line': '#5e7ce0', + 'devui-default-bg': '#f3f6f8', + // 字体设置相关 + 'devui-font-size': '12px', + 'devui-font-size-card-title': '14px', + 'devui-font-size-page-title': '16px', + 'devui-font-size-modal-title': '18px', + 'devui-font-size-price': '20px', + 'devui-font-size-data-overview': '24px', + 'devui-font-size-icon': '16px', + 'devui-font-size-sm': '12px', + 'devui-font-size-md': '12px', + 'devui-font-size-lg': '14px', + 'devui-font-title-weight': 'bold', + 'devui-font-content-weight': 'normal', + 'devui-line-height-base': '1.5', + // 圆角 + 'devui-border-radius': '2px', + 'devui-border-radius-feedback': '4px', + 'devui-border-radius-card': '6px', + // 阴影 + 'devui-shadow-length-base': '0 1px 4px 0', + 'devui-shadow-length-slide-left': '-2px 0 8px 0', + 'devui-shadow-length-slide-right': '2px 0 8px 0', + 'devui-shadow-length-connected-overlay': '0 2px 8px 0', + 'devui-shadow-length-hover': '0 4px 16px 0', + 'devui-shadow-length-feedback-overlay': '0 4px 16px 0', + 'devui-shadow-fullscreen-overlay': '0 8px 40px 0', + // 动效 + 'devui-animation-duration-slow': '300ms', + 'devui-animation-duration-base': '200ms', + 'devui-animation-duration-fast': '100ms', + 'devui-animation-ease-in': 'cubic-bezier(0.5, 0, 0.84, 0.25)', + 'devui-animation-ease-out': 'cubic-bezier(0.16, 0.75, 0.5, 1)', + 'devui-animation-ease-in-out': 'cubic-bezier(0.5, 0.05, 0.5, 0.95)', + 'devui-animation-ease-in-smooth': 'cubic-bezier(0.645, 0.045, 0.355, 1)', + 'devui-animation-linear': 'cubic-bezier(0, 0, 1, 1)', + // zIndex + 'devui-z-index-full-page-overlay': '1080', + 'devui-z-index-pop-up': '1060', + 'devui-z-index-dropdown': '1052', + 'devui-z-index-modal': '1050', + 'devui-z-index-drawer': '1040', + 'devui-z-index-framework': '1000' +} \ No newline at end of file diff --git a/devui/tooltip/src/tooltip.scss b/devui/tooltip/src/tooltip.scss index 0a799650311d673b25c1ea3b0f4ee32f15382397..f7f8a4b001d3dc893700b34d97b534d85b74fdde 100644 --- a/devui/tooltip/src/tooltip.scss +++ b/devui/tooltip/src/tooltip.scss @@ -1,22 +1,25 @@ .devui-tooltip { box-sizing: border-box; + .tooltip { box-sizing: border-box; position: absolute; width: fit-content; transition: all 0.5s; + .arrow { width: 0; height: 0; position: absolute; } + .tooltipcontent { box-sizing: border-box; padding: 10px; margin-left: 10px; width: fit-content; background-color: rgb(51, 51, 51); - color: #fff; + color: #ffffff; } } } diff --git a/devui/tooltip/src/tooltip.tsx b/devui/tooltip/src/tooltip.tsx index dd5cb3a0ead484ff63901fbd93c444a9bb9dfee5..4fdb75e9fee55af7cf34827397cf0854f74751de 100644 --- a/devui/tooltip/src/tooltip.tsx +++ b/devui/tooltip/src/tooltip.tsx @@ -7,20 +7,20 @@ export default defineComponent({ name: 'DTooltip', props: tooltipProps, setup(props, ctx){ - let position = reactive({ + const position = reactive({ left: 0, top: 0 }) - let show = ref(false) + const show = ref(false) // slotElement元素的ref - let slotElement = ref(null) + const slotElement = ref(null) // tooltip元素的引用 - let tooltip = ref(null) + const tooltip = ref(null) // arrow元素的引用 - let arrow = ref(null) + const arrow = ref(null) // tooltipcontent的引用 - let tooltipcontent = ref(null) + const tooltipcontent = ref(null) let enterEvent let leaveEvent diff --git a/package.json b/package.json index 3f36496317145022b4cbf599fa04816a606bbb15..702ec79ada68b8ade18ade2a5bff178876be43a4 100644 --- a/package.json +++ b/package.json @@ -27,13 +27,15 @@ "serve": "vitepress serve sites", "app:dev": "vite", "app:build": "vite build", - "build:lib": "yarn predev && yarn build:components && cp package.json build && cp README.md build", + "build:lib": "yarn predev && yarn build:components && yarn generate:theme && yarn copy", "test": "jest --config jest.config.js", "ls-lint": "ls-lint", "lint": "eslint \"{src,devui}/**/*.{vue,js,ts,jsx,tsx}\"", "lint:fix": "eslint --fix \"{src,devui}/**/*.{vue,js,ts,jsx,tsx}\"", "stylelint": "stylelint --fix \"{devui,src}/**/*.{scss,css}\"", "build:components": "node ./devui-cli/index.js build", + "generate:theme": "node ./devui-cli/index.js generate:theme", + "copy": "cp package.json build && cp README.md build && cp devui/theme/theme.scss build/theme", "clean:cli": "npm uninstall -g devui-cli & npm uninstall -g vue-devui", "cli:create": "node ./devui-cli/index.js create", "predev": "node ./devui-cli/index.js create -t vue-devui --ignore-parse-error" diff --git a/sites/.vitepress/devui-theme/components/NavBar.vue b/sites/.vitepress/devui-theme/components/NavBar.vue index 6d5248af56048e4a3fa11ffd5c9f6cd9161fe34d..95bf76f36aa916d8344a94b3af9e651d1b48b388 100644 --- a/sites/.vitepress/devui-theme/components/NavBar.vue +++ b/sites/.vitepress/devui-theme/components/NavBar.vue @@ -1,9 +1,23 @@ @@ -15,15 +29,24 @@ defineEmits(['toggle'])
-