From 45aa11e4dfb41875df8586376b978cefac1a6983 Mon Sep 17 00:00:00 2001 From: Jonson Petard <41122242+greenhat616@users.noreply.github.com> Date: Sun, 3 Dec 2023 00:36:58 +0800 Subject: [PATCH 1/6] feat: use framer-motion for smooth page transition --- package.json | 3 +- pnpm-lock.yaml | 148 +++++++++++++--------- src/assets/styles/anime.scss | 25 ---- src/assets/styles/page.scss | 2 +- src/components/layout/page-transition.tsx | 44 +++++++ src/pages/_layout.tsx | 67 ++++------ src/pages/_routers.tsx | 82 +++++++----- src/pages/connections.tsx | 52 ++++---- src/pages/logs.tsx | 26 ++-- src/pages/profiles.tsx | 66 +++++----- src/pages/proxies.tsx | 6 +- src/pages/rules.tsx | 18 ++- src/pages/settings.tsx | 18 ++- src/utils/index.ts | 9 ++ 14 files changed, 305 insertions(+), 261 deletions(-) delete mode 100644 src/assets/styles/anime.scss create mode 100644 src/components/layout/page-transition.tsx create mode 100644 src/utils/index.ts diff --git a/package.json b/package.json index 5af94d9da7..c2d7142ed3 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "ahooks": "^3.7.2", "axios": "^1.1.3", "dayjs": "1.11.5", + "framer-motion": "10.16.12", "i18next": "^22.0.4", "lodash-es": "^4.17.21", "monaco-editor": "^0.34.1", @@ -117,7 +118,7 @@ "stylelint-order": "6.0.3", "stylelint-scss": "5.3.1", "tsx": "4.5.0", - "typescript": "^4.7.4", + "typescript": "^5.3.2", "vite": "^4.5.0", "vite-plugin-monaco-editor": "^1.1.0", "vite-plugin-svgr": "^4.1.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 295e24702c..da7fe91b03 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,6 +47,9 @@ dependencies: dayjs: specifier: 1.11.5 version: 1.11.5 + framer-motion: + specifier: 10.16.12 + version: 10.16.12(react-dom@18.2.0)(react@18.2.0) i18next: specifier: ^22.0.4 version: 22.0.4 @@ -96,7 +99,7 @@ devDependencies: version: 5.0.3 '@commitlint/cli': specifier: 18.4.3 - version: 18.4.3(typescript@4.7.4) + version: 18.4.3(typescript@5.3.2) '@commitlint/config-conventional': specifier: 18.4.3 version: 18.4.3 @@ -126,10 +129,10 @@ devDependencies: version: 4.4.9 '@typescript-eslint/eslint-plugin': specifier: 6.13.1 - version: 6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.54.0)(typescript@4.7.4) + version: 6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.54.0)(typescript@5.3.2) '@typescript-eslint/parser': specifier: 6.13.1 - version: 6.13.1(eslint@8.54.0)(typescript@4.7.4) + version: 6.13.1(eslint@8.54.0)(typescript@5.3.2) '@vitejs/plugin-react': specifier: ^4.1.0 version: 4.1.0(vite@4.5.0) @@ -222,7 +225,7 @@ devDependencies: version: 1.54.8 stylelint: specifier: 15.11.0 - version: 15.11.0(typescript@4.7.4) + version: 15.11.0(typescript@5.3.2) stylelint-config-html: specifier: 1.1.0 version: 1.1.0(postcss-html@1.5.0)(stylelint@15.11.0) @@ -245,8 +248,8 @@ devDependencies: specifier: 4.5.0 version: 4.5.0 typescript: - specifier: ^4.7.4 - version: 4.7.4 + specifier: ^5.3.2 + version: 5.3.2 vite: specifier: ^4.5.0 version: 4.5.0(@types/node@18.19.0)(sass@1.54.8) @@ -255,7 +258,7 @@ devDependencies: version: 1.1.0(monaco-editor@0.34.1) vite-plugin-svgr: specifier: ^4.1.0 - version: 4.1.0(typescript@4.7.4)(vite@4.5.0) + version: 4.1.0(typescript@5.3.2)(vite@4.5.0) packages: @@ -506,14 +509,14 @@ packages: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 - /@commitlint/cli@18.4.3(typescript@4.7.4): + /@commitlint/cli@18.4.3(typescript@5.3.2): resolution: {integrity: sha512-zop98yfB3A6NveYAZ3P1Mb6bIXuCeWgnUfVNkH4yhIMQpQfzFwseadazOuSn0OOfTt0lWuFauehpm9GcqM5lww==} engines: {node: '>=v18'} hasBin: true dependencies: '@commitlint/format': 18.4.3 '@commitlint/lint': 18.4.3 - '@commitlint/load': 18.4.3(typescript@4.7.4) + '@commitlint/load': 18.4.3(typescript@5.3.2) '@commitlint/read': 18.4.3 '@commitlint/types': 18.4.3 execa: 5.1.1 @@ -583,7 +586,7 @@ packages: '@commitlint/types': 18.4.3 dev: true - /@commitlint/load@18.4.3(typescript@4.7.4): + /@commitlint/load@18.4.3(typescript@5.3.2): resolution: {integrity: sha512-v6j2WhvRQJrcJaj5D+EyES2WKTxPpxENmNpNG3Ww8MZGik3jWRXtph0QTzia5ZJyPh2ib5aC/6BIDymkUUM58Q==} engines: {node: '>=v18'} dependencies: @@ -593,8 +596,8 @@ packages: '@commitlint/types': 18.4.3 '@types/node': 18.19.0 chalk: 4.1.2 - cosmiconfig: 8.3.6(typescript@4.7.4) - cosmiconfig-typescript-loader: 5.0.0(@types/node@18.19.0)(cosmiconfig@8.3.6)(typescript@4.7.4) + cosmiconfig: 8.3.6(typescript@5.3.2) + cosmiconfig-typescript-loader: 5.0.0(@types/node@18.19.0)(cosmiconfig@8.3.6)(typescript@5.3.2) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -777,12 +780,25 @@ packages: resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} dev: false + /@emotion/is-prop-valid@0.8.8: + resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} + requiresBuild: true + dependencies: + '@emotion/memoize': 0.7.4 + dev: false + optional: true + /@emotion/is-prop-valid@1.2.1: resolution: {integrity: sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==} dependencies: '@emotion/memoize': 0.8.1 dev: false + /@emotion/memoize@0.7.4: + resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} + dev: false + optional: true + /@emotion/memoize@0.8.1: resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} dev: false @@ -1676,14 +1692,14 @@ packages: '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.23.2) dev: true - /@svgr/core@8.1.0(typescript@4.7.4): + /@svgr/core@8.1.0(typescript@5.3.2): resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} engines: {node: '>=14'} dependencies: '@babel/core': 7.23.2 '@svgr/babel-preset': 8.1.0(@babel/core@7.23.2) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@4.7.4) + cosmiconfig: 8.3.6(typescript@5.3.2) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -1706,7 +1722,7 @@ packages: dependencies: '@babel/core': 7.23.2 '@svgr/babel-preset': 8.1.0(@babel/core@7.23.2) - '@svgr/core': 8.1.0(typescript@4.7.4) + '@svgr/core': 8.1.0(typescript@5.3.2) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: @@ -1934,7 +1950,7 @@ packages: resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} dev: true - /@typescript-eslint/eslint-plugin@6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.54.0)(typescript@4.7.4): + /@typescript-eslint/eslint-plugin@6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.54.0)(typescript@5.3.2): resolution: {integrity: sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1946,10 +1962,10 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.13.1(eslint@8.54.0)(typescript@4.7.4) + '@typescript-eslint/parser': 6.13.1(eslint@8.54.0)(typescript@5.3.2) '@typescript-eslint/scope-manager': 6.13.1 - '@typescript-eslint/type-utils': 6.13.1(eslint@8.54.0)(typescript@4.7.4) - '@typescript-eslint/utils': 6.13.1(eslint@8.54.0)(typescript@4.7.4) + '@typescript-eslint/type-utils': 6.13.1(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/utils': 6.13.1(eslint@8.54.0)(typescript@5.3.2) '@typescript-eslint/visitor-keys': 6.13.1 debug: 4.3.4 eslint: 8.54.0 @@ -1957,13 +1973,13 @@ packages: ignore: 5.3.0 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@4.7.4) - typescript: 4.7.4 + ts-api-utils: 1.0.3(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.13.1(eslint@8.54.0)(typescript@4.7.4): + /@typescript-eslint/parser@6.13.1(eslint@8.54.0)(typescript@5.3.2): resolution: {integrity: sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1975,11 +1991,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 6.13.1 '@typescript-eslint/types': 6.13.1 - '@typescript-eslint/typescript-estree': 6.13.1(typescript@4.7.4) + '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) '@typescript-eslint/visitor-keys': 6.13.1 debug: 4.3.4 eslint: 8.54.0 - typescript: 4.7.4 + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true @@ -1992,7 +2008,7 @@ packages: '@typescript-eslint/visitor-keys': 6.13.1 dev: true - /@typescript-eslint/type-utils@6.13.1(eslint@8.54.0)(typescript@4.7.4): + /@typescript-eslint/type-utils@6.13.1(eslint@8.54.0)(typescript@5.3.2): resolution: {integrity: sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2002,12 +2018,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.13.1(typescript@4.7.4) - '@typescript-eslint/utils': 6.13.1(eslint@8.54.0)(typescript@4.7.4) + '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) + '@typescript-eslint/utils': 6.13.1(eslint@8.54.0)(typescript@5.3.2) debug: 4.3.4 eslint: 8.54.0 - ts-api-utils: 1.0.3(typescript@4.7.4) - typescript: 4.7.4 + ts-api-utils: 1.0.3(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true @@ -2017,7 +2033,7 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.13.1(typescript@4.7.4): + /@typescript-eslint/typescript-estree@6.13.1(typescript@5.3.2): resolution: {integrity: sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2032,13 +2048,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@4.7.4) - typescript: 4.7.4 + ts-api-utils: 1.0.3(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@6.13.1(eslint@8.54.0)(typescript@4.7.4): + /@typescript-eslint/utils@6.13.1(eslint@8.54.0)(typescript@5.3.2): resolution: {integrity: sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2049,7 +2065,7 @@ packages: '@types/semver': 7.5.6 '@typescript-eslint/scope-manager': 6.13.1 '@typescript-eslint/types': 6.13.1 - '@typescript-eslint/typescript-estree': 6.13.1(typescript@4.7.4) + '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) eslint: 8.54.0 semver: 7.5.4 transitivePeerDependencies: @@ -2656,7 +2672,7 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true - /cosmiconfig-typescript-loader@5.0.0(@types/node@18.19.0)(cosmiconfig@8.3.6)(typescript@4.7.4): + /cosmiconfig-typescript-loader@5.0.0(@types/node@18.19.0)(cosmiconfig@8.3.6)(typescript@5.3.2): resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==} engines: {node: '>=v16'} peerDependencies: @@ -2665,9 +2681,9 @@ packages: typescript: '>=4' dependencies: '@types/node': 18.19.0 - cosmiconfig: 8.3.6(typescript@4.7.4) + cosmiconfig: 8.3.6(typescript@5.3.2) jiti: 1.21.0 - typescript: 4.7.4 + typescript: 5.3.2 dev: true /cosmiconfig@7.0.1: @@ -2681,7 +2697,7 @@ packages: yaml: 1.10.2 dev: false - /cosmiconfig@8.3.6(typescript@4.7.4): + /cosmiconfig@8.3.6(typescript@5.3.2): resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} peerDependencies: @@ -2694,7 +2710,7 @@ packages: js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 - typescript: 4.7.4 + typescript: 5.3.2 dev: true /cross-env@7.0.3: @@ -3161,7 +3177,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.13.1(eslint@8.54.0)(typescript@4.7.4) + '@typescript-eslint/parser': 6.13.1(eslint@8.54.0)(typescript@5.3.2) debug: 3.2.7 eslint: 8.54.0 eslint-import-resolver-node: 0.3.9 @@ -3197,7 +3213,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.13.1(eslint@8.54.0)(typescript@4.7.4) + '@typescript-eslint/parser': 6.13.1(eslint@8.54.0)(typescript@5.3.2) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 @@ -3593,6 +3609,24 @@ packages: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true + /framer-motion@10.16.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-w7Yzx0OzQ5Uh6uNkxaX+4TuAPuOKz3haSbjmHpdrqDpGuCJCpq6YP9Dy7JJWdZ6mJjndrg3Ao3vUwDajKNikCA==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tslib: 2.6.2 + optionalDependencies: + '@emotion/is-prop-valid': 0.8.8 + dev: false + /fs-extra@10.0.1: resolution: {integrity: sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==} engines: {node: '>=12'} @@ -5844,7 +5878,7 @@ packages: stylelint: '>=14.0.0' dependencies: postcss-html: 1.5.0 - stylelint: 15.11.0(typescript@4.7.4) + stylelint: 15.11.0(typescript@5.3.2) dev: true /stylelint-config-recess-order@4.4.0(stylelint@15.11.0): @@ -5852,7 +5886,7 @@ packages: peerDependencies: stylelint: '>=15' dependencies: - stylelint: 15.11.0(typescript@4.7.4) + stylelint: 15.11.0(typescript@5.3.2) stylelint-order: 6.0.3(stylelint@15.11.0) dev: true @@ -5862,7 +5896,7 @@ packages: peerDependencies: stylelint: ^15.10.0 dependencies: - stylelint: 15.11.0(typescript@4.7.4) + stylelint: 15.11.0(typescript@5.3.2) dev: true /stylelint-config-standard@34.0.0(stylelint@15.11.0): @@ -5871,7 +5905,7 @@ packages: peerDependencies: stylelint: ^15.10.0 dependencies: - stylelint: 15.11.0(typescript@4.7.4) + stylelint: 15.11.0(typescript@5.3.2) stylelint-config-recommended: 13.0.0(stylelint@15.11.0) dev: true @@ -5881,7 +5915,7 @@ packages: peerDependencies: stylelint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 dependencies: - stylelint: 15.11.0(typescript@4.7.4) + stylelint: 15.11.0(typescript@5.3.2) dev: true /stylelint-order@6.0.3(stylelint@15.11.0): @@ -5891,7 +5925,7 @@ packages: dependencies: postcss: 8.4.31 postcss-sorting: 8.0.2(postcss@8.4.31) - stylelint: 15.11.0(typescript@4.7.4) + stylelint: 15.11.0(typescript@5.3.2) dev: true /stylelint-scss@5.3.1(stylelint@15.11.0): @@ -5904,10 +5938,10 @@ packages: postcss-resolve-nested-selector: 0.1.1 postcss-selector-parser: 6.0.13 postcss-value-parser: 4.2.0 - stylelint: 15.11.0(typescript@4.7.4) + stylelint: 15.11.0(typescript@5.3.2) dev: true - /stylelint@15.11.0(typescript@4.7.4): + /stylelint@15.11.0(typescript@5.3.2): resolution: {integrity: sha512-78O4c6IswZ9TzpcIiQJIN49K3qNoXTM8zEJzhaTE/xRTCZswaovSEVIa/uwbOltZrk16X4jAxjaOhzz/hTm1Kw==} engines: {node: ^14.13.1 || >=16.0.0} hasBin: true @@ -5918,7 +5952,7 @@ packages: '@csstools/selector-specificity': 3.0.0(postcss-selector-parser@6.0.13) balanced-match: 2.0.0 colord: 2.9.3 - cosmiconfig: 8.3.6(typescript@4.7.4) + cosmiconfig: 8.3.6(typescript@5.3.2) css-functions-list: 3.2.1 css-tree: 2.3.1 debug: 4.3.4 @@ -6070,13 +6104,13 @@ packages: engines: {node: '>=12'} dev: true - /ts-api-utils@1.0.3(typescript@4.7.4): + /ts-api-utils@1.0.3(typescript@5.3.2): resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 4.7.4 + typescript: 5.3.2 dev: true /tsconfig-paths@3.14.2: @@ -6177,9 +6211,9 @@ packages: is-typed-array: 1.1.12 dev: true - /typescript@4.7.4: - resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==} - engines: {node: '>=4.2.0'} + /typescript@5.3.2: + resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==} + engines: {node: '>=14.17'} hasBin: true dev: true @@ -6246,13 +6280,13 @@ packages: monaco-editor: 0.34.1 dev: true - /vite-plugin-svgr@4.1.0(typescript@4.7.4)(vite@4.5.0): + /vite-plugin-svgr@4.1.0(typescript@5.3.2)(vite@4.5.0): resolution: {integrity: sha512-v7Qic+FWmCChgQNGSI4V8X63OEYsdUoLt66iqIcHozq9bfK/Dwmr0V+LBy1NE8CE98Y8HouEBJ+pto4AMfN5xw==} peerDependencies: vite: ^2.6.0 || 3 || 4 dependencies: '@rollup/pluginutils': 5.0.5 - '@svgr/core': 8.1.0(typescript@4.7.4) + '@svgr/core': 8.1.0(typescript@5.3.2) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0) vite: 4.5.0(@types/node@18.19.0)(sass@1.54.8) transitivePeerDependencies: diff --git a/src/assets/styles/anime.scss b/src/assets/styles/anime.scss deleted file mode 100644 index 5e75e5d98c..0000000000 --- a/src/assets/styles/anime.scss +++ /dev/null @@ -1,25 +0,0 @@ -.page-enter { - opacity: 0; - transform: scale(0.9); -} - -.page-enter-active { - opacity: 1; - transition: - opacity 300ms, - transform 300ms; - transform: scale(1); -} - -.page-exit { - opacity: 1; - transform: scale(0); -} - -.page-exit-active { - opacity: 0; - transition: - opacity 300ms, - transform 300ms; - transform: scale(0.9); -} diff --git a/src/assets/styles/page.scss b/src/assets/styles/page.scss index a24f35cc94..b754dfad99 100644 --- a/src/assets/styles/page.scss +++ b/src/assets/styles/page.scss @@ -36,7 +36,7 @@ width: 90%; // max-width: 850px; margin: 0 auto; - animation: base-content-in 0.3s normal 1 forwards; + // animation: var(--base-content-animation, opacity-content-in) var(base-content-in, 300ms) normal 1 forwards; @keyframes base-content-in { 0% { diff --git a/src/components/layout/page-transition.tsx b/src/components/layout/page-transition.tsx new file mode 100644 index 0000000000..3a15c4f759 --- /dev/null +++ b/src/components/layout/page-transition.tsx @@ -0,0 +1,44 @@ +import { classNames } from "@/utils"; +import { motion, type HTMLMotionProps } from "framer-motion"; + +type Props = { + children?: React.ReactNode; +}; + +interface PageTransitionVariant { + initial: HTMLMotionProps<"div">["initial"]; + animate: HTMLMotionProps<"div">["animate"]; + exit: HTMLMotionProps<"div">["exit"]; + transition?: HTMLMotionProps<"div">["transition"]; +} + +const variants = { + blur: { + initial: { opacity: 0, filter: "blur(10px)" }, + animate: { opacity: 1, filter: "blur(0px)" }, + exit: { opacity: 0, filter: "blur(10px)" }, + }, + slide: { + initial: { translateY: "50%", opacity: 0, scale: 0.9 }, + animate: { translateY: "0%", opacity: 1, scale: 1 }, + exit: { translateY: "-50%", opacity: 0, scale: 0.9 }, + }, +} satisfies Record; + +export default function PageTransition({ children }: Props) { + return ( + + {children} + + ); +} diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index b02b97bef5..e83033eef8 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -1,34 +1,33 @@ -import dayjs from "dayjs"; -import i18next from "i18next"; -import relativeTime from "dayjs/plugin/relativeTime"; -import { SWRConfig, mutate } from "swr"; -import { useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { Route, Routes, useLocation } from "react-router-dom"; -import { CSSTransition, TransitionGroup } from "react-transition-group"; -import { alpha, List, Paper, ThemeProvider } from "@mui/material"; -import { listen } from "@tauri-apps/api/event"; -import { appWindow } from "@tauri-apps/api/window"; -import { routers } from "./_routers"; -import { getAxios } from "@/services/api"; -import { useVerge } from "@/hooks/use-verge"; import LogoSvg from "@/assets/image/logo.svg?react"; -import { BaseErrorBoundary } from "@/components/base"; -import { LayoutItem } from "@/components/layout/layout-item"; import { LayoutControl } from "@/components/layout/layout-control"; +import { LayoutItem } from "@/components/layout/layout-item"; import { LayoutTraffic } from "@/components/layout/layout-traffic"; import { UpdateButton } from "@/components/layout/update-button"; import { useCustomTheme } from "@/components/layout/use-custom-theme"; +import { useNotification } from "@/hooks/use-notification"; +import { useVerge } from "@/hooks/use-verge"; +import { getAxios } from "@/services/api"; import getSystem from "@/utils/get-system"; +import { List, Paper, ThemeProvider, alpha } from "@mui/material"; +import { listen } from "@tauri-apps/api/event"; +import { appWindow } from "@tauri-apps/api/window"; +import dayjs from "dayjs"; import "dayjs/locale/ru"; import "dayjs/locale/zh-cn"; -import { useNotification } from "@/hooks/use-notification"; +import relativeTime from "dayjs/plugin/relativeTime"; +import { AnimatePresence } from "framer-motion"; +import i18next from "i18next"; +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { useLocation, useRoutes } from "react-router-dom"; +import { SWRConfig, mutate } from "swr"; +import { routers } from "./_routers"; dayjs.extend(relativeTime); const OS = getSystem(); -const Layout = () => { +export default function Layout() { const { t } = useTranslation(); const { theme } = useCustomTheme(); @@ -37,6 +36,8 @@ const Layout = () => { const { theme_blur, language } = verge || {}; const location = useLocation(); + const routes = useRoutes(routers); + if (!routes) return null; useEffect(() => { window.addEventListener("keydown", (e) => { @@ -122,7 +123,7 @@ const Layout = () => { {routers.map((router) => ( - + {t(router.label)} ))} @@ -140,32 +141,12 @@ const Layout = () => { )} - - - - {routers.map(({ label, link, ele: Ele }) => ( - - - - } - /> - ))} - - - + + {React.cloneElement(routes, { key: location.pathname })} + ); -}; - -export default Layout; +} diff --git a/src/pages/_routers.tsx b/src/pages/_routers.tsx index f53ed487a4..1f75906c54 100644 --- a/src/pages/_routers.tsx +++ b/src/pages/_routers.tsx @@ -1,39 +1,51 @@ +import { BaseErrorBoundary } from "@/components/base"; +import PageTransition from "@/components/layout/page-transition"; +import type { RouteObject } from "react-router-dom"; +import ConnectionsPage from "./connections"; import LogsPage from "./logs"; -import ProxiesPage from "./proxies"; import ProfilesPage from "./profiles"; -import SettingsPage from "./settings"; -import ConnectionsPage from "./connections"; +import ProxiesPage from "./proxies"; import RulesPage from "./rules"; +import SettingsPage from "./settings"; -export const routers = [ - { - label: "Label-Proxies", - link: "/", - ele: ProxiesPage, - }, - { - label: "Label-Profiles", - link: "/profile", - ele: ProfilesPage, - }, - { - label: "Label-Connections", - link: "/connections", - ele: ConnectionsPage, - }, - { - label: "Label-Rules", - link: "/rules", - ele: RulesPage, - }, - { - label: "Label-Logs", - link: "/logs", - ele: LogsPage, - }, - { - label: "Label-Settings", - link: "/settings", - ele: SettingsPage, - }, -]; +export const routers = ( + [ + { + label: "Label-Proxies", + path: "/", + element: , + }, + { + label: "Label-Profiles", + path: "/profile", + element: , + }, + { + label: "Label-Connections", + path: "/connections", + element: , + }, + { + label: "Label-Rules", + path: "/rules", + element: , + }, + { + label: "Label-Logs", + path: "/logs", + element: , + }, + { + label: "Label-Settings", + path: "/settings", + element: , + }, + ] satisfies Array +).map((router) => ({ + ...router, + element: ( + + {router.element} + + ), +})); diff --git a/src/pages/connections.tsx b/src/pages/connections.tsx index 676160700d..89b08f34ad 100644 --- a/src/pages/connections.tsx +++ b/src/pages/connections.tsx @@ -1,5 +1,22 @@ -import { useEffect, useMemo, useRef, useState } from "react"; -import { useLockFn } from "ahooks"; +import { BaseEmpty, BasePage } from "@/components/base"; +import { + ConnectionDetail, + ConnectionDetailRef, +} from "@/components/connection/connection-detail"; +import { ConnectionItem } from "@/components/connection/connection-item"; +import { ConnectionTable } from "@/components/connection/connection-table"; +import { useClashInfo } from "@/hooks/use-clash"; +import { useWebsocket } from "@/hooks/use-websocket"; +import { closeAllConnections } from "@/services/api"; +import { atomConnectionSetting } from "@/services/states"; +import parseTraffic from "@/utils/parse-traffic"; +import { + ArrowDownward, + ArrowUpward, + Link, + TableChartRounded, + TableRowsRounded, +} from "@mui/icons-material"; import { Box, Button, @@ -11,34 +28,17 @@ import { TextField, Typography, } from "@mui/material"; -import { useRecoilState } from "recoil"; -import { Virtuoso } from "react-virtuoso"; +import { useLockFn } from "ahooks"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; -import { - ArrowDownward, - ArrowUpward, - Link, - TableChartRounded, - TableRowsRounded, -} from "@mui/icons-material"; -import { closeAllConnections } from "@/services/api"; -import { atomConnectionSetting } from "@/services/states"; -import { useClashInfo } from "@/hooks/use-clash"; -import { BaseEmpty, BasePage } from "@/components/base"; -import { useWebsocket } from "@/hooks/use-websocket"; -import { ConnectionItem } from "@/components/connection/connection-item"; -import { ConnectionTable } from "@/components/connection/connection-table"; -import { - ConnectionDetail, - ConnectionDetailRef, -} from "@/components/connection/connection-detail"; -import parseTraffic from "@/utils/parse-traffic"; +import { Virtuoso } from "react-virtuoso"; +import { useRecoilState } from "recoil"; const initConn = { uploadTotal: 0, downloadTotal: 0, connections: [] }; type OrderFunc = (list: IConnectionsItem[]) => IConnectionsItem[]; -const ConnectionsPage = () => { +export default function ConnectionsPage() { const { t, i18n } = useTranslation(); const { clashInfo } = useClashInfo(); @@ -261,6 +261,4 @@ const ConnectionsPage = () => { ); -}; - -export default ConnectionsPage; +} diff --git a/src/pages/logs.tsx b/src/pages/logs.tsx index a26b7eb42d..61c6ff849c 100644 --- a/src/pages/logs.tsx +++ b/src/pages/logs.tsx @@ -1,5 +1,10 @@ -import { useMemo, useState } from "react"; -import { useRecoilState } from "recoil"; +import { BaseEmpty, BasePage } from "@/components/base"; +import LogItem from "@/components/log/log-item"; +import { atomEnableLog, atomLogData } from "@/services/states"; +import { + PauseCircleOutlineRounded, + PlayCircleOutlineRounded, +} from "@mui/icons-material"; import { Box, Button, @@ -9,17 +14,12 @@ import { Select, TextField, } from "@mui/material"; -import { Virtuoso } from "react-virtuoso"; +import { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; -import { - PlayCircleOutlineRounded, - PauseCircleOutlineRounded, -} from "@mui/icons-material"; -import { atomEnableLog, atomLogData } from "@/services/states"; -import { BaseEmpty, BasePage } from "@/components/base"; -import LogItem from "@/components/log/log-item"; +import { Virtuoso } from "react-virtuoso"; +import { useRecoilState } from "recoil"; -const LogPage = () => { +export default function LogPage() { const { t } = useTranslation(); const [logData, setLogData] = useRecoilState(atomLogData); const [enableLog, setEnableLog] = useRecoilState(atomEnableLog); @@ -124,6 +124,4 @@ const LogPage = () => { ); -}; - -export default LogPage; +} diff --git a/src/pages/profiles.tsx b/src/pages/profiles.tsx index 1f54dce1f8..e087f3777c 100644 --- a/src/pages/profiles.tsx +++ b/src/pages/profiles.tsx @@ -1,22 +1,37 @@ -import useSWR, { mutate } from "swr"; -import { useMemo, useRef, useState } from "react"; -import { useLockFn } from "ahooks"; -import { useSetRecoilState } from "recoil"; -import { Box, Button, Grid, IconButton, Stack, TextField } from "@mui/material"; +import { BasePage, DialogRef } from "@/components/base"; +import { ProfileItem } from "@/components/profile/profile-item"; +import { ProfileMore } from "@/components/profile/profile-more"; +import { + ProfileViewer, + ProfileViewerRef, +} from "@/components/profile/profile-viewer"; +import { ConfigViewer } from "@/components/setting/mods/config-viewer"; +import { useNotification } from "@/hooks/use-notification"; +import { useProfiles } from "@/hooks/use-profiles"; +import { closeAllConnections } from "@/services/api"; +import { + deleteProfile, + enhanceProfiles, + getProfiles, + getRuntimeLogs, + importProfile, + reorderProfile, + updateProfile, +} from "@/services/cmds"; +import { atomLoadingCache } from "@/services/states"; import { DndContext, - closestCenter, + DragEndEvent, KeyboardSensor, PointerSensor, + closestCenter, useSensor, useSensors, - DragEndEvent, } from "@dnd-kit/core"; import { SortableContext, sortableKeyboardCoordinates, } from "@dnd-kit/sortable"; -import { LoadingButton } from "@mui/lab"; import { ClearRounded, ContentCopyRounded, @@ -24,31 +39,16 @@ import { RefreshRounded, TextSnippetOutlined, } from "@mui/icons-material"; -import { useTranslation } from "react-i18next"; -import { - getProfiles, - importProfile, - enhanceProfiles, - getRuntimeLogs, - deleteProfile, - updateProfile, - reorderProfile, -} from "@/services/cmds"; -import { atomLoadingCache } from "@/services/states"; -import { closeAllConnections } from "@/services/api"; -import { BasePage, DialogRef } from "@/components/base"; -import { - ProfileViewer, - ProfileViewerRef, -} from "@/components/profile/profile-viewer"; -import { ProfileItem } from "@/components/profile/profile-item"; -import { ProfileMore } from "@/components/profile/profile-more"; -import { useProfiles } from "@/hooks/use-profiles"; -import { ConfigViewer } from "@/components/setting/mods/config-viewer"; +import { LoadingButton } from "@mui/lab"; +import { Box, Button, Grid, IconButton, Stack, TextField } from "@mui/material"; +import { useLockFn } from "ahooks"; import { throttle } from "lodash-es"; -import { useNotification } from "@/hooks/use-notification"; +import { useMemo, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useSetRecoilState } from "recoil"; +import useSWR, { mutate } from "swr"; -const ProfilePage = () => { +export default function ProfilePage() { const { t } = useTranslation(); const [url, setUrl] = useState(""); @@ -379,6 +379,4 @@ const ProfilePage = () => { ); -}; - -export default ProfilePage; +} diff --git a/src/pages/proxies.tsx b/src/pages/proxies.tsx index 9d67fc77c6..b511618ddf 100644 --- a/src/pages/proxies.tsx +++ b/src/pages/proxies.tsx @@ -14,7 +14,7 @@ import { useEffect, useMemo } from "react"; import { useTranslation } from "react-i18next"; import useSWR from "swr"; -const ProxyPage = () => { +export default function ProxyPage() { const { t } = useTranslation(); const { data: clashConfig, mutate: mutateClash } = useSWR( @@ -88,6 +88,4 @@ const ProxyPage = () => { ); -}; - -export default ProxyPage; +} diff --git a/src/pages/rules.tsx b/src/pages/rules.tsx index 86cbdfa9d6..f81578b3d2 100644 --- a/src/pages/rules.tsx +++ b/src/pages/rules.tsx @@ -1,13 +1,13 @@ -import useSWR from "swr"; -import { useState, useMemo } from "react"; -import { useTranslation } from "react-i18next"; -import { Virtuoso } from "react-virtuoso"; -import { Box, Paper, TextField } from "@mui/material"; -import { getRules } from "@/services/api"; import { BaseEmpty, BasePage } from "@/components/base"; import RuleItem from "@/components/rule/rule-item"; +import { getRules } from "@/services/api"; +import { Box, Paper, TextField } from "@mui/material"; +import { useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Virtuoso } from "react-virtuoso"; +import useSWR from "swr"; -const RulesPage = () => { +export default function RulesPage() { const { t } = useTranslation(); const { data = [] } = useSWR("getRules", getRules); @@ -60,6 +60,4 @@ const RulesPage = () => { ); -}; - -export default RulesPage; +} diff --git a/src/pages/settings.tsx b/src/pages/settings.tsx index 0e488c370c..6aaa3a90f5 100644 --- a/src/pages/settings.tsx +++ b/src/pages/settings.tsx @@ -1,15 +1,15 @@ -import { Grid, IconButton, Paper } from "@mui/material"; -import { useLockFn } from "ahooks"; -import { useTranslation } from "react-i18next"; import { BasePage } from "@/components/base"; -import { GitHub } from "@mui/icons-material"; -import { openWebUrl } from "@/services/cmds"; -import SettingVerge from "@/components/setting/setting-verge"; import SettingClash from "@/components/setting/setting-clash"; import SettingSystem from "@/components/setting/setting-system"; +import SettingVerge from "@/components/setting/setting-verge"; import { useNotification } from "@/hooks/use-notification"; +import { openWebUrl } from "@/services/cmds"; +import { GitHub } from "@mui/icons-material"; +import { Grid, IconButton, Paper } from "@mui/material"; +import { useLockFn } from "ahooks"; +import { useTranslation } from "react-i18next"; -const SettingPage = () => { +export default function SettingPage() { const { t } = useTranslation(); const onError = (err: any) => { @@ -55,6 +55,4 @@ const SettingPage = () => { ); -}; - -export default SettingPage; +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000000..2bd973471b --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,9 @@ +/** + * classNames filter out falsy values and join the rest with a space + * @param classes - array of classes + * @returns string of classes + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function classNames(...classes: any[]) { + return classes.filter(Boolean).join(" "); +} From af006fa0f95cd19529124bc191434f3d0fef0bcf Mon Sep 17 00:00:00 2001 From: Jonson Petard <41122242+greenhat616@users.noreply.github.com> Date: Sun, 3 Dec 2023 00:41:29 +0800 Subject: [PATCH 2/6] fix: missing scss import --- src/assets/styles/index.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/src/assets/styles/index.scss b/src/assets/styles/index.scss index 4bf7ea016f..7a99ca38d0 100644 --- a/src/assets/styles/index.scss +++ b/src/assets/styles/index.scss @@ -1,6 +1,5 @@ @import "./layout.scss"; @import "./page.scss"; -@import "./anime.scss"; body { margin: 0; From 41fbbb7726428c9fb3b370e749cb5e59fe196502 Mon Sep 17 00:00:00 2001 From: Jonson Petard <41122242+greenhat616@users.noreply.github.com> Date: Sun, 3 Dec 2023 01:33:56 +0800 Subject: [PATCH 3/6] feat: add page transition mode switch --- backend/tauri/src/config/verge.rs | 7 +++++ src/components/layout/page-transition.tsx | 8 ++++-- src/components/setting/mods/layout-viewer.tsx | 27 ++++++++++++++++++- src/locales/en.json | 4 +++ src/locales/ru.json | 3 +++ src/locales/zh.json | 3 +++ src/pages/_theme.tsx | 1 + src/services/types.d.ts | 2 ++ 8 files changed, 52 insertions(+), 3 deletions(-) diff --git a/backend/tauri/src/config/verge.rs b/backend/tauri/src/config/verge.rs index 68919754a7..3ed27aca96 100644 --- a/backend/tauri/src/config/verge.rs +++ b/backend/tauri/src/config/verge.rs @@ -29,6 +29,9 @@ pub struct IVerge { /// show memory info (only for Clash Meta) pub enable_memory_usage: Option, + /// page transition animation, default is `slide` + pub page_transition_animation: Option, + /// clash tun mode pub enable_tun_mode: Option, @@ -108,6 +111,8 @@ pub struct IVergeTheme { pub font_family: Option, pub css_injection: Option, + + pub page_transition_duration: Option, } impl IVerge { @@ -145,6 +150,7 @@ impl IVerge { auto_close_connection: Some(true), enable_builtin_enhanced: Some(true), enable_clash_fields: Some(true), + page_transition_animation: Some("slide".into()), ..Self::default() } } @@ -171,6 +177,7 @@ impl IVerge { patch!(theme_blur); patch!(traffic_graph); patch!(enable_memory_usage); + patch!(page_transition_animation); patch!(enable_tun_mode); patch!(enable_service_mode); diff --git a/src/components/layout/page-transition.tsx b/src/components/layout/page-transition.tsx index 3a15c4f759..cdb87ce7cd 100644 --- a/src/components/layout/page-transition.tsx +++ b/src/components/layout/page-transition.tsx @@ -1,3 +1,4 @@ +import { useVerge } from "@/hooks/use-verge"; import { classNames } from "@/utils"; import { motion, type HTMLMotionProps } from "framer-motion"; @@ -12,7 +13,7 @@ interface PageTransitionVariant { transition?: HTMLMotionProps<"div">["transition"]; } -const variants = { +export const pageTransitionVariants = { blur: { initial: { opacity: 0, filter: "blur(10px)" }, animate: { opacity: 1, filter: "blur(0px)" }, @@ -26,11 +27,14 @@ const variants = { } satisfies Record; export default function PageTransition({ children }: Props) { + const { verge } = useVerge(); return ( ((props, ref) => { + {/* TODO: 将 select 单独开一个 Modal 以符合 Material Design 的设计 */} + + + ); diff --git a/src/locales/en.json b/src/locales/en.json index 7b68ee5f53..472d9906c5 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -92,6 +92,10 @@ "Hotkey Setting": "Hotkey Setting", "Traffic Graph": "Traffic Graph", "Memory Usage": "Memory Usage", + "Page Transition Animation": "Page Transition Animation", + "Page Transition Animation Slide": "Slide", + "Page Transition Animation Blur": "Blur", + "Language": "Language", "Open App Dir": "Open App Dir", "Open Core Dir": "Open Core Dir", diff --git a/src/locales/ru.json b/src/locales/ru.json index a11cdd65f2..25d6944405 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -83,6 +83,9 @@ "Theme Setting": "Настройка темы", "Hotkey Setting": "Настройка клавиатурных сокращений", "Traffic Graph": "График трафика", + "Page Transition Animation": "Анимация перехода страниц", + "Page Transition Animation Slide": "Слайд", + "Page Transition Animation Blur": "Размытие", "Language": "Язык", "Open App Dir": "Открыть папку приложения", "Open Core Dir": "Открыть папку ядра", diff --git a/src/locales/zh.json b/src/locales/zh.json index ec65690189..8cbc5b946d 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -92,6 +92,9 @@ "Hotkey Setting": "热键设置", "Traffic Graph": "流量图显", "Memory Usage": "内存使用", + "Page Transition Animation": "页面切换动画", + "Page Transition Animation Slide": "滑动", + "Page Transition Animation Blur": "模糊", "Language": "语言设置", "Open App Dir": "应用目录", "Open Core Dir": "内核目录", diff --git a/src/pages/_theme.tsx b/src/pages/_theme.tsx index f3cf07b334..d2f551e7cd 100644 --- a/src/pages/_theme.tsx +++ b/src/pages/_theme.tsx @@ -9,6 +9,7 @@ export const defaultTheme = { warning_color: "#ed6c02", success_color: "#2e7d32", font_family: `"Roboto", "Helvetica", "Arial", sans-serif`, + page_transition_duration: "0.3s", }; // dark mode diff --git a/src/services/types.d.ts b/src/services/types.d.ts index 2f2158b3a7..b8b5774506 100644 --- a/src/services/types.d.ts +++ b/src/services/types.d.ts @@ -160,6 +160,7 @@ interface IVergeConfig { theme_blur?: boolean; traffic_graph?: boolean; enable_memory_usage?: boolean; + page_transition_animation?: keyof typeof import("@/components/layout/page-transition").pageTransitionVariants; enable_tun_mode?: boolean; enable_auto_launch?: boolean; enable_service_mode?: boolean; @@ -183,6 +184,7 @@ interface IVergeConfig { success_color?: string; font_family?: string; css_injection?: string; + page_transition_duration?: number; }; auto_close_connection?: boolean; default_latency_test?: string; From 9087b9a204791a757d1922f0875c4646f0a80943 Mon Sep 17 00:00:00 2001 From: Jonson Petard <41122242+greenhat616@users.noreply.github.com> Date: Sun, 3 Dec 2023 03:03:57 +0800 Subject: [PATCH 4/6] feat(transition): add none and transparent variants --- src/components/layout/page-transition.tsx | 30 +++++++++++-------- src/components/setting/mods/layout-viewer.tsx | 6 ++++ src/locales/en.json | 2 ++ src/locales/ru.json | 2 ++ src/locales/zh.json | 2 ++ 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/components/layout/page-transition.tsx b/src/components/layout/page-transition.tsx index cdb87ce7cd..bcfd6e124b 100644 --- a/src/components/layout/page-transition.tsx +++ b/src/components/layout/page-transition.tsx @@ -8,21 +8,31 @@ type Props = { interface PageTransitionVariant { initial: HTMLMotionProps<"div">["initial"]; - animate: HTMLMotionProps<"div">["animate"]; - exit: HTMLMotionProps<"div">["exit"]; + visible: HTMLMotionProps<"div">["animate"]; + hidden: HTMLMotionProps<"div">["exit"]; transition?: HTMLMotionProps<"div">["transition"]; } export const pageTransitionVariants = { blur: { initial: { opacity: 0, filter: "blur(10px)" }, - animate: { opacity: 1, filter: "blur(0px)" }, - exit: { opacity: 0, filter: "blur(10px)" }, + visible: { opacity: 1, filter: "blur(0px)" }, + hidden: { opacity: 0, filter: "blur(10px)" }, }, slide: { initial: { translateY: "50%", opacity: 0, scale: 0.9 }, - animate: { translateY: "0%", opacity: 1, scale: 1 }, - exit: { translateY: "-50%", opacity: 0, scale: 0.9 }, + visible: { translateY: "0%", opacity: 1, scale: 1 }, + hidden: { translateY: "-50%", opacity: 0, scale: 0.9 }, + }, + transparent: { + initial: { opacity: 0 }, + visible: { opacity: 1 }, + hidden: { opacity: 0 }, + }, + none: { + initial: {}, + visible: {}, + hidden: {}, }, } satisfies Record; @@ -31,16 +41,12 @@ export default function PageTransition({ children }: Props) { return ( {children} diff --git a/src/components/setting/mods/layout-viewer.tsx b/src/components/setting/mods/layout-viewer.tsx index 512b8ac28c..2f573b5c4b 100644 --- a/src/components/setting/mods/layout-viewer.tsx +++ b/src/components/setting/mods/layout-viewer.tsx @@ -98,6 +98,12 @@ export const LayoutViewer = forwardRef((props, ref) => { {t("Page Transition Animation Blur")} + + {t("Page Transition Animation Transparent")} + + + {t("Page Transition Animation None")} + diff --git a/src/locales/en.json b/src/locales/en.json index 472d9906c5..180e5ebff3 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -95,6 +95,8 @@ "Page Transition Animation": "Page Transition Animation", "Page Transition Animation Slide": "Slide", "Page Transition Animation Blur": "Blur", + "Page Transition Animation Transparent": "Transparent", + "Page Transition Animation None": "None", "Language": "Language", "Open App Dir": "Open App Dir", diff --git a/src/locales/ru.json b/src/locales/ru.json index 25d6944405..acce5ede0c 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -86,6 +86,8 @@ "Page Transition Animation": "Анимация перехода страниц", "Page Transition Animation Slide": "Слайд", "Page Transition Animation Blur": "Размытие", + "Page Transition Animation Transparent": "Прозрачность", + "Page Transition Animation None": "Нет", "Language": "Язык", "Open App Dir": "Открыть папку приложения", "Open Core Dir": "Открыть папку ядра", diff --git a/src/locales/zh.json b/src/locales/zh.json index 8cbc5b946d..a923086d1e 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -95,6 +95,8 @@ "Page Transition Animation": "页面切换动画", "Page Transition Animation Slide": "滑动", "Page Transition Animation Blur": "模糊", + "Page Transition Animation Transparent": "透明", + "Page Transition Animation None": "无", "Language": "语言设置", "Open App Dir": "应用目录", "Open Core Dir": "内核目录", From 4bc980fbedc82fce3ba8c7a91d5f43d0f300238d Mon Sep 17 00:00:00 2001 From: Jonson Petard <41122242+greenhat616@users.noreply.github.com> Date: Sun, 3 Dec 2023 15:48:20 +0800 Subject: [PATCH 5/6] chore(transition): reduce slide animation duration --- src/components/layout/page-transition.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/layout/page-transition.tsx b/src/components/layout/page-transition.tsx index bcfd6e124b..9c4c1682cc 100644 --- a/src/components/layout/page-transition.tsx +++ b/src/components/layout/page-transition.tsx @@ -21,8 +21,18 @@ export const pageTransitionVariants = { }, slide: { initial: { translateY: "50%", opacity: 0, scale: 0.9 }, - visible: { translateY: "0%", opacity: 1, scale: 1 }, - hidden: { translateY: "-50%", opacity: 0, scale: 0.9 }, + visible: { + translateY: "0%", + opacity: 1, + scale: 1, + transition: { duration: 0.15 }, + }, + hidden: { + translateY: "-50%", + opacity: 0, + scale: 0.9, + transition: { duration: 0.15 }, + }, }, transparent: { initial: { opacity: 0 }, From 83b966051fbfe3e1b9d44db9982b3f9a3b07f49d Mon Sep 17 00:00:00 2001 From: Jonson Petard <41122242+greenhat616@users.noreply.github.com> Date: Sun, 3 Dec 2023 16:33:22 +0800 Subject: [PATCH 6/6] feat: add page transition duration options --- backend/tauri/src/config/verge.rs | 2 +- src/components/layout/page-transition.tsx | 38 ++++++++++++++++++-- src/components/setting/mods/theme-viewer.tsx | 30 +++++++++++++++- src/pages/_theme.tsx | 1 - 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/backend/tauri/src/config/verge.rs b/backend/tauri/src/config/verge.rs index 3ed27aca96..d4d7d3ce9d 100644 --- a/backend/tauri/src/config/verge.rs +++ b/backend/tauri/src/config/verge.rs @@ -112,7 +112,7 @@ pub struct IVergeTheme { pub font_family: Option, pub css_injection: Option, - pub page_transition_duration: Option, + pub page_transition_duration: Option, } impl IVerge { diff --git a/src/components/layout/page-transition.tsx b/src/components/layout/page-transition.tsx index 9c4c1682cc..dda9013f1e 100644 --- a/src/components/layout/page-transition.tsx +++ b/src/components/layout/page-transition.tsx @@ -46,14 +46,46 @@ export const pageTransitionVariants = { }, } satisfies Record; +function overrideVariantsTransition( + variants: Record, + transition?: HTMLMotionProps<"div">["transition"], +) { + if (!transition) return variants; + return Object.keys(variants).reduce( + (acc, cur) => { + acc[cur] = Object.entries(variants[cur]).reduce((acc, [key, value]) => { + if (key === "initial") { + acc[key] = value; + return acc; + } + // @ts-expect-error ts(7053) - 懒得针对工具方法做类型体操了 + acc[key] = { + ...value, + transition, + }; + return acc; + }, {} as PageTransitionVariant); + return acc; + }, + {} as Record, + ); +} + export default function PageTransition({ children }: Props) { const { verge } = useVerge(); + const { theme_setting } = verge ?? {}; + const variants = overrideVariantsTransition( + pageTransitionVariants, + theme_setting?.page_transition_duration + ? { + duration: theme_setting.page_transition_duration, + } + : undefined, + ) as typeof pageTransitionVariants; return ( ((props, ref) => { const onSave = useLockFn(async () => { try { - await patchVerge({ theme_setting: theme }); + const msgs = (Object.keys(theme) as Array).reduce( + (acc, cur) => { + if (theme[cur] === "") { + return acc; + } + // theme.page_transition_duration should be string here + if (cur === "page_transition_duration") { + acc[cur] = parseFloat( + theme.page_transition_duration as unknown as string, + ); + } else { + acc[cur] = theme[cur]; + } + return acc; + }, + {} as Exclude, + ); + await patchVerge({ theme_setting: msgs }); setOpen(false); } catch (err: any) { useNotification(t("Error"), err.message || err.toString()); @@ -119,6 +136,17 @@ export const ThemeViewer = forwardRef((props, ref) => { onKeyDown={(e) => e.key === "Enter" && onSave()} /> + + {/* 单位为秒,内容为浮点数 */} + + e.key === "Enter" && onSave()} + /> + ); diff --git a/src/pages/_theme.tsx b/src/pages/_theme.tsx index d2f551e7cd..f3cf07b334 100644 --- a/src/pages/_theme.tsx +++ b/src/pages/_theme.tsx @@ -9,7 +9,6 @@ export const defaultTheme = { warning_color: "#ed6c02", success_color: "#2e7d32", font_family: `"Roboto", "Helvetica", "Arial", sans-serif`, - page_transition_duration: "0.3s", }; // dark mode