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",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"lint": "eslint",
|
"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",
|
"start": "node --env-file .env.server dist/output/server/index.mjs",
|
||||||
"preview": "CF_PAGES=1 pnpm run build && wrangler pages dev",
|
"preview": "CF_PAGES=1 pnpm run build && wrangler pages dev",
|
||||||
"deploy": "CF_PAGES=1 pnpm run build && wrangler pages deploy",
|
"deploy": "CF_PAGES=1 pnpm run build && wrangler pages deploy",
|
||||||
@ -36,6 +36,7 @@
|
|||||||
"better-sqlite3": "^11.3.0",
|
"better-sqlite3": "^11.3.0",
|
||||||
"cheerio": "^1.0.0",
|
"cheerio": "^1.0.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"cmdk": "^1.0.0",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"cookie-es": "^1.2.2",
|
"cookie-es": "^1.2.2",
|
||||||
"dayjs": "1.11.13",
|
"dayjs": "1.11.13",
|
||||||
@ -60,6 +61,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint-react/eslint-plugin": "^1.14.3",
|
"@eslint-react/eslint-plugin": "^1.14.3",
|
||||||
"@iconify-json/ph": "^1.2.1",
|
"@iconify-json/ph": "^1.2.1",
|
||||||
|
"@napi-rs/pinyin": "^1.7.5",
|
||||||
"@ourongxing/eslint-config": "3.2.3-beta.6",
|
"@ourongxing/eslint-config": "3.2.3-beta.6",
|
||||||
"@ourongxing/tsconfig": "^0.0.4",
|
"@ourongxing/tsconfig": "^0.0.4",
|
||||||
"@rollup/pluginutils": "^5.1.3",
|
"@rollup/pluginutils": "^5.1.3",
|
||||||
|
598
pnpm-lock.yaml
generated
598
pnpm-lock.yaml
generated
@ -47,6 +47,9 @@ importers:
|
|||||||
clsx:
|
clsx:
|
||||||
specifier: ^2.1.1
|
specifier: ^2.1.1
|
||||||
version: 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:
|
consola:
|
||||||
specifier: ^3.2.3
|
specifier: ^3.2.3
|
||||||
version: 3.2.3
|
version: 3.2.3
|
||||||
@ -114,6 +117,9 @@ importers:
|
|||||||
'@iconify-json/ph':
|
'@iconify-json/ph':
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
|
'@napi-rs/pinyin':
|
||||||
|
specifier: ^1.7.5
|
||||||
|
version: 1.7.5
|
||||||
'@ourongxing/eslint-config':
|
'@ourongxing/eslint-config':
|
||||||
specifier: 3.2.3-beta.6
|
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))
|
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==}
|
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
|
||||||
hasBin: true
|
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':
|
'@netlify/functions@2.8.2':
|
||||||
resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==}
|
resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -1713,6 +1804,168 @@ packages:
|
|||||||
'@polka/url@1.0.0-next.28':
|
'@polka/url@1.0.0-next.28':
|
||||||
resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==}
|
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':
|
'@redocly/ajv@8.11.2':
|
||||||
resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==}
|
resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==}
|
||||||
|
|
||||||
@ -2445,6 +2698,10 @@ packages:
|
|||||||
argparse@2.0.1:
|
argparse@2.0.1:
|
||||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
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:
|
array-buffer-byte-length@1.0.1:
|
||||||
resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
|
resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -2698,6 +2955,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
||||||
engines: {node: '>=0.10.0'}
|
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:
|
color-convert@1.9.3:
|
||||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||||
|
|
||||||
@ -2958,6 +3221,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
|
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
detect-node-es@1.1.0:
|
||||||
|
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
|
||||||
|
|
||||||
doctrine@3.0.0:
|
doctrine@3.0.0:
|
||||||
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
@ -3570,6 +3836,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
|
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
|
||||||
engines: {node: '>= 0.4'}
|
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:
|
get-own-enumerable-property-symbols@3.0.2:
|
||||||
resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==}
|
resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==}
|
||||||
|
|
||||||
@ -3800,6 +4070,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
|
resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
invariant@2.2.4:
|
||||||
|
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
||||||
|
|
||||||
ioredis@5.4.1:
|
ioredis@5.4.1:
|
||||||
resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==}
|
resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==}
|
||||||
engines: {node: '>=12.22.0'}
|
engines: {node: '>=12.22.0'}
|
||||||
@ -4735,6 +5008,36 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^18.3.1
|
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:
|
react-universal-interface@0.6.2:
|
||||||
resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==}
|
resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -5622,6 +5925,26 @@ packages:
|
|||||||
urlpattern-polyfill@8.0.2:
|
urlpattern-polyfill@8.0.2:
|
||||||
resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==}
|
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:
|
use-sync-external-store@1.2.2:
|
||||||
resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
|
resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -7244,6 +7567,65 @@ snapshots:
|
|||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- 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':
|
'@netlify/functions@2.8.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@netlify/serverless-functions-api': 1.26.1
|
'@netlify/serverless-functions-api': 1.26.1
|
||||||
@ -7387,6 +7769,157 @@ snapshots:
|
|||||||
|
|
||||||
'@polka/url@1.0.0-next.28': {}
|
'@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':
|
'@redocly/ajv@8.11.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-deep-equal: 3.1.3
|
fast-deep-equal: 3.1.3
|
||||||
@ -8267,6 +8800,10 @@ snapshots:
|
|||||||
|
|
||||||
argparse@2.0.1: {}
|
argparse@2.0.1: {}
|
||||||
|
|
||||||
|
aria-hidden@1.2.4:
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.0
|
||||||
|
|
||||||
array-buffer-byte-length@1.0.1:
|
array-buffer-byte-length@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
@ -8587,6 +9124,16 @@ snapshots:
|
|||||||
|
|
||||||
cluster-key-slot@1.1.2: {}
|
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:
|
color-convert@1.9.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-name: 1.1.3
|
color-name: 1.1.3
|
||||||
@ -8784,6 +9331,8 @@ snapshots:
|
|||||||
|
|
||||||
detect-libc@2.0.3: {}
|
detect-libc@2.0.3: {}
|
||||||
|
|
||||||
|
detect-node-es@1.1.0: {}
|
||||||
|
|
||||||
doctrine@3.0.0:
|
doctrine@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
@ -9663,6 +10212,8 @@ snapshots:
|
|||||||
has-symbols: 1.0.3
|
has-symbols: 1.0.3
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
|
|
||||||
|
get-nonce@1.0.1: {}
|
||||||
|
|
||||||
get-own-enumerable-property-symbols@3.0.2: {}
|
get-own-enumerable-property-symbols@3.0.2: {}
|
||||||
|
|
||||||
get-port-please@3.1.2: {}
|
get-port-please@3.1.2: {}
|
||||||
@ -9924,6 +10475,10 @@ snapshots:
|
|||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
side-channel: 1.0.6
|
side-channel: 1.0.6
|
||||||
|
|
||||||
|
invariant@2.2.4:
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
|
||||||
ioredis@5.4.1:
|
ioredis@5.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ioredis/commands': 1.2.0
|
'@ioredis/commands': 1.2.0
|
||||||
@ -10914,6 +11469,34 @@ snapshots:
|
|||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
scheduler: 0.23.2
|
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):
|
react-universal-interface@0.6.2(react@18.3.1)(tslib@2.8.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
@ -11883,6 +12466,21 @@ snapshots:
|
|||||||
|
|
||||||
urlpattern-polyfill@8.0.2: {}
|
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):
|
use-sync-external-store@1.2.2(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 18.3.1
|
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) {
|
if (now - cache.updated < interval) {
|
||||||
return {
|
return {
|
||||||
status: "success",
|
status: "success",
|
||||||
|
id,
|
||||||
updatedTime: now,
|
updatedTime: now,
|
||||||
items: cache.data,
|
items: cache.data,
|
||||||
}
|
}
|
||||||
@ -46,6 +47,7 @@ export default defineEventHandler(async (event): Promise<SourceResponse> => {
|
|||||||
if (!latest || (!event.context.disabledLogin && !event.context.user)) {
|
if (!latest || (!event.context.disabledLogin && !event.context.user)) {
|
||||||
return {
|
return {
|
||||||
status: "cache",
|
status: "cache",
|
||||||
|
id,
|
||||||
updatedTime: cache.updated,
|
updatedTime: cache.updated,
|
||||||
items: cache.data,
|
items: cache.data,
|
||||||
}
|
}
|
||||||
@ -62,6 +64,7 @@ export default defineEventHandler(async (event): Promise<SourceResponse> => {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
status: "success",
|
status: "success",
|
||||||
|
id,
|
||||||
updatedTime: now,
|
updatedTime: now,
|
||||||
items: data,
|
items: data,
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { sources } from "./sources"
|
import { sources } from "./sources"
|
||||||
import { typeSafeObjectEntries, typeSafeObjectFromEntries } from "./type.util"
|
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
|
export const columns = {
|
||||||
|
|
||||||
const columnName: Record<ColumnID, { zh: string }> = {
|
|
||||||
china: {
|
china: {
|
||||||
zh: "国内",
|
zh: "国内",
|
||||||
},
|
},
|
||||||
@ -26,9 +24,12 @@ const columnName: Record<ColumnID, { zh: string }> = {
|
|||||||
hottest: {
|
hottest: {
|
||||||
zh: "最热",
|
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) {
|
switch (k) {
|
||||||
case "focus":
|
case "focus":
|
||||||
return [k, {
|
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 { colors } from "unocss/preset-mini"
|
||||||
import type { columnIds } from "./metadata"
|
import type { columns, fixedColumnIds } from "./metadata"
|
||||||
import type { originSources } from "./sources"
|
import type { originSources } from "./sources"
|
||||||
|
|
||||||
export type Color = "primary" | Exclude<keyof typeof colors, "current" | "inherit" | "transparent" | "black" | "white">
|
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 DisabledSourceID = Exclude<SourceID, MainSourceID>
|
||||||
|
|
||||||
export type ColumnID = (typeof columnIds)[number]
|
export type ColumnID = keyof typeof columns
|
||||||
export type Metadata = Record<ColumnID, Column>
|
export type Metadata = Record<ColumnID, Column>
|
||||||
|
|
||||||
export interface PrimitiveMetadata {
|
export interface PrimitiveMetadata {
|
||||||
updatedTime: number
|
updatedTime: number
|
||||||
data: Record<ColumnID, SourceID[]>
|
data: Record<FixedColumnID, SourceID[]>
|
||||||
action: "init" | "manual" | "sync"
|
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">> {
|
export interface OriginSource extends Partial<Omit<Source, "name" | "redirect">> {
|
||||||
name: string
|
name: string
|
||||||
@ -69,7 +70,7 @@ export interface Source {
|
|||||||
* Default normal timeline
|
* Default normal timeline
|
||||||
*/
|
*/
|
||||||
type?: "hottest" | "realtime"
|
type?: "hottest" | "realtime"
|
||||||
column?: ManualColumnID
|
column?: HiddenColumnID
|
||||||
home?: string
|
home?: string
|
||||||
/**
|
/**
|
||||||
* @default false
|
* @default false
|
||||||
@ -103,6 +104,7 @@ export interface NewsItem {
|
|||||||
|
|
||||||
export interface SourceResponse {
|
export interface SourceResponse {
|
||||||
status: "success" | "cache"
|
status: "success" | "cache"
|
||||||
|
id: SourceID
|
||||||
updatedTime: number | string
|
updatedTime: number | string
|
||||||
items: NewsItem[]
|
items: NewsItem[]
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { atom } from "jotai"
|
import { atom } from "jotai"
|
||||||
import type { ColumnID, SourceID } from "@shared/types"
|
import type { FixedColumnID, SourceID } from "@shared/types"
|
||||||
import { sources } from "@shared/sources"
|
import { sources } from "@shared/sources"
|
||||||
import { primitiveMetadataAtom } from "./primitiveMetadataAtom"
|
import { primitiveMetadataAtom } from "./primitiveMetadataAtom"
|
||||||
import type { ToastItem, Update } from "./types"
|
import type { Update } from "./types"
|
||||||
|
|
||||||
export { primitiveMetadataAtom, preprocessMetadata } from "./primitiveMetadataAtom"
|
export { primitiveMetadataAtom, preprocessMetadata } from "./primitiveMetadataAtom"
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ function initRefetchSources() {
|
|||||||
|
|
||||||
export const refetchSourcesAtom = atom(initRefetchSources())
|
export const refetchSourcesAtom = atom(initRefetchSources())
|
||||||
|
|
||||||
export const currentColumnIDAtom = atom<ColumnID>("focus")
|
export const currentColumnIDAtom = atom<FixedColumnID>("focus")
|
||||||
|
|
||||||
export const currentSourcesAtom = atom((get) => {
|
export const currentSourcesAtom = atom((get) => {
|
||||||
const id = get(currentColumnIDAtom)
|
const id = get(currentColumnIDAtom)
|
||||||
@ -56,5 +56,3 @@ export const goToTopAtom = atom({
|
|||||||
ok: false,
|
ok: false,
|
||||||
fn: undefined as (() => void) | undefined,
|
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 { typeSafeObjectEntries, typeSafeObjectFromEntries } from "@shared/type.util"
|
||||||
import type { PrimitiveAtom } from "jotai"
|
import type { PrimitiveAtom } from "jotai"
|
||||||
import { atom } 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 { verifyPrimitiveMetadata } from "@shared/verify"
|
||||||
import { sources } from "@shared/sources"
|
import { sources } from "@shared/sources"
|
||||||
import type { Update } from "./types"
|
import type { Update } from "./types"
|
||||||
@ -37,7 +37,9 @@ function createPrimitiveMetadataAtom(
|
|||||||
return derivedAtom
|
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) {
|
export function preprocessMetadata(target: PrimitiveMetadata) {
|
||||||
return {
|
return {
|
||||||
data: {
|
data: {
|
||||||
|
@ -9,9 +9,10 @@ import type { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities"
|
|||||||
import { ofetch } from "ofetch"
|
import { ofetch } from "ofetch"
|
||||||
import { useWindowSize } from "react-use"
|
import { useWindowSize } from "react-use"
|
||||||
import { OverlayScrollbar } from "../common/overlay-scrollbar"
|
import { OverlayScrollbar } from "../common/overlay-scrollbar"
|
||||||
import { focusSourcesAtom, refetchSourcesAtom } from "~/atoms"
|
import { refetchSourcesAtom } from "~/atoms"
|
||||||
import { useRelativeTime } from "~/hooks/useRelativeTime"
|
import { useRelativeTime } from "~/hooks/useRelativeTime"
|
||||||
import { safeParseString } from "~/utils"
|
import { safeParseString } from "~/utils"
|
||||||
|
import { useFocusWith } from "~/hooks/useFocus"
|
||||||
|
|
||||||
export interface ItemsProps extends React.HTMLAttributes<HTMLDivElement> {
|
export interface ItemsProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
id: SourceID
|
id: SourceID
|
||||||
@ -56,7 +57,6 @@ export const CardWrapper = forwardRef<HTMLDivElement, ItemsProps>(({ id, isDragg
|
|||||||
|
|
||||||
const prevSourceItems: Partial<Record<SourceID, NewsItem[]>> = {}
|
const prevSourceItems: Partial<Record<SourceID, NewsItem[]>> = {}
|
||||||
function NewsCard({ id, inView, handleListeners }: NewsCardProps) {
|
function NewsCard({ id, inView, handleListeners }: NewsCardProps) {
|
||||||
const [focusSources, setFocusSources] = useAtom(focusSourcesAtom)
|
|
||||||
const [refetchSource, setRefetchSource] = useAtom(refetchSourcesAtom)
|
const [refetchSource, setRefetchSource] = useAtom(refetchSourcesAtom)
|
||||||
const { data, isFetching, isPlaceholderData, isError } = useQuery({
|
const { data, isFetching, isPlaceholderData, isError } = useQuery({
|
||||||
queryKey: [id, refetchSource[id]],
|
queryKey: [id, refetchSource[id]],
|
||||||
@ -92,16 +92,15 @@ function NewsCard({ id, inView, handleListeners }: NewsCardProps) {
|
|||||||
},
|
},
|
||||||
// refetch 时显示原有的数据
|
// refetch 时显示原有的数据
|
||||||
placeholderData: (prev) => {
|
placeholderData: (prev) => {
|
||||||
if (prev?.items && sources[id].type === "hottest") prevSourceItems[id] = prev.items
|
if (prev?.id === id) {
|
||||||
return prev
|
if (prev?.items && sources[id].type === "hottest") prevSourceItems[id] = prev.items
|
||||||
|
return prev
|
||||||
|
}
|
||||||
},
|
},
|
||||||
staleTime: 1000 * 60 * 5,
|
staleTime: 1000 * 60 * 5,
|
||||||
enabled: inView,
|
enabled: inView,
|
||||||
})
|
})
|
||||||
|
|
||||||
const addFocusList = useCallback(() => {
|
|
||||||
setFocusSources(focusSources.includes(id) ? focusSources.filter(i => i !== id) : [...focusSources, id])
|
|
||||||
}, [setFocusSources, focusSources, id])
|
|
||||||
const manualRefetch = useCallback(() => {
|
const manualRefetch = useCallback(() => {
|
||||||
setRefetchSource(prev => ({
|
setRefetchSource(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
@ -111,12 +110,15 @@ function NewsCard({ id, inView, handleListeners }: NewsCardProps) {
|
|||||||
|
|
||||||
const isFreshFetching = useMemo(() => isFetching && !isPlaceholderData, [isFetching, isPlaceholderData])
|
const isFreshFetching = useMemo(() => isFetching && !isPlaceholderData, [isFetching, isPlaceholderData])
|
||||||
|
|
||||||
|
const { isFocused, toggleFocus } = useFocusWith(id)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={clsx("flex justify-between mx-2 mt-0 mb-2 items-center")}>
|
<div className={clsx("flex justify-between mx-2 mt-0 mb-2 items-center")}>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<a
|
<a
|
||||||
className={clsx("w-8 h-8 rounded-full bg-cover hover:animate-spin")}
|
className={clsx("w-8 h-8 rounded-full bg-cover hover:animate-spin")}
|
||||||
|
target="_blank"
|
||||||
href={sources[id].home}
|
href={sources[id].home}
|
||||||
title={sources[id].desc}
|
title={sources[id].desc}
|
||||||
style={{
|
style={{
|
||||||
@ -144,14 +146,16 @@ function NewsCard({ id, inView, handleListeners }: NewsCardProps) {
|
|||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={clsx("btn", focusSources.includes(id) ? "i-ph:star-fill" : "i-ph:star-duotone")}
|
className={clsx("btn", isFocused ? "i-ph:star-fill" : "i-ph:star-duotone")}
|
||||||
onClick={addFocusList}
|
onClick={toggleFocus}
|
||||||
/>
|
|
||||||
<button
|
|
||||||
{...handleListeners}
|
|
||||||
type="button"
|
|
||||||
className={clsx("btn", "i-ph:dots-six-vertical-duotone", "cursor-grab")}
|
|
||||||
/>
|
/>
|
||||||
|
{handleListeners && (
|
||||||
|
<button
|
||||||
|
{...handleListeners}
|
||||||
|
type="button"
|
||||||
|
className={clsx("btn", "i-ph:dots-six-vertical-duotone", "cursor-grab")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</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 { useAtomValue, useSetAtom } from "jotai"
|
||||||
import { useCallback, useMemo, useRef } from "react"
|
import { useCallback, useMemo, useRef } from "react"
|
||||||
import { useHoverDirty, useMount, useUpdateEffect, useWindowSize } from "react-use"
|
import { useHoverDirty, useMount, useUpdateEffect, useWindowSize } from "react-use"
|
||||||
import { toastAtom } from "~/atoms"
|
|
||||||
import type { ToastItem } from "~/atoms/types"
|
import type { ToastItem } from "~/atoms/types"
|
||||||
|
import { toastAtom } from "~/hooks/useToast"
|
||||||
import { Timer } from "~/utils"
|
import { Timer } from "~/utils"
|
||||||
|
|
||||||
const WIDTH = 320
|
const WIDTH = 320
|
||||||
|
@ -8,7 +8,14 @@ import { Homepage, Version } from "@shared/consts"
|
|||||||
import { NavBar } from "../navbar"
|
import { NavBar } from "../navbar"
|
||||||
import { Menu } from "./menu"
|
import { Menu } from "./menu"
|
||||||
import { currentSourcesAtom, goToTopAtom, refetchSourcesAtom } from "~/atoms"
|
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() {
|
function GoTop() {
|
||||||
const { ok, fn: goToTop } = useAtomValue(goToTopAtom)
|
const { ok, fn: goToTop } = useAtomValue(goToTopAtom)
|
||||||
return (
|
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">
|
<span className="justify-self-end flex gap-2 items-center text-xl text-primary-600 dark:text-primary">
|
||||||
<GoTop />
|
<GoTop />
|
||||||
<Refresh />
|
<Refresh />
|
||||||
|
<Search />
|
||||||
<Menu />
|
<Menu />
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
|
@ -1,24 +1,35 @@
|
|||||||
import { columnIds, metadata } from "@shared/metadata"
|
import { fixedColumnIds, metadata } from "@shared/metadata"
|
||||||
import { Link } from "@tanstack/react-router"
|
import { Link } from "@tanstack/react-router"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { useAtomValue } from "jotai"
|
import { useAtomValue } from "jotai"
|
||||||
import { currentColumnIDAtom } from "~/atoms"
|
import { currentColumnIDAtom } from "~/atoms"
|
||||||
|
import { useSearchBar } from "~/hooks/useSearch"
|
||||||
|
|
||||||
export function NavBar() {
|
export function NavBar() {
|
||||||
const currentId = useAtomValue(currentColumnIDAtom)
|
const currentId = useAtomValue(currentColumnIDAtom)
|
||||||
|
const { toggle } = useSearchBar()
|
||||||
return (
|
return (
|
||||||
<span className={clsx([
|
<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",
|
"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
|
<Link
|
||||||
key={columnId}
|
key={columnId}
|
||||||
to="/c/$column"
|
to="/c/$column"
|
||||||
params={{ column: columnId }}
|
params={{ column: columnId }}
|
||||||
className={clsx(
|
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",
|
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 { useCallback } from "react"
|
||||||
import { toastAtom } from "~/atoms"
|
|
||||||
import type { ToastItem } from "~/atoms/types"
|
import type { ToastItem } from "~/atoms/types"
|
||||||
|
|
||||||
|
export const toastAtom = atom<ToastItem[]>([])
|
||||||
export function useToast() {
|
export function useToast() {
|
||||||
const setToastItems = useSetAtom(toastAtom)
|
const setToastItems = useSetAtom(toastAtom)
|
||||||
return useCallback((msg: string, props?: Omit<ToastItem, "id" | "msg">) => {
|
return useCallback((msg: string, props?: Omit<ToastItem, "id" | "msg">) => {
|
||||||
|
@ -12,6 +12,7 @@ import { useSync } from "~/hooks/useSync"
|
|||||||
import { Footer } from "~/components/footer"
|
import { Footer } from "~/components/footer"
|
||||||
import { Toast } from "~/components/common/toast"
|
import { Toast } from "~/components/common/toast"
|
||||||
import { usePWA } from "~/hooks/usePWA"
|
import { usePWA } from "~/hooks/usePWA"
|
||||||
|
import { SearchBar } from "~/components/common/search-bar"
|
||||||
|
|
||||||
export const Route = createRootRouteWithContext<{
|
export const Route = createRootRouteWithContext<{
|
||||||
queryClient: QueryClient
|
queryClient: QueryClient
|
||||||
@ -73,6 +74,7 @@ function RootComponent() {
|
|||||||
</footer>
|
</footer>
|
||||||
</GlobalOverlayScrollbar>
|
</GlobalOverlayScrollbar>
|
||||||
<Toast />
|
<Toast />
|
||||||
|
<SearchBar />
|
||||||
{import.meta.env.DEV && (
|
{import.meta.env.DEV && (
|
||||||
<>
|
<>
|
||||||
<ReactQueryDevtools buttonPosition="bottom-left" />
|
<ReactQueryDevtools buttonPosition="bottom-left" />
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { createFileRoute, redirect } from "@tanstack/react-router"
|
import { createFileRoute, redirect } from "@tanstack/react-router"
|
||||||
import { columnIds } from "@shared/metadata"
|
import { fixedColumnIds } from "@shared/metadata"
|
||||||
import { Column } from "~/components/column"
|
import { Column } from "~/components/column"
|
||||||
|
|
||||||
export const Route = createFileRoute("/c/$column")({
|
export const Route = createFileRoute("/c/$column")({
|
||||||
component: SectionComponent,
|
component: SectionComponent,
|
||||||
params: {
|
params: {
|
||||||
parse: (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.`)
|
if (!column) throw new Error(`"${params.column}" is not a valid column.`)
|
||||||
return {
|
return {
|
||||||
column,
|
column,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user