From ca9e0833993c9243822a66b0ae184bf31a8b3677 Mon Sep 17 00:00:00 2001 From: joyzhao Date: Mon, 12 Jan 2026 09:46:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(comments):=20=E6=B7=BB=E5=8A=A0=20Waline?= =?UTF-8?q?=20=E8=AF=84=E8=AE=BA=E7=BB=84=E4=BB=B6=EF=BC=8C=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=20Giscus=20=E8=AF=84=E8=AE=BA=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- pnpm-lock.yaml | 240 +++++++++++++++++++++++++ src/components/blog/Comments.tsx | 61 +++++++ src/components/blog/GiscusComments.tsx | 52 ------ src/layouts/BlogPostLayout.astro | 4 +- src/pages/zh/blog/index.astro | 2 +- 6 files changed, 306 insertions(+), 56 deletions(-) create mode 100644 src/components/blog/Comments.tsx delete mode 100644 src/components/blog/GiscusComments.tsx diff --git a/package.json b/package.json index d3ee256..0973f1e 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "tw-animate-css": "^1.2.4" }, "devDependencies": { - "@tailwindcss/typography": "^0.5.16" + "@tailwindcss/typography": "^0.5.16", + "@waline/client": "^3.8.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c860678..2fedcaa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -75,6 +75,9 @@ importers: '@tailwindcss/typography': specifier: ^0.5.16 version: 0.5.16(tailwindcss@4.1.10) + '@waline/client': + specifier: ^3.8.0 + version: 3.8.0(typescript@5.8.3) packages: @@ -159,6 +162,10 @@ packages: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -172,6 +179,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} @@ -200,6 +212,10 @@ packages: resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + '@capsizecss/unpack@2.4.0': resolution: {integrity: sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==} @@ -510,6 +526,9 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -946,6 +965,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -955,6 +977,56 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + '@vue/compiler-core@3.5.26': + resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==} + + '@vue/compiler-dom@3.5.26': + resolution: {integrity: sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==} + + '@vue/compiler-sfc@3.5.26': + resolution: {integrity: sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==} + + '@vue/compiler-ssr@3.5.26': + resolution: {integrity: sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==} + + '@vue/reactivity@3.5.26': + resolution: {integrity: sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==} + + '@vue/runtime-core@3.5.26': + resolution: {integrity: sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==} + + '@vue/runtime-dom@3.5.26': + resolution: {integrity: sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==} + + '@vue/server-renderer@3.5.26': + resolution: {integrity: sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==} + peerDependencies: + vue: 3.5.26 + + '@vue/shared@3.5.26': + resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==} + + '@vueuse/core@14.1.0': + resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/metadata@14.1.0': + resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==} + + '@vueuse/shared@14.1.0': + resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==} + peerDependencies: + vue: ^3.5.0 + + '@waline/api@1.0.0': + resolution: {integrity: sha512-o0lWjt+/oZH1/4q3DJxTf5kdkgNbSmoLRXIiGznW225A6hq9/9IkOO1DiAijIsxGYJS6psFC+58+IzkD1EerBA==} + engines: {node: '>=18'} + + '@waline/client@3.8.0': + resolution: {integrity: sha512-UAbqLmqy2Pns/CXFlrLYEDG4F1peRPo+wp2FmpfFL9BO0ceQO6KvvAJXw3EhX3wWcMiKlX29G0gJVtG4UlCzGw==} + engines: {node: '>=18'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1015,6 +1087,9 @@ packages: engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true + autosize@6.0.1: + resolution: {integrity: sha512-f86EjiUKE6Xvczc4ioP1JBlWG7FKrE13qe/DxBCpe8GCipCq2nFw73aO8QEBKHfSbYGDN5eB9jXWKen7tspDqQ==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -1153,6 +1228,9 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + debug@4.4.1: resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} @@ -1224,6 +1302,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + entities@7.0.0: + resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==} + engines: {node: '>=0.12'} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -1713,6 +1795,9 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magicast@0.3.5: resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} @@ -1723,6 +1808,16 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked-highlight@2.2.3: + resolution: {integrity: sha512-FCfZRxW/msZAiasCML4isYpxyQWKEEx44vOgdn5Kloae+Qc3q4XR7WjpKKf8oMLk7JP9ZCRd2vhtclJFdwxlWQ==} + peerDependencies: + marked: '>=4 <18' + + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + mdast-util-definitions@6.0.0: resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} @@ -2003,6 +2098,10 @@ packages: resolution: {integrity: sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + prismjs@1.30.0: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} @@ -2037,6 +2136,9 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + recaptcha-v3@1.11.3: + resolution: {integrity: sha512-sEE6J0RzUkS+sKEBpgCD/AqCU0ffrAVOADGjvAx9vcttN+VLK42SWMkj/J/I6vHu3Kew+xcfbBqDVb65N0QGDw==} + recma-build-jsx@1.0.0: resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} @@ -2430,6 +2532,14 @@ packages: vite: optional: true + vue@3.5.26: + resolution: {integrity: sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} @@ -2661,6 +2771,8 @@ snapshots: '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.27.6': @@ -2672,6 +2784,10 @@ snapshots: dependencies: '@babel/types': 7.27.6 + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 @@ -2707,6 +2823,11 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@capsizecss/unpack@2.4.0': dependencies: blob-to-buffer: 1.2.9 @@ -2898,6 +3019,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -3291,6 +3414,8 @@ snapshots: '@types/unist@3.0.3': {} + '@types/web-bluetooth@0.0.21': {} + '@ungap/structured-clone@1.3.0': {} '@vitejs/plugin-react@4.5.2(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.30.1))': @@ -3305,6 +3430,87 @@ snapshots: transitivePeerDependencies: - supports-color + '@vue/compiler-core@3.5.26': + dependencies: + '@babel/parser': 7.28.5 + '@vue/shared': 3.5.26 + entities: 7.0.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.26': + dependencies: + '@vue/compiler-core': 3.5.26 + '@vue/shared': 3.5.26 + + '@vue/compiler-sfc@3.5.26': + dependencies: + '@babel/parser': 7.28.5 + '@vue/compiler-core': 3.5.26 + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-ssr': 3.5.26 + '@vue/shared': 3.5.26 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.6 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.26': + dependencies: + '@vue/compiler-dom': 3.5.26 + '@vue/shared': 3.5.26 + + '@vue/reactivity@3.5.26': + dependencies: + '@vue/shared': 3.5.26 + + '@vue/runtime-core@3.5.26': + dependencies: + '@vue/reactivity': 3.5.26 + '@vue/shared': 3.5.26 + + '@vue/runtime-dom@3.5.26': + dependencies: + '@vue/reactivity': 3.5.26 + '@vue/runtime-core': 3.5.26 + '@vue/shared': 3.5.26 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.26(vue@3.5.26(typescript@5.8.3))': + dependencies: + '@vue/compiler-ssr': 3.5.26 + '@vue/shared': 3.5.26 + vue: 3.5.26(typescript@5.8.3) + + '@vue/shared@3.5.26': {} + + '@vueuse/core@14.1.0(vue@3.5.26(typescript@5.8.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.1.0 + '@vueuse/shared': 14.1.0(vue@3.5.26(typescript@5.8.3)) + vue: 3.5.26(typescript@5.8.3) + + '@vueuse/metadata@14.1.0': {} + + '@vueuse/shared@14.1.0(vue@3.5.26(typescript@5.8.3))': + dependencies: + vue: 3.5.26(typescript@5.8.3) + + '@waline/api@1.0.0': {} + + '@waline/client@3.8.0(typescript@5.8.3)': + dependencies: + '@vueuse/core': 14.1.0(vue@3.5.26(typescript@5.8.3)) + '@waline/api': 1.0.0 + autosize: 6.0.1 + marked: 16.4.2 + marked-highlight: 2.2.3(marked@16.4.2) + recaptcha-v3: 1.11.3 + vue: 3.5.26(typescript@5.8.3) + transitivePeerDependencies: + - typescript + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -3457,6 +3663,8 @@ snapshots: - uploadthing - yaml + autosize@6.0.1: {} + axobject-query@4.1.0: {} bail@2.0.2: {} @@ -3582,6 +3790,8 @@ snapshots: csstype@3.1.3: {} + csstype@3.2.3: {} + debug@4.4.1: dependencies: ms: 2.1.3 @@ -3631,6 +3841,8 @@ snapshots: entities@6.0.1: {} + entities@7.0.0: {} + es-module-lexer@1.7.0: {} esast-util-from-estree@2.0.0: @@ -4157,6 +4369,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + magicast@0.3.5: dependencies: '@babel/parser': 7.27.5 @@ -4167,6 +4383,12 @@ snapshots: markdown-table@3.0.4: {} + marked-highlight@2.2.3(marked@16.4.2): + dependencies: + marked: 16.4.2 + + marked@16.4.2: {} + mdast-util-definitions@6.0.0: dependencies: '@types/mdast': 4.0.4 @@ -4713,6 +4935,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prismjs@1.30.0: {} prompts@2.4.2: @@ -4737,6 +4965,8 @@ snapshots: readdirp@4.1.2: {} + recaptcha-v3@1.11.3: {} + recma-build-jsx@1.0.0: dependencies: '@types/estree': 1.0.8 @@ -5191,6 +5421,16 @@ snapshots: optionalDependencies: vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.30.1) + vue@3.5.26(typescript@5.8.3): + dependencies: + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-sfc': 3.5.26 + '@vue/runtime-dom': 3.5.26 + '@vue/server-renderer': 3.5.26(vue@3.5.26(typescript@5.8.3)) + '@vue/shared': 3.5.26 + optionalDependencies: + typescript: 5.8.3 + web-namespaces@2.0.1: {} webidl-conversions@3.0.1: {} diff --git a/src/components/blog/Comments.tsx b/src/components/blog/Comments.tsx new file mode 100644 index 0000000..16166fa --- /dev/null +++ b/src/components/blog/Comments.tsx @@ -0,0 +1,61 @@ +import { useEffect, useRef } from 'react'; +import type { WalineInstance, WalineInitOptions } from '@waline/client'; +import { init } from '@waline/client'; +import '@waline/client/style'; + +import type { Lang } from '@/types/i18n'; + +export type CommentsProps = Partial> & { lang?: Lang }; + +export default function Comments({ lang = 'en', ...props }: CommentsProps) { + const walineInstanceRef = useRef(null); + const containerRef = useRef(null); + + const walineLang = lang === 'zh' ? 'zh-CN' : 'en'; + + useEffect(() => { + if (!containerRef.current) return; + + const getTheme = () => document.documentElement.classList.contains('dark') ? 'html.dark' : false; + + const pathname = window.location.pathname; + const postsMatch = pathname.match(/\/posts\/([^/]+)/); + const path = postsMatch ? postsMatch[1] : pathname; + + walineInstanceRef.current = init({ + ...props, + el: containerRef.current, + serverURL: import.meta.env.PUBLIC_WALINE_SERVER_URL, + lang: walineLang, + dark: getTheme(), + path, + }); + + return () => walineInstanceRef.current?.destroy(); + }, []); + + useEffect(() => { + const getTheme = () => document.documentElement.classList.contains('dark') ? 'html.dark' : false; + + walineInstanceRef.current?.update({ + ...props, + lang: walineLang, + dark: getTheme(), + }); + + const handleThemeChange = () => { + walineInstanceRef.current?.update({ + ...props, + lang: walineLang, + dark: getTheme(), + }); + }; + + const observer = new MutationObserver(handleThemeChange); + observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }); + + return () => observer.disconnect(); + }, [lang, props, walineLang]); + + return
; +} diff --git a/src/components/blog/GiscusComments.tsx b/src/components/blog/GiscusComments.tsx deleted file mode 100644 index 71286af..0000000 --- a/src/components/blog/GiscusComments.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import Giscus from '@giscus/react'; -import type { Lang } from '@/types/i18n'; -import { useEffect, useState } from 'react'; - -export interface GiscusCommentsProps { - lang?: Lang; -} - -export default function GiscusComments({ lang = 'en' }: GiscusCommentsProps) { - const [theme, setTheme] = useState<'light' | 'dark'>('light'); - const [term, setTerm] = useState(''); - - const giscusLang = lang === 'zh' ? 'zh-CN' : lang; - - useEffect(() => { - const getTheme = () => document.documentElement.classList.contains('dark') ? 'dark' : 'light'; - - const pathname = window.location.pathname; - const postsMatch = pathname.match(/\/posts\/([^/]+)/); - const discussionTerm = postsMatch ? postsMatch[1] : pathname; - - setTheme(getTheme()); - setTerm(discussionTerm); - - const observer = new MutationObserver(() => { - setTheme(getTheme()); - }); - - observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }); - - return () => observer.disconnect(); - }, []); - - - return ( - - ); -} diff --git a/src/layouts/BlogPostLayout.astro b/src/layouts/BlogPostLayout.astro index fac6ddd..5bcd264 100644 --- a/src/layouts/BlogPostLayout.astro +++ b/src/layouts/BlogPostLayout.astro @@ -12,7 +12,7 @@ import TableOfContents from '@/components/layout/TableOfContents.astro'; import BlogNavigation from '@/components/layout/BlogNavigation.astro'; import PostMeta from '@/components/blog/PostMeta.astro'; import Container from '../components/ui/Container'; -import GiscusComments from '@/components/blog/GiscusComments'; +import Comments from '@/components/blog/Comments'; // Use Astro's MarkdownLayoutProps for proper type safety export type Props = MarkdownLayoutProps; @@ -107,7 +107,7 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde
- +
diff --git a/src/pages/zh/blog/index.astro b/src/pages/zh/blog/index.astro index 344ea2b..5d3f7ac 100644 --- a/src/pages/zh/blog/index.astro +++ b/src/pages/zh/blog/index.astro @@ -55,7 +55,7 @@ const tags = extractTags(allPostsArray); --- - +