Reapply "Fix/tailwindcss v4"

This reverts commit a9fd75d619.
This commit is contained in:
Yumin Gui
2025-07-18 21:31:17 -07:00
parent 99345c703c
commit d525e12e17
37 changed files with 667 additions and 1244 deletions

22
.commitlintrc.json Normal file
View File

@@ -0,0 +1,22 @@
{
"extends": ["@commitlint/config-conventional"],
"rules": {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"chore",
"style",
"refactor",
"ci",
"test",
"perf",
"revert",
"vercel"
]
]
}
}

View File

@@ -1,84 +0,0 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
plugins: ['@typescript-eslint', 'simple-import-sort', 'unused-imports'],
extends: [
'eslint:recommended',
'next',
'next/core-web-vitals',
'plugin:@typescript-eslint/recommended',
'prettier',
],
rules: {
'no-unused-vars': 'off',
'no-console': 'warn',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'react/no-unescaped-entities': 'off',
'react/display-name': 'off',
'react/jsx-curly-brace-presence': [
'warn',
{ props: 'never', children: 'never' },
],
//#region //*=========== Unused Import ===========
'@typescript-eslint/no-unused-vars': 'off',
'unused-imports/no-unused-imports': 'warn',
'unused-imports/no-unused-vars': [
'warn',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
],
//#endregion //*======== Unused Import ===========
//#region //*=========== Import Sort ===========
'simple-import-sort/exports': 'warn',
'simple-import-sort/imports': [
'warn',
{
groups: [
// ext library & side effect imports
['^@?\\w', '^\\u0000'],
// {s}css files
['^.+\\.s?css$'],
// Lib and hooks
['^@/lib', '^@/hooks'],
// static data
['^@/data'],
// components
['^@/components', '^@/container'],
// zustand store
['^@/store'],
// Other imports
['^@/'],
// relative paths up until 3 level
[
'^\\./?$',
'^\\.(?!/?$)',
'^\\.\\./?$',
'^\\.\\.(?!/?$)',
'^\\.\\./\\.\\./?$',
'^\\.\\./\\.\\.(?!/?$)',
'^\\.\\./\\.\\./\\.\\./?$',
'^\\.\\./\\.\\./\\.\\.(?!/?$)',
],
['^@/types'],
// other that didnt fit in
['^'],
],
},
],
//#endregion //*======== Import Sort ===========
},
globals: {
React: true,
JSX: true,
},
};

68
.eslintrc.json Normal file
View File

@@ -0,0 +1,68 @@
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"plugins": ["@typescript-eslint", "simple-import-sort", "unused-imports"],
"extends": [
"eslint:recommended",
"next",
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"no-unused-vars": "off",
"no-console": "warn",
"@typescript-eslint/explicit-module-boundary-types": "off",
"react/no-unescaped-entities": "off",
"react/display-name": "off",
"react/jsx-curly-brace-presence": [
"warn",
{ "props": "never", "children": "never" }
],
"@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "warn",
"unused-imports/no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
}
],
"simple-import-sort/exports": "warn",
"simple-import-sort/imports": [
"warn",
{
"groups": [
["^@?\\w", "^\\u0000"],
["^.+\\.s?css$"],
["^@/lib", "^@/hooks"],
["^@/data"],
["^@/components", "^@/container"],
["^@/store"],
["^@/"],
[
"^\\./?$",
"^\\.(?!/?$)",
"^\\.\\./?$",
"^\\.\\.(?!/?$)",
"^\\.\\./\\.\\./?$",
"^\\.\\./\\.\\.(?!/?$)",
"^\\.\\./\\.\\./\\.\\./?$",
"^\\.\\./\\.\\./\\.\\.(?!/?$)"
],
["^@/types"],
["^"]
]
}
]
},
"globals": {
"React": true,
"JSX": true
}
}

4
.gitignore vendored
View File

@@ -42,4 +42,6 @@ sitemap-*.xml
# generated files
src/lib/runtime.ts
public/manifest.json
public/manifest.json
public/sw.js
public/workbox-*.js

View File

