From 59b4f7d9f82ba4d9103812c683bba5709c48153a Mon Sep 17 00:00:00 2001 From: vben Date: Tue, 28 May 2024 23:53:15 +0800 Subject: [PATCH] fix: stylelint not work --- .vscode/settings.json | 3 +- .../stylelint-config/package.json | 2 +- .../stylelint-config/src/index.ts | 2 +- internal/tailwind-config/package.json | 3 + internal/tailwind-config/src/index.ts | 9 +- internal/tailwind-config/src/module.d.ts | 3 + internal/tailwind-config/src/plugins.ts | 22 - .../tailwind-config/src/postcss.config.ts | 3 +- .../vite-config/src/config/application.ts | 5 - package.json | 2 +- .../@vben-core/shared/chche/build.config.ts | 7 + packages/@vben-core/shared/chche/package.json | 43 ++ packages/@vben-core/shared/chche/src/index.ts | 1 + .../shared/chche/src/storage-cache.test.ts | 104 +++ .../shared/chche/src/storage-cache.ts | 145 ++++ packages/@vben-core/shared/chche/src/types.ts | 17 + .../@vben-core/shared/chche/tsconfig.json | 5 + .../shared/design-tokens/src/dark/index.scss | 2 + .../design-tokens/src/default/index.scss | 3 + .../@vben-core/shared/design/build.config.ts | 2 +- .../shared/design/src/scss/common/base.scss | 2 +- .../@vben-core/shared/design/src/tailwind.css | 19 +- .../src/authentication/qrcode-login.vue | 2 +- .../common-ui/src/fallback/fallback.vue | 2 +- .../common-ui/src/preference/trigger.vue | 2 +- .../common-ui/src/spinner/spinner.vue | 4 +- .../src/authentication/authentication.vue | 2 +- .../layouts/src/authentication/from-view.vue | 4 +- packages/styles/src/tokens/dark.scss | 2 - pnpm-lock.yaml | 707 ++++++------------ turbo.json | 2 + vben-admin.code-workspace | 4 + 32 files changed, 585 insertions(+), 550 deletions(-) create mode 100644 internal/tailwind-config/src/module.d.ts delete mode 100644 internal/tailwind-config/src/plugins.ts create mode 100644 packages/@vben-core/shared/chche/build.config.ts create mode 100644 packages/@vben-core/shared/chche/package.json create mode 100644 packages/@vben-core/shared/chche/src/index.ts create mode 100644 packages/@vben-core/shared/chche/src/storage-cache.test.ts create mode 100644 packages/@vben-core/shared/chche/src/storage-cache.ts create mode 100644 packages/@vben-core/shared/chche/src/types.ts create mode 100644 packages/@vben-core/shared/chche/tsconfig.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 7ed1ca79..a009863e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -134,7 +134,8 @@ "stylelint.enable": true, "stylelint.packageManager": "pnpm", - "stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"], + "stylelint.validate": ["css", "less", "postcss", "scss", "vue"], + "stylelint.snippet": ["css", "less", "postcss", "scss", "vue"], "typescript.inlayHints.enumMemberValues.enabled": true, "typescript.preferences.preferTypeOnlyAutoImports": true, diff --git a/internal/lint-configs/stylelint-config/package.json b/internal/lint-configs/stylelint-config/package.json index e6f47b21..037a7cda 100644 --- a/internal/lint-configs/stylelint-config/package.json +++ b/internal/lint-configs/stylelint-config/package.json @@ -40,7 +40,7 @@ "postcss-html": "^1.7.0", "postcss-scss": "^4.0.9", "prettier": "^3.2.5", - "stylelint": "^16.6.0", + "stylelint": "^16.6.1", "stylelint-config-recommended": "^14.0.0", "stylelint-config-recommended-scss": "^14.0.0", "stylelint-config-recommended-vue": "^1.5.0", diff --git a/internal/lint-configs/stylelint-config/src/index.ts b/internal/lint-configs/stylelint-config/src/index.ts index 64b0a99f..7ef175cc 100644 --- a/internal/lint-configs/stylelint-config/src/index.ts +++ b/internal/lint-configs/stylelint-config/src/index.ts @@ -11,7 +11,7 @@ export default { overrides: [ { customSyntax: 'postcss-html', - files: ['**/*.(css|html|vue)'], + files: ['*.(html|vue)', '**/*.(html|vue)'], rules: { 'selector-pseudo-class-no-unknown': [ true, diff --git a/internal/tailwind-config/package.json b/internal/tailwind-config/package.json index dd9c5dab..2bf28d4a 100644 --- a/internal/tailwind-config/package.json +++ b/internal/tailwind-config/package.json @@ -48,16 +48,19 @@ "@iconify/json": "^2.2.214", "@iconify/tailwind": "^1.1.1", "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/nesting": "0.0.0-insiders.565cd3e", "@tailwindcss/typography": "^0.5.13", "autoprefixer": "^10.4.19", "cssnano": "^7.0.1", "postcss": "^8.4.38", "postcss-antd-fixes": "^0.2.0", + "postcss-import": "^16.1.0", "postcss-preset-env": "^9.5.14", "tailwindcss": "^3.4.3", "tailwindcss-animate": "^1.0.7" }, "devDependencies": { + "@types/postcss-import": "^14.0.3", "@vben/node-utils": "workspace:*" } } diff --git a/internal/tailwind-config/src/index.ts b/internal/tailwind-config/src/index.ts index 5384ba4c..ff46fc2a 100644 --- a/internal/tailwind-config/src/index.ts +++ b/internal/tailwind-config/src/index.ts @@ -8,7 +8,6 @@ import typographyPlugin from '@tailwindcss/typography'; import { fs, getPackagesSync } from '@vben/node-utils'; import animate from 'tailwindcss-animate'; -import { plugins } from './plugins'; // import defaultTheme from 'tailwindcss/defaultTheme'; const { packages } = getPackagesSync(); @@ -30,13 +29,7 @@ export default { ), ], darkMode: 'class', - plugins: [ - ...plugins, - animate, - formsPlugin, - typographyPlugin, - addDynamicIconSelectors(), - ], + plugins: [animate, formsPlugin, typographyPlugin, addDynamicIconSelectors()], prefix: '', safelist: ['dark'], theme: { diff --git a/internal/tailwind-config/src/module.d.ts b/internal/tailwind-config/src/module.d.ts new file mode 100644 index 00000000..a3996533 --- /dev/null +++ b/internal/tailwind-config/src/module.d.ts @@ -0,0 +1,3 @@ +declare module '@tailwindcss/nesting' { + export default any; +} diff --git a/internal/tailwind-config/src/plugins.ts b/internal/tailwind-config/src/plugins.ts deleted file mode 100644 index 697b04af..00000000 --- a/internal/tailwind-config/src/plugins.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Config } from 'tailwindcss'; - -import plugin from 'tailwindcss/plugin'; - -const flexCenterStyles = { - 'align-items': 'center', - display: 'flex', - 'justify-content': 'center', -}; - -const plugins = [ - plugin(({ addUtilities }) => { - addUtilities({ - '.flex-center': flexCenterStyles, - '.flex-col-center': { - ...flexCenterStyles, - }, - }); - }), -] as unknown as Config['plugins'][]; - -export { plugins }; diff --git a/internal/tailwind-config/src/postcss.config.ts b/internal/tailwind-config/src/postcss.config.ts index 7b86c6dd..43b30b35 100644 --- a/internal/tailwind-config/src/postcss.config.ts +++ b/internal/tailwind-config/src/postcss.config.ts @@ -7,8 +7,9 @@ export default { autoprefixer: {}, // 修复 element-plus 和 ant-design-vue 的样式和tailwindcss冲突问题 'postcss-antd-fixes': { prefixes: ['ant', 'el'] }, + 'postcss-import': {}, 'postcss-preset-env': {}, - // here to share the same config across the entire monorepo tailwindcss: { config }, + 'tailwindcss/nesting': {}, }, }; diff --git a/internal/vite-config/src/config/application.ts b/internal/vite-config/src/config/application.ts index e015b03b..4f7f8a1e 100644 --- a/internal/vite-config/src/config/application.ts +++ b/internal/vite-config/src/config/application.ts @@ -55,11 +55,6 @@ function defineApplicationConfig(options: DefineAppcationOptions = {}) { legalComments: 'none', }, plugins, - // css: { - // preprocessorOptions: { - // scss: { - // additionalData: `@import "@vben-core/design/global";`, - // }, resolve: { alias: [ { diff --git a/package.json b/package.json index 1ad13028..12b7f20f 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "version": "pnpm exec changeset version && pnpm install --no-frozen-lockfile" }, "devDependencies": { - "@changesets/cli": "^2.27.3", + "@changesets/cli": "^2.27.5", "@ls-lint/ls-lint": "^2.2.3", "@types/jsdom": "^21.1.6", "@types/node": "^20.12.12", diff --git a/packages/@vben-core/shared/chche/build.config.ts b/packages/@vben-core/shared/chche/build.config.ts new file mode 100644 index 00000000..97e572c5 --- /dev/null +++ b/packages/@vben-core/shared/chche/build.config.ts @@ -0,0 +1,7 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + declaration: true, + entries: ['src/index'], +}); diff --git a/packages/@vben-core/shared/chche/package.json b/packages/@vben-core/shared/chche/package.json new file mode 100644 index 00000000..7f97ec82 --- /dev/null +++ b/packages/@vben-core/shared/chche/package.json @@ -0,0 +1,43 @@ +{ + "name": "@vben-core/cache", + "version": "1.0.0", + "type": "module", + "license": "MIT", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/@vben-core/shared/toolkit" + }, + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "scripts": { + "build": "pnpm unbuild", + "stub": "pnpm unbuild --stub" + }, + "files": [ + "dist" + ], + "sideEffects": false, + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "imports": { + "#*": "./src/*" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "development": "./src/index.ts", + "default": "./dist/index.mjs" + } + }, + "publishConfig": { + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.mjs" + } + } + }, + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/@vben-core/shared/chche/src/index.ts b/packages/@vben-core/shared/chche/src/index.ts new file mode 100644 index 00000000..5fe5d857 --- /dev/null +++ b/packages/@vben-core/shared/chche/src/index.ts @@ -0,0 +1 @@ +export * from './storage-cache'; diff --git a/packages/@vben-core/shared/chche/src/storage-cache.test.ts b/packages/@vben-core/shared/chche/src/storage-cache.test.ts new file mode 100644 index 00000000..b10909b9 --- /dev/null +++ b/packages/@vben-core/shared/chche/src/storage-cache.test.ts @@ -0,0 +1,104 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { StorageCache } from './storage-cache'; + +describe('storageCache', () => { + let localStorageCache: StorageCache; + let sessionStorageCache: StorageCache; + + beforeEach(() => { + localStorageCache = new StorageCache('prefix_', 'localStorage'); + sessionStorageCache = new StorageCache('prefix_', 'sessionStorage'); + localStorage.clear(); + sessionStorage.clear(); + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it('should set and get an item with prefix in localStorage', () => { + localStorageCache.setItem('testKey', 'testValue'); + const value = localStorageCache.getItem('testKey'); + expect(value).toBe('testValue'); + expect(localStorage.getItem('prefix_testKey')).not.toBeNull(); + }); + + it('should set and get an item with prefix in sessionStorage', () => { + sessionStorageCache.setItem('testKey', 'testValue'); + const value = sessionStorageCache.getItem('testKey'); + expect(value).toBe('testValue'); + expect(sessionStorage.getItem('prefix_testKey')).not.toBeNull(); + }); + + it('should return null for expired item in localStorage', () => { + localStorageCache.setItem('testKey', 'testValue', 1 / 60); // 1 second expiry + vi.advanceTimersByTime(2000); // Fast-forward 2 seconds + const value = localStorageCache.getItem('testKey'); + expect(value).toBeNull(); + }); + + it('should return null for expired item in sessionStorage', () => { + sessionStorageCache.setItem('testKey', 'testValue', 1 / 60); // 1 second expiry + vi.advanceTimersByTime(2000); // Fast-forward 2 seconds + const value = sessionStorageCache.getItem('testKey'); + expect(value).toBeNull(); + }); + + it('should remove an item with prefix in localStorage', () => { + localStorageCache.setItem('testKey', 'testValue'); + localStorageCache.removeItem('testKey'); + const value = localStorageCache.getItem('testKey'); + expect(value).toBeNull(); + expect(localStorage.getItem('prefix_testKey')).toBeNull(); + }); + + it('should remove an item with prefix in sessionStorage', () => { + sessionStorageCache.setItem('testKey', 'testValue'); + sessionStorageCache.removeItem('testKey'); + const value = sessionStorageCache.getItem('testKey'); + expect(value).toBeNull(); + expect(sessionStorage.getItem('prefix_testKey')).toBeNull(); + }); + + it('should clear all items in localStorage', () => { + localStorageCache.setItem('testKey1', 'testValue1'); + localStorageCache.setItem('testKey2', 'testValue2'); + localStorageCache.clear(); + expect(localStorageCache.length()).toBe(0); + }); + + it('should clear all items in sessionStorage', () => { + sessionStorageCache.setItem('testKey1', 'testValue1'); + sessionStorageCache.setItem('testKey2', 'testValue2'); + sessionStorageCache.clear(); + expect(sessionStorageCache.length()).toBe(0); + }); + + it('should return correct length in localStorage', () => { + localStorageCache.setItem('testKey1', 'testValue1'); + localStorageCache.setItem('testKey2', 'testValue2'); + expect(localStorageCache.length()).toBe(2); + }); + + it('should return correct length in sessionStorage', () => { + sessionStorageCache.setItem('testKey1', 'testValue1'); + sessionStorageCache.setItem('testKey2', 'testValue2'); + expect(sessionStorageCache.length()).toBe(2); + }); + + it('should return correct key by index in localStorage', () => { + localStorageCache.setItem('testKey1', 'testValue1'); + localStorageCache.setItem('testKey2', 'testValue2'); + expect(localStorageCache.key(0)).toBe('prefix_testKey1'); + expect(localStorageCache.key(1)).toBe('prefix_testKey2'); + }); + + it('should return correct key by index in sessionStorage', () => { + sessionStorageCache.setItem('testKey1', 'testValue1'); + sessionStorageCache.setItem('testKey2', 'testValue2'); + expect(sessionStorageCache.key(0)).toBe('prefix_testKey1'); + expect(sessionStorageCache.key(1)).toBe('prefix_testKey2'); + }); +}); diff --git a/packages/@vben-core/shared/chche/src/storage-cache.ts b/packages/@vben-core/shared/chche/src/storage-cache.ts new file mode 100644 index 00000000..294b47d5 --- /dev/null +++ b/packages/@vben-core/shared/chche/src/storage-cache.ts @@ -0,0 +1,145 @@ +import type { IStorageCache, StorageType, StorageValue } from './types'; + +class StorageCache implements IStorageCache { + protected prefix: string; + protected storage: Storage; + + constructor(prefix: string = '', storageType: StorageType = 'localStorage') { + this.prefix = prefix; + this.storage = + storageType === 'localStorage' ? localStorage : sessionStorage; + } + + // 获取带前缀的键名 + private getFullKey(key: string): string { + return this.prefix + key; + } + + // 获取项之后的钩子方法 + protected afterGetItem(_key: string, _value: T | null): void {} + + // 设置项之后的钩子方法 + protected afterSetItem( + _key: string, + _value: T, + _expiryInMinutes?: number, + ): void {} + + // 获取项之前的钩子方法 + protected beforeGetItem(_key: string): void {} + + // 设置项之前的钩子方法 + protected beforeSetItem( + _key: string, + _value: T, + _expiryInMinutes?: number, + ): void {} + + /** + * 清空存储 + */ + clear(): void { + try { + this.storage.clear(); + } catch (error) { + console.error('Error clearing storage', error); + } + } + + /** + * 获取存储项 + * @param key 存储键 + * @returns 存储值或 null + */ + getItem(key: string): T | null { + const fullKey = this.getFullKey(key); + this.beforeGetItem(fullKey); + + let value: T | null = null; + try { + const item = this.storage.getItem(fullKey); + if (item) { + const storageValue: StorageValue = JSON.parse(item); + if (storageValue.expiry && storageValue.expiry < Date.now()) { + this.storage.removeItem(fullKey); + } else { + value = storageValue.data; + } + } + } catch (error) { + console.error('Error getting item from storage', error); + } + + this.afterGetItem(fullKey, value); + return value; + } + + /** + * 获取存储中的键 + * @param index 键的索引 + * @returns 存储键或 null + */ + key(index: number): null | string { + try { + return this.storage.key(index); + } catch (error) { + console.error('Error getting key from storage', error); + return null; + } + } + + /** + * 获取存储项的数量 + * @returns 存储项的数量 + */ + length(): number { + try { + return this.storage.length; + } catch (error) { + console.error('Error getting storage length', error); + return 0; + } + } + + /** + * 删除存储项 + * @param key 存储键 + */ + removeItem(key: string): void { + const fullKey = this.getFullKey(key); + try { + this.storage.removeItem(fullKey); + } catch (error) { + console.error('Error removing item from storage', error); + } + } + + /** + * 设置存储项 + * @param key 存储键 + * @param value 存储值 + * @param expiryInMinutes 过期时间(分钟) + */ + setItem(key: string, value: T, expiryInMinutes?: number): void { + const fullKey = this.getFullKey(key); + this.beforeSetItem(fullKey, value, expiryInMinutes); + + const now = Date.now(); + const expiry = expiryInMinutes ? now + expiryInMinutes * 60_000 : null; + + const storageValue: StorageValue = { + data: value, + expiry, + }; + + try { + this.storage.setItem(fullKey, JSON.stringify(storageValue)); + } catch (error) { + console.error('Error setting item in storage', error); + } + + this.afterSetItem(fullKey, value, expiryInMinutes); + } +} + +export { StorageCache }; diff --git a/packages/@vben-core/shared/chche/src/types.ts b/packages/@vben-core/shared/chche/src/types.ts new file mode 100644 index 00000000..869472f2 --- /dev/null +++ b/packages/@vben-core/shared/chche/src/types.ts @@ -0,0 +1,17 @@ +type StorageType = 'localStorage' | 'sessionStorage'; + +interface StorageValue { + data: T; + expiry: null | number; +} + +interface IStorageCache { + clear(): void; + getItem(key: string): T | null; + key(index: number): null | string; + length(): number; + removeItem(key: string): void; + setItem(key: string, value: T, expiryInMinutes?: number): void; +} + +export type { IStorageCache, StorageType, StorageValue }; diff --git a/packages/@vben-core/shared/chche/tsconfig.json b/packages/@vben-core/shared/chche/tsconfig.json new file mode 100644 index 00000000..03b23c68 --- /dev/null +++ b/packages/@vben-core/shared/chche/tsconfig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/library.json", + "include": ["src"] +} diff --git a/packages/@vben-core/shared/design-tokens/src/dark/index.scss b/packages/@vben-core/shared/design-tokens/src/dark/index.scss index 7138e481..a7627eb6 100644 --- a/packages/@vben-core/shared/design-tokens/src/dark/index.scss +++ b/packages/@vben-core/shared/design-tokens/src/dark/index.scss @@ -76,4 +76,6 @@ /* 基本圆角大小 */ --radius-base: 0.5rem; + + color-scheme: dark; } diff --git a/packages/@vben-core/shared/design-tokens/src/default/index.scss b/packages/@vben-core/shared/design-tokens/src/default/index.scss index 2096c57e..588c6b14 100644 --- a/packages/@vben-core/shared/design-tokens/src/default/index.scss +++ b/packages/@vben-core/shared/design-tokens/src/default/index.scss @@ -89,5 +89,8 @@ // --color-menu-opened-dark: 225deg 12.12% 11%; --color-menu: 0deg 0% 100%; --color-menu-darken: 0deg 0% 95%; + + accent-color: var(--color-primary); + color-scheme: light; // --color-menu-opened: 0deg 0% 100%; } diff --git a/packages/@vben-core/shared/design/build.config.ts b/packages/@vben-core/shared/design/build.config.ts index 189c008c..7de447e2 100644 --- a/packages/@vben-core/shared/design/build.config.ts +++ b/packages/@vben-core/shared/design/build.config.ts @@ -14,7 +14,7 @@ export default defineBuildConfig({ { builder: 'mkdist', input: './src', - // loaders: ['postcss'], + loaders: ['postcss'], outDir: './dist', pattern: ['tailwind.css'], }, diff --git a/packages/@vben-core/shared/design/src/scss/common/base.scss b/packages/@vben-core/shared/design/src/scss/common/base.scss index 99101c23..443b0333 100644 --- a/packages/@vben-core/shared/design/src/scss/common/base.scss +++ b/packages/@vben-core/shared/design/src/scss/common/base.scss @@ -34,7 +34,7 @@ html { font-synthesis-weight: none; scroll-behavior: smooth; text-rendering: optimizelegibility; - -webkit-tap-highlight-color: rgb(128 128 128 / 50%); + -webkit-tap-highlight-color: transparent; } a, diff --git a/packages/@vben-core/shared/design/src/tailwind.css b/packages/@vben-core/shared/design/src/tailwind.css index 99817876..87c52c3c 100644 --- a/packages/@vben-core/shared/design/src/tailwind.css +++ b/packages/@vben-core/shared/design/src/tailwind.css @@ -8,20 +8,31 @@ } } -@layer components { +@layer utilities { + .flex-center { + @apply flex items-center justify-center; + } + + .flex-col-center { + @apply flex flex-col items-center justify-center; + } + .outline-box { - &:after { + @apply outline-border relative cursor-pointer rounded-md p-1 outline outline-1; + + &::after { @apply absolute left-1/2 top-1/2 z-20 h-0 w-[1px] rounded-sm opacity-0 outline outline-2 outline-transparent transition-all duration-300 content-['']; } &.outline-box-active { @apply outline-primary outline outline-2; - &:after { + + &::after { display: none; } } - &:not(.outline-box-active):hover:after { + &:not(.outline-box-active):hover::after { @apply outline-primary left-0 top-0 h-full w-full p-1 opacity-100; } } diff --git a/packages/business/common-ui/src/authentication/qrcode-login.vue b/packages/business/common-ui/src/authentication/qrcode-login.vue index ac146a35..dad6ab81 100644 --- a/packages/business/common-ui/src/authentication/qrcode-login.vue +++ b/packages/business/common-ui/src/authentication/qrcode-login.vue @@ -37,7 +37,7 @@ function handleGo(path: string) { -
+
qrcode

{{ $t('authentication.qrcode-prompt') }} diff --git a/packages/business/common-ui/src/fallback/fallback.vue b/packages/business/common-ui/src/fallback/fallback.vue index 444bf77f..65315280 100644 --- a/packages/business/common-ui/src/fallback/fallback.vue +++ b/packages/business/common-ui/src/fallback/fallback.vue @@ -63,7 +63,7 @@ function back() { > -

+

{{ titleText }}

diff --git a/packages/business/common-ui/src/preference/trigger.vue b/packages/business/common-ui/src/preference/trigger.vue index e956513e..84331561 100644 --- a/packages/business/common-ui/src/preference/trigger.vue +++ b/packages/business/common-ui/src/preference/trigger.vue @@ -12,7 +12,7 @@ defineOptions({ -