mirror of
https://github.com/ourongxing/newsnow.git
synced 2025-01-19 03:09:14 +08:00
feat: use command bar to search and focus source
This commit is contained in:
parent
ae8cb37f7a
commit
c3a825de74
@ -15,7 +15,7 @@
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"lint": "eslint",
|
||||
"favicon": "tsx ./scripts/favicon.ts",
|
||||
"source": "tsx ./scripts/favicon.ts && tsx ./scripts/pinyin.ts",
|
||||
"start": "node --env-file .env.server dist/output/server/index.mjs",
|
||||
"preview": "CF_PAGES=1 pnpm run build && wrangler pages dev",
|
||||
"deploy": "CF_PAGES=1 pnpm run build && wrangler pages deploy",
|
||||
@ -36,6 +36,7 @@
|
||||
"better-sqlite3": "^11.3.0",
|
||||
"cheerio": "^1.0.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"consola": "^3.2.3",
|
||||
"cookie-es": "^1.2.2",
|
||||
"dayjs": "1.11.13",
|
||||
@ -60,6 +61,7 @@
|
||||
"devDependencies": {
|
||||
"@eslint-react/eslint-plugin": "^1.14.3",
|
||||
"@iconify-json/ph": "^1.2.1",
|
||||
"@napi-rs/pinyin": "^1.7.5",
|
||||
"@ourongxing/eslint-config": "3.2.3-beta.6",
|
||||
"@ourongxing/tsconfig": "^0.0.4",
|
||||
"@rollup/pluginutils": "^5.1.3",
|
||||
|
598
pnpm-lock.yaml
generated
598
pnpm-lock.yaml
generated
@ -47,6 +47,9 @@ importers:
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
cmdk:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
consola:
|
||||
specifier: ^3.2.3
|
||||
version: 3.2.3
|
||||
@ -114,6 +117,9 @@ importers:
|
||||
'@iconify-json/ph':
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
'@napi-rs/pinyin':
|
||||
specifier: ^1.7.5
|
||||
version: 1.7.5
|
||||
'@ourongxing/eslint-config':
|
||||
specifier: 3.2.3-beta.6
|
||||
version: 3.2.3-beta.6(@eslint-react/eslint-plugin@1.15.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(@typescript-eslint/utils@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(@vue/compiler-sfc@3.5.12)(eslint-plugin-react-hooks@5.1.0-rc-fb9a90fa48-20240614(eslint@9.13.0(jiti@2.3.3)))(eslint-plugin-react-refresh@0.4.13(eslint@9.13.0(jiti@2.3.3)))(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3)(vitest@2.1.3(@types/node@22.7.9)(terser@5.36.0))
|
||||
@ -1547,6 +1553,91 @@ packages:
|
||||
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
|
||||
hasBin: true
|
||||
|
||||
'@napi-rs/pinyin-android-arm-eabi@1.7.5':
|
||||
resolution: {integrity: sha512-dnurqJdedbU8D1Ngudf10nXvc4BbVSe4ki9U2LUZoGMDGa069t4c87BHRXvcy2By3YpOozORv9/QTMxAQFVOLg==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@napi-rs/pinyin-android-arm64@1.7.5':
|
||||
resolution: {integrity: sha512-75OFmFNpw3L1rDhs8rprG44inVSHouY0jaxL5a4WRHDErqE5PebDbpKUD3ATFUSENJV2iUFT4I9liP9PHOJHwQ==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@napi-rs/pinyin-darwin-arm64@1.7.5':
|
||||
resolution: {integrity: sha512-DNtRvfiW7XLtTIv1iFYPAfmhFLoPqYFKs/LpElIuI7JKHpJIBfKs6/+9ln3WINji9cWz7lvW/XvT+DEpLVdSMA==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@napi-rs/pinyin-darwin-x64@1.7.5':
|
||||
resolution: {integrity: sha512-h0WwbhdooPwaSIeYkMW7RDnr7tvECgQRR78nsDPxX6lQa6iqQvwWTlGpXBZC1AO6L2O+nJRriphwL95mUBYZ8w==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@napi-rs/pinyin-freebsd-x64@1.7.5':
|
||||
resolution: {integrity: sha512-9ImT5sYKkqiFAIJkmZBLzQsc/2X0/ne7Jf6ZmrD7xFh3YIbSvFhEPc23qKqW6HDKV2FgA3FDfZeT9ZhCAL3l+w==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@napi-rs/pinyin-linux-arm-gnueabihf@1.7.5':
|
||||
resolution: {integrity: sha512-OslQ3DJDXCrd8hdXXUu2HWdb2o5bqTbOzRqvh5dp8gVkXlx/L8mUwBlDy62hxJkpkFxC7NaL8lJRzEvlpEdnBg==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/pinyin-linux-arm64-gnu@1.7.5':
|
||||
resolution: {integrity: sha512-xGAB86BZFFmZ9BDRmAoZmsaxAGqBAek9+paGDze8/cIgIhK9rvNTfknyZjUQUeGXlESL5XuMsIp0VtjcOr6m5A==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/pinyin-linux-arm64-musl@1.7.5':
|
||||
resolution: {integrity: sha512-aK2VLMjde8/1AkoH+BqQ94r3w8YVdTCl5hJLI05GhhrNSz62ScrgPAsKNJmD9+8dcfexTdl/ORedAnenodnPzA==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/pinyin-linux-x64-gnu@1.7.5':
|
||||
resolution: {integrity: sha512-duTEnMo2m9H8AyQY32bM0OrLvZ14na6AH1DAD7/e3HX/TGow9p3LF1v4b8IlGeLZFZRyTdkWX6olHkolQ9fQkA==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/pinyin-linux-x64-musl@1.7.5':
|
||||
resolution: {integrity: sha512-aZhzqTZh3VFwy5rs0LFEtpyqKwWZMWxrRYJk5awbwJg+nu4rSrFtv/9QbmfFhY5vJT2rc4ICabyxmSHngiNKog==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/pinyin-win32-arm64-msvc@1.7.5':
|
||||
resolution: {integrity: sha512-qMlqDnRXM/dzt3KQKntZ53ea3E0vVXMWOp8EmyQaXhppkaPUBurCKsEYVNu4tO3R9LWFv6crT02bs7uTu1eUHw==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@napi-rs/pinyin-win32-ia32-msvc@1.7.5':
|
||||
resolution: {integrity: sha512-lmpmY6FM4SymqsDM+1v0469Wpjc1CGvUUedMDzoqHAmdKHaxl4Db95km/DrvvFb9SPWFx6Gma1I8BbztJRlzeA==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@napi-rs/pinyin-win32-x64-msvc@1.7.5':
|
||||
resolution: {integrity: sha512-0GrSIMZ4kVJzj3/hG76t4mPPLQbiQbQZk8AEBbFNakNnyoms6aCfbmxAG1qoqs1o+M+TAEJlW6mmI6VmSPqTfg==}
|
||||
engines: {node: '>= 10.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@napi-rs/pinyin@1.7.5':
|
||||
resolution: {integrity: sha512-RaONcl+ue1xt31ScGajc1SJ45TQcyEuNugAZ9ZDsJ+EgjnvVpw0qpD7VvK8+E8Nvc1VW3BfdTF0Ej+zIBtwHSw==}
|
||||
engines: {node: '>= 10.0'}
|
||||
|
||||
'@napi-rs/triples@1.2.0':
|
||||
resolution: {integrity: sha512-HAPjR3bnCsdXBsATpDIP5WCrw0JcACwhhrwIAQhiR46n+jm+a2F8kBsfseAuWtSyQ+H3Yebt2k43B5dy+04yMA==}
|
||||
|
||||
'@netlify/functions@2.8.2':
|
||||
resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@ -1713,6 +1804,168 @@ packages:
|
||||
'@polka/url@1.0.0-next.28':
|
||||
resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==}
|
||||
|
||||
'@radix-ui/primitive@1.0.1':
|
||||
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
|
||||
|
||||
'@radix-ui/react-compose-refs@1.0.1':
|
||||
resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-context@1.0.1':
|
||||
resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-dialog@1.0.5':
|
||||
resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-dismissable-layer@1.0.5':
|
||||
resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-focus-guards@1.0.1':
|
||||
resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-focus-scope@1.0.4':
|
||||
resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-id@1.0.1':
|
||||
resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-portal@1.0.4':
|
||||
resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-presence@1.0.1':
|
||||
resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-primitive@1.0.3':
|
||||
resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-slot@1.0.2':
|
||||
resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-callback-ref@1.0.1':
|
||||
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-controllable-state@1.0.1':
|
||||
resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-escape-keydown@1.0.3':
|
||||
resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-layout-effect@1.0.1':
|
||||
resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@redocly/ajv@8.11.2':
|
||||
resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==}
|
||||
|
||||
@ -2445,6 +2698,10 @@ packages:
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
|
||||
aria-hidden@1.2.4:
|
||||
resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
array-buffer-byte-length@1.0.1:
|
||||
resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -2698,6 +2955,12 @@ packages:
|
||||
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
cmdk@1.0.0:
|
||||
resolution: {integrity: sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==}
|
||||
peerDependencies:
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
|
||||
color-convert@1.9.3:
|
||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||
|
||||
@ -2958,6 +3221,9 @@ packages:
|
||||
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
detect-node-es@1.1.0:
|
||||
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
|
||||
|
||||
doctrine@3.0.0:
|
||||
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
@ -3570,6 +3836,10 @@ packages:
|
||||
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-nonce@1.0.1:
|
||||
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
get-own-enumerable-property-symbols@3.0.2:
|
||||
resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==}
|
||||
|
||||
@ -3800,6 +4070,9 @@ packages:
|
||||
resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
invariant@2.2.4:
|
||||
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
||||
|
||||
ioredis@5.4.1:
|
||||
resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
@ -4735,6 +5008,36 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^18.3.1
|
||||
|
||||
react-remove-scroll-bar@2.3.6:
|
||||
resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react-remove-scroll@2.5.5:
|
||||
resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react-style-singleton@2.2.1:
|
||||
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react-universal-interface@0.6.2:
|
||||
resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==}
|
||||
peerDependencies:
|
||||
@ -5622,6 +5925,26 @@ packages:
|
||||
urlpattern-polyfill@8.0.2:
|
||||
resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==}
|
||||
|
||||
use-callback-ref@1.3.2:
|
||||
resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
use-sidecar@1.1.2:
|
||||
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
use-sync-external-store@1.2.2:
|
||||
resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
|
||||
peerDependencies:
|
||||
@ -7244,6 +7567,65 @@ snapshots:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
'@napi-rs/pinyin-android-arm-eabi@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-android-arm64@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-darwin-arm64@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-darwin-x64@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-freebsd-x64@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-linux-arm-gnueabihf@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-linux-arm64-gnu@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-linux-arm64-musl@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-linux-x64-gnu@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-linux-x64-musl@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-win32-arm64-msvc@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-win32-ia32-msvc@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin-win32-x64-msvc@1.7.5':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/pinyin@1.7.5':
|
||||
dependencies:
|
||||
'@napi-rs/triples': 1.2.0
|
||||
optionalDependencies:
|
||||
'@napi-rs/pinyin-android-arm-eabi': 1.7.5
|
||||
'@napi-rs/pinyin-android-arm64': 1.7.5
|
||||
'@napi-rs/pinyin-darwin-arm64': 1.7.5
|
||||
'@napi-rs/pinyin-darwin-x64': 1.7.5
|
||||
'@napi-rs/pinyin-freebsd-x64': 1.7.5
|
||||
'@napi-rs/pinyin-linux-arm-gnueabihf': 1.7.5
|
||||
'@napi-rs/pinyin-linux-arm64-gnu': 1.7.5
|
||||
'@napi-rs/pinyin-linux-arm64-musl': 1.7.5
|
||||
'@napi-rs/pinyin-linux-x64-gnu': 1.7.5
|
||||
'@napi-rs/pinyin-linux-x64-musl': 1.7.5
|
||||
'@napi-rs/pinyin-win32-arm64-msvc': 1.7.5
|
||||
'@napi-rs/pinyin-win32-ia32-msvc': 1.7.5
|
||||
'@napi-rs/pinyin-win32-x64-msvc': 1.7.5
|
||||
|
||||
'@napi-rs/triples@1.2.0': {}
|
||||
|
||||
'@netlify/functions@2.8.2':
|
||||
dependencies:
|
||||
'@netlify/serverless-functions-api': 1.26.1
|
||||
@ -7387,6 +7769,157 @@ snapshots:
|
||||
|
||||
'@polka/url@1.0.0-next.28': {}
|
||||
|
||||
'@radix-ui/primitive@1.0.1':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
|
||||
'@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.12)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
'@radix-ui/react-context@1.0.1(@types/react@18.3.12)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
'@radix-ui/react-dialog@1.0.5(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
'@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-id': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
'@radix-ui/react-portal': 1.0.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-presence': 1.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-slot': 1.0.2(@types/react@18.3.12)(react@18.3.1)
|
||||
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
aria-hidden: 1.2.4
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
react-remove-scroll: 2.5.5(@types/react@18.3.12)(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
'@types/react-dom': 18.3.1
|
||||
|
||||
'@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
'@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.3.12)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
'@types/react-dom': 18.3.1
|
||||
|
||||
'@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.12)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
'@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
'@types/react-dom': 18.3.1
|
||||
|
||||
'@radix-ui/react-id@1.0.1(@types/react@18.3.12)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
'@radix-ui/react-portal@1.0.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
'@types/react-dom': 18.3.1
|
||||
|
||||
'@radix-ui/react-presence@1.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
'@types/react-dom': 18.3.1
|
||||
|
||||
'@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/react-slot': 1.0.2(@types/react@18.3.12)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
'@types/react-dom': 18.3.1
|
||||
|
||||
'@radix-ui/react-slot@1.0.2(@types/react@18.3.12)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
'@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.12)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
'@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.3.12)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
'@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.12)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.12)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
'@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.12)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.9
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
'@redocly/ajv@8.11.2':
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
@ -8267,6 +8800,10 @@ snapshots:
|
||||
|
||||
argparse@2.0.1: {}
|
||||
|
||||
aria-hidden@1.2.4:
|
||||
dependencies:
|
||||
tslib: 2.8.0
|
||||
|
||||
array-buffer-byte-length@1.0.1:
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
@ -8587,6 +9124,16 @@ snapshots:
|
||||
|
||||
cluster-key-slot@1.1.2: {}
|
||||
|
||||
cmdk@1.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@radix-ui/react-dialog': 1.0.5(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
- '@types/react-dom'
|
||||
|
||||
color-convert@1.9.3:
|
||||
dependencies:
|
||||
color-name: 1.1.3
|
||||
@ -8784,6 +9331,8 @@ snapshots:
|
||||
|
||||
detect-libc@2.0.3: {}
|
||||
|
||||
detect-node-es@1.1.0: {}
|
||||
|
||||
doctrine@3.0.0:
|
||||
dependencies:
|
||||
esutils: 2.0.3
|
||||
@ -9663,6 +10212,8 @@ snapshots:
|
||||
has-symbols: 1.0.3
|
||||
hasown: 2.0.2
|
||||
|
||||
get-nonce@1.0.1: {}
|
||||
|
||||
get-own-enumerable-property-symbols@3.0.2: {}
|
||||
|
||||
get-port-please@3.1.2: {}
|
||||
@ -9924,6 +10475,10 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
side-channel: 1.0.6
|
||||
|
||||
invariant@2.2.4:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
ioredis@5.4.1:
|
||||
dependencies:
|
||||
'@ioredis/commands': 1.2.0
|
||||
@ -10914,6 +11469,34 @@ snapshots:
|
||||
react: 18.3.1
|
||||
scheduler: 0.23.2
|
||||
|
||||
react-remove-scroll-bar@2.3.6(@types/react@18.3.12)(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
react-style-singleton: 2.2.1(@types/react@18.3.12)(react@18.3.1)
|
||||
tslib: 2.8.0
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
react-remove-scroll@2.5.5(@types/react@18.3.12)(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
react-remove-scroll-bar: 2.3.6(@types/react@18.3.12)(react@18.3.1)
|
||||
react-style-singleton: 2.2.1(@types/react@18.3.12)(react@18.3.1)
|
||||
tslib: 2.8.0
|
||||
use-callback-ref: 1.3.2(@types/react@18.3.12)(react@18.3.1)
|
||||
use-sidecar: 1.1.2(@types/react@18.3.12)(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
react-style-singleton@2.2.1(@types/react@18.3.12)(react@18.3.1):
|
||||
dependencies:
|
||||
get-nonce: 1.0.1
|
||||
invariant: 2.2.4
|
||||
react: 18.3.1
|
||||
tslib: 2.8.0
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
react-universal-interface@0.6.2(react@18.3.1)(tslib@2.8.0):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
@ -11883,6 +12466,21 @@ snapshots:
|
||||
|
||||
urlpattern-polyfill@8.0.2: {}
|
||||
|
||||
use-callback-ref@1.3.2(@types/react@18.3.12)(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
tslib: 2.8.0
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
use-sidecar@1.1.2(@types/react@18.3.12)(react@18.3.1):
|
||||
dependencies:
|
||||
detect-node-es: 1.1.0
|
||||
react: 18.3.1
|
||||
tslib: 2.8.0
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
use-sync-external-store@1.2.2(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
13
scripts/pinyin.ts
Normal file
13
scripts/pinyin.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { pinyin } from "@napi-rs/pinyin"
|
||||
import { projectDir } from "../shared/dir"
|
||||
import { sources } from "../shared/sources"
|
||||
|
||||
const pinyinMap = Object.fromEntries(Object.entries(sources)
|
||||
.filter(([, v]) => !v.redirect)
|
||||
.map(([k, v]) => {
|
||||
return [k, pinyin(v.title ? `${v.name}-${v.title}` : v.name).join("")]
|
||||
}))
|
||||
|
||||
writeFileSync(join(projectDir, "./shared/pinyin.json"), JSON.stringify(pinyinMap, undefined, 2))
|
@ -30,6 +30,7 @@ export default defineEventHandler(async (event): Promise<SourceResponse> => {
|
||||
if (now - cache.updated < interval) {
|
||||
return {
|
||||
status: "success",
|
||||
id,
|
||||
updatedTime: now,
|
||||
items: cache.data,
|
||||
}
|
||||
@ -46,6 +47,7 @@ export default defineEventHandler(async (event): Promise<SourceResponse> => {
|
||||
if (!latest || (!event.context.disabledLogin && !event.context.user)) {
|
||||
return {
|
||||
status: "cache",
|
||||
id,
|
||||
updatedTime: cache.updated,
|
||||
items: cache.data,
|
||||
}
|
||||
@ -62,6 +64,7 @@ export default defineEventHandler(async (event): Promise<SourceResponse> => {
|
||||
}
|
||||
return {
|
||||
status: "success",
|
||||
id,
|
||||
updatedTime: now,
|
||||
items: data,
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { sources } from "./sources"
|
||||
import { typeSafeObjectEntries, typeSafeObjectFromEntries } from "./type.util"
|
||||
import type { ColumnID, Metadata, SourceID } from "./types"
|
||||
import type { ColumnID, HiddenColumnID, Metadata, SourceID } from "./types"
|
||||
|
||||
export const columnIds = ["focus", "realtime", "hottest", "china", "world", "tech", "finance"] as const
|
||||
|
||||
const columnName: Record<ColumnID, { zh: string }> = {
|
||||
export const columns = {
|
||||
china: {
|
||||
zh: "国内",
|
||||
},
|
||||
@ -26,9 +24,12 @@ const columnName: Record<ColumnID, { zh: string }> = {
|
||||
hottest: {
|
||||
zh: "最热",
|
||||
},
|
||||
}
|
||||
} as const
|
||||
|
||||
export const metadata: Metadata = typeSafeObjectFromEntries(typeSafeObjectEntries(columnName).map(([k, v]) => {
|
||||
export const fixedColumnIds = ["focus", "hottest", "realtime"] as const satisfies Partial<ColumnID>[]
|
||||
export const hiddenColumns = Object.keys(sources).filter(id => !fixedColumnIds.includes(id as any)) as HiddenColumnID[]
|
||||
|
||||
export const metadata: Metadata = typeSafeObjectFromEntries(typeSafeObjectEntries(columns).map(([k, v]) => {
|
||||
switch (k) {
|
||||
case "focus":
|
||||
return [k, {
|
||||
|
30
shared/pinyin.json
Normal file
30
shared/pinyin.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"v2ex-share": "V2EX-zuixinfenxiang",
|
||||
"zhihu": "zhihu",
|
||||
"weibo": "weibo-shishiresou",
|
||||
"zaobao": "lianhezaobao",
|
||||
"coolapk": "kuan-jinrizuire",
|
||||
"wallstreetcn-quick": "huaerjiejianwen-shishikuaixun",
|
||||
"wallstreetcn-news": "huaerjiejianwen-zuixinzixun",
|
||||
"wallstreetcn-hot": "huaerjiejianwen-zuirewenzhang",
|
||||
"douyin": "douyin",
|
||||
"tieba": "baidutieba-reyi",
|
||||
"toutiao": "jinritoutiao",
|
||||
"ithome": "ITzhijia",
|
||||
"thepaper": "pengpaixinwen-rebang",
|
||||
"cankaoxiaoxi": "cankaoxiaoxi",
|
||||
"cls-telegraph": "cailianshe-dianbao",
|
||||
"cls-depth": "cailianshe-shendutoutiao",
|
||||
"xueqiu-hotstock": "xueqiu-remengupiao",
|
||||
"gelonghui": "gelonghui-shijian",
|
||||
"fastbull-express": "fabucaijing-kuaixun",
|
||||
"fastbull-news": "fabucaijing-toutiao",
|
||||
"solidot": "Solidot",
|
||||
"hackernews": "Hacker News",
|
||||
"producthunt": "Product Hunt",
|
||||
"github-trending-today": "Github-Today",
|
||||
"bilibili-hot-search": "bilibili-resou",
|
||||
"kaopu": "kaopuxinwen",
|
||||
"jin10": "jinshishuju",
|
||||
"baidu": "baiduresou"
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import type { colors } from "unocss/preset-mini"
|
||||
import type { columnIds } from "./metadata"
|
||||
import type { columns, fixedColumnIds } from "./metadata"
|
||||
import type { originSources } from "./sources"
|
||||
|
||||
export type Color = "primary" | Exclude<keyof typeof colors, "current" | "inherit" | "transparent" | "black" | "white">
|
||||
@ -24,16 +24,17 @@ export type AllSourceID = {
|
||||
|
||||
// export type DisabledSourceID = Exclude<SourceID, MainSourceID>
|
||||
|
||||
export type ColumnID = (typeof columnIds)[number]
|
||||
export type ColumnID = keyof typeof columns
|
||||
export type Metadata = Record<ColumnID, Column>
|
||||
|
||||
export interface PrimitiveMetadata {
|
||||
updatedTime: number
|
||||
data: Record<ColumnID, SourceID[]>
|
||||
data: Record<FixedColumnID, SourceID[]>
|
||||
action: "init" | "manual" | "sync"
|
||||
}
|
||||
|
||||
type ManualColumnID = Exclude<ColumnID, "focus" | "realtime" | "hottest">
|
||||
export type FixedColumnID = (typeof fixedColumnIds)[number]
|
||||
export type HiddenColumnID = Exclude<ColumnID, FixedColumnID>
|
||||
|
||||
export interface OriginSource extends Partial<Omit<Source, "name" | "redirect">> {
|
||||
name: string
|
||||
@ -69,7 +70,7 @@ export interface Source {
|
||||
* Default normal timeline
|
||||
*/
|
||||
type?: "hottest" | "realtime"
|
||||
column?: ManualColumnID
|
||||
column?: HiddenColumnID
|
||||
home?: string
|
||||
/**
|
||||
* @default false
|
||||
@ -103,6 +104,7 @@ export interface NewsItem {
|
||||
|
||||
export interface SourceResponse {
|
||||
status: "success" | "cache"
|
||||
id: SourceID
|
||||
updatedTime: number | string
|
||||
items: NewsItem[]
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { atom } from "jotai"
|
||||
import type { ColumnID, SourceID } from "@shared/types"
|
||||
import type { FixedColumnID, SourceID } from "@shared/types"
|
||||
import { sources } from "@shared/sources"
|
||||
import { primitiveMetadataAtom } from "./primitiveMetadataAtom"
|
||||
import type { ToastItem, Update } from "./types"
|
||||
import type { Update } from "./types"
|
||||
|
||||
export { primitiveMetadataAtom, preprocessMetadata } from "./primitiveMetadataAtom"
|
||||
|
||||
@ -35,7 +35,7 @@ function initRefetchSources() {
|
||||
|
||||
export const refetchSourcesAtom = atom(initRefetchSources())
|
||||
|
||||
export const currentColumnIDAtom = atom<ColumnID>("focus")
|
||||
export const currentColumnIDAtom = atom<FixedColumnID>("focus")
|
||||
|
||||
export const currentSourcesAtom = atom((get) => {
|
||||
const id = get(currentColumnIDAtom)
|
||||
@ -56,5 +56,3 @@ export const goToTopAtom = atom({
|
||||
ok: false,
|
||||
fn: undefined as (() => void) | undefined,
|
||||
})
|
||||
|
||||
export const toastAtom = atom<ToastItem[]>([])
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { metadata } from "@shared/metadata"
|
||||
import { fixedColumnIds, metadata } from "@shared/metadata"
|
||||
import { typeSafeObjectEntries, typeSafeObjectFromEntries } from "@shared/type.util"
|
||||
import type { PrimitiveAtom } from "jotai"
|
||||
import { atom } from "jotai"
|
||||
import type { ColumnID, PrimitiveMetadata, SourceID } from "@shared/types"
|
||||
import type { FixedColumnID, PrimitiveMetadata, SourceID } from "@shared/types"
|
||||
import { verifyPrimitiveMetadata } from "@shared/verify"
|
||||
import { sources } from "@shared/sources"
|
||||
import type { Update } from "./types"
|
||||
@ -37,7 +37,9 @@ function createPrimitiveMetadataAtom(
|
||||
return derivedAtom
|
||||
}
|
||||
|
||||
const initialMetadata = typeSafeObjectFromEntries(typeSafeObjectEntries(metadata).map(([id, val]) => [id, val.sources] as [ColumnID, SourceID[]]))
|
||||
const initialMetadata = typeSafeObjectFromEntries(typeSafeObjectEntries(metadata)
|
||||
.filter(([id]) => fixedColumnIds.includes(id as any))
|
||||
.map(([id, val]) => [id, val.sources] as [FixedColumnID, SourceID[]]))
|
||||
export function preprocessMetadata(target: PrimitiveMetadata) {
|
||||
return {
|
||||
data: {
|
||||
|
@ -9,9 +9,10 @@ import type { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities"
|
||||
import { ofetch } from "ofetch"
|
||||
import { useWindowSize } from "react-use"
|
||||
import { OverlayScrollbar } from "../common/overlay-scrollbar"
|
||||
import { focusSourcesAtom, refetchSourcesAtom } from "~/atoms"
|
||||
import { refetchSourcesAtom } from "~/atoms"
|
||||
import { useRelativeTime } from "~/hooks/useRelativeTime"
|
||||
import { safeParseString } from "~/utils"
|
||||
import { useFocusWith } from "~/hooks/useFocus"
|
||||
|
||||
export interface ItemsProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
id: SourceID
|
||||
@ -56,7 +57,6 @@ export const CardWrapper = forwardRef<HTMLDivElement, ItemsProps>(({ id, isDragg
|
||||
|
||||
const prevSourceItems: Partial<Record<SourceID, NewsItem[]>> = {}
|
||||
function NewsCard({ id, inView, handleListeners }: NewsCardProps) {
|
||||
const [focusSources, setFocusSources] = useAtom(focusSourcesAtom)
|
||||
const [refetchSource, setRefetchSource] = useAtom(refetchSourcesAtom)
|
||||
const { data, isFetching, isPlaceholderData, isError } = useQuery({
|
||||
queryKey: [id, refetchSource[id]],
|
||||
@ -92,16 +92,15 @@ function NewsCard({ id, inView, handleListeners }: NewsCardProps) {
|
||||
},
|
||||
// refetch 时显示原有的数据
|
||||
placeholderData: (prev) => {
|
||||
if (prev?.items && sources[id].type === "hottest") prevSourceItems[id] = prev.items
|
||||
return prev
|
||||
if (prev?.id === id) {
|
||||
if (prev?.items && sources[id].type === "hottest") prevSourceItems[id] = prev.items
|
||||
return prev
|
||||
}
|
||||
},
|
||||
staleTime: 1000 * 60 * 5,
|
||||
enabled: inView,
|
||||
})
|
||||
|
||||
const addFocusList = useCallback(() => {
|
||||
setFocusSources(focusSources.includes(id) ? focusSources.filter(i => i !== id) : [...focusSources, id])
|
||||
}, [setFocusSources, focusSources, id])
|
||||
const manualRefetch = useCallback(() => {
|
||||
setRefetchSource(prev => ({
|
||||
...prev,
|
||||
@ -111,12 +110,15 @@ function NewsCard({ id, inView, handleListeners }: NewsCardProps) {
|
||||
|
||||
const isFreshFetching = useMemo(() => isFetching && !isPlaceholderData, [isFetching, isPlaceholderData])
|
||||
|
||||
const { isFocused, toggleFocus } = useFocusWith(id)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={clsx("flex justify-between mx-2 mt-0 mb-2 items-center")}>
|
||||
<div className="flex gap-2 items-center">
|
||||
<a
|
||||
className={clsx("w-8 h-8 rounded-full bg-cover hover:animate-spin")}
|
||||
target="_blank"
|
||||
href={sources[id].home}
|
||||
title={sources[id].desc}
|
||||
style={{
|
||||
@ -144,14 +146,16 @@ function NewsCard({ id, inView, handleListeners }: NewsCardProps) {
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className={clsx("btn", focusSources.includes(id) ? "i-ph:star-fill" : "i-ph:star-duotone")}
|
||||
onClick={addFocusList}
|
||||
/>
|
||||
<button
|
||||
{...handleListeners}
|
||||
type="button"
|
||||
className={clsx("btn", "i-ph:dots-six-vertical-duotone", "cursor-grab")}
|
||||
className={clsx("btn", isFocused ? "i-ph:star-fill" : "i-ph:star-duotone")}
|
||||
onClick={toggleFocus}
|
||||
/>
|
||||
{handleListeners && (
|
||||
<button
|
||||
{...handleListeners}
|
||||
type="button"
|
||||
className={clsx("btn", "i-ph:dots-six-vertical-duotone", "cursor-grab")}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
77
src/components/common/search-bar/cmdk.css
Normal file
77
src/components/common/search-bar/cmdk.css
Normal file
@ -0,0 +1,77 @@
|
||||
[data-radix-focus-guard] {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
[cmdk-item] {
|
||||
--at-apply: p-1 mb-1 rounded-md;
|
||||
}
|
||||
|
||||
[cmdk-item]:hover {
|
||||
--at-apply: bg-neutral-400/10;
|
||||
}
|
||||
|
||||
[cmdk-item][data-selected=true] {
|
||||
--at-apply: bg-neutral-400/20;
|
||||
}
|
||||
|
||||
[cmdk-input]{
|
||||
--at-apply: w-full p-3 outline-none bg-transparent placeholder:color-neutral-500/60 border-color-neutral/10 border-b;
|
||||
}
|
||||
|
||||
[cmdk-list] {
|
||||
--at-apply: px-3 flex flex-col gap-2 items-stretch h-400px;
|
||||
}
|
||||
|
||||
[cmdk-group-heading] {
|
||||
--at-apply: text-sm font-bold op-70 ml-1 my-2;
|
||||
}
|
||||
|
||||
[cmdk-dialog] {
|
||||
--at-apply: bg-base sprinkle-primary bg-op-97 backdrop-blur-5 shadow pb-4 rounded-2xl shadow-2xl relative outline-none;
|
||||
position: fixed;
|
||||
width: 80vw ;
|
||||
max-width: 675px;
|
||||
z-index: 999;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
|
||||
[cmdk-dialog] {
|
||||
transition: opacity;
|
||||
transform-origin: center center;
|
||||
animation: dialogIn 0.3s forwards
|
||||
}
|
||||
|
||||
[cmdk-dialog][data-state=closed]{
|
||||
animation: dialogOut 0.2s forwards
|
||||
}
|
||||
|
||||
@keyframes dialogIn{
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes dialogOut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
[cmdk-empty] {
|
||||
--at-apply: flex justify-center items-center text-sm whitespace-pre-wrap op-70;
|
||||
}
|
||||
|
||||
[cmdk-overlay] {
|
||||
--at-apply: fixed inset-0 bg-black bg-op-50;
|
||||
}
|
142
src/components/common/search-bar/index.tsx
Normal file
142
src/components/common/search-bar/index.tsx
Normal file
@ -0,0 +1,142 @@
|
||||
import { Command } from "cmdk"
|
||||
import { useMount } from "react-use"
|
||||
import type { SourceID } from "@shared/types"
|
||||
import { useMemo, useRef, useState } from "react"
|
||||
import { sources } from "@shared/sources"
|
||||
import clsx from "clsx"
|
||||
import { typeSafeObjectEntries } from "@shared/type.util"
|
||||
import pinyin from "@shared/pinyin.json"
|
||||
import { columns } from "@shared/metadata"
|
||||
import { OverlayScrollbar } from "../overlay-scrollbar"
|
||||
import { useSearchBar } from "~/hooks/useSearch"
|
||||
import { CardWrapper } from "~/components/column/card"
|
||||
import { useFocusWith } from "~/hooks/useFocus"
|
||||
|
||||
import "./cmdk.css"
|
||||
|
||||
interface SourceItemProps {
|
||||
id: SourceID
|
||||
name: string
|
||||
title?: string
|
||||
column: any
|
||||
pinyin: string
|
||||
}
|
||||
|
||||
function groupByColumn(items: SourceItemProps[]) {
|
||||
return items.reduce((acc, item) => {
|
||||
const k = acc.find(i => i.column === item.column)
|
||||
if (k) k.sources = [...k.sources, item]
|
||||
else acc.push({ column: item.column, sources: [item] })
|
||||
return acc
|
||||
}, [] as {
|
||||
column: string
|
||||
sources: SourceItemProps[]
|
||||
}[]).sort((m, n) => {
|
||||
if (m.column === "科技") return -1
|
||||
if (n.column === "科技") return 1
|
||||
|
||||
if (m.column === "未分类") return 1
|
||||
if (n.column === "未分类") return -1
|
||||
|
||||
return m.column < n.column ? -1 : 1
|
||||
})
|
||||
}
|
||||
|
||||
export function SearchBar() {
|
||||
const { opened, toggle } = useSearchBar()
|
||||
const sourceItems = useMemo(
|
||||
() =>
|
||||
groupByColumn(typeSafeObjectEntries(sources)
|
||||
.filter(([_, source]) => !source.redirect)
|
||||
.map(([k, source]) => ({
|
||||
id: k,
|
||||
title: source.title,
|
||||
column: source.column ? columns[source.column].zh : "未分类",
|
||||
name: source.name,
|
||||
pinyin: pinyin?.[k as keyof typeof pinyin],
|
||||
})))
|
||||
, [],
|
||||
)
|
||||
const inputRef = useRef<HTMLInputElement | null>(null)
|
||||
|
||||
const [value, setValue] = useState<SourceID>("github-trending-today")
|
||||
|
||||
useMount(() => {
|
||||
inputRef?.current?.focus()
|
||||
const keydown = (e: KeyboardEvent) => {
|
||||
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
||||
e.preventDefault()
|
||||
toggle()
|
||||
}
|
||||
}
|
||||
document.addEventListener("keydown", keydown)
|
||||
return () => {
|
||||
document.removeEventListener("keydown", keydown)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<Command.Dialog
|
||||
open={opened}
|
||||
onOpenChange={toggle}
|
||||
value={value}
|
||||
onValueChange={(v) => {
|
||||
if (v in sources) {
|
||||
setValue(v as SourceID)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Command.Input
|
||||
ref={inputRef}
|
||||
autoFocus
|
||||
placeholder="搜索你想要的"
|
||||
/>
|
||||
<div className="md:flex pt-2">
|
||||
<OverlayScrollbar defer={false} className="overflow-y-auto md:min-w-275px">
|
||||
<Command.List>
|
||||
<Command.Empty> 没有找到,可以前往 Github 提 issue </Command.Empty>
|
||||
{
|
||||
sourceItems.map(({ column, sources }) => (
|
||||
<Command.Group heading={column} key={column}>
|
||||
{
|
||||
sources.map(item => <SourceItem item={item} key={item.id} />)
|
||||
}
|
||||
</Command.Group>
|
||||
),
|
||||
)
|
||||
}
|
||||
</Command.List>
|
||||
</OverlayScrollbar>
|
||||
<div className="flex-1 pt-2 px-4 min-w-350px max-md:hidden">
|
||||
<CardWrapper id={value} />
|
||||
</div>
|
||||
</div>
|
||||
</Command.Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
function SourceItem({ item }: {
|
||||
item: SourceItemProps
|
||||
}) {
|
||||
const { isFocused, toggleFocus } = useFocusWith(item.id)
|
||||
return (
|
||||
<Command.Item
|
||||
keywords={[item.name, item.title ?? "", item.pinyin]}
|
||||
value={item.id}
|
||||
className="flex justify-between items-center p-2"
|
||||
onSelect={toggleFocus}
|
||||
>
|
||||
<span className="flex gap-2 items-center">
|
||||
<span
|
||||
className={clsx("w-4 h-4 rounded-md bg-cover")}
|
||||
style={{
|
||||
backgroundImage: `url(/icons/${item.id.split("-")[0]}.png)`,
|
||||
}}
|
||||
/>
|
||||
<span>{item.name}</span>
|
||||
<span className="text-xs text-neutral-400/80 self-end mb-3px">{item.title}</span>
|
||||
</span>
|
||||
<span className={clsx(isFocused ? "i-ph-star-fill" : "i-ph-star-duotone", "bg-primary op-40")}></span>
|
||||
</Command.Item>
|
||||
)
|
||||
}
|
@ -3,8 +3,8 @@ import { AnimatePresence, motion } from "framer-motion"
|
||||
import { useAtomValue, useSetAtom } from "jotai"
|
||||
import { useCallback, useMemo, useRef } from "react"
|
||||
import { useHoverDirty, useMount, useUpdateEffect, useWindowSize } from "react-use"
|
||||
import { toastAtom } from "~/atoms"
|
||||
import type { ToastItem } from "~/atoms/types"
|
||||
import { toastAtom } from "~/hooks/useToast"
|
||||
import { Timer } from "~/utils"
|
||||
|
||||
const WIDTH = 320
|
||||
|
@ -8,7 +8,14 @@ import { Homepage, Version } from "@shared/consts"
|
||||
import { NavBar } from "../navbar"
|
||||
import { Menu } from "./menu"
|
||||
import { currentSourcesAtom, goToTopAtom, refetchSourcesAtom } from "~/atoms"
|
||||
import { useSearchBar } from "~/hooks/useSearch"
|
||||
|
||||
export function Search() {
|
||||
const { toggle } = useSearchBar()
|
||||
return (
|
||||
<button type="button" className="i-ph:magnifying-glass-duotone btn" onClick={() => toggle()} />
|
||||
)
|
||||
}
|
||||
function GoTop() {
|
||||
const { ok, fn: goToTop } = useAtomValue(goToTopAtom)
|
||||
return (
|
||||
@ -74,6 +81,7 @@ export function Header() {
|
||||
<span className="justify-self-end flex gap-2 items-center text-xl text-primary-600 dark:text-primary">
|
||||
<GoTop />
|
||||
<Refresh />
|
||||
<Search />
|
||||
<Menu />
|
||||
</span>
|
||||
</>
|
||||
|
@ -1,24 +1,35 @@
|
||||
import { columnIds, metadata } from "@shared/metadata"
|
||||
import { fixedColumnIds, metadata } from "@shared/metadata"
|
||||
import { Link } from "@tanstack/react-router"
|
||||
import clsx from "clsx"
|
||||
import { useAtomValue } from "jotai"
|
||||
import { currentColumnIDAtom } from "~/atoms"
|
||||
import { useSearchBar } from "~/hooks/useSearch"
|
||||
|
||||
export function NavBar() {
|
||||
const currentId = useAtomValue(currentColumnIDAtom)
|
||||
const { toggle } = useSearchBar()
|
||||
return (
|
||||
<span className={clsx([
|
||||
"flex p-3 rounded-2xl bg-primary/1",
|
||||
"flex p-3 rounded-2xl bg-primary/1 text-sm",
|
||||
"shadow shadow-primary/20 hover:shadow-primary/50 transition-shadow-500",
|
||||
])}
|
||||
>
|
||||
{columnIds.map(columnId => (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toggle(true)}
|
||||
className={clsx(
|
||||
"px-2 hover:(bg-primary/10 rounded-md) op-70 dark:op-90",
|
||||
)}
|
||||
>
|
||||
更多
|
||||
</button>
|
||||
{fixedColumnIds.map(columnId => (
|
||||
<Link
|
||||
key={columnId}
|
||||
to="/c/$column"
|
||||
params={{ column: columnId }}
|
||||
className={clsx(
|
||||
"text-sm px-2 hover:(bg-primary/10 rounded-md)",
|
||||
"px-2 hover:(bg-primary/10 rounded-md)",
|
||||
currentId === columnId ? "color-primary font-bold" : "op-70 dark:op-90",
|
||||
)}
|
||||
>
|
||||
|
30
src/hooks/useFocus.ts
Normal file
30
src/hooks/useFocus.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { useCallback, useMemo } from "react"
|
||||
import { useAtom } from "jotai"
|
||||
import type { SourceID } from "@shared/types"
|
||||
import { focusSourcesAtom } from "~/atoms"
|
||||
|
||||
export function useFocus() {
|
||||
const [focusSources, setFocusSources] = useAtom(focusSourcesAtom)
|
||||
const toggleFocus = useCallback((id: SourceID) => {
|
||||
setFocusSources(focusSources.includes(id) ? focusSources.filter(i => i !== id) : [...focusSources, id])
|
||||
}, [setFocusSources, focusSources])
|
||||
const isFocused = useCallback((id: SourceID) => focusSources.includes(id), [focusSources])
|
||||
|
||||
return {
|
||||
toggleFocus,
|
||||
isFocused,
|
||||
}
|
||||
}
|
||||
|
||||
export function useFocusWith(id: SourceID) {
|
||||
const [focusSources, setFocusSources] = useAtom(focusSourcesAtom)
|
||||
const toggleFocus = useCallback(() => {
|
||||
setFocusSources(focusSources.includes(id) ? focusSources.filter(i => i !== id) : [...focusSources, id])
|
||||
}, [setFocusSources, focusSources, id])
|
||||
const isFocused = useMemo(() => focusSources.includes(id), [id, focusSources])
|
||||
|
||||
return {
|
||||
toggleFocus,
|
||||
isFocused,
|
||||
}
|
||||
}
|
16
src/hooks/useSearch.ts
Normal file
16
src/hooks/useSearch.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { atom, useAtom } from "jotai"
|
||||
import { useCallback } from "react"
|
||||
|
||||
const searchBarAtom = atom(false)
|
||||
|
||||
export function useSearchBar() {
|
||||
const [opened, setOpened] = useAtom(searchBarAtom)
|
||||
const toggle = useCallback((status?: boolean) => {
|
||||
if (status !== undefined) setOpened(status)
|
||||
else setOpened(v => !v)
|
||||
}, [setOpened])
|
||||
return {
|
||||
opened,
|
||||
toggle,
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import { useSetAtom } from "jotai"
|
||||
import { atom, useSetAtom } from "jotai"
|
||||
import { useCallback } from "react"
|
||||
import { toastAtom } from "~/atoms"
|
||||
import type { ToastItem } from "~/atoms/types"
|
||||
|
||||
export const toastAtom = atom<ToastItem[]>([])
|
||||
export function useToast() {
|
||||
const setToastItems = useSetAtom(toastAtom)
|
||||
return useCallback((msg: string, props?: Omit<ToastItem, "id" | "msg">) => {
|
||||
|
@ -12,6 +12,7 @@ import { useSync } from "~/hooks/useSync"
|
||||
import { Footer } from "~/components/footer"
|
||||
import { Toast } from "~/components/common/toast"
|
||||
import { usePWA } from "~/hooks/usePWA"
|
||||
import { SearchBar } from "~/components/common/search-bar"
|
||||
|
||||
export const Route = createRootRouteWithContext<{
|
||||
queryClient: QueryClient
|
||||
@ -73,6 +74,7 @@ function RootComponent() {
|
||||
</footer>
|
||||
</GlobalOverlayScrollbar>
|
||||
<Toast />
|
||||
<SearchBar />
|
||||
{import.meta.env.DEV && (
|
||||
<>
|
||||
<ReactQueryDevtools buttonPosition="bottom-left" />
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router"
|
||||
import { columnIds } from "@shared/metadata"
|
||||
import { fixedColumnIds } from "@shared/metadata"
|
||||
import { Column } from "~/components/column"
|
||||
|
||||
export const Route = createFileRoute("/c/$column")({
|
||||
component: SectionComponent,
|
||||
params: {
|
||||
parse: (params) => {
|
||||
const column = columnIds.find(x => x === params.column.toLowerCase())
|
||||
const column = fixedColumnIds.find(x => x === params.column.toLowerCase())
|
||||
if (!column) throw new Error(`"${params.column}" is not a valid column.`)
|
||||
return {
|
||||
column,
|
||||
|
Loading…
x
Reference in New Issue
Block a user