@@ -1,5 +1,5 @@
module.exports = {
arrowParens: 'always',
export default {
arrowParens: "always",
singleQuote: true,
jsxSingleQuote: true,
tabWidth: 2,

View File

@@ -53,7 +53,7 @@
| 分类 | 主要依赖 |
| --------- | ----------------------------------------------------------------------------------------------------- |
| 前端框架 | [Next.js 14](https://nextjs.org/) · App Router |
| UI & 样式 | [Tailwind CSS 3](https://tailwindcss.com/) |
| UI & 样式 | [Tailwind CSS 4](https://tailwindcss.com/) |
| 语言 | TypeScript 4 |
| 播放器 | [ArtPlayer](https://github.com/zhw2590582/ArtPlayer) · [HLS.js](https://github.com/video-dev/hls.js/) |
| 代码质量 | ESLint · Prettier · Jest |

View File

@@ -1,23 +1,23 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
export default {
extends: ["@commitlint/config-conventional"],
rules: {
// TODO Add Scope Enum Here
// 'scope-enum': [2, 'always', ['yourscope', 'yourscope']],
'type-enum': [
"type-enum": [
2,
'always',
"always",
[
'feat',
'fix',
'docs',
'chore',
'style',
'refactor',
'ci',
'test',
'perf',
'revert',
'vercel',
"feat",
"fix",
"docs",
"chore",
"style",
"refactor",
"ci",
"test",
"perf",
"revert",
"vercel",
],
],
},

View File

@@ -1,28 +1,28 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const nextJest = require('next/jest');
const nextJest = require("next/jest");
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
dir: "./",
});
// Add any custom config to be passed to Jest
const customJestConfig = {
// Add more setup options before each test is run
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleDirectories: ['node_modules', '<rootDir>/'],
moduleDirectories: ["node_modules", "<rootDir>/"],
testEnvironment: 'jest-environment-jsdom',
testEnvironment: "jest-environment-jsdom",
/**
* Absolute imports and Module Path Aliases
*/
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
'^~/(.*)$': '<rootDir>/public/$1',
'^.+\\.(svg)$': '<rootDir>/src/__mocks__/svg.tsx',
"^@/(.*)$": "<rootDir>/src/$1",
"^~/(.*)$": "<rootDir>/public/$1",
"^.+\\.(svg)$": "<rootDir>/src/__mocks__/svg.tsx",
},
};

View File

@@ -1,5 +1,5 @@
import '@testing-library/jest-dom/extend-expect';
import "@testing-library/jest-dom/extend-expect";
// Allow router mocks.
// eslint-disable-next-line no-undef
jest.mock('next/router', () => require('next-router-mock'));
jest.mock("next/router", () => require("next-router-mock"));

View File

@@ -1,9 +1,10 @@
/** @type {import('next').NextConfig} */
/* eslint-disable @typescript-eslint/no-var-requires */
import withPWA from "next-pwa";
const nextConfig = {
output: 'standalone',
output: "standalone",
eslint: {
dirs: ['src'],
dirs: ["src"],
},
reactStrictMode: false,
@@ -14,12 +15,12 @@ const nextConfig = {
unoptimized: true,
remotePatterns: [
{
protocol: 'https',
hostname: '**',
protocol: "https",
hostname: "**",
},
{
protocol: 'http',
hostname: '**',
protocol: "http",
hostname: "**",
},
],
},
@@ -27,7 +28,7 @@ const nextConfig = {
webpack(config) {
// Grab the existing rule that handles SVG imports
const fileLoaderRule = config.module.rules.find((rule) =>
rule.test?.test?.('.svg')
rule.test?.test?.(".svg")
);
config.module.rules.push(
@@ -42,7 +43,7 @@ const nextConfig = {
test: /\.svg$/i,
issuer: { not: /\.(css|scss|sass)$/ },
resourceQuery: { not: /url/ }, // exclude if *.svg?url
loader: '@svgr/webpack',
loader: "@svgr/webpack",
options: {
dimensions: false,
titleProp: true,
@@ -64,11 +65,11 @@ const nextConfig = {
},
};
const withPWA = require('next-pwa')({
dest: 'public',
disable: process.env.NODE_ENV === 'development',
const pwaConfig = withPWA({
dest: "public",
disable: process.env.NODE_ENV === "development",
register: true,
skipWaiting: true,
});
module.exports = withPWA(nextConfig);
export default pwaConfig(nextConfig);

View File

@@ -2,13 +2,14 @@
"name": "moontv",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "pnpm gen:runtime && pnpm gen:manifest && next dev -H 0.0.0.0",
"build": "pnpm gen:runtime && pnpm gen:manifest && next build",
"start": "next start",
"lint": "next lint",
"lint:fix": "eslint src --fix && pnpm format",
"lint:strict": "eslint --max-warnings=0 src",
"lint:strict": "eslint --max-warnings=10 src",
"typecheck": "tsc --noEmit --incremental false",
"test:watch": "jest --watch",
"test": "jest",
@@ -54,6 +55,7 @@
"@commitlint/config-conventional": "^16.2.4",
"@svgr/webpack": "^8.1.0",
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.1.11",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^15.0.7",
"@types/node": "24.0.3",
@@ -62,7 +64,6 @@
"@types/testing-library__jest-dom": "^5.14.9",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.1",
"eslint-config-next": "^14.2.23",
"eslint-config-prettier": "^8.10.0",
@@ -74,13 +75,13 @@
"next-router-mock": "^0.9.0",
"postcss": "^8.5.1",
"prettier": "^2.8.8",
"prettier-plugin-tailwindcss": "^0.5.0",
"tailwindcss": "^3.4.17",
"prettier-plugin-tailwindcss": "^0.6.14",
"tailwindcss": "^4.1.11",
"typescript": "^4.9.5"
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": [
"eslint --max-warnings=0",
"eslint --max-warnings=10",
"prettier -w"
],
"**/*.{json,css,scss,md,webmanifest}": [
@@ -88,4 +89,4 @@
]
},
"packageManager": "pnpm@10.12.4+sha512.5ea8b0deed94ed68691c9bad4c955492705c5eeb8a87ef86bc62c74a26b037b08ff9570f108b2e4dbd1dd1a9186fea925e527f141c648e85af45631074680184"
}
}

556
pnpm-lock.yaml generated
View File

@@ -101,7 +101,10 @@ importers:
version: 8.1.0(typescript@4.9.5)
'@tailwindcss/forms':
specifier: ^0.5.10
version: 0.5.10(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.0.3)(typescript@4.9.5)))
version: 0.5.10(tailwindcss@4.1.11)
'@tailwindcss/postcss':
specifier: ^4.1.11
version: 4.1.11
'@testing-library/jest-dom':
specifier: ^5.17.0
version: 5.17.0
@@ -126,9 +129,6 @@ importers:
'@typescript-eslint/parser':
specifier: ^5.62.0
version: 5.62.0(eslint@8.57.1)(typescript@4.9.5)
autoprefixer:
specifier: ^10.4.20
version: 10.4.21(postcss@8.5.6)
eslint:
specifier: ^8.57.1
version: 8.57.1
@@ -163,11 +163,11 @@ importers:
specifier: ^2.8.8
version: 2.8.8
prettier-plugin-tailwindcss:
specifier: ^0.5.0
version: 0.5.14(prettier@2.8.8)
specifier: ^0.6.14
version: 0.6.14(prettier@2.8.8)
tailwindcss:
specifier: ^3.4.17
version: 3.4.17(ts-node@10.9.2(@types/node@24.0.3)(typescript@4.9.5))
specifier: ^4.1.11
version: 4.1.11
typescript:
specifier: ^4.9.5
version: 4.9.5
@@ -1783,6 +1783,94 @@ packages:
peerDependencies:
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1'
'@tailwindcss/node@4.1.11':
resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==}
'@tailwindcss/oxide-android-arm64@4.1.11':
resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
'@tailwindcss/oxide-darwin-arm64@4.1.11':
resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@tailwindcss/oxide-darwin-x64@4.1.11':
resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@tailwindcss/oxide-freebsd-x64@4.1.11':
resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [freebsd]
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11':
resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
'@tailwindcss/oxide-linux-arm64-gnu@4.1.11':
resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@tailwindcss/oxide-linux-arm64-musl@4.1.11':
resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@tailwindcss/oxide-linux-x64-gnu@4.1.11':
resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@tailwindcss/oxide-linux-x64-musl@4.1.11':
resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@tailwindcss/oxide-wasm32-wasi@4.1.11':
resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
bundledDependencies:
- '@napi-rs/wasm-runtime'
- '@emnapi/core'
- '@emnapi/runtime'
- '@tybys/wasm-util'
- '@emnapi/wasi-threads'
- tslib
'@tailwindcss/oxide-win32-arm64-msvc@4.1.11':
resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@tailwindcss/oxide-win32-x64-msvc@4.1.11':
resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
'@tailwindcss/oxide@4.1.11':
resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==}
engines: {node: '>= 10'}
'@tailwindcss/postcss@4.1.11':
resolution: {integrity: sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA==}
'@tanstack/react-virtual@3.13.10':
resolution: {integrity: sha512-nvrzk4E9mWB4124YdJ7/yzwou7IfHxlSef6ugCFcBfRmsnsma3heciiiV97sBNxyc3VuwtZvmwXd0aB5BpucVw==}
peerDependencies:
@@ -2353,9 +2441,6 @@ packages:
arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
@@ -2468,13 +2553,6 @@ packages:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
autoprefixer@10.4.21:
resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
postcss: ^8.1.0
available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
@@ -2608,10 +2686,6 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
camelcase-css@2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
camelcase-keys@6.2.2:
resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
engines: {node: '>=8'}
@@ -2755,10 +2829,6 @@ packages:
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
commander@4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
commander@7.2.0:
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
engines: {node: '>= 10'}
@@ -2872,11 +2942,6 @@ packages:
css.escape@1.5.1:
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
hasBin: true
csso@5.0.5:
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
@@ -3002,9 +3067,6 @@ packages:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
engines: {node: '>=8'}
didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
diff-sequences@27.5.1:
resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
@@ -3017,9 +3079,6 @@ packages:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
doctrine@2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
@@ -3678,9 +3737,6 @@ packages:
resolution: {integrity: sha512-q5YBMeWy6E2Un0nMGWMgI65MAKtaylxfNJGJxpGh45YDciZB4epbWpaAfImil6CPAPTYB4sh0URQNDRIZG5F2w==}
engines: {node: '>= 6'}
fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
framer-motion@12.18.1:
resolution: {integrity: sha512-6o4EDuRPLk4LSZ1kRnnEOurbQ86MklVk+Y1rFBUKiF+d2pCdvMjWVu0ZkyMVCTwl5UyTH2n/zJEJx+jvTYuxow==}
peerDependencies:
@@ -4351,8 +4407,8 @@ packages:
node-notifier:
optional: true
jiti@1.21.7:
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
jiti@2.4.2:
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
hasBin: true
jose@5.9.6:
@@ -4459,14 +4515,74 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
lightningcss-darwin-arm64@1.30.1:
resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [darwin]
lightningcss-darwin-x64@1.30.1:
resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [darwin]
lightningcss-freebsd-x64@1.30.1:
resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [freebsd]
lightningcss-linux-arm-gnueabihf@1.30.1:
resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==}
engines: {node: '>= 12.0.0'}
cpu: [arm]
os: [linux]
lightningcss-linux-arm64-gnu@1.30.1:
resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
lightningcss-linux-arm64-musl@1.30.1:
resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
lightningcss-linux-x64-gnu@1.30.1:
resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
lightningcss-linux-x64-musl@1.30.1:
resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
lightningcss-win32-arm64-msvc@1.30.1:
resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [win32]
lightningcss-win32-x64-msvc@1.30.1:
resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [win32]
lightningcss@1.30.1:
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
engines: {node: '>= 12.0.0'}
lilconfig@2.0.5:
resolution: {integrity: sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==}
engines: {node: '>=10'}
lilconfig@3.1.3:
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
engines: {node: '>=14'}
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
@@ -4545,6 +4661,9 @@ packages:
magic-string@0.25.9:
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
make-dir@3.1.0:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
@@ -4719,9 +4838,6 @@ packages:
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
hasBin: true
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -4832,10 +4948,6 @@ packages:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
normalize-range@0.1.2:
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
engines: {node: '>=0.10.0'}
npm-run-path@4.0.1:
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
engines: {node: '>=8'}
@@ -4850,10 +4962,6 @@ packages:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
object-hash@3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
object-inspect@1.13.4:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
@@ -4979,7 +5087,6 @@ packages:
path-match@1.2.4:
resolution: {integrity: sha512-UWlehEdqu36jmh4h5CWJ7tARp1OEVKGHKm6+dg9qMq5RKUTV5WJrGgaZ3dN2m7WFAXDbjlHzvJvL/IUpy84Ktw==}
deprecated: This package is archived and no longer maintained. For support, visit https://github.com/expressjs/express/discussions
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
@@ -5057,43 +5164,6 @@ packages:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'}
postcss-import@15.1.0:
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
engines: {node: '>=14.0.0'}
peerDependencies:
postcss: ^8.0.0
postcss-js@4.0.1:
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
engines: {node: ^12 || ^14 || >= 16}
peerDependencies:
postcss: ^8.4.21
postcss-load-config@4.0.2:
resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
engines: {node: '>= 14'}
peerDependencies:
postcss: '>=8.0.9'
ts-node: '>=9.0.0'
peerDependenciesMeta:
postcss:
optional: true
ts-node:
optional: true
postcss-nested@6.2.0:
resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==}
engines: {node: '>=12.0'}
peerDependencies:
postcss: ^8.2.14
postcss-selector-parser@6.1.2:
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
engines: {node: '>=4'}
postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
postcss@8.4.31:
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
engines: {node: ^10 || ^12 || >=14}
@@ -5106,21 +5176,24 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
prettier-plugin-tailwindcss@0.5.14:
resolution: {integrity: sha512-Puaz+wPUAhFp8Lo9HuciYKM2Y2XExESjeT+9NQoVFXZsPPnc9VYss2SpxdQ6vbatmt8/4+SN0oe0I1cPDABg9Q==}
prettier-plugin-tailwindcss@0.6.14:
resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==}
engines: {node: '>=14.21.3'}
peerDependencies:
'@ianvs/prettier-plugin-sort-imports': '*'
'@prettier/plugin-hermes': '*'
'@prettier/plugin-oxc': '*'
'@prettier/plugin-pug': '*'
'@shopify/prettier-plugin-liquid': '*'
'@trivago/prettier-plugin-sort-imports': '*'
'@zackad/prettier-plugin-twig-melody': '*'
'@zackad/prettier-plugin-twig': '*'
prettier: ^3.0
prettier-plugin-astro: '*'
prettier-plugin-css-order: '*'
prettier-plugin-import-sort: '*'
prettier-plugin-jsdoc: '*'
prettier-plugin-marko: '*'
prettier-plugin-multiline-arrays: '*'
prettier-plugin-organize-attributes: '*'
prettier-plugin-organize-imports: '*'
prettier-plugin-sort-imports: '*'
@@ -5129,13 +5202,17 @@ packages:
peerDependenciesMeta:
'@ianvs/prettier-plugin-sort-imports':
optional: true
'@prettier/plugin-hermes':
optional: true
'@prettier/plugin-oxc':
optional: true
'@prettier/plugin-pug':
optional: true
'@shopify/prettier-plugin-liquid':
optional: true
'@trivago/prettier-plugin-sort-imports':
optional: true
'@zackad/prettier-plugin-twig-melody':
'@zackad/prettier-plugin-twig':
optional: true
prettier-plugin-astro:
optional: true
@@ -5147,6 +5224,8 @@ packages:
optional: true
prettier-plugin-marko:
optional: true
prettier-plugin-multiline-arrays:
optional: true
prettier-plugin-organize-attributes:
optional: true
prettier-plugin-organize-imports:
@@ -5247,9 +5326,6 @@ packages:
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
engines: {node: '>=0.10.0'}
read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
read-pkg-up@7.0.1:
resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
engines: {node: '>=8'}
@@ -5705,11 +5781,6 @@ packages:
babel-plugin-macros:
optional: true
sucrase@3.35.0:
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@@ -5754,10 +5825,8 @@ packages:
tailwind-merge@2.6.0:
resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==}
tailwindcss@3.4.17:
resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==}
engines: {node: '>=14.0.0'}
hasBin: true
tailwindcss@4.1.11:
resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==}
tapable@2.2.2:
resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==}
@@ -5815,13 +5884,6 @@ packages:
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
thenify-all@1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
engines: {node: '>=0.8'}
thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
throat@6.0.2:
resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==}
@@ -5879,9 +5941,6 @@ packages:
resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
engines: {node: '>=8'}
ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
ts-morph@12.0.0:
resolution: {integrity: sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==}
@@ -6337,11 +6396,6 @@ packages:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
yaml@2.8.0:
resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==}
engines: {node: '>= 14.6'}
hasBin: true
yargs-parser@20.2.9:
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
engines: {node: '>=10'}
@@ -8191,10 +8245,82 @@ snapshots:
'@swc/counter': 0.1.3
tslib: 2.8.1
'@tailwindcss/forms@0.5.10(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.0.3)(typescript@4.9.5)))':
'@tailwindcss/forms@0.5.10(tailwindcss@4.1.11)':
dependencies:
mini-svg-data-uri: 1.4.4
tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@24.0.3)(typescript@4.9.5))
tailwindcss: 4.1.11
'@tailwindcss/node@4.1.11':
dependencies:
'@ampproject/remapping': 2.3.0
enhanced-resolve: 5.18.2
jiti: 2.4.2
lightningcss: 1.30.1
magic-string: 0.30.17
source-map-js: 1.2.1
tailwindcss: 4.1.11
'@tailwindcss/oxide-android-arm64@4.1.11':
optional: true
'@tailwindcss/oxide-darwin-arm64@4.1.11':
optional: true
'@tailwindcss/oxide-darwin-x64@4.1.11':
optional: true
'@tailwindcss/oxide-freebsd-x64@4.1.11':
optional: true
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11':
optional: true
'@tailwindcss/oxide-linux-arm64-gnu@4.1.11':
optional: true
'@tailwindcss/oxide-linux-arm64-musl@4.1.11':
optional: true
'@tailwindcss/oxide-linux-x64-gnu@4.1.11':
optional: true
'@tailwindcss/oxide-linux-x64-musl@4.1.11':
optional: true
'@tailwindcss/oxide-wasm32-wasi@4.1.11':
optional: true
'@tailwindcss/oxide-win32-arm64-msvc@4.1.11':
optional: true
'@tailwindcss/oxide-win32-x64-msvc@4.1.11':
optional: true
'@tailwindcss/oxide@4.1.11':
dependencies:
detect-libc: 2.0.4
tar: 7.4.3
optionalDependencies:
'@tailwindcss/oxide-android-arm64': 4.1.11
'@tailwindcss/oxide-darwin-arm64': 4.1.11
'@tailwindcss/oxide-darwin-x64': 4.1.11
'@tailwindcss/oxide-freebsd-x64': 4.1.11
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.11
'@tailwindcss/oxide-linux-arm64-gnu': 4.1.11
'@tailwindcss/oxide-linux-arm64-musl': 4.1.11
'@tailwindcss/oxide-linux-x64-gnu': 4.1.11
'@tailwindcss/oxide-linux-x64-musl': 4.1.11
'@tailwindcss/oxide-wasm32-wasi': 4.1.11
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.11
'@tailwindcss/oxide-win32-x64-msvc': 4.1.11
'@tailwindcss/postcss@4.1.11':
dependencies:
'@alloc/quick-lru': 5.2.0
'@tailwindcss/node': 4.1.11
'@tailwindcss/oxide': 4.1.11
postcss: 8.5.6
tailwindcss: 4.1.11
'@tanstack/react-virtual@3.13.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@@ -8882,8 +9008,6 @@ snapshots:
arg@4.1.3: {}
arg@5.0.2: {}
argparse@1.0.10:
dependencies:
sprintf-js: 1.0.3
@@ -9011,16 +9135,6 @@ snapshots:
at-least-node@1.0.0: {}
autoprefixer@10.4.21(postcss@8.5.6):
dependencies:
browserslist: 4.25.0
caniuse-lite: 1.0.30001723
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.1.1
postcss: 8.5.6
postcss-value-parser: 4.2.0
available-typed-arrays@1.0.7:
dependencies:
possible-typed-array-names: 1.1.0
@@ -9189,8 +9303,6 @@ snapshots:
callsites@3.1.0: {}
camelcase-css@2.0.1: {}
camelcase-keys@6.2.2:
dependencies:
camelcase: 5.3.1
@@ -9318,8 +9430,6 @@ snapshots:
commander@2.20.3: {}
commander@4.1.1: {}
commander@7.2.0: {}
commander@9.5.0: {}
@@ -9432,8 +9542,6 @@ snapshots:
css.escape@1.5.1: {}
cssesc@3.0.0: {}
csso@5.0.5:
dependencies:
css-tree: 2.2.1
@@ -9541,8 +9649,6 @@ snapshots:
detect-newline@3.1.0: {}
didyoumean@1.2.2: {}
diff-sequences@27.5.1: {}
diff@4.0.2: {}
@@ -9551,8 +9657,6 @@ snapshots:
dependencies:
path-type: 4.0.0
dlv@1.1.3: {}
doctrine@2.1.0:
dependencies:
esutils: 2.0.3
@@ -10310,8 +10414,6 @@ snapshots:
es-set-tostringtag: 2.1.0
mime-types: 2.1.35
fraction.js@4.3.7: {}
framer-motion@12.18.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
motion-dom: 12.18.1
@@ -11241,7 +11343,7 @@ snapshots:
- ts-node
- utf-8-validate
jiti@1.21.7: {}
jiti@2.4.2: {}
jose@5.9.6: {}
@@ -11355,9 +11457,52 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
lilconfig@2.0.5: {}
lightningcss-darwin-arm64@1.30.1:
optional: true
lilconfig@3.1.3: {}
lightningcss-darwin-x64@1.30.1:
optional: true
lightningcss-freebsd-x64@1.30.1:
optional: true
lightningcss-linux-arm-gnueabihf@1.30.1:
optional: true
lightningcss-linux-arm64-gnu@1.30.1:
optional: true
lightningcss-linux-arm64-musl@1.30.1:
optional: true
lightningcss-linux-x64-gnu@1.30.1:
optional: true
lightningcss-linux-x64-musl@1.30.1:
optional: true
lightningcss-win32-arm64-msvc@1.30.1:
optional: true
lightningcss-win32-x64-msvc@1.30.1:
optional: true
lightningcss@1.30.1:
dependencies:
detect-libc: 2.0.4
optionalDependencies:
lightningcss-darwin-arm64: 1.30.1
lightningcss-darwin-x64: 1.30.1
lightningcss-freebsd-x64: 1.30.1
lightningcss-linux-arm-gnueabihf: 1.30.1
lightningcss-linux-arm64-gnu: 1.30.1
lightningcss-linux-arm64-musl: 1.30.1
lightningcss-linux-x64-gnu: 1.30.1
lightningcss-linux-x64-musl: 1.30.1
lightningcss-win32-arm64-msvc: 1.30.1
lightningcss-win32-x64-msvc: 1.30.1
lilconfig@2.0.5: {}
lines-and-columns@1.2.4: {}
@@ -11450,6 +11595,10 @@ snapshots:
dependencies:
sourcemap-codec: 1.4.8
magic-string@0.30.17:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
make-dir@3.1.0:
dependencies:
semver: 6.3.1
@@ -11620,12 +11769,6 @@ snapshots:
mustache@4.2.0: {}
mz@2.7.0:
dependencies:
any-promise: 1.3.0
object-assign: 4.1.1
thenify-all: 1.6.0
nanoid@3.3.11: {}
napi-postinstall@0.2.4: {}
@@ -11732,8 +11875,6 @@ snapshots:
normalize-path@3.0.0: {}
normalize-range@0.1.2: {}
npm-run-path@4.0.1:
dependencies:
path-key: 3.1.1
@@ -11746,8 +11887,6 @@ snapshots:
object-assign@4.1.1: {}
object-hash@3.0.0: {}
object-inspect@1.13.4: {}
object-keys@1.1.1: {}
@@ -11935,38 +12074,6 @@ snapshots:
possible-typed-array-names@1.1.0: {}
postcss-import@15.1.0(postcss@8.5.6):
dependencies:
postcss: 8.5.6
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.10
postcss-js@4.0.1(postcss@8.5.6):
dependencies:
camelcase-css: 2.0.1
postcss: 8.5.6
postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.0.3)(typescript@4.9.5)):
dependencies:
lilconfig: 3.1.3
yaml: 2.8.0
optionalDependencies:
postcss: 8.5.6
ts-node: 10.9.2(@types/node@24.0.3)(typescript@4.9.5)
postcss-nested@6.2.0(postcss@8.5.6):
dependencies:
postcss: 8.5.6
postcss-selector-parser: 6.1.2
postcss-selector-parser@6.1.2:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
postcss-value-parser@4.2.0: {}
postcss@8.4.31:
dependencies:
nanoid: 3.3.11
@@ -11981,7 +12088,7 @@ snapshots:
prelude-ls@1.2.1: {}
prettier-plugin-tailwindcss@0.5.14(prettier@2.8.8):
prettier-plugin-tailwindcss@0.6.14(prettier@2.8.8):
dependencies:
prettier: 2.8.8
@@ -12065,10 +12172,6 @@ snapshots:
dependencies:
loose-envify: 1.4.0
read-cache@1.0.0:
dependencies:
pify: 2.3.0
read-pkg-up@7.0.1:
dependencies:
find-up: 4.1.0
@@ -12595,16 +12698,6 @@ snapshots:
optionalDependencies:
'@babel/core': 7.27.4
sucrase@3.35.0:
dependencies:
'@jridgewell/gen-mapping': 0.3.8
commander: 4.1.1
glob: 10.4.5
lines-and-columns: 1.2.4
mz: 2.7.0
pirates: 4.0.7
ts-interface-checker: 0.1.13
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
@@ -12644,32 +12737,7 @@ snapshots:
tailwind-merge@2.6.0: {}
tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.0.3)(typescript@4.9.5)):
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
chokidar: 3.6.0
didyoumean: 1.2.2
dlv: 1.1.3
fast-glob: 3.3.3
glob-parent: 6.0.2
is-glob: 4.0.3
jiti: 1.21.7
lilconfig: 3.1.3
micromatch: 4.0.8
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.1.1
postcss: 8.5.6
postcss-import: 15.1.0(postcss@8.5.6)
postcss-js: 4.0.1(postcss@8.5.6)
postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.0.3)(typescript@4.9.5))
postcss-nested: 6.2.0(postcss@8.5.6)
postcss-selector-parser: 6.1.2
resolve: 1.22.10
sucrase: 3.35.0
transitivePeerDependencies:
- ts-node
tailwindcss@4.1.11: {}
tapable@2.2.2: {}
@@ -12731,14 +12799,6 @@ snapshots:
text-table@0.2.0: {}
thenify-all@1.6.0:
dependencies:
thenify: 3.3.1
thenify@3.3.1:
dependencies:
any-promise: 1.3.0
throat@6.0.2: {}
throttleit@2.1.0: {}
@@ -12789,8 +12849,6 @@ snapshots:
trim-newlines@3.0.1: {}
ts-interface-checker@0.1.13: {}
ts-morph@12.0.0:
dependencies:
'@ts-morph/common': 0.11.1
@@ -13395,8 +13453,6 @@ snapshots:
yaml@1.10.2: {}
yaml@2.8.0: {}
yargs-parser@20.2.9: {}
yargs-parser@21.1.1: {}

