fix: stylelint not work

This commit is contained in:
vben 2024-05-28 23:53:15 +08:00
parent 11a36ef03f
commit 59b4f7d9f8
32 changed files with 585 additions and 550 deletions

View File

@ -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,

View File

@ -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",

View File

@ -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,

View File

@ -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:*"
}
}

View File

@ -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: {

View File

@ -0,0 +1,3 @@
declare module '@tailwindcss/nesting' {
export default any;
}

View File

@ -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 };

View File

@ -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': {},
},
};

View File

@ -55,11 +55,6 @@ function defineApplicationConfig(options: DefineAppcationOptions = {}) {
legalComments: 'none',
},
plugins,
// css: {
// preprocessorOptions: {
// scss: {
// additionalData: `@import "@vben-core/design/global";`,
// },
resolve: {
alias: [
{

View File

@ -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",

View File

@ -0,0 +1,7 @@
import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
clean: true,
declaration: true,
entries: ['src/index'],
});

View File

@ -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": {}
}

View File

@ -0,0 +1 @@
export * from './storage-cache';

View File

@ -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<string>('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<string>('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<string>('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<string>('testKey');
expect(value).toBeNull();
});
it('should remove an item with prefix in localStorage', () => {
localStorageCache.setItem('testKey', 'testValue');
localStorageCache.removeItem('testKey');
const value = localStorageCache.getItem<string>('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<string>('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');
});
});

View File

@ -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<T>(_key: string, _value: T | null): void {}
// 设置项之后的钩子方法
protected afterSetItem<T>(
_key: string,
_value: T,
_expiryInMinutes?: number,
): void {}
// 获取项之前的钩子方法
protected beforeGetItem(_key: string): void {}
// 设置项之前的钩子方法
protected beforeSetItem<T>(
_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<T>(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<T> = 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<T>(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<T> = {
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 };

View File

@ -0,0 +1,17 @@
type StorageType = 'localStorage' | 'sessionStorage';
interface StorageValue<T> {
data: T;
expiry: null | number;
}
interface IStorageCache {
clear(): void;
getItem<T>(key: string): T | null;
key(index: number): null | string;
length(): number;
removeItem(key: string): void;
setItem<T>(key: string, value: T, expiryInMinutes?: number): void;
}
export type { IStorageCache, StorageType, StorageValue };

View File

@ -0,0 +1,5 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@vben/tsconfig/library.json",
"include": ["src"]
}

View File

@ -76,4 +76,6 @@
/* 基本圆角大小 */
--radius-base: 0.5rem;
color-scheme: dark;
}

View File

@ -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%;
}

View File

@ -14,7 +14,7 @@ export default defineBuildConfig({
{
builder: 'mkdist',
input: './src',
// loaders: ['postcss'],
loaders: ['postcss'],
outDir: './dist',
pattern: ['tailwind.css'],
},

View File

@ -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,

View File

@ -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;
}
}

View File

@ -37,7 +37,7 @@ function handleGo(path: string) {
</template>
</Title>
<div class="mt-6 flex flex-col items-center justify-center">
<div class="flex-col-center mt-6">
<img :src="qrcode" alt="qrcode" class="w-1/2" />
<p class="text-muted-foreground mt-4 text-sm">
{{ $t('authentication.qrcode-prompt') }}

View File

@ -63,7 +63,7 @@ function back() {
>
<img v-if="image" :src="image" class="md:1/3 w-1/2 lg:w-1/4" />
<FeedbackIcon v-else class="md:1/3 h-1/3 w-1/2 lg:w-1/4" />
<div class="flex flex-col items-center justify-center">
<div class="flex-col-center">
<p class="text-foreground mt-12 text-3xl md:text-4xl lg:text-5xl">
{{ titleText }}
</p>

View File

@ -12,7 +12,7 @@ defineOptions({
<template>
<VbenButton
class="bg-primary flex-center h-9 w-9 cursor-pointer flex-col rounded-l-md rounded-r-none border-none"
class="bg-primary flex-col-center h-9 w-9 cursor-pointer rounded-l-md rounded-r-none border-none"
:title="$t('preference.preferences')"
>
<IconSetting class="text-lg" />

View File

@ -59,9 +59,7 @@ watch(
</div>
</template>
<style lang="scss" scoped>
@import '@vben-core/design/global';
<style scoped>
@keyframes jump-ani {
15% {
border-bottom-right-radius: 3px;

View File

@ -47,7 +47,7 @@ const { authPanelCenter, authPanelLeft, authPanelRight } = usePreference();
<div
class="absolute inset-0 h-full w-full bg-[var(--color-authentication)]"
>
<div class="flex-center mr-20 flex h-full flex-col">
<div class="flex-col-center mr-20 h-full">
<SloganIcon
:alt="preference.appName"
class="animate-float h-64 w-2/5"

View File

@ -8,9 +8,7 @@ defineOptions({
});
</script>
<template>
<div
class="relative flex flex-col items-center justify-center px-6 py-10 lg:flex-initial lg:px-8"
>
<div class="flex-col-center relative px-6 py-10 lg:flex-initial lg:px-8">
<slot name="toolbar">
<Toolbar />
</slot>

View File

@ -1,6 +1,4 @@
:root.dark {
/* authentication */
--color-authentication: hsl(240deg 11% 2%);
color-scheme: dark;
}

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,8 @@
},
"stub": {},
"dev": {
"dependsOn": ["^build"],
"outputs": [""],
"cache": false,
"persistent": true
},

View File

@ -40,6 +40,10 @@
"name": "@vben/vite-config",
"path": "internal/vite-config",
},
{
"name": "@vben-core/cache",
"path": "packages/@vben-core/shared/chche",
},
{
"name": "@vben-core/design",
"path": "packages/@vben-core/shared/design",