From ddb89496aaf2d267a96f995b61879054d7d711dc Mon Sep 17 00:00:00 2001 From: Kuingsmile <96409857+Kuingsmile@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:16:56 +0800 Subject: [PATCH] :construction: WIP(custom): migrate to tailwindcss --- .prettierrc | 4 +- .stylelintrc.cjs | 1 + electron.vite.config.js | 2 + package.json | 3 + src/renderer/App.vue | 33 +- src/renderer/assets/css/theme.css | 53 + src/renderer/assets/css/utilities.css | 23 + src/renderer/index.css | 173 ++ src/renderer/layouts/Main.vue | 183 +- src/renderer/main.ts | 1 + src/renderer/pages/Upload.vue | 454 +++-- src/renderer/pages/css/UploadPage.css | 2264 +------------------------ yarn.lock | 249 ++- 13 files changed, 811 insertions(+), 2632 deletions(-) create mode 100644 src/renderer/assets/css/theme.css create mode 100644 src/renderer/assets/css/utilities.css create mode 100644 src/renderer/index.css diff --git a/.prettierrc b/.prettierrc index e61a93a0..a33a2958 100644 --- a/.prettierrc +++ b/.prettierrc @@ -14,5 +14,7 @@ "tabWidth": 2, "trailingComma": "all", "useTabs": false, - "endOfLine": "lf" + "endOfLine": "lf", + "plugins": ["prettier-plugin-tailwindcss"], + "tailwindStylesheet": "./src/renderer/index.css" } diff --git a/.stylelintrc.cjs b/.stylelintrc.cjs index 6e580c45..4b18a900 100644 --- a/.stylelintrc.cjs +++ b/.stylelintrc.cjs @@ -2,6 +2,7 @@ module.exports = { extends: ['stylelint-config-standard', 'stylelint-config-html/vue', 'stylelint-config-standard-vue'], plugins: [], rules: { + 'import-notation': null, // 这里是允许了空的style标签 'no-empty-source': null, 'selector-class-pattern': null, diff --git a/electron.vite.config.js b/electron.vite.config.js index f2c843f5..0ffb7eda 100644 --- a/electron.vite.config.js +++ b/electron.vite.config.js @@ -3,6 +3,7 @@ import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite' +import tailwindcss from '@tailwindcss/vite' import vue from '@vitejs/plugin-vue' import { defineConfig } from 'electron-vite' @@ -39,6 +40,7 @@ export default defineConfig({ alias, }, plugins: [ + tailwindcss(), vue(), VueI18nPlugin({ /* options */ diff --git a/package.json b/package.json index 150816e1..39095c11 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "@headlessui/vue": "^1.7.23", "@highlightjs/vue-plugin": "^2.1.2", "@intlify/unplugin-vue-i18n": "^11.0.3", + "@tailwindcss/vite": "^4.1.18", "@types/adm-zip": "^0.5.7", "@types/ali-oss": "^6.23.0", "@types/fs-extra": "^11.0.4", @@ -129,6 +130,7 @@ "postcss": "^8.5.6", "postcss-html": "^1.8.0", "prettier": "^3.7.4", + "prettier-plugin-tailwindcss": "^0.7.2", "qrcode.vue": "^3.6.0", "stylelint": "^16.26.1", "stylelint-config-html": "^1.1.0", @@ -136,6 +138,7 @@ "stylelint-config-standard-vue": "^1.0.0", "stylelint-order": "^7.0.1", "stylus": "^0.64.0", + "tailwindcss": "^4.1.18", "typescript": "5.8.2", "typescript-eslint": "^8.52.0", "video.js": "^8.23.4", diff --git a/src/renderer/App.vue b/src/renderer/App.vue index 148e928e..f7828e9d 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -1,7 +1,9 @@ @@ -27,30 +29,3 @@ export default { name: 'PicList', } - - diff --git a/src/renderer/assets/css/theme.css b/src/renderer/assets/css/theme.css new file mode 100644 index 00000000..19ccad25 --- /dev/null +++ b/src/renderer/assets/css/theme.css @@ -0,0 +1,53 @@ + +@theme { + --background-image-custom: var(--background-image, none); + --blur-custom: var(--background-blur, none); + --opacity-custom: var(--background-image-opacity); + --color-main: var(--color-text-primary); + --color-secondary: var(--color-text-secondary); + --color-tertiary: var(--color-text-tertiary); + --color-bg: var(--color-background-primary); + --color-bg-secondary: var(--color-background-secondary); + --color-bg-tertiary: var(--color-background-tertiary); + --color-surface: var(--color-surface); + --color-surface-elevated: var(--color-surface-elevated); + --color-border: var(--color-border); + --color-border-secondary: var(--color-border-secondary); + --color-primary: var(--color-primary); + --color-primary-hover: var(--color-primary-hover); + --color-accent: var(--color-accent); + --color-accent-hover: var(--color-accent-hover); + --color-success: var(--color-success); + --color-warning: var(--color-warning); + --color-danger: var(--color-danger); + --color-error: var(--color-error); + + /* shadows */ + --shadow-sm: var(--shadow-sm); + --shadow-md: var(--shadow-md); + --shadow-lg: var(--shadow-lg); + --shadow-xl: var(--shadow-xl); + + /* radius */ + --radius-sm: 6px; + --radius-md: 8px; + --radius-lg: 12px; + --radius-xl: 16px; + --radius-2xl: 20px; + --radius-round: 50%; + + /* transition */ + --transition-duration-fast: 150ms; + --transition-duration-medium: 250ms; + --transition-duration-slow: 350ms; + --ease-standard: cubic-bezier(0.4, 0, 0.2, 1); + --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); + --ease-apple: cubic-bezier(0.3, 1, 0.3, 1); + + /* breakpoints */ + --breakpoint-xs: 480px; + --breakpoint-sm: 640px; + --breakpoint-md: 768px; + --breakpoint-lg: 1024px; + --breakpoint-xl: 1280px; +} diff --git a/src/renderer/assets/css/utilities.css b/src/renderer/assets/css/utilities.css new file mode 100644 index 00000000..8af244ff --- /dev/null +++ b/src/renderer/assets/css/utilities.css @@ -0,0 +1,23 @@ +/* stylelint-disable nesting-selector-no-missing-scoping-root */ + +@import 'tailwindcss' reference; + +@utility no-scrollbar { + &::-webkit-scrollbar { + display: none; + } + + scrollbar-width: none; + -ms-overflow-style: none; +} + +@utility advanced-animation { + @apply border border-black/30 bg-black/20 shadow-[0_8px_32px_rgba(0,0,0,0.1)] backdrop-blur-[5px] backdrop-saturate-[1.8]; +} + + +@utility focus-ring { + &:focus-visible { + @apply outline-2 outline-offset-2 outline-accent outline-solid; + } +} diff --git a/src/renderer/index.css b/src/renderer/index.css new file mode 100644 index 00000000..358a6c9c --- /dev/null +++ b/src/renderer/index.css @@ -0,0 +1,173 @@ +@import 'tailwindcss'; +@import './assets/css/theme.css'; +@import './assets/css/utilities.css'; + +@layer base { + body { + @apply m-0 h-full overflow-hidden bg-bg p-0 font-[inherit] text-main; + } + + html { + @apply m-0 h-full p-0; + } + + :focus { + @apply outline-none; + } + + :focus-visible { + @apply outline-2 outline-offset-2 outline-accent outline-solid; + } + + ::selection { + @apply bg-accent/20 text-main; + } + + ::-webkit-scrollbar { + @apply h-3 w-2; + } + + ::-webkit-scrollbar-track { + @apply bg-transparent; + } + + ::-webkit-scrollbar-thumb { + @apply rounded-sm bg-accent/50 transition-colors duration-fast ease-standard; + } + + ::-webkit-scrollbar-thumb:hover { + @apply bg-accent/70; + } + + ::-webkit-scrollbar-corner { + @apply bg-bg; + } + + @media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + } + + :root, + .light, + [data-theme='light'] { + font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 1.5; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizelegibility; + + --background-image: none; + --background-image-opacity: 1; + --color-text-primary: #1d1d1f; + --color-text-secondary: #6e6e73; + --color-text-tertiary: #86868b; + --color-background-primary: #ffffff; + --color-background-secondary: #f5f5f7; + --color-background-tertiary: #fbfbfd; + --color-surface: rgb(255 255 255 / 80%); + --color-surface-elevated: rgb(255 255 255 / 95%); + --color-border: rgb(0 0 0 / 10%); + --color-border-secondary: rgb(0 0 0 / 5%); + --color-primary: #6366f1; + --color-primary-hover: #4f46e5; + --color-accent: #007aff; + --color-accent-hover: #3b82f6; + --color-success: #34c759; + --color-warning: #f1930f; + --color-danger: #ff3b30; + --color-error: #cb2431; + --shadow-sm: 0 1px 3px rgb(0 0 0 / 4%), 0 1px 2px rgb(0 0 0 / 6%); + --shadow-md: 0 4px 6px rgb(0 0 0 / 5%), 0 2px 4px rgb(0 0 0 / 6%); + --shadow-lg: 0 10px 15px rgb(0 0 0 / 8%), 0 4px 6px rgb(0 0 0 / 5%); + --shadow-xl: 0 20px 25px rgb(0 0 0 / 10%), 0 10px 10px rgb(0 0 0 / 4%); + } + + :root.dark { + --color-text-primary: #f5f5f7; + --color-text-secondary: #a1a1a6; + --color-text-tertiary: #86868b; + --color-background-primary: #000000; + --color-background-secondary: #1c1c1e; + --color-background-tertiary: #2c2c2e; + --color-surface: rgb(28 28 30 / 80%); + --color-surface-elevated: rgb(44 44 46 / 95%); + --color-border: rgb(255 255 255 / 10%); + --color-border-secondary: rgb(255 255 255 / 5%); + --color-primary: #6366f1; + --color-primary-hover: #818cf8; + --color-accent: #0a84ff; + --color-accent-hover: #409cff; + --color-success: #34c759; + --color-warning: #f1930f; + --color-danger: #ff3b30; + --color-error: #cb2431; + --shadow-sm: 0 1px 3px rgb(0 0 0 / 4%), 0 1px 2px rgb(0 0 0 / 6%); + --shadow-md: 0 4px 6px rgb(0 0 0 / 5%), 0 2px 4px rgb(0 0 0 / 6%); + --shadow-lg: 0 10px 15px rgb(0 0 0 / 8%), 0 4px 6px rgb(0 0 0 / 5%); + --shadow-xl: 0 20px 25px rgb(0 0 0 / 10%), 0 10px 10px rgb(0 0 0 / 4%); + } + + @keyframes badge-scroll { + 0% { + transform: translateX(0); + } + + 100% { + transform: translateX(-50%); + } + } + + @keyframes fade-in { + from { + opacity: 0; + transform: scale(0.8); + } + + to { + opacity: 1; + transform: scale(1); + } + } + + @keyframes float { + 0%, + 100% { + transform: translateY(0); + } + + 50% { + transform: translateY(-10px); + } + } + + @keyframes badge-pulse { + 0%, + 100% { + transform: translateY(-50%) scale(1); + box-shadow: 0 2px 6px rgb(0 122 255 / 40%); + } + + 50% { + transform: translateY(-50%) scale(1.1); + box-shadow: 0 2px 6px rgb(0 122 255 / 60%); + } + } + + @keyframes spin { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } + } +} diff --git a/src/renderer/layouts/Main.vue b/src/renderer/layouts/Main.vue index 01a430bc..3fdca1bb 100644 --- a/src/renderer/layouts/Main.vue +++ b/src/renderer/layouts/Main.vue @@ -1,10 +1,10 @@