View File

@@ -1,6 +1,5 @@
module.exports = {
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
"@tailwindcss/postcss": {},
},
};

View File

@@ -3,28 +3,34 @@
// AUTO-GENERATED SCRIPT: Converts config.json to TypeScript definition.
// Usage: node scripts/convert-config.js
const fs = require('fs');
const path = require('path');
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { dirname } from "path";
// Get __dirname equivalent for ES modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Resolve project root (one level up from scripts folder)
const projectRoot = path.resolve(__dirname, '..');
const projectRoot = path.resolve(__dirname, "..");
// Paths
const configPath = path.join(projectRoot, 'config.json');
const libDir = path.join(projectRoot, 'src', 'lib');
const oldRuntimePath = path.join(libDir, 'runtime.ts');
const newRuntimePath = path.join(libDir, 'runtime.ts');
const configPath = path.join(projectRoot, "config.json");
const libDir = path.join(projectRoot, "src", "lib");
const oldRuntimePath = path.join(libDir, "runtime.ts");
const newRuntimePath = path.join(libDir, "runtime.ts");
// Delete the old runtime.ts file if it exists
if (fs.existsSync(oldRuntimePath)) {
fs.unlinkSync(oldRuntimePath);
console.log('旧的 runtime.ts 已删除');
console.log("旧的 runtime.ts 已删除");
}
// Read and parse config.json
let rawConfig;
try {
rawConfig = fs.readFileSync(configPath, 'utf8');
rawConfig = fs.readFileSync(configPath, "utf8");
} catch (err) {
console.error(`无法读取 ${configPath}:`, err);
process.exit(1);
@@ -34,7 +40,7 @@ let config;
try {
config = JSON.parse(rawConfig);
} catch (err) {
console.error('config.json 不是有效的 JSON:', err);
console.error("config.json 不是有效的 JSON:", err);
process.exit(1);
}
@@ -53,9 +59,9 @@ if (!fs.existsSync(libDir)) {
// Write to runtime.ts
try {
fs.writeFileSync(newRuntimePath, tsContent, 'utf8');
console.log('已生成 src/lib/runtime.ts');
fs.writeFileSync(newRuntimePath, tsContent, "utf8");
console.log("已生成 src/lib/runtime.ts");
} catch (err) {
console.error('写入 runtime.ts 失败:', err);
console.error("写入 runtime.ts 失败:", err);
process.exit(1);
}

View File

@@ -2,50 +2,56 @@
/* eslint-disable */
// 根据 SITE_NAME 动态生成 manifest.json
const fs = require('fs');
const path = require('path');
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { dirname } from "path";
// Get __dirname equivalent for ES modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// 获取项目根目录
const projectRoot = path.resolve(__dirname, '..');
const publicDir = path.join(projectRoot, 'public');
const manifestPath = path.join(publicDir, 'manifest.json');
const projectRoot = path.resolve(__dirname, "..");
const publicDir = path.join(projectRoot, "public");
const manifestPath = path.join(publicDir, "manifest.json");
// 从环境变量获取站点名称
const siteName = process.env.SITE_NAME || 'MoonTV';
const siteName = process.env.SITE_NAME || "MoonTV";
// manifest.json 模板
const manifestTemplate = {
"name": siteName,
"short_name": siteName,
"description": "影视聚合",
"start_url": "/",
"scope": "/",
"display": "standalone",
"background_color": "#000000",
name: siteName,
short_name: siteName,
description: "影视聚合",
start_url: "/",
scope: "/",
display: "standalone",
background_color: "#000000",
"apple-mobile-web-app-capable": "yes",
"apple-mobile-web-app-status-bar-style": "black",
"icons": [
icons: [
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
src: "/icons/icon-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
"src": "/icons/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
src: "/icons/icon-256x256.png",
sizes: "256x256",
type: "image/png",
},
{
"src": "/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
src: "/icons/icon-384x384.png",
sizes: "384x384",
type: "image/png",
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
src: "/icons/icon-512x512.png",
sizes: "512x512",
type: "image/png",
},
],
};
try {
@@ -58,6 +64,6 @@ try {
fs.writeFileSync(manifestPath, JSON.stringify(manifestTemplate, null, 2));
console.log(`✅ Generated manifest.json with site name: ${siteName}`);
} catch (error) {
console.error('❌ Error generating manifest.json:', error);
console.error("❌ Error generating manifest.json:", error);
process.exit(1);
}

View File

@@ -80,7 +80,7 @@ const CollapsibleTab = ({
children,
}: CollapsibleTabProps) => {
return (
<div className='rounded-xl shadow-sm mb-4 overflow-hidden bg-white/80 backdrop-blur-md dark:bg-gray-800/50 dark:ring-1 dark:ring-gray-700'>
<div className='rounded-xl shadow-xs mb-4 overflow-hidden bg-white/80 backdrop-blur-md dark:bg-gray-800/50 dark:ring-1 dark:ring-gray-700'>
<button
onClick={onToggle}
className='w-full px-6 py-4 flex items-center justify-between bg-gray-50/70 dark:bg-gray-800/60 hover:bg-gray-100/80 dark:hover:bg-gray-700/60 transition-colors'
@@ -308,7 +308,7 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
toggleAllowRegister(!userSettings.enableRegistration)
}
disabled={isD1Storage}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 ${
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-hidden focus:ring-2 focus:ring-green-500 focus:ring-offset-2 ${
userSettings.enableRegistration
? 'bg-green-600'
: 'bg-gray-200 dark:bg-gray-700'
@@ -425,7 +425,7 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
)}
{/* 用户列表 */}
<div className='border border-gray-200 dark:border-gray-700 rounded-lg max-h-[28rem] overflow-y-auto overflow-x-auto'>
<div className='border border-gray-200 dark:border-gray-700 rounded-lg max-h-112 overflow-y-auto overflow-x-auto'>
<table className='min-w-full divide-y divide-gray-200 dark:divide-gray-700'>
<thead className='bg-gray-50 dark:bg-gray-900'>
<tr>
@@ -758,18 +758,18 @@ const VideoSourceConfig = ({
{source.key}
</td>
<td
className='px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100 max-w-[12rem] truncate'
className='px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100 max-w-48 truncate'
title={source.api}
>
{source.api}
</td>
<td
className='px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100 max-w-[8rem] truncate'
className='px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100 max-w-32 truncate'
title={source.detail || '-'}
>
{source.detail || '-'}
</td>
<td className='px-6 py-4 whitespace-nowrap max-w-[1rem]'>
<td className='px-6 py-4 whitespace-nowrap max-w-4'>
<span
className={`px-2 py-1 text-xs rounded-full ${
!source.disabled
@@ -880,7 +880,7 @@ const VideoSourceConfig = ({
)}
{/* 视频源表格 */}
<div className='border border-gray-200 dark:border-gray-700 rounded-lg max-h-[28rem] overflow-y-auto overflow-x-auto'>
<div className='border border-gray-200 dark:border-gray-700 rounded-lg max-h-112 overflow-y-auto overflow-x-auto'>
<table className='min-w-full divide-y divide-gray-200 dark:divide-gray-700'>
<thead className='bg-gray-50 dark:bg-gray-900'>
<tr>

View File

@@ -267,7 +267,7 @@ function DoubanPageClient() {
</div>
{/* 选择器组件 */}
<div className='bg-white/60 dark:bg-gray-800/40 rounded-2xl p-4 sm:p-6 border border-gray-200/30 dark:border-gray-700/30 backdrop-blur-sm'>
<div className='bg-white/60 dark:bg-gray-800/40 rounded-2xl p-4 sm:p-6 border border-gray-200/30 dark:border-gray-700/30 backdrop-blur-xs'>
<DoubanSelector
type={type as 'movie' | 'tv' | 'show'}
primarySelection={primarySelection}

View File

@@ -1,14 +1,30 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import 'tailwindcss';
@layer utilities {
.scrollbar-hide {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
@config "../../tailwind.config.ts";
/*
The default border color has changed to `currentcolor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentcolor);
}
}
.scrollbar-hide::-webkit-scrollbar {
@utility scrollbar-hide {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
&::-webkit-scrollbar {
display: none; /* Chrome, Safari and Opera */
}
}

View File

@@ -93,8 +93,8 @@ function LoginPageClient() {
<div className='absolute top-4 right-4'>
<ThemeToggle />
</div>
<div className='relative z-10 w-full max-w-md rounded-3xl bg-gradient-to-b from-white/90 via-white/70 to-white/40 dark:from-zinc-900/90 dark:via-zinc-900/70 dark:to-zinc-900/40 backdrop-blur-xl shadow-2xl p-10 dark:border dark:border-zinc-800'>
<h1 className='text-green-600 tracking-tight text-center text-3xl font-extrabold mb-8 bg-clip-text drop-shadow-sm'>
<div className='relative z-10 w-full max-w-md rounded-3xl bg-linear-to-b from-white/90 via-white/70 to-white/40 dark:from-zinc-900/90 dark:via-zinc-900/70 dark:to-zinc-900/40 backdrop-blur-xl shadow-2xl p-10 dark:border dark:border-zinc-800'>
<h1 className='text-green-600 tracking-tight text-center text-3xl font-extrabold mb-8 bg-clip-text drop-shadow-xs'>
{siteName}
</h1>
<form onSubmit={handleSubmit} className='space-y-8'>
@@ -107,7 +107,7 @@ function LoginPageClient() {
id='username'
type='text'
autoComplete='username'
className='block w-full rounded-lg border-0 py-3 px-4 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-white/60 dark:ring-white/20 placeholder:text-gray-500 dark:placeholder:text-gray-400 focus:ring-2 focus:ring-green-500 focus:outline-none sm:text-base bg-white/60 dark:bg-zinc-800/60 backdrop-blur'
className='block w-full rounded-lg border-0 py-3 px-4 text-gray-900 dark:text-gray-100 shadow-xs ring-1 ring-white/60 dark:ring-white/20 placeholder:text-gray-500 dark:placeholder:text-gray-400 focus:ring-2 focus:ring-green-500 focus:outline-hidden sm:text-base bg-white/60 dark:bg-zinc-800/60 backdrop-blur-sm'
placeholder='输入用户名'
value={username}
onChange={(e) => setUsername(e.target.value)}
@@ -123,7 +123,7 @@ function LoginPageClient() {
id='password'
type='password'
autoComplete='current-password'
className='block w-full rounded-lg border-0 py-3 px-4 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-white/60 dark:ring-white/20 placeholder:text-gray-500 dark:placeholder:text-gray-400 focus:ring-2 focus:ring-green-500 focus:outline-none sm:text-base bg-white/60 dark:bg-zinc-800/60 backdrop-blur'
className='block w-full rounded-lg border-0 py-3 px-4 text-gray-900 dark:text-gray-100 shadow-xs ring-1 ring-white/60 dark:ring-white/20 placeholder:text-gray-500 dark:placeholder:text-gray-400 focus:ring-2 focus:ring-green-500 focus:outline-hidden sm:text-base bg-white/60 dark:bg-zinc-800/60 backdrop-blur-sm'
placeholder='输入访问密码'
value={password}
onChange={(e) => setPassword(e.target.value)}

View File

@@ -183,7 +183,7 @@ function HomeClient() {
</button>
)}
</div>
<div className='justify-start grid grid-cols-3 gap-x-2 gap-y-14 sm:gap-y-20 px-0 sm:px-2 sm:grid-cols-[repeat(auto-fill,_minmax(11rem,_1fr))] sm:gap-x-8'>
<div className='justify-start grid grid-cols-3 gap-x-2 gap-y-14 sm:gap-y-20 px-0 sm:px-2 sm:grid-cols-[repeat(auto-fill,minmax(11rem,1fr))] sm:gap-x-8'>
{favoriteItems.map((item) => (
<div key={item.id + item.source} className='w-full'>
<VideoCard
@@ -228,10 +228,10 @@ function HomeClient() {
key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
>
<div className='relative aspect-[2/3] w-full overflow-hidden rounded-lg bg-gray-200 animate-pulse dark:bg-gray-800'>
<div className='relative aspect-2/3 w-full overflow-hidden rounded-lg bg-gray-200 animate-pulse dark:bg-gray-800'>
<div className='absolute inset-0 bg-gray-300 dark:bg-gray-700'></div>
</div>
<div className='mt-2 h-4 bg-gray-200 rounded animate-pulse dark:bg-gray-800'></div>
<div className='mt-2 h-4 bg-gray-200 rounded-sm animate-pulse dark:bg-gray-800'></div>
</div>
))
: // 显示真实数据
@@ -275,10 +275,10 @@ function HomeClient() {
key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
>
<div className='relative aspect-[2/3] w-full overflow-hidden rounded-lg bg-gray-200 animate-pulse dark:bg-gray-800'>
<div className='relative aspect-2/3 w-full overflow-hidden rounded-lg bg-gray-200 animate-pulse dark:bg-gray-800'>
<div className='absolute inset-0 bg-gray-300 dark:bg-gray-700'></div>
</div>
<div className='mt-2 h-4 bg-gray-200 rounded animate-pulse dark:bg-gray-800'></div>
<div className='mt-2 h-4 bg-gray-200 rounded-sm animate-pulse dark:bg-gray-800'></div>
</div>
))
: // 显示真实数据
@@ -305,7 +305,7 @@ function HomeClient() {
</div>
{announcement && showAnnouncement && (
<div
className={`fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm dark:bg-black/70 p-4 transition-opacity duration-300 ${
className={`fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-xs dark:bg-black/70 p-4 transition-opacity duration-300 ${
showAnnouncement ? '' : 'opacity-0 pointer-events-none'
}`}
>
@@ -330,7 +330,7 @@ function HomeClient() {
</div>
<button
onClick={() => handleCloseAnnouncement(announcement)}
className='w-full rounded-lg bg-gradient-to-r from-green-600 to-green-700 px-4 py-3 text-white font-medium shadow-md hover:shadow-lg hover:from-green-700 hover:to-green-800 dark:from-green-600 dark:to-green-700 dark:hover:from-green-700 dark:hover:to-green-800 transition-all duration-300 transform hover:-translate-y-0.5'
className='w-full rounded-lg bg-linear-to-r from-green-600 to-green-700 px-4 py-3 text-white font-medium shadow-md hover:shadow-lg hover:from-green-700 hover:to-green-800 dark:from-green-600 dark:to-green-700 dark:hover:from-green-700 dark:hover:to-green-800 transition-all duration-300 transform hover:-translate-y-0.5'
>
</button>

View File

@@ -1286,7 +1286,7 @@ function PlayPageClient() {
<div className='text-center max-w-md mx-auto px-6'>
{/* 动画影院图标 */}
<div className='relative mb-8'>
<div className='relative mx-auto w-24 h-24 bg-gradient-to-r from-green-500 to-emerald-600 rounded-2xl shadow-2xl flex items-center justify-center transform hover:scale-105 transition-transform duration-300'>
<div className='relative mx-auto w-24 h-24 bg-linear-to-r from-green-500 to-emerald-600 rounded-2xl shadow-2xl flex items-center justify-center transform hover:scale-105 transition-transform duration-300'>
<div className='text-white text-4xl'>
{loadingStage === 'searching' && '🔍'}
{loadingStage === 'preferring' && '⚡'}
@@ -1294,7 +1294,7 @@ function PlayPageClient() {
{loadingStage === 'ready' && '✨'}
</div>
{/* 旋转光环 */}
<div className='absolute -inset-2 bg-gradient-to-r from-green-500 to-emerald-600 rounded-2xl opacity-20 animate-spin'></div>
<div className='absolute -inset-2 bg-linear-to-r from-green-500 to-emerald-600 rounded-2xl opacity-20 animate-spin'></div>
</div>
{/* 浮动粒子效果 */}
@@ -1345,7 +1345,7 @@ function PlayPageClient() {
{/* 进度条 */}
<div className='w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2 overflow-hidden'>
<div
className='h-full bg-gradient-to-r from-green-500 to-emerald-600 rounded-full transition-all duration-1000 ease-out'
className='h-full bg-linear-to-r from-green-500 to-emerald-600 rounded-full transition-all duration-1000 ease-out'
style={{
width:
loadingStage === 'searching' ||
@@ -1378,10 +1378,10 @@ function PlayPageClient() {
<div className='text-center max-w-md mx-auto px-6'>
{/* 错误图标 */}
<div className='relative mb-8'>
<div className='relative mx-auto w-24 h-24 bg-gradient-to-r from-red-500 to-orange-500 rounded-2xl shadow-2xl flex items-center justify-center transform hover:scale-105 transition-transform duration-300'>
<div className='relative mx-auto w-24 h-24 bg-linear-to-r from-red-500 to-orange-500 rounded-2xl shadow-2xl flex items-center justify-center transform hover:scale-105 transition-transform duration-300'>
<div className='text-white text-4xl'>😵</div>
{/* 脉冲效果 */}
<div className='absolute -inset-2 bg-gradient-to-r from-red-500 to-orange-500 rounded-2xl opacity-20 animate-pulse'></div>
<div className='absolute -inset-2 bg-linear-to-r from-red-500 to-orange-500 rounded-2xl opacity-20 animate-pulse'></div>
</div>
{/* 浮动错误粒子 */}
@@ -1421,7 +1421,7 @@ function PlayPageClient() {
? router.push(`/search?q=${encodeURIComponent(videoTitle)}`)
: router.back()
}
className='w-full px-6 py-3 bg-gradient-to-r from-green-500 to-emerald-600 text-white rounded-xl font-medium hover:from-green-600 hover:to-emerald-700 transform hover:scale-105 transition-all duration-200 shadow-lg hover:shadow-xl'
className='w-full px-6 py-3 bg-linear-to-r from-green-500 to-emerald-600 text-white rounded-xl font-medium hover:from-green-600 hover:to-emerald-700 transform hover:scale-105 transition-all duration-200 shadow-lg hover:shadow-xl'
>
{videoTitle ? '🔍 返回搜索' : '← 返回上页'}
</button>
@@ -1441,7 +1441,7 @@ function PlayPageClient() {
return (
<PageLayout activePath='/play'>
<div className='flex flex-col gap-3 py-4 px-5 lg:px-[3rem] 2xl:px-20'>
<div className='flex flex-col gap-3 py-4 px-5 lg:px-12 2xl:px-20'>
{/* 第一行:影片标题 */}
<div className='py-1'>
<h1 className='text-xl font-semibold text-gray-900 dark:text-gray-100'>
@@ -1461,7 +1461,7 @@ function PlayPageClient() {
onClick={() =>
setIsEpisodeSelectorCollapsed(!isEpisodeSelectorCollapsed)
}
className='group relative flex items-center space-x-1.5 px-3 py-1.5 rounded-full bg-white/80 hover:bg-white dark:bg-gray-800/80 dark:hover:bg-gray-800 backdrop-blur-sm border border-gray-200/50 dark:border-gray-700/50 shadow-sm hover:shadow-md transition-all duration-200'
className='group relative flex items-center space-x-1.5 px-3 py-1.5 rounded-full bg-white/80 hover:bg-white dark:bg-gray-800/80 dark:hover:bg-gray-800 backdrop-blur-xs border border-gray-200/50 dark:border-gray-700/50 shadow-xs hover:shadow-md transition-all duration-200'
title={
isEpisodeSelectorCollapsed ? '显示选集面板' : '隐藏选集面板'
}
@@ -1517,14 +1517,14 @@ function PlayPageClient() {
{/* 换源加载蒙层 */}
{isVideoLoading && (
<div className='absolute inset-0 bg-black/85 backdrop-blur-sm rounded-xl flex items-center justify-center z-[500] transition-all duration-300'>
<div className='absolute inset-0 bg-black/85 backdrop-blur-xs rounded-xl flex items-center justify-center z-500 transition-all duration-300'>
<div className='text-center max-w-md mx-auto px-6'>
{/* 动画影院图标 */}
<div className='relative mb-8'>
<div className='relative mx-auto w-24 h-24 bg-gradient-to-r from-green-500 to-emerald-600 rounded-2xl shadow-2xl flex items-center justify-center transform hover:scale-105 transition-transform duration-300'>
<div className='relative mx-auto w-24 h-24 bg-linear-to-r from-green-500 to-emerald-600 rounded-2xl shadow-2xl flex items-center justify-center transform hover:scale-105 transition-transform duration-300'>
<div className='text-white text-4xl'>🎬</div>
{/* 旋转光环 */}
<div className='absolute -inset-2 bg-gradient-to-r from-green-500 to-emerald-600 rounded-2xl opacity-20 animate-spin'></div>
<div className='absolute -inset-2 bg-linear-to-r from-green-500 to-emerald-600 rounded-2xl opacity-20 animate-spin'></div>
</div>
{/* 浮动粒子效果 */}
@@ -1586,21 +1586,21 @@ function PlayPageClient() {
<div className='md:col-span-3'>
<div className='p-6 flex flex-col min-h-0'>
{/* 标题 */}
<h1 className='text-3xl font-bold mb-2 tracking-wide flex items-center flex-shrink-0 text-center md:text-left w-full'>
<h1 className='text-3xl font-bold mb-2 tracking-wide flex items-center shrink-0 text-center md:text-left w-full'>
{videoTitle || '影片标题'}
<button
onClick={(e) => {
e.stopPropagation();
handleToggleFavorite();
}}
className='ml-3 flex-shrink-0 hover:opacity-80 transition-opacity'
className='ml-3 shrink-0 hover:opacity-80 transition-opacity'
>
<FavoriteIcon filled={favorited} />
</button>
</h1>
{/* 关键信息行 */}
<div className='flex flex-wrap items-center gap-3 text-base mb-4 opacity-80 flex-shrink-0'>
<div className='flex flex-wrap items-center gap-3 text-base mb-4 opacity-80 shrink-0'>
{detail?.class && (
<span className='text-green-600 font-semibold'>
{detail.class}
@@ -1610,7 +1610,7 @@ function PlayPageClient() {
<span>{detail?.year || videoYear}</span>
)}
{detail?.source_name && (
<span className='border border-gray-500/60 px-2 py-[1px] rounded'>
<span className='border border-gray-500/60 px-2 py-px rounded-sm'>
{detail.source_name}
</span>
)}
@@ -1631,7 +1631,7 @@ function PlayPageClient() {
{/* 封面展示 */}
<div className='hidden md:block md:col-span-1 md:order-first'>
<div className='pl-0 py-4 pr-6'>
<div className='bg-gray-300 dark:bg-gray-700 aspect-[2/3] flex items-center justify-center rounded-xl overflow-hidden'>
<div className='bg-gray-300 dark:bg-gray-700 aspect-2/3 flex items-center justify-center rounded-xl overflow-hidden'>
{videoCover ? (
<img
src={processImageUrl(videoCover)}
@@ -1673,7 +1673,7 @@ const FavoriteIcon = ({ filled }: { filled: boolean }) => {
);
}
return (
<Heart className='h-7 w-7 stroke-[1] text-gray-600 dark:text-gray-300' />
<Heart className='h-7 w-7 stroke-1 text-gray-600 dark:text-gray-300' />
);
};

View File

@@ -195,7 +195,7 @@ function SearchPageClient() {
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder='搜索电影、电视剧...'
className='w-full h-12 rounded-lg bg-gray-50/80 py-3 pl-10 pr-4 text-sm text-gray-700 placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-green-400 focus:bg-white border border-gray-200/50 shadow-sm dark:bg-gray-800 dark:text-gray-300 dark:placeholder-gray-500 dark:focus:bg-gray-700 dark:border-gray-700'
className='w-full h-12 rounded-lg bg-gray-50/80 py-3 pl-10 pr-4 text-sm text-gray-700 placeholder-gray-400 focus:outline-hidden focus:ring-2 focus:ring-green-400 focus:bg-white border border-gray-200/50 shadow-xs dark:bg-gray-800 dark:text-gray-300 dark:placeholder-gray-500 dark:focus:bg-gray-700 dark:border-gray-700'
/>
</div>
</form>
@@ -235,7 +235,7 @@ function SearchPageClient() {
</div>
<div
key={`search-results-${viewMode}`}
className='justify-start grid grid-cols-3 gap-x-2 gap-y-14 sm:gap-y-20 px-0 sm:px-2 sm:grid-cols-[repeat(auto-fill,_minmax(11rem,_1fr))] sm:gap-x-8'
className='justify-start grid grid-cols-3 gap-x-2 gap-y-14 sm:gap-y-20 px-0 sm:px-2 sm:grid-cols-[repeat(auto-fill,minmax(11rem,1fr))] sm:gap-x-8'
>
{viewMode === 'agg'
? aggregatedResults.map(([mapKey, group]) => {

View File

@@ -69,7 +69,7 @@ const CapsuleSwitch: React.FC<CapsuleSwitchProps> = ({
{/* 滑动的白色背景指示器 */}
{indicatorStyle.width > 0 && (
<div
className='absolute top-1 bottom-1 bg-white dark:bg-gray-500 rounded-full shadow-sm transition-all duration-300 ease-out'
className='absolute top-1 bottom-1 bg-white dark:bg-gray-500 rounded-full shadow-xs transition-all duration-300 ease-out'
style={{
left: `${indicatorStyle.left}px`,
width: `${indicatorStyle.width}px`,

View File

@@ -111,11 +111,11 @@ export default function ContinueWatching({ className }: ContinueWatchingProps) {
key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
>
<div className='relative aspect-[2/3] w-full overflow-hidden rounded-lg bg-gray-200 animate-pulse dark:bg-gray-800'>
<div className='relative aspect-2/3 w-full overflow-hidden rounded-lg bg-gray-200 animate-pulse dark:bg-gray-800'>
<div className='absolute inset-0 bg-gray-300 dark:bg-gray-700'></div>
</div>
<div className='mt-2 h-4 bg-gray-200 rounded animate-pulse dark:bg-gray-800'></div>
<div className='mt-1 h-3 bg-gray-200 rounded animate-pulse dark:bg-gray-800'></div>
<div className='mt-2 h-4 bg-gray-200 rounded-sm animate-pulse dark:bg-gray-800'></div>
<div className='mt-1 h-3 bg-gray-200 rounded-sm animate-pulse dark:bg-gray-800'></div>
</div>
))
: // 显示真实数据

View File

@@ -5,12 +5,12 @@ const DoubanCardSkeleton = () => {
<div className='w-full'>
<div className='group relative w-full rounded-lg bg-transparent shadow-none flex flex-col'>
{/* 图片占位符 - 骨架屏效果 */}
<ImagePlaceholder aspectRatio='aspect-[2/3]' />
<ImagePlaceholder aspectRatio='aspect-2/3' />
{/* 信息层骨架 */}
<div className='absolute top-[calc(100%+0.5rem)] left-0 right-0'>
<div className='flex flex-col items-center justify-center'>
<div className='h-4 w-24 sm:w-32 bg-gray-200 rounded animate-pulse mb-2'></div>
<div className='h-4 w-24 sm:w-32 bg-gray-200 rounded-sm animate-pulse mb-2'></div>
</div>
</div>
</div>

View File

@@ -217,12 +217,12 @@ const DoubanSelector: React.FC<DoubanSelectorProps> = ({
return (
<div
ref={containerRef}
className='relative inline-flex bg-gray-200/60 rounded-full p-0.5 sm:p-1 dark:bg-gray-700/60 backdrop-blur-sm'
className='relative inline-flex bg-gray-200/60 rounded-full p-0.5 sm:p-1 dark:bg-gray-700/60 backdrop-blur-xs'
>
{/* 滑动的白色背景指示器 */}
{indicatorStyle.width > 0 && (
<div
className='absolute top-0.5 bottom-0.5 sm:top-1 sm:bottom-1 bg-white dark:bg-gray-500 rounded-full shadow-sm transition-all duration-300 ease-out'
className='absolute top-0.5 bottom-0.5 sm:top-1 sm:bottom-1 bg-white dark:bg-gray-500 rounded-full shadow-xs transition-all duration-300 ease-out'
style={{
left: `${indicatorStyle.left}px`,
width: `${indicatorStyle.width}px`,

View File

@@ -280,7 +280,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
return (
<div className='md:ml-2 px-4 py-0 h-full rounded-xl bg-black/10 dark:bg-white/5 flex flex-col border border-white/0 dark:border-white/30 overflow-hidden'>
{/* 主要的 Tab 切换 - 无缝融入设计 */}
<div className='flex mb-1 -mx-6 flex-shrink-0'>
<div className='flex mb-1 -mx-6 shrink-0'>
{totalEpisodes > 1 && (
<div
onClick={() => setActiveTab('episodes')}
@@ -313,7 +313,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
{activeTab === 'episodes' && (
<>
{/* 分类标签 */}
<div className='flex items-center gap-4 mb-4 border-b border-gray-300 dark:border-gray-700 -mx-6 px-6 flex-shrink-0'>
<div className='flex items-center gap-4 mb-4 border-b border-gray-300 dark:border-gray-700 -mx-6 px-6 shrink-0'>
<div className='flex-1 overflow-x-auto' ref={categoryContainerRef}>
<div className='flex gap-2 min-w-max'>
{categories.map((label, idx) => {
@@ -325,7 +325,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
buttonRefs.current[idx] = el;
}}
onClick={() => handleCategoryClick(idx)}
className={`w-20 relative py-2 text-sm font-medium transition-colors whitespace-nowrap flex-shrink-0 text-center
className={`w-20 relative py-2 text-sm font-medium transition-colors whitespace-nowrap shrink-0 text-center
${
isActive
? 'text-green-500 dark:text-green-400'
@@ -344,7 +344,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
</div>
{/* 向上/向下按钮 */}
<button
className='flex-shrink-0 w-8 h-8 rounded-md flex items-center justify-center text-gray-700 hover:text-green-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:text-green-400 dark:hover:bg-white/20 transition-colors transform translate-y-[-4px]'
className='shrink-0 w-8 h-8 rounded-md flex items-center justify-center text-gray-700 hover:text-green-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:text-green-400 dark:hover:bg-white/20 transition-colors transform translate-y-[-4px]'
onClick={() => {
// 切换集数排序(正序/倒序)
setDescending((prev) => !prev);
@@ -465,7 +465,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
}`.trim()}
>
{/* 封面 */}
<div className='flex-shrink-0 w-12 h-20 bg-gray-300 dark:bg-gray-600 rounded overflow-hidden'>
<div className='shrink-0 w-12 h-20 bg-gray-300 dark:bg-gray-600 rounded-sm overflow-hidden'>
{source.episodes && source.episodes.length > 0 && (
<img
src={processImageUrl(source.poster)}
@@ -489,7 +489,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
</h3>
{/* 标题级别的 tooltip - 第一个元素不显示 */}
{index !== 0 && (
<div className='absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-3 py-1 bg-gray-800 text-white text-xs rounded-md shadow-lg opacity-0 invisible group-hover/title:opacity-100 group-hover/title:visible transition-all duration-200 ease-out delay-100 whitespace-nowrap z-[500] pointer-events-none'>
<div className='absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-3 py-1 bg-gray-800 text-white text-xs rounded-md shadow-lg opacity-0 invisible group-hover/title:opacity-100 group-hover/title:visible transition-all duration-200 ease-out delay-100 whitespace-nowrap z-500 pointer-events-none'>
{source.title}
<div className='absolute top-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-4 border-r-4 border-t-4 border-transparent border-t-gray-800'></div>
</div>
@@ -502,7 +502,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
if (videoInfo && videoInfo.quality !== '未知') {
if (videoInfo.hasError) {
return (
<div className='bg-gray-500/10 dark:bg-gray-400/20 text-red-600 dark:text-red-400 px-1.5 py-0 rounded text-xs flex-shrink-0 min-w-[50px] text-center'>
<div className='bg-gray-500/10 dark:bg-gray-400/20 text-red-600 dark:text-red-400 px-1.5 py-0 rounded-sm text-xs shrink-0 min-w-[50px] text-center'>
</div>
);
@@ -522,7 +522,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
return (
<div
className={`bg-gray-500/10 dark:bg-gray-400/20 ${textColorClasses} px-1.5 py-0 rounded text-xs flex-shrink-0 min-w-[50px] text-center`}
className={`bg-gray-500/10 dark:bg-gray-400/20 ${textColorClasses} px-1.5 py-0 rounded-sm text-xs shrink-0 min-w-[50px] text-center`}
>
{videoInfo.quality}
</div>
@@ -536,7 +536,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
{/* 源名称和集数信息 - 垂直居中 */}
<div className='flex items-center justify-between'>
<span className='text-xs px-2 py-1 border border-gray-500/60 rounded text-gray-700 dark:text-gray-300'>
<span className='text-xs px-2 py-1 border border-gray-500/60 rounded-sm text-gray-700 dark:text-gray-300'>
{source.source_name}
</span>
{source.episodes.length > 1 && (
@@ -577,7 +577,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
</div>
);
})}
<div className='flex-shrink-0 mt-auto pt-2 border-t border-gray-400 dark:border-gray-700'>
<div className='shrink-0 mt-auto pt-2 border-t border-gray-400 dark:border-gray-700'>
<button
onClick={() => {
if (videoTitle) {

View File

@@ -53,7 +53,7 @@ const MobileBottomNav = ({ activePath }: MobileBottomNavProps) => {
return (
<nav
className='md:hidden fixed left-0 right-0 z-[600] bg-white/90 backdrop-blur-xl border-t border-gray-200/50 overflow-hidden dark:bg-gray-900/80 dark:border-gray-700/50'
className='md:hidden fixed left-0 right-0 z-600 bg-white/90 backdrop-blur-xl border-t border-gray-200/50 overflow-hidden dark:bg-gray-900/80 dark:border-gray-700/50'
style={{
/* 紧贴视口底部,同时在内部留出安全区高度 */
bottom: 0,
@@ -64,7 +64,7 @@ const MobileBottomNav = ({ activePath }: MobileBottomNavProps) => {
{navItems.map((item) => {
const active = isActive(item.href);
return (
<li key={item.href} className='flex-shrink-0 w-1/5'>
<li key={item.href} className='shrink-0 w-1/5'>
<Link
href={item.href}
className='flex flex-col items-center justify-center w-full h-14 gap-1 text-xs'

View File

@@ -15,7 +15,7 @@ interface MobileHeaderProps {
const MobileHeader = ({ showBackButton = false }: MobileHeaderProps) => {
const { siteName } = useSite();
return (
<header className='md:hidden relative w-full bg-white/70 backdrop-blur-xl border-b border-gray-200/50 shadow-sm dark:bg-gray-900/70 dark:border-gray-700/50'>
<header className='md:hidden relative w-full bg-white/70 backdrop-blur-xl border-b border-gray-200/50 shadow-xs dark:bg-gray-900/70 dark:border-gray-700/50'>
<div className='h-12 flex items-center justify-between px-4'>
{/* 左侧:返回按钮和设置按钮 */}
<div className='flex items-center gap-2'>

View File

@@ -109,7 +109,7 @@ export default function ScrollableRow({
</div>
{showLeftScroll && (
<div
className={`hidden sm:flex absolute left-0 top-0 bottom-0 w-16 items-center justify-center z-[600] transition-opacity duration-200 ${
className={`hidden sm:flex absolute left-0 top-0 bottom-0 w-16 items-center justify-center z-600 transition-opacity duration-200 ${
isHovered ? 'opacity-100' : 'opacity-0'
}`}
style={{
@@ -138,7 +138,7 @@ export default function ScrollableRow({
{showRightScroll && (
<div
className={`hidden sm:flex absolute right-0 top-0 bottom-0 w-16 items-center justify-center z-[600] transition-opacity duration-200 ${
className={`hidden sm:flex absolute right-0 top-0 bottom-0 w-16 items-center justify-center z-600 transition-opacity duration-200 ${
isHovered ? 'opacity-100' : 'opacity-0'
}`}
style={{

View File

@@ -133,12 +133,12 @@ export const SettingsButton: React.FC = () => {
<>
{/* 背景遮罩 */}
<div
className='fixed inset-0 bg-black/50 backdrop-blur-sm z-[1000]'
className='fixed inset-0 bg-black/50 backdrop-blur-xs z-1000'
onClick={handleClosePanel}
/>
{/* 设置面板 */}
<div className='fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-md bg-white dark:bg-gray-900 rounded-xl shadow-xl z-[1001] p-6'>
<div className='fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-md bg-white dark:bg-gray-900 rounded-xl shadow-xl z-1001 p-6'>
{/* 标题栏 */}
<div className='flex items-center justify-between mb-6'>
<div className='flex items-center gap-3'>
@@ -147,7 +147,7 @@ export const SettingsButton: React.FC = () => {
</h3>
<button
onClick={handleResetSettings}
className='px-2 py-1 text-xs text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 border border-red-200 hover:border-red-300 dark:border-red-800 dark:hover:border-red-700 hover:bg-red-50 dark:hover:bg-red-900/20 rounded transition-colors'
className='px-2 py-1 text-xs text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 border border-red-200 hover:border-red-300 dark:border-red-800 dark:hover:border-red-700 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-sm transition-colors'
title='重置为默认设置'
>
@@ -224,7 +224,7 @@ export const SettingsButton: React.FC = () => {
</div>
<input
type='text'
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md text-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent'
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md text-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 focus:outline-hidden focus:ring-2 focus:ring-blue-500 focus:border-transparent'
placeholder='例如: https://proxy.example.com/fetch?url='
value={doubanProxyUrl}
onChange={(e) => handleDoubanProxyUrlChange(e.target.value)}
@@ -267,7 +267,7 @@ export const SettingsButton: React.FC = () => {
</div>
<input
type='text'
className={`w-full px-3 py-2 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors ${
className={`w-full px-3 py-2 border rounded-md text-sm focus:outline-hidden focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors ${
enableImageProxy
? 'border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400'
: 'border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 text-gray-400 dark:text-gray-500 placeholder-gray-400 dark:placeholder-gray-600 cursor-not-allowed'

View File

@@ -267,13 +267,13 @@ export default function VideoCard({
return (
<div
className='group relative w-full rounded-lg bg-transparent cursor-pointer transition-all duration-300 ease-in-out hover:scale-[1.05] hover:z-[500]'
className='group relative w-full rounded-lg bg-transparent cursor-pointer transition-all duration-300 ease-in-out hover:scale-[1.05] hover:z-500'
onClick={handleClick}
>
{/* 海报容器 */}
<div className='relative aspect-[2/3] overflow-hidden rounded-lg'>
<div className='relative aspect-2/3 overflow-hidden rounded-lg'>
{/* 骨架屏 */}
{!isLoading && <ImagePlaceholder aspectRatio='aspect-[2/3]' />}
{!isLoading && <ImagePlaceholder aspectRatio='aspect-2/3' />}
{/* 图片 */}
<Image
src={processImageUrl(actualPoster)}
@@ -285,7 +285,7 @@ export default function VideoCard({
/>
{/* 悬浮遮罩 */}
<div className='absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent opacity-0 transition-opacity duration-300 ease-in-out group-hover:opacity-100' />
<div className='absolute inset-0 bg-linear-to-t from-black/80 via-black/20 to-transparent opacity-0 transition-opacity duration-300 ease-in-out group-hover:opacity-100' />
{/* 播放按钮 */}
{config.showPlayButton && (
@@ -377,7 +377,7 @@ export default function VideoCard({
</div>
{config.showSourceName && source_name && (
<span className='block text-xs text-gray-500 dark:text-gray-400 mt-1'>
<span className='inline-block border rounded px-2 py-0.5 border-gray-500/60 dark:border-gray-400/60 transition-all duration-300 ease-in-out group-hover:border-green-500/60 group-hover:text-green-600 dark:group-hover:text-green-400'>
<span className='inline-block border rounded-sm px-2 py-0.5 border-gray-500/60 dark:border-gray-400/60 transition-all duration-300 ease-in-out group-hover:border-green-500/60 group-hover:text-green-600 dark:group-hover:text-green-400'>
{source_name}
</span>
</span>

View File

@@ -1,550 +0,0 @@
/* //!STARTERCONF Remove this file after copying your desired color, this is a large file you should remove it. */
.slate {
--tw-color-primary-50: 248 250 252;
--tw-color-primary-100: 241 245 249;
--tw-color-primary-200: 226 232 240;
--tw-color-primary-300: 203 213 225;
--tw-color-primary-400: 148 163 184;
--tw-color-primary-500: 100 116 139;
--tw-color-primary-600: 71 85 105;
--tw-color-primary-700: 51 65 85;
--tw-color-primary-800: 30 41 59;
--tw-color-primary-900: 15 23 42;
--tw-color-primary-950: 2 6 23;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #f8fafc */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #f1f5f9 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #e2e8f0 */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #cbd5e1 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #94a3b8 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #64748b */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #475569 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #334155 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #1e293b */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #0f172a */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #020617 */
}
.gray {
--tw-color-primary-50: 249 250 251;
--tw-color-primary-100: 243 244 246;
--tw-color-primary-200: 229 231 235;
--tw-color-primary-300: 209 213 219;
--tw-color-primary-400: 156 163 175;
--tw-color-primary-500: 107 114 128;
--tw-color-primary-600: 75 85 99;
--tw-color-primary-700: 55 65 81;
--tw-color-primary-800: 31 41 55;
--tw-color-primary-900: 17 24 39;
--tw-color-primary-950: 3 7 18;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #f9fafb */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #f3f4f6 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #e5e7eb */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #d1d5db */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #9ca3af */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #6b7280 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #4b5563 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #374151 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #1f2937 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #111827 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #030712 */
}
.zinc {
--tw-color-primary-50: 250 250 250;
--tw-color-primary-100: 244 244 245;
--tw-color-primary-200: 228 228 231;
--tw-color-primary-300: 212 212 216;
--tw-color-primary-400: 161 161 170;
--tw-color-primary-500: 113 113 122;
--tw-color-primary-600: 82 82 91;
--tw-color-primary-700: 63 63 70;
--tw-color-primary-800: 39 39 42;
--tw-color-primary-900: 24 24 27;
--tw-color-primary-950: 9 9 11;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fafafa */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #f4f4f5 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #e4e4e7 */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #d4d4d8 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #a1a1aa */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #71717a */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #52525b */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #3f3f46 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #27272a */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #18181b */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #09090b */
}
.neutral {
--tw-color-primary-50: 250 250 250;
--tw-color-primary-100: 245 245 245;
--tw-color-primary-200: 229 229 229;
--tw-color-primary-300: 212 212 212;
--tw-color-primary-400: 163 163 163;
--tw-color-primary-500: 115 115 115;
--tw-color-primary-600: 82 82 82;
--tw-color-primary-700: 64 64 64;
--tw-color-primary-800: 38 38 38;
--tw-color-primary-900: 23 23 23;
--tw-color-primary-950: 10 10 10;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fafafa */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #f5f5f5 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #e5e5e5 */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #d4d4d4 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #a3a3a3 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #737373 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #525252 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #404040 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #262626 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #171717 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #0a0a0a */
}
.stone {
--tw-color-primary-50: 250 250 249;
--tw-color-primary-100: 245 245 244;
--tw-color-primary-200: 231 229 228;
--tw-color-primary-300: 214 211 209;
--tw-color-primary-400: 168 162 158;
--tw-color-primary-500: 120 113 108;
--tw-color-primary-600: 87 83 78;
--tw-color-primary-700: 68 64 60;
--tw-color-primary-800: 41 37 36;
--tw-color-primary-900: 28 25 23;
--tw-color-primary-950: 12 10 9;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fafaf9 */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #f5f5f4 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #e7e5e4 */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #d6d3d1 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #a8a29e */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #78716c */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #57534e */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #44403c */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #292524 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #1c1917 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #0c0a09 */
}
.red {
--tw-color-primary-50: 254 242 242;
--tw-color-primary-100: 254 226 226;
--tw-color-primary-200: 254 202 202;
--tw-color-primary-300: 252 165 165;
--tw-color-primary-400: 248 113 113;
--tw-color-primary-500: 239 68 68;
--tw-color-primary-600: 220 38 38;
--tw-color-primary-700: 185 28 28;
--tw-color-primary-800: 153 27 27;
--tw-color-primary-900: 127 29 29;
--tw-color-primary-950: 69 10 10;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fef2f2 */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #fee2e2 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #fecaca */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #fca5a5 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #f87171 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #ef4444 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #dc2626 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #b91c1c */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #991b1b */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #7f1d1d */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #450a0a */
}
.orange {
--tw-color-primary-50: 255 247 237;
--tw-color-primary-100: 255 237 213;
--tw-color-primary-200: 254 215 170;
--tw-color-primary-300: 253 186 116;
--tw-color-primary-400: 251 146 60;
--tw-color-primary-500: 249 115 22;
--tw-color-primary-600: 234 88 12;
--tw-color-primary-700: 194 65 12;
--tw-color-primary-800: 154 52 18;
--tw-color-primary-900: 124 45 18;
--tw-color-primary-950: 67 20 7;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fff7ed */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #ffedd5 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #fed7aa */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #fdba74 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #fb923c */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #f97316 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #ea580c */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #c2410c */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #9a3412 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #7c2d12 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #431407 */
}
.amber {
--tw-color-primary-50: 255 251 235;
--tw-color-primary-100: 254 243 199;
--tw-color-primary-200: 253 230 138;
--tw-color-primary-300: 252 211 77;
--tw-color-primary-400: 251 191 36;
--tw-color-primary-500: 245 158 11;
--tw-color-primary-600: 217 119 6;
--tw-color-primary-700: 180 83 9;
--tw-color-primary-800: 146 64 14;
--tw-color-primary-900: 120 53 15;
--tw-color-primary-950: 69 26 3;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fffbeb */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #fef3c7 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #fde68a */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #fcd34d */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #fbbf24 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #f59e0b */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #d97706 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #b45309 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #92400e */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #78350f */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #451a03 */
}
.yellow {
--tw-color-primary-50: 254 252 232;
--tw-color-primary-100: 254 249 195;
--tw-color-primary-200: 254 240 138;
--tw-color-primary-300: 253 224 71;
--tw-color-primary-400: 250 204 21;
--tw-color-primary-500: 234 179 8;
--tw-color-primary-600: 202 138 4;
--tw-color-primary-700: 161 98 7;
--tw-color-primary-800: 133 77 14;
--tw-color-primary-900: 113 63 18;
--tw-color-primary-950: 66 32 6;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fefce8 */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #fef9c3 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #fef08a */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #fde047 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #facc15 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #eab308 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #ca8a04 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #a16207 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #854d0e */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #713f12 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #422006 */
}
.lime {
--tw-color-primary-50: 247 254 231;
--tw-color-primary-100: 236 252 203;
--tw-color-primary-200: 217 249 157;
--tw-color-primary-300: 190 242 100;
--tw-color-primary-400: 163 230 53;
--tw-color-primary-500: 132 204 22;
--tw-color-primary-600: 101 163 13;
--tw-color-primary-700: 77 124 15;
--tw-color-primary-800: 63 98 18;
--tw-color-primary-900: 54 83 20;
--tw-color-primary-950: 26 46 5;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #f7fee7 */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #ecfccb */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #d9f99d */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #bef264 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #a3e635 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #84cc16 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #65a30d */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #4d7c0f */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #3f6212 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #365314 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #1a2e05 */
}
.green {
--tw-color-primary-50: 240 253 244;
--tw-color-primary-100: 220 252 231;
--tw-color-primary-200: 187 247 208;
--tw-color-primary-300: 134 239 172;
--tw-color-primary-400: 74 222 128;
--tw-color-primary-500: 34 197 94;
--tw-color-primary-600: 22 163 74;
--tw-color-primary-700: 21 128 61;
--tw-color-primary-800: 22 101 52;
--tw-color-primary-900: 20 83 45;
--tw-color-primary-950: 5 46 22;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #f0fdf4 */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #dcfce7 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #bbf7d0 */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #86efac */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #4ade80 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #22c55e */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #16a34a */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #15803d */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #166534 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #14532d */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #052e16 */
}
.emerald {
--tw-color-primary-50: 236 253 245;
--tw-color-primary-100: 209 250 229;
--tw-color-primary-200: 167 243 208;
--tw-color-primary-300: 110 231 183;
--tw-color-primary-400: 52 211 153;
--tw-color-primary-500: 16 185 129;
--tw-color-primary-600: 5 150 105;
--tw-color-primary-700: 4 120 87;
--tw-color-primary-800: 6 95 70;
--tw-color-primary-900: 6 78 59;
--tw-color-primary-950: 2 44 34;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #ecfdf5 */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #d1fae5 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #a7f3d0 */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #6ee7b7 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #34d399 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #10b981 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #059669 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #047857 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #065f46 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #064e3b */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #022c22 */
}
.teal {
--tw-color-primary-50: 240 253 250;
--tw-color-primary-100: 204 251 241;
--tw-color-primary-200: 153 246 228;
--tw-color-primary-300: 94 234 212;
--tw-color-primary-400: 45 212 191;
--tw-color-primary-500: 20 184 166;
--tw-color-primary-600: 13 148 136;
--tw-color-primary-700: 15 118 110;
--tw-color-primary-800: 17 94 89;
--tw-color-primary-900: 19 78 74;
--tw-color-primary-950: 4 47 46;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #f0fdfa */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #ccfbf1 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #99f6e4 */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #5eead4 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #2dd4bf */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #14b8a6 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #0d9488 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #0f766e */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #115e59 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #134e4a */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #042f2e */
}
.cyan {
--tw-color-primary-50: 236 254 255;
--tw-color-primary-100: 207 250 254;
--tw-color-primary-200: 165 243 252;
--tw-color-primary-300: 103 232 249;
--tw-color-primary-400: 34 211 238;
--tw-color-primary-500: 6 182 212;
--tw-color-primary-600: 8 145 178;
--tw-color-primary-700: 14 116 144;
--tw-color-primary-800: 21 94 117;
--tw-color-primary-900: 22 78 99;
--tw-color-primary-950: 8 51 68;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #ecfeff */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #cffafe */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #a5f3fc */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #67e8f9 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #22d3ee */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #06b6d4 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #0891b2 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #0e7490 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #155e75 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #164e63 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #083344 */
}
.sky {
--tw-color-primary-50: 240 249 255;
--tw-color-primary-100: 224 242 254;
--tw-color-primary-200: 186 230 253;
--tw-color-primary-300: 125 211 252;
--tw-color-primary-400: 56 189 248;
--tw-color-primary-500: 14 165 233;
--tw-color-primary-600: 2 132 199;
--tw-color-primary-700: 3 105 161;
--tw-color-primary-800: 7 89 133;
--tw-color-primary-900: 12 74 110;
--tw-color-primary-950: 8 47 73;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #f0f9ff */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #e0f2fe */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #bae6fd */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #7dd3fc */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #38bdf8 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #0ea5e9 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #0284c7 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #0369a1 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #075985 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #0c4a6e */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #082f49 */
}
.blue {
--tw-color-primary-50: 239 246 255;
--tw-color-primary-100: 219 234 254;
--tw-color-primary-200: 191 219 254;
--tw-color-primary-300: 147 197 253;
--tw-color-primary-400: 96 165 250;
--tw-color-primary-500: 59 130 246;
--tw-color-primary-600: 37 99 235;
--tw-color-primary-700: 29 78 216;
--tw-color-primary-800: 30 64 175;
--tw-color-primary-900: 30 58 138;
--tw-color-primary-950: 23 37 84;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #eff6ff */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #dbeafe */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #bfdbfe */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #93c5fd */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #60a5fa */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #3b82f6 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #2563eb */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #1d4ed8 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #1e40af */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #1e3a8a */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #172554 */
}
.indigo {
--tw-color-primary-50: 238 242 255;
--tw-color-primary-100: 224 231 255;
--tw-color-primary-200: 199 210 254;
--tw-color-primary-300: 165 180 252;
--tw-color-primary-400: 129 140 248;
--tw-color-primary-500: 99 102 241;
--tw-color-primary-600: 79 70 229;
--tw-color-primary-700: 67 56 202;
--tw-color-primary-800: 55 48 163;
--tw-color-primary-900: 49 46 129;
--tw-color-primary-950: 30 27 75;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #eef2ff */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #e0e7ff */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #c7d2fe */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #a5b4fc */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #818cf8 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #6366f1 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #4f46e5 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #4338ca */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #3730a3 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #312e81 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #1e1b4b */
}
.violet {
--tw-color-primary-50: 245 243 255;
--tw-color-primary-100: 237 233 254;
--tw-color-primary-200: 221 214 254;
--tw-color-primary-300: 196 181 253;
--tw-color-primary-400: 167 139 250;
--tw-color-primary-500: 139 92 246;
--tw-color-primary-600: 124 58 237;
--tw-color-primary-700: 109 40 217;
--tw-color-primary-800: 91 33 182;
--tw-color-primary-900: 76 29 149;
--tw-color-primary-950: 46 16 101;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #f5f3ff */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #ede9fe */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #ddd6fe */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #c4b5fd */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #a78bfa */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #8b5cf6 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #7c3aed */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #6d28d9 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #5b21b6 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #4c1d95 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #2e1065 */
}
.purple {
--tw-color-primary-50: 250 245 255;
--tw-color-primary-100: 243 232 255;
--tw-color-primary-200: 233 213 255;
--tw-color-primary-300: 216 180 254;
--tw-color-primary-400: 192 132 252;
--tw-color-primary-500: 168 85 247;
--tw-color-primary-600: 147 51 234;
--tw-color-primary-700: 126 34 206;
--tw-color-primary-800: 107 33 168;
--tw-color-primary-900: 88 28 135;
--tw-color-primary-950: 59 7 100;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #faf5ff */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #f3e8ff */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #e9d5ff */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #d8b4fe */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #c084fc */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #a855f7 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #9333ea */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #7e22ce */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #6b21a8 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #581c87 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #3b0764 */
}
.fuchsia {
--tw-color-primary-50: 253 244 255;
--tw-color-primary-100: 250 232 255;
--tw-color-primary-200: 245 208 254;
--tw-color-primary-300: 240 171 252;
--tw-color-primary-400: 232 121 249;
--tw-color-primary-500: 217 70 239;
--tw-color-primary-600: 192 38 211;
--tw-color-primary-700: 162 28 175;
--tw-color-primary-800: 134 25 143;
--tw-color-primary-900: 112 26 117;
--tw-color-primary-950: 74 4 78;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fdf4ff */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #fae8ff */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #f5d0fe */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #f0abfc */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #e879f9 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #d946ef */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #c026d3 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #a21caf */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #86198f */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #701a75 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #4a044e */
}
.pink {
--tw-color-primary-50: 253 242 248;
--tw-color-primary-100: 252 231 243;
--tw-color-primary-200: 251 207 232;
--tw-color-primary-300: 249 168 212;
--tw-color-primary-400: 244 114 182;
--tw-color-primary-500: 236 72 153;
--tw-color-primary-600: 219 39 119;
--tw-color-primary-700: 190 24 93;
--tw-color-primary-800: 157 23 77;
--tw-color-primary-900: 131 24 67;
--tw-color-primary-950: 80 4 36;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fdf2f8 */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #fce7f3 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #fbcfe8 */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #f9a8d4 */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #f472b6 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #ec4899 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #db2777 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #be185d */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #9d174d */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #831843 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #500724 */
}
.rose {
--tw-color-primary-50: 255 241 242;
--tw-color-primary-100: 255 228 230;
--tw-color-primary-200: 254 205 211;
--tw-color-primary-300: 253 164 175;
--tw-color-primary-400: 251 113 133;
--tw-color-primary-500: 244 63 94;
--tw-color-primary-600: 225 29 72;
--tw-color-primary-700: 190 18 60;
--tw-color-primary-800: 159 18 57;
--tw-color-primary-900: 136 19 55;
--tw-color-primary-950: 76 5 25;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #fff1f2 */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #ffe4e6 */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #fecdd3 */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #fda4af */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #fb7185 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #f43f5e */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #e11d48 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #be123c */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #9f1239 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #881337 */
--color-primary-950: rgb(var(--tw-color-primary-950)); /* #4c0519 */
}

View File

@@ -1,118 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
/* #region /**=========== Primary Color =========== */
/* !STARTERCONF Customize these variable, copy and paste from /styles/colors.css for list of colors */
--tw-color-primary-50: 240 249 255;
--tw-color-primary-100: 224 242 254;
--tw-color-primary-200: 186 230 253;
--tw-color-primary-300: 125 211 252;
--tw-color-primary-400: 56 189 248;
--tw-color-primary-500: 14 165 233;
--tw-color-primary-600: 2 132 199;
--tw-color-primary-700: 3 105 161;
--tw-color-primary-800: 7 89 133;
--tw-color-primary-900: 12 74 110;
--color-primary-50: rgb(var(--tw-color-primary-50)); /* #f0f9ff */
--color-primary-100: rgb(var(--tw-color-primary-100)); /* #e0f2fe */
--color-primary-200: rgb(var(--tw-color-primary-200)); /* #bae6fd */
--color-primary-300: rgb(var(--tw-color-primary-300)); /* #7dd3fc */
--color-primary-400: rgb(var(--tw-color-primary-400)); /* #38bdf8 */
--color-primary-500: rgb(var(--tw-color-primary-500)); /* #0ea5e9 */
--color-primary-600: rgb(var(--tw-color-primary-600)); /* #0284c7 */
--color-primary-700: rgb(var(--tw-color-primary-700)); /* #0369a1 */
--color-primary-800: rgb(var(--tw-color-primary-800)); /* #075985 */
--color-primary-900: rgb(var(--tw-color-primary-900)); /* #0c4a6e */
/* #endregion /**======== Primary Color =========== */
}
@layer base {
/* inter var - latin */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: block;
src: url('/fonts/inter-var-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212,
U+2215, U+FEFF, U+FFFD;
}
.cursor-newtab {
cursor: url('/images/new-tab.png') 10 10, pointer;
}
/* #region /**=========== Typography =========== */
.h0 {
@apply font-primary text-3xl font-bold md:text-5xl;
}
h1,
.h1 {
@apply font-primary text-2xl font-bold md:text-4xl;
}
h2,
.h2 {
@apply font-primary text-xl font-bold md:text-3xl;
}
h3,
.h3 {
@apply font-primary text-lg font-bold md:text-2xl;
}
h4,
.h4 {
@apply font-primary text-base font-bold md:text-lg;
}
body,
.p {
@apply font-primary text-sm md:text-base;
}
/* #endregion /**======== Typography =========== */
.layout {
/* 1100px */
max-width: 68.75rem;
@apply mx-auto w-11/12;
}
.bg-dark a.custom-link {
@apply border-gray-200 hover:border-gray-200/0;
}
/* Class to adjust with sticky footer */
.min-h-main {
@apply min-h-[calc(100vh-56px)];
}
}
@layer utilities {
.animated-underline {
background-image: linear-gradient(#33333300, #33333300),
linear-gradient(
to right,
var(--color-primary-400),
var(--color-primary-500)
);
background-size: 100% 2px, 0 2px;
background-position: 100% 100%, 0 100%;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: no-preference) {
.animated-underline {
transition: 0.3s ease;
transition-property: background-size, color, background-color,
border-color;
}
}
.animated-underline:hover,
.animated-underline:focus-visible {
background-size: 0 2px, 100% 2px;
}
}

View File

@@ -1,22 +1,22 @@
#!/usr/bin/env node
/* eslint-disable no-console,@typescript-eslint/no-var-requires */
const http = require('http');
const path = require('path');
const http = require("http");
const path = require("path");
// 调用 generate-manifest.js 生成 manifest.json
function generateManifest() {
console.log('Generating manifest.json for Docker deployment...');
console.log("Generating manifest.json for Docker deployment...");
try {
const generateManifestScript = path.join(
__dirname,
'scripts',
'generate-manifest.js'
"scripts",
"generate-manifest.js"
);
require(generateManifestScript);
} catch (error) {
console.error('❌ Error calling generate-manifest.js:', error);
console.error("❌ Error calling generate-manifest.js:", error);
throw error;
}
}
@@ -24,10 +24,10 @@ function generateManifest() {
generateManifest();
// 直接在当前进程中启动 standalone Server`server.js`
require('./server.js');
require("./server.js");
// 每 1 秒轮询一次,直到请求成功
const TARGET_URL = `http://${process.env.HOSTNAME || 'localhost'}:${
const TARGET_URL = `http://${process.env.HOSTNAME || "localhost"}:${
process.env.PORT || 3000
}/login`;
@@ -37,7 +37,7 @@ const intervalId = setInterval(() => {
const req = http.get(TARGET_URL, (res) => {
// 当返回 2xx 状态码时认为成功,然后停止轮询
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
console.log('Server is up, stop polling.');
console.log("Server is up, stop polling.");
clearInterval(intervalId);
// 服务器启动后,立即执行一次 cron 任务
@@ -57,34 +57,34 @@ const intervalId = setInterval(() => {
// 执行 cron 任务的函数
function executeCronJob() {
const cronUrl = `http://${process.env.HOSTNAME || 'localhost'}:${
const cronUrl = `http://${process.env.HOSTNAME || "localhost"}:${
process.env.PORT || 3000
}/api/cron`;
console.log(`Executing cron job: ${cronUrl}`);
const req = http.get(cronUrl, (res) => {
let data = '';
let data = "";
res.on('data', (chunk) => {
res.on("data", (chunk) => {
data += chunk;
});
res.on('end', () => {
res.on("end", () => {
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
console.log('Cron job executed successfully:', data);
console.log("Cron job executed successfully:", data);
} else {
console.error('Cron job failed:', res.statusCode, data);
console.error("Cron job failed:", res.statusCode, data);
}
});
});
req.on('error', (err) => {
console.error('Error executing cron job:', err);
req.on("error", (err) => {
console.error("Error executing cron job:", err);
});
req.setTimeout(30000, () => {
console.error('Cron job timeout');
console.error("Cron job timeout");
req.destroy();
});
}

View File

@@ -1,86 +1,85 @@
import type { Config } from 'tailwindcss';
import defaultTheme from 'tailwindcss/defaultTheme';
import forms from "@tailwindcss/forms";
const config: Config = {
darkMode: 'class',
const config = {
darkMode: "class",
content: [
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
screens: {
'mobile-landscape': {
raw: '(orientation: landscape) and (max-height: 700px)',
"mobile-landscape": {
raw: "(orientation: landscape) and (max-height: 700px)",
},
},
fontFamily: {
primary: ['Inter', ...defaultTheme.fontFamily.sans],
primary: ["Inter", "ui-sans-serif", "system-ui", "sans-serif"],
},
colors: {
primary: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
50: "#f0f9ff",
100: "#e0f2fe",
200: "#bae6fd",
300: "#7dd3fc",
400: "#38bdf8",
500: "#0ea5e9",
600: "#0284c7",
700: "#0369a1",
800: "#075985",
900: "#0c4a6e",
},
dark: '#222222',
dark: "#222222",
},
keyframes: {
flicker: {
'0%, 19.999%, 22%, 62.999%, 64%, 64.999%, 70%, 100%': {
opacity: '0.99',
"0%, 19.999%, 22%, 62.999%, 64%, 64.999%, 70%, 100%": {
opacity: "0.99",
filter:
'drop-shadow(0 0 1px rgba(252, 211, 77)) drop-shadow(0 0 15px rgba(245, 158, 11)) drop-shadow(0 0 1px rgba(252, 211, 77))',
"drop-shadow(0 0 1px rgba(252, 211, 77)) drop-shadow(0 0 15px rgba(245, 158, 11)) drop-shadow(0 0 1px rgba(252, 211, 77))",
},
'20%, 21.999%, 63%, 63.999%, 65%, 69.999%': {
opacity: '0.4',
filter: 'none',
"20%, 21.999%, 63%, 63.999%, 65%, 69.999%": {
opacity: "0.4",
filter: "none",
},
},
shimmer: {
'0%': {
backgroundPosition: '-700px 0',
"0%": {
backgroundPosition: "-700px 0",
},
'100%': {
backgroundPosition: '700px 0',
"100%": {
backgroundPosition: "700px 0",
},
},
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
"0%": { opacity: "0" },
"100%": { opacity: "1" },
},
slideUp: {
'0%': { transform: 'translateY(10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
"0%": { transform: "translateY(10px)", opacity: "0" },
"100%": { transform: "translateY(0)", opacity: "1" },
},
slideDown: {
'0%': { transform: 'translateY(-10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
"0%": { transform: "translateY(-10px)", opacity: "0" },
"100%": { transform: "translateY(0)", opacity: "1" },
},
},
animation: {
flicker: 'flicker 3s linear infinite',
shimmer: 'shimmer 1.3s linear infinite',
'fade-in': 'fadeIn 0.3s ease-in-out',
'slide-up': 'slideUp 0.3s ease-in-out',
'slide-down': 'slideDown 0.3s ease-in-out',
flicker: "flicker 3s linear infinite",
shimmer: "shimmer 1.3s linear infinite",
"fade-in": "fadeIn 0.3s ease-in-out",
"slide-up": "slideUp 0.3s ease-in-out",
"slide-down": "slideDown 0.3s ease-in-out",
},
backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic':
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
},
},
},
plugins: [require('@tailwindcss/forms')],
} satisfies Config;
plugins: [forms],
};
export default config;

View File

@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "ES2022",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
@@ -8,8 +8,8 @@
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "Node16",
"moduleResolution": "node16",
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
@@ -26,6 +26,5 @@
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"],
"moduleResolution": ["node_modules", ".next", "node"]
"exclude": ["node_modules"]
}