From 1e9ff8a0dec8ae027e2050e5cd839be9a9111e14 Mon Sep 17 00:00:00 2001 From: QuentinHsu Date: Mon, 1 Jun 2026 23:31:51 +0800 Subject: [PATCH 1/2] feat(web): support classic Rsbuild dev and build - migrate the classic frontend from Vite to Rsbuild with JSX, Semi UI, proxy, and production build config. - update make dev-web to run both default and classic frontends for local theme switching. - fix classic public page height, footer, CORS proxy, error handling, and constant export warnings. - update Dockerfile and release workflow to install from the web workspace root with the shared lockfile. --- .github/workflows/release.yml | 30 +++-- Dockerfile | 34 +++--- makefile | 37 +++++- web/bun.lock | 73 ++---------- web/classic/index.html | 1 - web/classic/package.json | 21 ++-- web/classic/rsbuild.config.ts | 106 +++++++++++++++++ web/classic/src/components/auth/LoginForm.jsx | 2 +- .../components/auth/PasswordResetConfirm.jsx | 2 +- .../src/components/auth/PasswordResetForm.jsx | 2 +- .../src/components/auth/RegisterForm.jsx | 2 +- .../common/DocumentRenderer/index.jsx | 10 +- .../src/components/layout/PageLayout.jsx | 15 ++- web/classic/src/constants/index.js | 52 +++++++-- web/classic/src/helpers/render.jsx | 4 +- web/classic/src/helpers/utils.jsx | 2 +- web/classic/src/index.css | 34 +++++- web/classic/src/pages/About/index.jsx | 11 +- web/classic/src/pages/Forbidden/index.jsx | 2 +- web/classic/src/pages/Home/index.jsx | 12 +- web/classic/src/pages/NotFound/index.jsx | 2 +- web/classic/vite.config.js | 107 ------------------ web/default/rsbuild.config.ts | 1 + 23 files changed, 302 insertions(+), 260 deletions(-) create mode 100644 web/classic/rsbuild.config.ts delete mode 100644 web/classic/vite.config.js diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 513bbb29..ff62d7bb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,16 +33,18 @@ jobs: env: CI: "" run: | - cd web/default - bun install + cd web + bun install --frozen-lockfile + cd default DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$VERSION bun run build cd ../.. - name: Build Frontend (classic) env: CI: "" run: | - cd web/classic - bun install + cd web + bun install --frozen-lockfile + cd classic VITE_REACT_APP_VERSION=$VERSION bun run build cd ../.. - name: Set up Go @@ -91,16 +93,18 @@ jobs: CI: "" NODE_OPTIONS: "--max-old-space-size=4096" run: | - cd web/default - bun install + cd web + bun install --frozen-lockfile + cd default DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$VERSION bun run build cd ../.. - name: Build Frontend (classic) env: CI: "" run: | - cd web/classic - bun install + cd web + bun install --frozen-lockfile + cd classic VITE_REACT_APP_VERSION=$VERSION bun run build cd ../.. - name: Set up Go @@ -146,16 +150,18 @@ jobs: env: CI: "" run: | - cd web/default - bun install + cd web + bun install --frozen-lockfile + cd default DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$VERSION bun run build cd ../.. - name: Build Frontend (classic) env: CI: "" run: | - cd web/classic - bun install + cd web + bun install --frozen-lockfile + cd classic VITE_REACT_APP_VERSION=$VERSION bun run build cd ../.. - name: Set up Go diff --git a/Dockerfile b/Dockerfile index 17c4398d..d01ab3f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,24 @@ FROM oven/bun:1@sha256:0733e50325078969732ebe3b15ce4c4be5082f18c4ac1a0f0ca4839c2e4e42a7 AS builder -WORKDIR /build -COPY web/default/package.json . -COPY web/default/bun.lock . -RUN bun install -COPY ./web/default . -COPY ./VERSION . -RUN DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat VERSION) bun run build +WORKDIR /build/web +COPY web/package.json web/bun.lock ./ +COPY web/default/package.json ./default/package.json +COPY web/classic/package.json ./classic/package.json +RUN bun install --frozen-lockfile +COPY ./web/default ./default +COPY ./VERSION /build/VERSION +RUN cd default && DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat /build/VERSION) bun run build FROM oven/bun:1@sha256:0733e50325078969732ebe3b15ce4c4be5082f18c4ac1a0f0ca4839c2e4e42a7 AS builder-classic -WORKDIR /build -COPY web/classic/package.json . -COPY web/classic/bun.lock . -RUN bun install -COPY ./web/classic . -COPY ./VERSION . -RUN VITE_REACT_APP_VERSION=$(cat VERSION) bun run build +WORKDIR /build/web +COPY web/package.json web/bun.lock ./ +COPY web/default/package.json ./default/package.json +COPY web/classic/package.json ./classic/package.json +RUN bun install --frozen-lockfile +COPY ./web/classic ./classic +COPY ./VERSION /build/VERSION +RUN cd classic && VITE_REACT_APP_VERSION=$(cat /build/VERSION) bun run build FROM golang:1.26.1-alpine@sha256:2389ebfa5b7f43eeafbd6be0c3700cc46690ef842ad962f6c5bd6be49ed82039 AS builder2 ENV GO111MODULE=on CGO_ENABLED=0 @@ -32,8 +34,8 @@ ADD go.mod go.sum ./ RUN go mod download COPY . . -COPY --from=builder /build/dist ./web/default/dist -COPY --from=builder-classic /build/dist ./web/classic/dist +COPY --from=builder /build/web/default/dist ./web/default/dist +COPY --from=builder-classic /build/web/classic/dist ./web/classic/dist RUN go build -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$(cat VERSION)'" -o new-api FROM debian:bookworm-slim@sha256:f06537653ac770703bc45b4b113475bd402f451e85223f0f2837acbf89ab020a diff --git a/makefile b/makefile index d98ec63f..76b5d61b 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,8 @@ FRONTEND_DIR = ./web/default FRONTEND_CLASSIC_DIR = ./web/classic BACKEND_DIR = . +DEV_FRONTEND_DEFAULT_PORT ?= 5173 +DEV_FRONTEND_CLASSIC_PORT ?= 5174 DEV_COMPOSE_FILE = docker-compose.dev.yml DEV_POSTGRES_SERVICE = postgres DEV_BACKEND_SERVICE = new-api @@ -14,11 +16,13 @@ all: build-all-frontends start-backend build-frontend: @echo "Building default frontend..." - @cd $(FRONTEND_DIR) && bun install && DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat ../../VERSION) bun run build + @cd ./web && bun install --frozen-lockfile + @cd $(FRONTEND_DIR) && DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat ../../VERSION) bun run build build-frontend-classic: @echo "Building classic frontend..." - @cd $(FRONTEND_CLASSIC_DIR) && bun install && VITE_REACT_APP_VERSION=$(cat ../../VERSION) bun run build + @cd ./web && bun install --frozen-lockfile + @cd $(FRONTEND_CLASSIC_DIR) && VITE_REACT_APP_VERSION=$(cat ../../VERSION) bun run build build-all-frontends: build-frontend build-frontend-classic @@ -35,12 +39,35 @@ dev-api-rebuild: @docker compose -f $(DEV_COMPOSE_FILE) up -d --build $(DEV_BACKEND_SERVICE) dev-web: - @echo "Starting frontend dev server..." - @cd $(FRONTEND_DIR) && bun install && bun run dev + @echo "Starting both frontend dev servers..." + @echo "Default frontend: http://localhost:$(DEV_FRONTEND_DEFAULT_PORT)" + @echo "Classic frontend: http://localhost:$(DEV_FRONTEND_CLASSIC_PORT)" + @cd ./web && bun install + @(cd $(FRONTEND_DIR) && bun run dev -- --host 0.0.0.0 --port $(DEV_FRONTEND_DEFAULT_PORT)) & \ + default_pid=$$!; \ + (cd $(FRONTEND_CLASSIC_DIR) && bun run dev -- --host 0.0.0.0 --port $(DEV_FRONTEND_CLASSIC_PORT)) & \ + classic_pid=$$!; \ + trap 'kill $$default_pid $$classic_pid 2>/dev/null; wait $$default_pid $$classic_pid 2>/dev/null; exit 130' INT TERM; \ + while kill -0 $$default_pid 2>/dev/null && kill -0 $$classic_pid 2>/dev/null; do \ + sleep 1; \ + done; \ + if ! kill -0 $$default_pid 2>/dev/null; then \ + wait $$default_pid; \ + status=$$?; \ + kill $$classic_pid 2>/dev/null; \ + wait $$classic_pid 2>/dev/null; \ + exit $$status; \ + fi; \ + wait $$classic_pid; \ + status=$$?; \ + kill $$default_pid 2>/dev/null; \ + wait $$default_pid 2>/dev/null; \ + exit $$status dev-web-classic: @echo "Starting classic frontend dev server..." - @cd $(FRONTEND_CLASSIC_DIR) && bun install && bun run dev + @cd ./web && bun install + @cd $(FRONTEND_CLASSIC_DIR) && bun run dev -- --host 0.0.0.0 --port $(DEV_FRONTEND_CLASSIC_PORT) dev: dev-api dev-web diff --git a/web/bun.lock b/web/bun.lock index 8ce702f7..18ec756e 100644 --- a/web/bun.lock +++ b/web/bun.lock @@ -10,6 +10,7 @@ "version": "0.1.0", "dependencies": { "@douyinfe/semi-icons": "^2.63.1", + "@douyinfe/semi-illustrations": "^2.69.1", "@douyinfe/semi-ui": "^2.69.1", "@lobehub/icons": "catalog:", "@visactor/react-vchart": "~1.8.8", @@ -18,6 +19,7 @@ "axios": "catalog:", "clsx": "catalog:", "dayjs": "catalog:", + "highlight.js": "^11.11.1", "history": "^5.3.0", "i18next": "^23.16.8", "i18next-browser-languagedetector": "^7.2.0", @@ -26,8 +28,8 @@ "marked": "^4.1.1", "mermaid": "^11.6.0", "qrcode.react": "catalog:", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", "react-dropzone": "^14.2.3", "react-fireworks": "^1.0.4", "react-i18next": "^13.0.0", @@ -47,20 +49,19 @@ "use-debounce": "^10.0.4", }, "devDependencies": { - "@douyinfe/vite-plugin-semi": "^2.74.0-alpha.6", + "@rsbuild/core": "^2.0.7", + "@rsbuild/plugin-react": "^2.0.0", "@so1ve/prettier-config": "^3.1.0", - "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.21", - "code-inspector-plugin": "^1.3.3", "eslint": "8.57.0", "eslint-plugin-header": "^3.1.1", "eslint-plugin-react-hooks": "^5.2.0", "i18next-cli": "^1.10.3", "postcss": "^8.5.3", "prettier": "catalog:", + "prop-types": "^15.8.1", "tailwindcss": "^3", "typescript": "4.4.2", - "vite": "^5.2.0", }, }, "default": { @@ -234,10 +235,6 @@ "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.29.7", "", { "dependencies": { "@babel/helper-module-transforms": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ=="], - "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw=="], - - "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q=="], - "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/plugin-syntax-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw=="], "@babel/preset-typescript": ["@babel/preset-typescript@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "@babel/plugin-syntax-jsx": "^7.29.7", "@babel/plugin-transform-modules-commonjs": "^7.29.7", "@babel/plugin-transform-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ=="], @@ -258,18 +255,6 @@ "@chevrotain/types": ["@chevrotain/types@11.1.2", "", {}, "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw=="], - "@code-inspector/core": ["@code-inspector/core@1.5.1", "", { "dependencies": { "@vue/compiler-dom": "^3.5.13", "chalk": "^4.1.1", "dotenv": "^16.1.4", "launch-ide": "1.4.3", "portfinder": "^1.0.28" } }, "sha512-Y9JdgoxVh93xRMupTa1lT/v+UlcBEpM7Y1BTxQy924wSe6VVEXsJ1nPJ/Ob2HPMUAA6F568aHALi2KDUhA2kzg=="], - - "@code-inspector/esbuild": ["@code-inspector/esbuild@1.5.1", "", { "dependencies": { "@code-inspector/core": "1.5.1" } }, "sha512-Z/WZVCG6WaB9HTcDC8l15RpgEsfFj/WKLLr6cKNX/JzAYBroadLPw1N0sbUJUIQnow5cCo7KYpHrC1T27WVMnw=="], - - "@code-inspector/mako": ["@code-inspector/mako@1.5.1", "", { "dependencies": { "@code-inspector/core": "1.5.1" } }, "sha512-EQmqQnnyW8tf3EBRlYyRYv1n3W1PUcfaYuuXXAfBdfJIGMwJjj0PcrDsdiI5MNyFmIx3QdMREhWmPMx1LoAANg=="], - - "@code-inspector/turbopack": ["@code-inspector/turbopack@1.5.1", "", { "dependencies": { "@code-inspector/core": "1.5.1", "@code-inspector/webpack": "1.5.1" } }, "sha512-PeLbcDtKDoSrKPsWnwQc+Yj9KgCa3xbHxEwXa/aGVykilvfvYP9AH1z5BRyZLDgB21diSV75BPNpF+o/FQRYug=="], - - "@code-inspector/vite": ["@code-inspector/vite@1.5.1", "", { "dependencies": { "@code-inspector/core": "1.5.1", "chalk": "4.1.1" } }, "sha512-gkfmSmawYb1yDDuCft4DESXCAD3JxPt59dGiRoD78GhQzSYHk3tnLPZMH/GLBpdeFNbKHi1FtEMbAAECIJG9xg=="], - - "@code-inspector/webpack": ["@code-inspector/webpack@1.5.1", "", { "dependencies": { "@code-inspector/core": "1.5.1" } }, "sha512-8i3QI/bSirORDF/0P16T6NhNy1RxO7soip8sWeV/2btLbYCwyiaDnqT4Bw3JaM8MNz0N8NaA2qItUrrKE7TtCg=="], - "@croct/json": ["@croct/json@2.1.0", "", {}, "sha512-UrWfjNQVlBxN+OVcFwHmkjARMW55MBN04E9KfGac8ac8z1QnFVuiOOFtMWXCk3UwsyRqhsNaFoYLZC+xxqsVjQ=="], "@croct/json5-parser": ["@croct/json5-parser@0.2.2", "", { "dependencies": { "@croct/json": "^2.1.0" } }, "sha512-0NJMLrbeLbQ0eCVj3UoH/kG2QckUgOASfwmfDTjyW1xAYPyTNJXcWVT/dssJdTJd0pRchW+qF0VFWQHcxs1OVw=="], @@ -306,8 +291,6 @@ "@douyinfe/semi-ui": ["@douyinfe/semi-ui@2.99.3", "", { "dependencies": { "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.1", "@douyinfe/semi-animation": "2.99.3", "@douyinfe/semi-animation-react": "2.99.3", "@douyinfe/semi-foundation": "2.99.3", "@douyinfe/semi-icons": "2.99.3", "@douyinfe/semi-illustrations": "2.99.3", "@douyinfe/semi-theme-default": "2.99.3", "@tiptap/core": "^3.10.7", "@tiptap/extension-document": "^3.10.7", "@tiptap/extension-hard-break": "^3.10.7", "@tiptap/extension-image": "^3.10.7", "@tiptap/extension-mention": "^3.10.7", "@tiptap/extension-paragraph": "^3.10.7", "@tiptap/extension-text": "^3.10.7", "@tiptap/extension-text-align": "^3.10.7", "@tiptap/extension-text-style": "^3.10.7", "@tiptap/extensions": "^3.10.7", "@tiptap/pm": "^3.10.7", "@tiptap/react": "^3.10.7", "@tiptap/starter-kit": "^3.10.7", "async-validator": "^3.5.0", "classnames": "^2.2.6", "copy-text-to-clipboard": "^2.1.1", "date-fns": "^2.29.3", "date-fns-tz": "^1.3.8", "fast-copy": "^3.0.1 ", "jsonc-parser": "^3.3.1", "lodash": "^4.17.21", "prop-types": "^15.7.2", "prosemirror-state": "^1.4.3", "react-resizable": "^3.0.5", "react-window": "^1.8.2", "scroll-into-view-if-needed": "^2.2.24", "utility-types": "^3.10.0" }, "peerDependencies": { "react": ">=16.0.0", "react-dom": ">=16.0.0" } }, "sha512-6NkeijjZZWzD31omteNVLz+oZuuMKQm3nEcwLI8+44Vv+VUSJPb87WnSFSD3F6eUIt/hZp2vJbCXHWW9SbCpDw=="], - "@douyinfe/vite-plugin-semi": ["@douyinfe/vite-plugin-semi@2.74.0-alpha.6", "", { "dependencies": { "sass": "^1.85.1" }, "peerDependencies": { "vite": "5.1.0" } }, "sha512-juyKSG0onVBG29FLdGPBA0yHT9Kh7P8e0FDtwhp0DuMk6drd45bDQZuU171gzx0ahv9rJaojnD6CgcBiggtQ3A=="], - "@ecies/ciphers": ["@ecies/ciphers@0.2.6", "", { "peerDependencies": { "@noble/ciphers": "^1.0.0" } }, "sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g=="], "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], @@ -814,8 +797,6 @@ "@resvg/resvg-js-win32-x64-msvc": ["@resvg/resvg-js-win32-x64-msvc@2.4.1", "", { "os": "win32", "cpu": "x64" }, "sha512-vY4kTLH2S3bP+puU5x7hlAxHv+ulFgcK6Zn3efKSr0M0KnZ9A3qeAjZteIpkowEFfUeMPNg2dvvoFRJA9zqxSw=="], - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.61.0", "", { "os": "android", "cpu": "arm" }, "sha512-dnxczajOqt0gesZlN5pGQ1s1imQVrsmCw5G2Ci4oM+0WvNz3pyRnlWrT7McoZIb8VlFwCawdmbWRmxRn7HI+VQ=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.61.0", "", { "os": "android", "cpu": "arm64" }, "sha512-Bp3JpGP00Vu3f238ivRrjf7z3xSzVPXqCmaJYA9t2c+c8vKYvOzmXF7LkkeUalTEGd6cZcSWe+PFIP3Vy48fRg=="], @@ -1126,14 +1107,6 @@ "@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="], - "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], - - "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], - - "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], - - "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - "@types/d3": ["@types/d3@7.4.3", "", { "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", "@types/d3-brush": "*", "@types/d3-chord": "*", "@types/d3-color": "*", "@types/d3-contour": "*", "@types/d3-delaunay": "*", "@types/d3-dispatch": "*", "@types/d3-drag": "*", "@types/d3-dsv": "*", "@types/d3-ease": "*", "@types/d3-fetch": "*", "@types/d3-force": "*", "@types/d3-format": "*", "@types/d3-geo": "*", "@types/d3-hierarchy": "*", "@types/d3-interpolate": "*", "@types/d3-path": "*", "@types/d3-polygon": "*", "@types/d3-quadtree": "*", "@types/d3-random": "*", "@types/d3-scale": "*", "@types/d3-scale-chromatic": "*", "@types/d3-selection": "*", "@types/d3-shape": "*", "@types/d3-time": "*", "@types/d3-time-format": "*", "@types/d3-timer": "*", "@types/d3-transition": "*", "@types/d3-zoom": "*" } }, "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww=="], "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], @@ -1314,14 +1287,6 @@ "@visactor/vutils-extension": ["@visactor/vutils-extension@2.0.22", "", { "dependencies": { "@visactor/vdataset": "~1.0.23", "@visactor/vutils": "~1.0.23" } }, "sha512-PRxjplZF1/Qdsflb1hYh9DGGJdblq91yIG7CCC6MIlMMSlDYEAMJzJ9y2clnR1MgWa2AsAtMtuu+MSdG3DctUA=="], - "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], - - "@vue/compiler-core": ["@vue/compiler-core@3.5.35", "", { "dependencies": { "@babel/parser": "^7.29.3", "@vue/shared": "3.5.35", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw=="], - - "@vue/compiler-dom": ["@vue/compiler-dom@3.5.35", "", { "dependencies": { "@vue/compiler-core": "3.5.35", "@vue/shared": "3.5.35" } }, "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA=="], - - "@vue/shared": ["@vue/shared@3.5.35", "", {}, "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA=="], - "@xyflow/react": ["@xyflow/react@12.10.2", "", { "dependencies": { "@xyflow/system": "0.0.76", "classcat": "^5.0.3", "zustand": "^4.4.0" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-CgIi6HwlcHXwlkTpr0fxLv/0sRVNZ8IdwKLzzeCscaYBwpvfcH1QFOCeaTCuEn1FQEs/B8CjnTSjhs8udgmBgQ=="], "@xyflow/system": ["@xyflow/system@0.0.76", "", { "dependencies": { "@types/d3-drag": "^3.0.7", "@types/d3-interpolate": "^3.0.4", "@types/d3-selection": "^3.0.10", "@types/d3-transition": "^3.0.8", "@types/d3-zoom": "^3.0.8", "d3-drag": "^3.0.0", "d3-interpolate": "^3.0.1", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0" } }, "sha512-hvwvnRS1B3REwVDlWexsq7YQaPZeG3/mKo1jv38UmnpWmxihp14bW6VtEOuHEwJX2FvzFw8k77LyKSk/wiZVNA=="], @@ -1374,8 +1339,6 @@ "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], - "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], - "async-validator": ["async-validator@3.5.2", "", {}, "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="], "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], @@ -1466,8 +1429,6 @@ "code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="], - "code-inspector-plugin": ["code-inspector-plugin@1.5.1", "", { "dependencies": { "@code-inspector/core": "1.5.1", "@code-inspector/esbuild": "1.5.1", "@code-inspector/mako": "1.5.1", "@code-inspector/turbopack": "1.5.1", "@code-inspector/vite": "1.5.1", "@code-inspector/webpack": "1.5.1", "chalk": "4.1.1" } }, "sha512-7gOqqBurKCucnls1ZHw0KWb7Z5u7gg3Q2pFSY9rrttFmwRaFJfJiscKEbm7X9IKmeEvkFRtNvNrHbSVQ67L8pQ=="], - "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], @@ -2098,8 +2059,6 @@ "knip": ["knip@6.15.0", "", { "dependencies": { "fdir": "^6.5.0", "formatly": "^0.3.0", "get-tsconfig": "4.14.0", "jiti": "^2.7.0", "minimist": "^1.2.8", "oxc-parser": "^0.133.0", "oxc-resolver": "^11.20.0", "picomatch": "^4.0.4", "smol-toml": "^1.6.1", "strip-json-comments": "5.0.3", "tinyglobby": "^0.2.16", "unbash": "^3.0.0", "yaml": "^2.9.0", "zod": "^4.1.11" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-uBaKFEGcu/HG4EY2gWFBMr+fBF43Jftoc2riJX51TKME1Z46C8UQIbNEusenYbEWihphxe2PY0Kns0yPvPYz4A=="], - "launch-ide": ["launch-ide@1.4.3", "", { "dependencies": { "chalk": "^4.1.1", "dotenv": "^16.1.4" } }, "sha512-v2xMAarJOFy51kuesYEIIx5r4WHvsV+VLMU49K24bdiRZGUpo1ZulO1DRrLozM5BMbXUfRfrUTM2PbBfYCeA4Q=="], - "layout-base": ["layout-base@1.0.2", "", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="], "leva": ["leva@0.10.1", "", { "dependencies": { "@radix-ui/react-portal": "^1.1.4", "@radix-ui/react-tooltip": "^1.1.8", "@stitches/react": "^1.2.8", "@use-gesture/react": "^10.2.5", "colord": "^2.9.2", "dequal": "^2.0.2", "merge-value": "^1.0.0", "react-colorful": "^5.5.1", "react-dropzone": "^12.0.0", "v8n": "^1.3.3", "zustand": "^3.6.9" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-BcjnfUX8jpmwZUz2L7AfBtF9vn4ggTH33hmeufDULbP3YgNZ/C+ss/oO3stbrqRQyaOmRwy70y7BGTGO81S3rA=="], @@ -2458,8 +2417,6 @@ "polished": ["polished@4.3.1", "", { "dependencies": { "@babel/runtime": "^7.17.8" } }, "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA=="], - "portfinder": ["portfinder@1.0.38", "", { "dependencies": { "async": "^3.2.6", "debug": "^4.3.6" } }, "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg=="], - "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], "postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="], @@ -3066,8 +3023,6 @@ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@code-inspector/core/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], - "@dotenvx/dotenvx/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], "@dotenvx/dotenvx/execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], @@ -3224,12 +3179,6 @@ "@visactor/vutils/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], - "@vitejs/plugin-react/react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], - - "@vue/compiler-core/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], - - "@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - "@xyflow/react/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], "accepts/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], @@ -3290,8 +3239,6 @@ "katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], - "launch-ide/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], - "leva/react-dropzone": ["react-dropzone@12.1.0", "", { "dependencies": { "attr-accept": "^2.2.2", "file-selector": "^0.5.0", "prop-types": "^15.8.1" }, "peerDependencies": { "react": ">= 16.8" } }, "sha512-iBYHA1rbopIvtzokEX4QubO6qk5IF/x3BtKGu74rF2JkQDXnwC4uO/lHKpaw4PJIV6iIAYOlwLv2FpiGyqHNog=="], "leva/zustand": ["zustand@3.7.2", "", { "peerDependencies": { "react": ">=16.8" }, "optionalPeers": ["react"] }, "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA=="], @@ -3344,10 +3291,6 @@ "react-template/lucide-react": ["lucide-react@0.511.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w=="], - "react-template/react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], - - "react-template/react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], - "react-template/react-i18next": ["react-i18next@13.5.0", "", { "dependencies": { "@babel/runtime": "^7.22.5", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { "i18next": ">= 23.2.3", "react": ">= 16.8.0" } }, "sha512-CFJ5NDGJ2MUyBohEHxljOq/39NQ972rh1ajnadG9BjTk+UXbHLq4z5DKEbEQBDoIhUmmbuS/fIMJKo6VOax1HA=="], "react-template/tailwindcss": ["tailwindcss@3.4.19", "", { "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.2", "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.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ=="], @@ -3580,8 +3523,6 @@ "react-template/eslint/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], - "react-template/react-dom/scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], - "react-template/tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "react-template/tailwindcss/jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], diff --git a/web/classic/index.html b/web/classic/index.html index d6bd2433..814b8e6a 100644 --- a/web/classic/index.html +++ b/web/classic/index.html @@ -24,6 +24,5 @@
- diff --git a/web/classic/package.json b/web/classic/package.json index 0955acb8..8a840d67 100644 --- a/web/classic/package.json +++ b/web/classic/package.json @@ -4,6 +4,7 @@ "private": true, "type": "module", "dependencies": { + "@douyinfe/semi-illustrations": "^2.69.1", "@douyinfe/semi-icons": "^2.63.1", "@douyinfe/semi-ui": "^2.69.1", "@lobehub/icons": "catalog:", @@ -14,6 +15,7 @@ "clsx": "catalog:", "dayjs": "catalog:", "history": "^5.3.0", + "highlight.js": "^11.11.1", "i18next": "^23.16.8", "i18next-browser-languagedetector": "^7.2.0", "katex": "^0.16.22", @@ -21,8 +23,8 @@ "marked": "^4.1.1", "mermaid": "^11.6.0", "qrcode.react": "catalog:", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", "react-dropzone": "^14.2.3", "react-fireworks": "^1.0.4", "react-i18next": "^13.0.0", @@ -42,13 +44,13 @@ "use-debounce": "^10.0.4" }, "scripts": { - "dev": "vite", - "build": "vite build", + "dev": "rsbuild dev", + "build": "rsbuild build", "lint": "prettier . --check", "lint:fix": "prettier . --write", "eslint": "bunx eslint \"**/*.{js,jsx}\" --cache", "eslint:fix": "bunx eslint \"**/*.{js,jsx}\" --fix --cache", - "preview": "vite preview", + "preview": "rsbuild preview", "i18n:extract": "bunx i18next-cli extract", "i18n:status": "bunx i18next-cli status", "i18n:sync": "bunx i18next-cli sync", @@ -73,20 +75,19 @@ ] }, "devDependencies": { - "@douyinfe/vite-plugin-semi": "^2.74.0-alpha.6", + "@rsbuild/core": "^2.0.7", + "@rsbuild/plugin-react": "^2.0.0", "@so1ve/prettier-config": "^3.1.0", - "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.21", - "code-inspector-plugin": "^1.3.3", "eslint": "8.57.0", "eslint-plugin-header": "^3.1.1", "eslint-plugin-react-hooks": "^5.2.0", "i18next-cli": "^1.10.3", "postcss": "^8.5.3", + "prop-types": "^15.8.1", "prettier": "catalog:", "tailwindcss": "^3", - "typescript": "4.4.2", - "vite": "^5.2.0" + "typescript": "4.4.2" }, "prettier": { "singleQuote": true, diff --git a/web/classic/rsbuild.config.ts b/web/classic/rsbuild.config.ts new file mode 100644 index 00000000..0a37a0bb --- /dev/null +++ b/web/classic/rsbuild.config.ts @@ -0,0 +1,106 @@ +import path from 'path' +import { createRequire } from 'module' +import { fileURLToPath } from 'url' +import { defineConfig, loadEnv } from '@rsbuild/core' +import { pluginReact } from '@rsbuild/plugin-react' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const require = createRequire(import.meta.url) +const semiUiDir = path.resolve( + path.dirname(require.resolve('@douyinfe/semi-ui')), + '../..', +) + +export default defineConfig(({ envMode }) => { + const env = loadEnv({ mode: envMode, prefixes: ['VITE_'] }) + const clientServerUrl = + process.env.VITE_REACT_APP_SERVER_URL || + env.rawPublicVars.VITE_REACT_APP_SERVER_URL || + '' + const proxyServerUrl = + clientServerUrl || + 'http://localhost:3000' + const isProd = envMode === 'production' + const devProxy = Object.fromEntries( + (['/api', '/mj', '/pg'] as const).map((key) => [ + key, + { target: proxyServerUrl, changeOrigin: true }, + ]), + ) as Record + + return { + plugins: [pluginReact()], + source: { + entry: { + index: './src/index.jsx', + }, + define: { + 'import.meta.env.VITE_REACT_APP_SERVER_URL': JSON.stringify( + clientServerUrl, + ), + }, + }, + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + '@douyinfe/semi-ui/dist/css/semi.css': path.resolve( + semiUiDir, + 'dist/css/semi.css', + ), + }, + }, + html: { + template: './index.html', + }, + server: { + host: '0.0.0.0', + strictPort: true, + proxy: devProxy, + }, + output: { + minify: isProd, + target: 'web', + distPath: { + root: 'dist', + }, + }, + performance: { + removeConsole: isProd ? ['log'] : false, + buildCache: { + cacheDigest: [process.env.VITE_REACT_APP_VERSION], + }, + }, + tools: { + rspack: { + module: { + rules: [ + { + test: /src[\\/].*\.js$/, + type: 'javascript/auto', + use: [ + { + loader: 'builtin:swc-loader', + options: { + jsc: { + parser: { + syntax: 'ecmascript', + jsx: true, + }, + transform: { + react: { + runtime: 'automatic', + development: !isProd, + refresh: !isProd, + }, + }, + }, + }, + }, + ], + }, + ], + }, + }, + }, + } +}) diff --git a/web/classic/src/components/auth/LoginForm.jsx b/web/classic/src/components/auth/LoginForm.jsx index 7e8c0ce0..63305e83 100644 --- a/web/classic/src/components/auth/LoginForm.jsx +++ b/web/classic/src/components/auth/LoginForm.jsx @@ -947,7 +947,7 @@ const LoginForm = () => { }; return ( -
+
{/* 背景模糊晕染球 */}
{ } return ( -
+
{/* 背景模糊晕染球 */}
{ } return ( -
+
{/* 背景模糊晕染球 */}
{ }; return ( -
+
{/* 背景模糊晕染球 */}
{ // 显示加载状态 if (loading) { return ( -
+
); @@ -150,7 +150,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => { // 如果没有内容,显示空状态 if (!content || content.trim() === '') { return ( -
+
{ // 如果是 URL,显示链接卡片 if (isUrl(content)) { return ( -
+
@@ -196,7 +196,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => { // 如果是 HTML 内容,直接渲染 if (isHtmlContent(content)) { return ( - <div className='min-h-screen bg-gray-50'> + <div className='classic-page-fill bg-gray-50'> <div className='max-w-4xl mx-auto py-12 px-4 sm:px-6 lg:px-8'> <div className='bg-white rounded-lg shadow-sm p-8'> <Title heading={2} className='text-center mb-8'> @@ -214,7 +214,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => { // 其他内容统一使用 Markdown 渲染器 return ( - <div className='min-h-screen bg-gray-50'> + <div className='classic-page-fill bg-gray-50'> <div className='max-w-4xl mx-auto py-12 px-4 sm:px-6 lg:px-8'> <div className='bg-white rounded-lg shadow-sm p-8'> <Title heading={2} className='text-center mb-8'> diff --git a/web/classic/src/components/layout/PageLayout.jsx b/web/classic/src/components/layout/PageLayout.jsx index ca38ed50..962a22e4 100644 --- a/web/classic/src/components/layout/PageLayout.jsx +++ b/web/classic/src/components/layout/PageLayout.jsx @@ -71,6 +71,7 @@ const PageLayout = () => { const isConsoleRoute = location.pathname.startsWith('/console'); const showSider = isConsoleRoute && (!isMobile || drawerOpen); + const isFixedLayout = isConsoleRoute || location.pathname === '/pricing'; useEffect(() => { if (isMobile && drawerOpen && collapsed) { @@ -146,11 +147,11 @@ const PageLayout = () => { return ( <Layout - className='app-layout' + className={`app-layout${isFixedLayout ? ' app-layout-fixed' : ''}`} style={{ display: 'flex', flexDirection: 'column', - overflow: isMobile ? 'visible' : 'hidden', + overflow: isFixedLayout && !isMobile ? 'hidden' : 'visible', }} > <Header @@ -171,9 +172,10 @@ const PageLayout = () => { </Header> <Layout style={{ - overflow: isMobile ? 'visible' : 'auto', + overflow: isFixedLayout && !isMobile ? 'auto' : 'visible', display: 'flex', flexDirection: 'column', + flex: '1 1 auto', }} > {showSider && ( @@ -206,15 +208,18 @@ const PageLayout = () => { flex: '1 1 auto', display: 'flex', flexDirection: 'column', + minHeight: 0, }} > <Content + className={isFixedLayout ? undefined : 'public-page-content'} style={{ - flex: '1 0 auto', - overflowY: isMobile ? 'visible' : 'hidden', + flex: isFixedLayout ? '1 0 auto' : '1 1 auto', + overflowY: isFixedLayout && !isMobile ? 'hidden' : 'visible', WebkitOverflowScrolling: 'touch', padding: shouldInnerPadding ? (isMobile ? '5px' : '24px') : '0', position: 'relative', + minHeight: 0, }} > <ErrorBoundary> diff --git a/web/classic/src/constants/index.js b/web/classic/src/constants/index.js index edd9f50b..10c746d5 100644 --- a/web/classic/src/constants/index.js +++ b/web/classic/src/constants/index.js @@ -17,12 +17,46 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. For commercial licensing, please contact support@quantumnous.com */ -export * from './channel.constants'; -export * from './user.constants'; -export * from './toast.constants'; -export * from './common.constant'; -export * from './dashboard.constants'; -export * from './playground.constants'; -export * from './redemption.constants'; -export * from './channel-affinity-template.constants'; -export * from './billing.constants'; +export { + CHANNEL_OPTIONS, + MODEL_FETCHABLE_CHANNEL_TYPES, + MODEL_TABLE_PAGE_SIZE, +} from './channel.constants'; +export { userConstants } from './user.constants'; +export { toastConstants } from './toast.constants'; +export { + ITEMS_PER_PAGE, + DEFAULT_ENDPOINT, + TABLE_COMPACT_MODES_KEY, + API_ENDPOINTS, + TASK_ACTION_GENERATE, + TASK_ACTION_TEXT_GENERATE, + TASK_ACTION_FIRST_TAIL_GENERATE, + TASK_ACTION_REFERENCE_GENERATE, + TASK_ACTION_REMIX_GENERATE, +} from './common.constant'; +export { + REDEMPTION_STATUS, + REDEMPTION_STATUS_MAP, + REDEMPTION_ACTIONS, +} from './redemption.constants'; +export { + CODEX_CLI_HEADER_PASSTHROUGH_HEADERS, + CLAUDE_CLI_HEADER_PASSTHROUGH_HEADERS, + CODEX_CLI_HEADER_PASSTHROUGH_TEMPLATE, + CLAUDE_CLI_HEADER_PASSTHROUGH_TEMPLATE, + CHANNEL_AFFINITY_RULE_TEMPLATES, + cloneChannelAffinityTemplate, +} from './channel-affinity-template.constants'; +export { + BILLING_VARS, + BILLING_VAR_KEYS, + BILLING_PRICING_VARS, + BILLING_EXTRA_VARS, + BILLING_VAR_KEY_TO_FIELD, + BILLING_VAR_FIELD_TO_LABEL, + BILLING_VAR_FIELD_TO_SHORT_LABEL, + BILLING_CACHE_VAR_MAP, + BILLING_VAR_REGEX, + BILLING_CONDITION_VARS, +} from './billing.constants'; diff --git a/web/classic/src/helpers/render.jsx b/web/classic/src/helpers/render.jsx index 46c95b23..f48fe1f8 100644 --- a/web/classic/src/helpers/render.jsx +++ b/web/classic/src/helpers/render.jsx @@ -94,7 +94,6 @@ import { SiGitlab, SiGoogle, SiKeycloak, - SiLinkedin, SiNextcloud, SiNotion, SiOkta, @@ -106,6 +105,7 @@ import { SiWechat, SiX, } from 'react-icons/si'; +import { FaLinkedin } from 'react-icons/fa'; // 获取侧边栏Lucide图标组件 export function getLucideIcon(key, selected = false) { @@ -509,7 +509,7 @@ const oauthProviderIconMap = { google: SiGoogle, discord: SiDiscord, facebook: SiFacebook, - linkedin: SiLinkedin, + linkedin: FaLinkedin, x: SiX, twitter: SiX, slack: SiSlack, diff --git a/web/classic/src/helpers/utils.jsx b/web/classic/src/helpers/utils.jsx index 7c7e63c7..c2e72820 100644 --- a/web/classic/src/helpers/utils.jsx +++ b/web/classic/src/helpers/utils.jsx @@ -123,7 +123,7 @@ export function showError(error) { console.error(error); if (error.message) { if (error.name === 'AxiosError') { - switch (error.response.status) { + switch (error.response?.status) { case 401: // 清除用户状态 localStorage.removeItem('user'); diff --git a/web/classic/src/index.css b/web/classic/src/index.css index 57b8c4be..05194759 100644 --- a/web/classic/src/index.css +++ b/web/classic/src/index.css @@ -31,18 +31,40 @@ body { background-color: var(--semi-color-bg-0); } -/* 桌面端禁止 body 纵向滚动 - 防止 VChart tooltip 触发页面滚动条 */ -@media (min-width: 768px) { - body { - overflow-y: hidden; - } +.app-layout { + min-height: 100vh; + min-height: 100dvh; } -.app-layout { +.app-layout-fixed { height: 100vh; height: 100dvh; } +.public-page-content { + display: flex; + flex-direction: column; +} + +.classic-page-fill { + flex: 1 0 auto; + min-height: 100%; +} + +.classic-home-page, +.classic-home-default { + display: flex; + flex-direction: column; +} + +.classic-home-default { + flex: 1 0 auto; +} + +.classic-home-hero { + flex: 1 0 auto; +} + .app-sider { height: calc(100vh - 64px); height: calc(100dvh - 64px); diff --git a/web/classic/src/pages/About/index.jsx b/web/classic/src/pages/About/index.jsx index cd4ad8f1..2f8091a9 100644 --- a/web/classic/src/pages/About/index.jsx +++ b/web/classic/src/pages/About/index.jsx @@ -133,9 +133,9 @@ const About = () => { ); return ( - <div className='mt-[60px] px-2'> + <div className='classic-page-fill flex flex-col pt-[60px] px-2'> {aboutLoaded && about === '' ? ( - <div className='flex justify-center items-center h-screen p-8'> + <div className='flex flex-1 justify-center items-center p-8'> <Empty image={ <IllustrationConstruction style={{ width: 150, height: 150 }} /> @@ -156,7 +156,12 @@ const About = () => { {about.startsWith('https://') ? ( <iframe src={about} - style={{ width: '100%', height: '100vh', border: 'none' }} + style={{ + width: '100%', + flex: '1 1 auto', + minHeight: 0, + border: 'none', + }} /> ) : ( <div diff --git a/web/classic/src/pages/Forbidden/index.jsx b/web/classic/src/pages/Forbidden/index.jsx index f36f12bf..5a14d372 100644 --- a/web/classic/src/pages/Forbidden/index.jsx +++ b/web/classic/src/pages/Forbidden/index.jsx @@ -28,7 +28,7 @@ import { useTranslation } from 'react-i18next'; const Forbidden = () => { const { t } = useTranslation(); return ( - <div className='flex justify-center items-center h-screen p-8'> + <div className='classic-page-fill flex justify-center items-center p-8'> <Empty image={<IllustrationNoAccess style={{ width: 250, height: 250 }} />} darkModeImage={ diff --git a/web/classic/src/pages/Home/index.jsx b/web/classic/src/pages/Home/index.jsx index c242e086..def3a3ee 100644 --- a/web/classic/src/pages/Home/index.jsx +++ b/web/classic/src/pages/Home/index.jsx @@ -149,20 +149,20 @@ const Home = () => { }, [endpointItems.length]); return ( - <div className='w-full overflow-x-hidden'> + <div className='classic-page-fill classic-home-page w-full overflow-x-hidden'> <NoticeModal visible={noticeVisible} onClose={() => setNoticeVisible(false)} isMobile={isMobile} /> {homePageContentLoaded && homePageContent === '' ? ( - <div className='w-full overflow-x-hidden'> + <div className='classic-home-default w-full overflow-x-hidden'> {/* Banner 部分 */} - <div className='w-full border-b border-semi-color-border min-h-[500px] md:min-h-[600px] lg:min-h-[700px] relative overflow-x-hidden'> + <div className='classic-home-hero w-full border-b border-semi-color-border relative overflow-x-hidden'> {/* 背景模糊晕染球 */} <div className='blur-ball blur-ball-indigo' /> <div className='blur-ball blur-ball-teal' /> - <div className='flex items-center justify-center h-full px-4 py-20 md:py-24 lg:py-32 mt-10'> + <div className='flex items-center justify-center px-4 pt-24 pb-8'> {/* 居中内容区 */} <div className='flex flex-col items-center justify-center text-center max-w-4xl mx-auto'> <div className='flex flex-col items-center justify-center mb-6 md:mb-8'> @@ -335,11 +335,11 @@ const Home = () => { </div> </div> ) : ( - <div className='overflow-x-hidden w-full'> + <div className='classic-page-fill overflow-x-hidden w-full'> {homePageContent.startsWith('https://') ? ( <iframe src={homePageContent} - className='w-full h-screen border-none' + className='w-full h-full border-none' /> ) : ( <div diff --git a/web/classic/src/pages/NotFound/index.jsx b/web/classic/src/pages/NotFound/index.jsx index d15ab2df..156ea409 100644 --- a/web/classic/src/pages/NotFound/index.jsx +++ b/web/classic/src/pages/NotFound/index.jsx @@ -28,7 +28,7 @@ import { useTranslation } from 'react-i18next'; const NotFound = () => { const { t } = useTranslation(); return ( - <div className='flex justify-center items-center h-screen p-8'> + <div className='classic-page-fill flex justify-center items-center p-8'> <Empty image={<IllustrationNotFound style={{ width: 250, height: 250 }} />} darkModeImage={ diff --git a/web/classic/vite.config.js b/web/classic/vite.config.js deleted file mode 100644 index 73e46212..00000000 --- a/web/classic/vite.config.js +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright (C) 2025 QuantumNous - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see <https://www.gnu.org/licenses/>. - -For commercial licensing, please contact support@quantumnous.com -*/ - -import react from '@vitejs/plugin-react'; -import { defineConfig, transformWithEsbuild } from 'vite'; -import pkg from '@douyinfe/vite-plugin-semi'; -import path from 'path'; -import { codeInspectorPlugin } from 'code-inspector-plugin'; -const { vitePluginSemi } = pkg; - -// https://vitejs.dev/config/ -export default defineConfig({ - resolve: { - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, - plugins: [ - codeInspectorPlugin({ - bundler: 'vite', - }), - { - name: 'treat-js-files-as-jsx', - async transform(code, id) { - if (!/src\/.*\.js$/.test(id)) { - return null; - } - - // Use the exposed transform from vite, instead of directly - // transforming with esbuild - return transformWithEsbuild(code, id, { - loader: 'jsx', - jsx: 'automatic', - }); - }, - }, - react(), - vitePluginSemi({ - cssLayer: true, - }), - ], - optimizeDeps: { - force: true, - esbuildOptions: { - loader: { - '.js': 'jsx', - '.json': 'json', - }, - }, - }, - build: { - rollupOptions: { - output: { - manualChunks: { - 'react-core': ['react', 'react-dom', 'react-router-dom'], - 'semi-ui': ['@douyinfe/semi-icons', '@douyinfe/semi-ui'], - tools: ['axios', 'history', 'marked'], - 'react-components': [ - 'react-dropzone', - 'react-fireworks', - 'react-telegram-login', - 'react-toastify', - 'react-turnstile', - ], - i18n: [ - 'i18next', - 'react-i18next', - 'i18next-browser-languagedetector', - ], - }, - }, - }, - }, - server: { - host: '0.0.0.0', - proxy: { - '/api': { - target: 'http://localhost:3000', - changeOrigin: true, - }, - '/mj': { - target: 'http://localhost:3000', - changeOrigin: true, - }, - '/pg': { - target: 'http://localhost:3000', - changeOrigin: true, - }, - }, - }, -}); diff --git a/web/default/rsbuild.config.ts b/web/default/rsbuild.config.ts index 3c60ab50..be1d9774 100644 --- a/web/default/rsbuild.config.ts +++ b/web/default/rsbuild.config.ts @@ -65,6 +65,7 @@ export default defineConfig(({ envMode }) => { }, server: { host: '0.0.0.0', + strictPort: true, proxy: devProxy, }, output: { From 0bbcaa899974e402bdfd80374c00e9d7904e10d0 Mon Sep 17 00:00:00 2001 From: QuentinHsu <xuquentinyang@gmail.com> Date: Tue, 2 Jun 2026 00:50:29 +0800 Subject: [PATCH 2/2] fix(classic): inject Semi React 19 adapter --- web/classic/src/index.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/classic/src/index.jsx b/web/classic/src/index.jsx index 5162b0cb..f24f0ec0 100644 --- a/web/classic/src/index.jsx +++ b/web/classic/src/index.jsx @@ -1,3 +1,5 @@ +import '@douyinfe/semi-ui/react19-adapter'; + /* Copyright (C) 2025 QuantumNous