Compare commits
8 Commits
9f05776781
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21539772ef | ||
|
|
b8a8cc474b | ||
|
|
78c468a7d2 | ||
|
|
ca9e083399 | ||
|
|
1952f4de64 | ||
|
|
bdf9fad89f | ||
|
|
c97d31afe4 | ||
|
|
7675b6c299 |
@@ -1,59 +0,0 @@
|
|||||||
name: Deploy docs for Site
|
|
||||||
run-name: ${{ gitea.actor }} is building out Gitea Actions 🚀
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [20.x]
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository code
|
|
||||||
uses: https://gitea.com/actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: 'main'
|
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
|
|
||||||
# Skip pnpm cache to reduce overhead
|
|
||||||
- name: Install pnpm
|
|
||||||
run: |
|
|
||||||
if ! command -v pnpm &> /dev/null; then
|
|
||||||
npm install -g pnpm@9
|
|
||||||
else
|
|
||||||
echo "pnpm is already installed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Check Node.js and pnpm versions
|
|
||||||
run: |
|
|
||||||
echo "pnpm version ===>" && pnpm -v
|
|
||||||
echo "node version ===>" && node -v
|
|
||||||
|
|
||||||
# Simplify node_modules handling without caching
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
if [ ! -d "node_modules" ] || [ "$(find package.json -newer node_modules)" ]; then
|
|
||||||
echo "Dependencies are outdated or missing, installing..."
|
|
||||||
pnpm install
|
|
||||||
else
|
|
||||||
echo "Dependencies are up-to-date, skipping installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build site
|
|
||||||
run: pnpm build
|
|
||||||
|
|
||||||
- name: ssh deploy
|
|
||||||
uses: easingthemes/ssh-deploy@v5.1.0
|
|
||||||
with:
|
|
||||||
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_PRIVATE_KEY }}
|
|
||||||
REMOTE_HOST: ${{ secrets.DEPLOY_HOST }}
|
|
||||||
REMOTE_USER: ${{ secrets.DEPLOY_USER }}
|
|
||||||
SOURCE: "/dist/"
|
|
||||||
TARGET: "/opt/1panel/apps/openresty/openresty/www/sites/zhaoguiyang.com/index/dist"
|
|
||||||
EXCLUDE: "/node_modules/"
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -24,3 +24,6 @@ pnpm-debug.log*
|
|||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
.trae/
|
.trae/
|
||||||
|
|
||||||
|
# deploy script
|
||||||
|
deploy.sh
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
"tw-animate-css": "^1.2.4"
|
"tw-animate-css": "^1.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.16"
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
|
"@waline/client": "^3.8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
240
pnpm-lock.yaml
generated
240
pnpm-lock.yaml
generated
@@ -75,6 +75,9 @@ importers:
|
|||||||
'@tailwindcss/typography':
|
'@tailwindcss/typography':
|
||||||
specifier: ^0.5.16
|
specifier: ^0.5.16
|
||||||
version: 0.5.16(tailwindcss@4.1.10)
|
version: 0.5.16(tailwindcss@4.1.10)
|
||||||
|
'@waline/client':
|
||||||
|
specifier: ^3.8.0
|
||||||
|
version: 3.8.0(typescript@5.8.3)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -159,6 +162,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
|
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
|
||||||
engines: {node: '>=6.9.0'}
|
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':
|
'@babel/helper-validator-option@7.27.1':
|
||||||
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
|
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -172,6 +179,11 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
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':
|
'@babel/plugin-transform-react-jsx-self@7.27.1':
|
||||||
resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
|
resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -200,6 +212,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
|
resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
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':
|
'@capsizecss/unpack@2.4.0':
|
||||||
resolution: {integrity: sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==}
|
resolution: {integrity: sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==}
|
||||||
|
|
||||||
@@ -510,6 +526,9 @@ packages:
|
|||||||
'@jridgewell/sourcemap-codec@1.5.0':
|
'@jridgewell/sourcemap-codec@1.5.0':
|
||||||
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
|
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5':
|
||||||
|
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||||
|
|
||||||
'@jridgewell/trace-mapping@0.3.25':
|
'@jridgewell/trace-mapping@0.3.25':
|
||||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||||
|
|
||||||
@@ -946,6 +965,9 @@ packages:
|
|||||||
'@types/unist@3.0.3':
|
'@types/unist@3.0.3':
|
||||||
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
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':
|
'@ungap/structured-clone@1.3.0':
|
||||||
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
|
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
|
||||||
|
|
||||||
@@ -955,6 +977,56 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
|
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:
|
acorn-jsx@5.3.2:
|
||||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||||
peerDependencies:
|
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'}
|
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
autosize@6.0.1:
|
||||||
|
resolution: {integrity: sha512-f86EjiUKE6Xvczc4ioP1JBlWG7FKrE13qe/DxBCpe8GCipCq2nFw73aO8QEBKHfSbYGDN5eB9jXWKen7tspDqQ==}
|
||||||
|
|
||||||
axobject-query@4.1.0:
|
axobject-query@4.1.0:
|
||||||
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
|
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -1153,6 +1228,9 @@ packages:
|
|||||||
csstype@3.1.3:
|
csstype@3.1.3:
|
||||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||||
|
|
||||||
|
csstype@3.2.3:
|
||||||
|
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||||
|
|
||||||
debug@4.4.1:
|
debug@4.4.1:
|
||||||
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
|
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
|
||||||
engines: {node: '>=6.0'}
|
engines: {node: '>=6.0'}
|
||||||
@@ -1224,6 +1302,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
|
entities@7.0.0:
|
||||||
|
resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==}
|
||||||
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
es-module-lexer@1.7.0:
|
es-module-lexer@1.7.0:
|
||||||
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
|
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
|
||||||
|
|
||||||
@@ -1713,6 +1795,9 @@ packages:
|
|||||||
magic-string@0.30.17:
|
magic-string@0.30.17:
|
||||||
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
||||||
|
|
||||||
|
magic-string@0.30.21:
|
||||||
|
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||||
|
|
||||||
magicast@0.3.5:
|
magicast@0.3.5:
|
||||||
resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
|
resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
|
||||||
|
|
||||||
@@ -1723,6 +1808,16 @@ packages:
|
|||||||
markdown-table@3.0.4:
|
markdown-table@3.0.4:
|
||||||
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
|
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:
|
mdast-util-definitions@6.0.0:
|
||||||
resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==}
|
resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==}
|
||||||
|
|
||||||
@@ -2003,6 +2098,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==}
|
resolution: {integrity: sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
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:
|
prismjs@1.30.0:
|
||||||
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -2037,6 +2136,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
||||||
engines: {node: '>= 14.18.0'}
|
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:
|
recma-build-jsx@1.0.0:
|
||||||
resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==}
|
resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==}
|
||||||
|
|
||||||
@@ -2430,6 +2532,14 @@ packages:
|
|||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
vue@3.5.26:
|
||||||
|
resolution: {integrity: sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
|
||||||
web-namespaces@2.0.1:
|
web-namespaces@2.0.1:
|
||||||
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
|
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
|
||||||
|
|
||||||
@@ -2661,6 +2771,8 @@ snapshots:
|
|||||||
|
|
||||||
'@babel/helper-validator-identifier@7.27.1': {}
|
'@babel/helper-validator-identifier@7.27.1': {}
|
||||||
|
|
||||||
|
'@babel/helper-validator-identifier@7.28.5': {}
|
||||||
|
|
||||||
'@babel/helper-validator-option@7.27.1': {}
|
'@babel/helper-validator-option@7.27.1': {}
|
||||||
|
|
||||||
'@babel/helpers@7.27.6':
|
'@babel/helpers@7.27.6':
|
||||||
@@ -2672,6 +2784,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.27.6
|
'@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)':
|
'@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.27.4
|
'@babel/core': 7.27.4
|
||||||
@@ -2707,6 +2823,11 @@ snapshots:
|
|||||||
'@babel/helper-string-parser': 7.27.1
|
'@babel/helper-string-parser': 7.27.1
|
||||||
'@babel/helper-validator-identifier': 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':
|
'@capsizecss/unpack@2.4.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
blob-to-buffer: 1.2.9
|
blob-to-buffer: 1.2.9
|
||||||
@@ -2898,6 +3019,8 @@ snapshots:
|
|||||||
|
|
||||||
'@jridgewell/sourcemap-codec@1.5.0': {}
|
'@jridgewell/sourcemap-codec@1.5.0': {}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||||
|
|
||||||
'@jridgewell/trace-mapping@0.3.25':
|
'@jridgewell/trace-mapping@0.3.25':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
@@ -3291,6 +3414,8 @@ snapshots:
|
|||||||
|
|
||||||
'@types/unist@3.0.3': {}
|
'@types/unist@3.0.3': {}
|
||||||
|
|
||||||
|
'@types/web-bluetooth@0.0.21': {}
|
||||||
|
|
||||||
'@ungap/structured-clone@1.3.0': {}
|
'@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))':
|
'@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:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- 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):
|
acorn-jsx@5.3.2(acorn@8.15.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
@@ -3457,6 +3663,8 @@ snapshots:
|
|||||||
- uploadthing
|
- uploadthing
|
||||||
- yaml
|
- yaml
|
||||||
|
|
||||||
|
autosize@6.0.1: {}
|
||||||
|
|
||||||
axobject-query@4.1.0: {}
|
axobject-query@4.1.0: {}
|
||||||
|
|
||||||
bail@2.0.2: {}
|
bail@2.0.2: {}
|
||||||
@@ -3582,6 +3790,8 @@ snapshots:
|
|||||||
|
|
||||||
csstype@3.1.3: {}
|
csstype@3.1.3: {}
|
||||||
|
|
||||||
|
csstype@3.2.3: {}
|
||||||
|
|
||||||
debug@4.4.1:
|
debug@4.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
@@ -3631,6 +3841,8 @@ snapshots:
|
|||||||
|
|
||||||
entities@6.0.1: {}
|
entities@6.0.1: {}
|
||||||
|
|
||||||
|
entities@7.0.0: {}
|
||||||
|
|
||||||
es-module-lexer@1.7.0: {}
|
es-module-lexer@1.7.0: {}
|
||||||
|
|
||||||
esast-util-from-estree@2.0.0:
|
esast-util-from-estree@2.0.0:
|
||||||
@@ -4157,6 +4369,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@jridgewell/sourcemap-codec': 1.5.0
|
||||||
|
|
||||||
|
magic-string@0.30.21:
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
magicast@0.3.5:
|
magicast@0.3.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/parser': 7.27.5
|
'@babel/parser': 7.27.5
|
||||||
@@ -4167,6 +4383,12 @@ snapshots:
|
|||||||
|
|
||||||
markdown-table@3.0.4: {}
|
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:
|
mdast-util-definitions@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/mdast': 4.0.4
|
'@types/mdast': 4.0.4
|
||||||
@@ -4713,6 +4935,12 @@ snapshots:
|
|||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
source-map-js: 1.2.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: {}
|
prismjs@1.30.0: {}
|
||||||
|
|
||||||
prompts@2.4.2:
|
prompts@2.4.2:
|
||||||
@@ -4737,6 +4965,8 @@ snapshots:
|
|||||||
|
|
||||||
readdirp@4.1.2: {}
|
readdirp@4.1.2: {}
|
||||||
|
|
||||||
|
recaptcha-v3@1.11.3: {}
|
||||||
|
|
||||||
recma-build-jsx@1.0.0:
|
recma-build-jsx@1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/estree': 1.0.8
|
'@types/estree': 1.0.8
|
||||||
@@ -5191,6 +5421,16 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.30.1)
|
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: {}
|
web-namespaces@2.0.1: {}
|
||||||
|
|
||||||
webidl-conversions@3.0.1: {}
|
webidl-conversions@3.0.1: {}
|
||||||
|
|||||||
64
src/components/blog/Comments.tsx
Normal file
64
src/components/blog/Comments.tsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import type { WalineInstance, WalineInitOptions } from '@waline/client';
|
||||||
|
import { init } from '@waline/client';
|
||||||
|
import '@waline/client/style';
|
||||||
|
import '@/styles/waline-custom.css';
|
||||||
|
|
||||||
|
import type { Lang } from '@/types/i18n';
|
||||||
|
|
||||||
|
export type CommentsProps = Partial<Omit<WalineInitOptions, 'el' | 'serverURL'>> & { lang?: Lang };
|
||||||
|
|
||||||
|
export default function Comments({ lang = 'en', ...props }: CommentsProps) {
|
||||||
|
const walineInstanceRef = useRef<WalineInstance | null>(null);
|
||||||
|
const containerRef = useRef<HTMLDivElement>(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(),
|
||||||
|
pageview: true,
|
||||||
|
comment: true,
|
||||||
|
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 <div ref={containerRef} className="waline-container" />;
|
||||||
|
}
|
||||||
@@ -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<string>('');
|
|
||||||
|
|
||||||
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 (
|
|
||||||
<Giscus
|
|
||||||
repo="zguiyang/blog-giscus"
|
|
||||||
repoId="R_kgDOQ2Wnxw"
|
|
||||||
category="Announcements"
|
|
||||||
categoryId="DIC_kwDOQ2Wnx84C0vSJ"
|
|
||||||
mapping="specific"
|
|
||||||
term={term}
|
|
||||||
strict="0"
|
|
||||||
reactionsEnabled="1"
|
|
||||||
emitMetadata="0"
|
|
||||||
inputPosition="top"
|
|
||||||
theme={theme}
|
|
||||||
lang={giscusLang}
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,7 @@ export const translations = {
|
|||||||
},
|
},
|
||||||
hero: {
|
hero: {
|
||||||
greeting: "Hello, I'm",
|
greeting: "Hello, I'm",
|
||||||
viewProjects: 'View Projects',
|
viewProjects: 'About Me',
|
||||||
contactMe: 'Contact Me',
|
contactMe: 'Contact Me',
|
||||||
lookingForJob: 'Looking for a Frontend/TS Full-stack Engineer (Remote)? Contact me!',
|
lookingForJob: 'Looking for a Frontend/TS Full-stack Engineer (Remote)? Contact me!',
|
||||||
digitalNomad: 'Exploring the freelance journey, striving to become a digital nomad',
|
digitalNomad: 'Exploring the freelance journey, striving to become a digital nomad',
|
||||||
@@ -77,7 +77,7 @@ export const translations = {
|
|||||||
},
|
},
|
||||||
hero: {
|
hero: {
|
||||||
greeting: '你好,我是',
|
greeting: '你好,我是',
|
||||||
viewProjects: '查看项目',
|
viewProjects: '关于我',
|
||||||
contactMe: '联系我',
|
contactMe: '联系我',
|
||||||
lookingForJob: '正在寻找前端/TS 全栈工程师(远程)?联系我!',
|
lookingForJob: '正在寻找前端/TS 全栈工程师(远程)?联系我!',
|
||||||
digitalNomad: '探索自由职业道路,努力成为数字游民',
|
digitalNomad: '探索自由职业道路,努力成为数字游民',
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import TableOfContents from '@/components/layout/TableOfContents.astro';
|
|||||||
import BlogNavigation from '@/components/layout/BlogNavigation.astro';
|
import BlogNavigation from '@/components/layout/BlogNavigation.astro';
|
||||||
import PostMeta from '@/components/blog/PostMeta.astro';
|
import PostMeta from '@/components/blog/PostMeta.astro';
|
||||||
import Container from '../components/ui/Container';
|
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
|
// Use Astro's MarkdownLayoutProps for proper type safety
|
||||||
export type Props = MarkdownLayoutProps<FrontmatterProps>;
|
export type Props = MarkdownLayoutProps<FrontmatterProps>;
|
||||||
@@ -107,7 +107,7 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde
|
|||||||
|
|
||||||
<!-- Comments Section -->
|
<!-- Comments Section -->
|
||||||
<div class="mt-10 sm:mt-16 border-t border-border pt-10">
|
<div class="mt-10 sm:mt-16 border-t border-border pt-10">
|
||||||
<GiscusComments client:only="react" lang={lang} />
|
<Comments client:only="react" lang={lang} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Author Card moved to bottom with enhanced styling -->
|
<!-- Author Card moved to bottom with enhanced styling -->
|
||||||
|
|||||||
127
src/pages/blog/posts/2024060801.md
Normal file
127
src/pages/blog/posts/2024060801.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
---
|
||||||
|
layout: "@/layouts/BlogPostLayout.astro"
|
||||||
|
title: "1Panel Automated Deployment Notes: Say Goodbye to Manual Uploads, One-Command Takeoff from Local"
|
||||||
|
description: "Learn how to build a lightweight deployment pipeline using 1Panel with SSH key authentication and ACL permissions. Complete guide for solo developers to automate server deployments."
|
||||||
|
date: "2024-06-08"
|
||||||
|
image: "https://images.unsplash.com/photo-1558494949-ef010cbdcc31?q=80&w=1470&auto=format&fit=crop"
|
||||||
|
tags: ["1Panel", "DevOps", "Automation", "SSH", "Deployment"]
|
||||||
|
tagId: ["1panel", "devops", "automation", "ssh", "deployment"]
|
||||||
|
category: "DevOps"
|
||||||
|
categoryId: "devops"
|
||||||
|
readTime: "5 min read"
|
||||||
|
---
|
||||||
|
|
||||||
|
Updating code used to make me feel like a "human FTP client":
|
||||||
|
|
||||||
|
1. Package everything locally, sweat included
|
||||||
|
2. Open browser, log into 1Panel (forgot password again?)
|
||||||
|
3. Dig through file manager like an archaeologist
|
||||||
|
4. Manual upload, manual overwrite, plus manual cleanup of old files
|
||||||
|
|
||||||
|
This whole ritual took at least 5 minutes each time, and last week I actually brought the site down for 10 minutes because I forgot to upload a new config file. Enough is enough—I built this lightweight deployment pipeline. No heavy Jenkins setup needed, perfect for solo developers or small projects. Fast, reliable, and nobody else to blame.
|
||||||
|
|
||||||
|
## 1. Create a "Deployment Runner" Account
|
||||||
|
|
||||||
|
Running scripts as root? That's like performing surgery with a chainsaw. Let's create a dedicated account just for deployments.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create the deployment account
|
||||||
|
sudo adduser deploy_user
|
||||||
|
|
||||||
|
# Critical: disable password login, SSH keys only
|
||||||
|
# Even if someone guesses the password, they can't get in
|
||||||
|
# -l locks the password account (disabled password login)
|
||||||
|
# -u unlocks the password account (if you need enabled password login)
|
||||||
|
sudo passwd -l deploy_user
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. The Permission Puzzle: ACL to the Rescue
|
||||||
|
|
||||||
|
Here's the tricky part: 1Panel has its own permission system. If you `chown` everything to your deployment user, websites in the panel might start throwing 500 errors.
|
||||||
|
|
||||||
|
My solution: **ACL** (Access Control Lists). Think of it as giving your deployment user a "VIP backstage pass"—it can read/write files without messing with 1Panel's original file ownership.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install ACL tools first
|
||||||
|
sudo apt install acl -y
|
||||||
|
|
||||||
|
# Grant access to sites directory (make sure this is your web root)
|
||||||
|
# -R means recursive, but be careful if directory has other sites
|
||||||
|
sudo setfacl -R -m u:deploy_user:rwx /opt/1panel/www/sites
|
||||||
|
|
||||||
|
# Set default inheritance: new sites get access automatically
|
||||||
|
sudo setfacl -R -d -m u:deploy_user:rwx /opt/1panel/www/sites
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. SSH Key Access: No More Password Typing
|
||||||
|
|
||||||
|
Copy your local SSH public key to the server, and never type a password again.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create SSH directory for deployment user
|
||||||
|
sudo -u deploy_user mkdir -p /home/deploy_user/.ssh
|
||||||
|
|
||||||
|
# Append your public key (using >> not > to avoid overwriting)
|
||||||
|
echo "your-ssh-public-key-content" >> /home/deploy_user/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# Permissions must be exact, or SSH will refuse
|
||||||
|
sudo chown -R deploy_user:deploy_user /home/deploy_user/.ssh
|
||||||
|
sudo chmod 700 /home/deploy_user/.ssh
|
||||||
|
sudo chmod 600 /home/deploy_user/.ssh/authorized_keys
|
||||||
|
```
|
||||||
|
|
||||||
|
**Even lazier method**: If you have `ssh-copy-id` locally, just run `ssh-copy-id deploy_user@your-server-ip`.
|
||||||
|
|
||||||
|
## 4. SSH Aliases (For the Truly Lazy)
|
||||||
|
|
||||||
|
Memorize IP addresses? Not in this decade. Add this to your local `~/.ssh/config`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Host your-server-alias # Nickname for your server
|
||||||
|
HostName your-server-ip-address # Your server IP
|
||||||
|
User deploy_user # Login user
|
||||||
|
IdentityFile ~/.ssh/id_rsa # Private key path
|
||||||
|
```
|
||||||
|
|
||||||
|
Now just type `ssh your-server-alias` and you're in. Magic.
|
||||||
|
|
||||||
|
## 5. The Grand Finale: One-Command Deployment
|
||||||
|
|
||||||
|
Create `deploy.sh` in your project root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# For frontend projects, build first
|
||||||
|
# echo "📦 Building..."
|
||||||
|
# npm run build
|
||||||
|
|
||||||
|
echo "🚀 Syncing to production..."
|
||||||
|
# rsync for incremental updates
|
||||||
|
# -a: archive mode (preserves everything)
|
||||||
|
# -v: verbose (show me what's happening)
|
||||||
|
# -z: compress during transfer
|
||||||
|
# --delete: ⚠️ Warning: removes files on target that don't exist locally!
|
||||||
|
# Remove this flag for first sync to be safe
|
||||||
|
rsync -avz --delete --progress ./dist/ your-server-alias:/opt/1panel/www/sites/your-project-directory/
|
||||||
|
|
||||||
|
echo "✅ Deployment complete!"
|
||||||
|
echo "⏱️ Next time just run: ./deploy.sh"
|
||||||
|
```
|
||||||
|
|
||||||
|
Make it executable: `chmod +x deploy.sh`. Now deploying is literally one command.
|
||||||
|
|
||||||
|
## 6. Pitfalls I Stepped In (So You Don't Have To)
|
||||||
|
|
||||||
|
1. **Skip `--delete` on first sync**: Do a dry run first. This flag can delete important files if you're not careful.
|
||||||
|
2. **Check ACL permissions**: If files still have permission issues, run `getfacl /opt/1panel/www/sites/your-project` to verify.
|
||||||
|
3. **Verify paths**: 1Panel's default path is `/opt/1panel/www/sites/`, but check if you customized it.
|
||||||
|
4. **Frontend projects**: Don't upload `node_modules`. Your server doesn't need that 200MB baggage.
|
||||||
|
|
||||||
|
## Wrapping Up
|
||||||
|
|
||||||
|
I've been using this setup for weeks, and it just works. What used to be a 5-minute chore is now a 30-second command. The mental load is gone—no more "did I forget that one file?" anxiety.
|
||||||
|
|
||||||
|
For small to medium projects that don't need full CI/CD complexity, this lightweight approach is perfect. A few minutes to set up, a lifetime of easy deployments.
|
||||||
|
|
||||||
|
**Final reminder**: Automation is powerful but dangerous. Test with a dummy directory first, especially before using `--delete`. Happy deploying, and may your uptime be forever!
|
||||||
@@ -55,7 +55,7 @@ const tags = extractTags(allPostsArray);
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<BlogLayout title="博客 - 赵桂阳" description="深入我对编程、技术趋势和开发者生活的思考。探索我的最新文章。">
|
<BlogLayout title="博客 - Joy Zhao" description="深入我对编程、技术趋势和开发者生活的思考。探索我的最新文章。">
|
||||||
<main class="min-h-screen">
|
<main class="min-h-screen">
|
||||||
<!-- 头部区域 -->
|
<!-- 头部区域 -->
|
||||||
<Container client:load className="pt-24 pb-12">
|
<Container client:load className="pt-24 pb-12">
|
||||||
|
|||||||
127
src/pages/zh/blog/posts/2024060801.md
Normal file
127
src/pages/zh/blog/posts/2024060801.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
---
|
||||||
|
layout: "@/layouts/BlogPostLayout.astro"
|
||||||
|
title: "1Panel 自动化部署笔记:告别\"手动操作\",本地一键起飞"
|
||||||
|
description: "学习如何基于 1Panel 构建轻量级部署流水线,配合 SSH 密钥认证和 ACL 权限管理。本文为单兵作战的开发者提供了完整的自动化部署方案。"
|
||||||
|
date: "2024-06-08"
|
||||||
|
image: "https://images.unsplash.com/photo-1558494949-ef010cbdcc31?q=80&w=1470&auto=format&fit=crop"
|
||||||
|
tags: ["1Panel", "DevOps", "自动化", "SSH", "部署"]
|
||||||
|
tagId: ["1panel", "devops", "automation", "ssh", "deployment"]
|
||||||
|
category: "DevOps"
|
||||||
|
categoryId: "devops"
|
||||||
|
readTime: "5 min read"
|
||||||
|
---
|
||||||
|
|
||||||
|
以前每次更新代码,都感觉自己像个"人肉传输带":
|
||||||
|
|
||||||
|
1. 本地吭哧吭哧打包
|
||||||
|
2. 打开浏览器,输密码登录 1Panel 面板
|
||||||
|
3. 在文件管理器里翻来覆去找目录
|
||||||
|
4. 手动上传、手动覆盖,有时候还得手动删服务器上的旧文件,就怕哪个缓存文件没清干净
|
||||||
|
|
||||||
|
这一套流程下来,没个三五分钟搞不定,关键还特别容易漏文件。上周就因为我忘记上传一个新加的配置文件,线上挂了十分钟才反应过来。痛定思痛,我决定搞一套轻量级部署方案——不用整 Jenkins 那种大炮打蚊子,特别适合我这种单兵作战的小项目,要的就是快、稳、不求人。
|
||||||
|
|
||||||
|
## 1. 先整个"跑腿小弟"账号
|
||||||
|
|
||||||
|
用 root 跑脚本?那太野了,万一脚本写崩了,服务器直接原地升天。得建个专门干这活的"小弟账号"。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 创建专门负责部署的账号
|
||||||
|
sudo adduser deploy_user
|
||||||
|
|
||||||
|
# 关键一步:禁用这个账号的密码登录,只认 SSH 密钥
|
||||||
|
# 这样就算有人猜到密码也进不来,安全第一
|
||||||
|
# -l 锁定账号密码(禁用密码登录)
|
||||||
|
# -u 解锁账号密码(如需恢复密码登录)
|
||||||
|
sudo passwd -l deploy_user
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 权限难题的"优雅解法":ACL 授权
|
||||||
|
|
||||||
|
这里有个坑:1Panel 管理的文件有自己的一套权限体系,如果你用 `chown` 强行改属主,面板里的网站可能就直接 500 错误了。
|
||||||
|
|
||||||
|
我的解决方案是 **ACL**(访问控制列表)。这玩意就像给文件加了张"访客通行证",让 `deploy_user` 这个账号能读写文件,但又不会破坏 1Panel 原本的文件归属关系。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 先安装 ACL 工具
|
||||||
|
sudo apt install acl -y
|
||||||
|
|
||||||
|
# 给 sites 目录开绿灯(注意:确认这是你的网站根目录)
|
||||||
|
# -R 表示递归,但如果目录里已有其他站点,建议先备份或确认操作
|
||||||
|
sudo setfacl -R -m u:deploy_user:rwx /opt/1panel/www/sites
|
||||||
|
|
||||||
|
# 设置默认权限继承:以后在面板里新建的站点,自动给 deploy_user 权限
|
||||||
|
sudo setfacl -R -d -m u:deploy_user:rwx /opt/1panel/www/sites
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. SSH 免密登录:从此进出如风
|
||||||
|
|
||||||
|
把你本地电脑的 SSH 公钥塞到服务器上,以后就不用输密码了。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 切换到部署账号的家目录
|
||||||
|
sudo -u deploy_user mkdir -p /home/deploy_user/.ssh
|
||||||
|
|
||||||
|
# 追加你的公钥(用 >> 而不是 >,避免覆盖别人的密钥)
|
||||||
|
echo "your-ssh-public-key-content" >> /home/deploy_user/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# 权限必须严格设置,否则 SSH 会拒绝连接
|
||||||
|
sudo chown -R deploy_user:deploy_user /home/deploy_user/.ssh
|
||||||
|
sudo chmod 700 /home/deploy_user/.ssh
|
||||||
|
sudo chmod 600 /home/deploy_user/.ssh/authorized_keys
|
||||||
|
```
|
||||||
|
|
||||||
|
**更懒的方法**:如果你本地有 `ssh-copy-id` 命令,直接 `ssh-copy-id deploy_user@your-server-ip-address`。
|
||||||
|
|
||||||
|
## 4. SSH 别名配置(懒癌患者的福音)
|
||||||
|
|
||||||
|
记 IP 地址?不存在的。在本地 `~/.ssh/config` 文件里加一段:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Host your-server-alias # 给你服务器起的外号,随便起,好记就行
|
||||||
|
HostName your-server-ip-address # 你的服务器 IP
|
||||||
|
User deploy_user # 登录用户
|
||||||
|
IdentityFile ~/.ssh/id_rsa # 私钥路径
|
||||||
|
```
|
||||||
|
|
||||||
|
配置完,以后登录就直接 `ssh your-server-alias`,爽!
|
||||||
|
|
||||||
|
## 5. 终极一击:一键部署脚本
|
||||||
|
|
||||||
|
在项目根目录创建 `deploy.sh`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 如果是前端项目,先打包
|
||||||
|
# echo "📦 正在打包..."
|
||||||
|
# npm run build
|
||||||
|
|
||||||
|
echo "🚀 开始同步到生产环境..."
|
||||||
|
# 使用 rsync 增量同步
|
||||||
|
# -a: 归档模式,保持文件属性
|
||||||
|
# -v: 显示详细过程
|
||||||
|
# -z: 压缩传输
|
||||||
|
# --delete: ⚠️ 注意:这会删除目标端有而源端没有的文件!
|
||||||
|
# 首次同步建议先去掉这个参数,确认无误后再加上
|
||||||
|
rsync -avz --delete --progress ./dist/ your-server-alias:/opt/1panel/www/sites/your-project-directory/
|
||||||
|
|
||||||
|
echo "✅ 部署完成!"
|
||||||
|
echo "⏱️ 下次更新只需: ./deploy.sh"
|
||||||
|
```
|
||||||
|
|
||||||
|
给脚本执行权限:`chmod +x deploy.sh`,以后部署就是一行命令的事儿。
|
||||||
|
|
||||||
|
## 6. 我踩过的坑和注意事项
|
||||||
|
|
||||||
|
1. **首次同步别用 `--delete`**:先完整同步一次,确认文件都对,再加这个参数。不然可能把服务器上的重要文件删了。
|
||||||
|
2. **ACL 权限检查**:如果同步后还是没权限,可以用 `getfacl /opt/1panel/www/sites/your-project-directory` 看看 ACL 设置是否生效。
|
||||||
|
3. **文件路径要对**:1Panel 的默认站点路径是 `/opt/1panel/www/sites/`,但如果你改过,记得调整。
|
||||||
|
4. **前端项目注意**:打包前清理 `node_modules`,这玩意别传到服务器。
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
这套方案我从上周用到现在,真香!以前更新一次至少折腾5分钟,现在30秒搞定。关键是心理负担小了——再也不用担心漏传文件,`rsync` 会帮我搞定一切。
|
||||||
|
|
||||||
|
对于还没到需要 CI/CD 的中小型项目,这种轻量级方案简直完美。几分钟配置,一劳永逸。如果你也在用 1Panel,又被手动上传困扰,试试这个方案吧。
|
||||||
|
|
||||||
|
**最后提醒**:任何自动化操作都有风险,尤其是删除操作。第一次在生产环境用的时候,建议先找个测试目录跑一遍,确认无误再上。祝大家部署顺利,永不宕机!
|
||||||
342
src/styles/waline-custom.css
Normal file
342
src/styles/waline-custom.css
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
/**
|
||||||
|
* Waline Custom Styles
|
||||||
|
* 适配网站主题风格 - 紫色渐变主题
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ========== 基础变量覆盖 ========== */
|
||||||
|
:root {
|
||||||
|
/* 主题色 - 使用网站的紫色渐变accent */
|
||||||
|
--waline-theme-color: #8B5CF6;
|
||||||
|
--waline-active-color: #EC4899;
|
||||||
|
|
||||||
|
/* 背景色 */
|
||||||
|
--waline-bg-color: oklch(1 0 0);
|
||||||
|
--waline-bg-color-light: oklch(0.97 0 0);
|
||||||
|
--waline-bg-color-hover: oklch(0.93 0 0);
|
||||||
|
|
||||||
|
/* 文字颜色 */
|
||||||
|
--waline-color: oklch(0.4 0 0);
|
||||||
|
--waline-light-grey: oklch(0.65 0 0);
|
||||||
|
--waline-dark-grey: oklch(0.3 0 0);
|
||||||
|
|
||||||
|
/* 边框颜色 */
|
||||||
|
--waline-border-color: oklch(0.87 0 0);
|
||||||
|
|
||||||
|
/* 其他颜色 */
|
||||||
|
--waline-badge-color: #8B5CF6;
|
||||||
|
--waline-info-bg-color: oklch(0.97 0 0);
|
||||||
|
--waline-info-color: oklch(0.55 0 0);
|
||||||
|
--waline-bq-color: oklch(0.93 0 0);
|
||||||
|
|
||||||
|
/* 代码块背景 */
|
||||||
|
--waline-code-bg-color: oklch(0.25 0 0);
|
||||||
|
|
||||||
|
/* 圆角 - 与网站一致 */
|
||||||
|
--waline-border-radius: var(--radius, 0.75rem);
|
||||||
|
|
||||||
|
/* 阴影 */
|
||||||
|
--waline-box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, 0.08));
|
||||||
|
|
||||||
|
/* 头像圆角 - 使用网站风格 */
|
||||||
|
--waline-avatar-radius: var(--radius-md, 0.5rem);
|
||||||
|
|
||||||
|
/* 按钮样式 */
|
||||||
|
--waline-btn-radius: var(--radius, 0.75rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 暗黑模式 ========== */
|
||||||
|
.dark {
|
||||||
|
--waline-bg-color: oklch(0.205 0 0);
|
||||||
|
--waline-bg-color-light: oklch(0.269 0 0);
|
||||||
|
--waline-bg-color-hover: oklch(0.32 0 0);
|
||||||
|
|
||||||
|
--waline-color: oklch(0.9 0 0);
|
||||||
|
--waline-light-grey: oklch(0.6 0 0);
|
||||||
|
--waline-dark-grey: oklch(0.75 0 0);
|
||||||
|
|
||||||
|
--waline-border-color: oklch(1 0 0 / 15%);
|
||||||
|
|
||||||
|
--waline-info-bg-color: oklch(0.269 0 0);
|
||||||
|
--waline-info-color: oklch(0.6 0 0);
|
||||||
|
--waline-bq-color: oklch(0.269 0 0);
|
||||||
|
|
||||||
|
--waline-code-bg-color: oklch(0.12 0 0);
|
||||||
|
|
||||||
|
--waline-box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, 0.25));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 评论面板样式 ========== */
|
||||||
|
.wl-panel {
|
||||||
|
border-radius: var(--waline-border-radius) !important;
|
||||||
|
border: 1px solid var(--waline-border-color) !important;
|
||||||
|
box-shadow: var(--waline-box-shadow) !important;
|
||||||
|
background: var(--waline-bg-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 输入框样式 ========== */
|
||||||
|
.wl-header {
|
||||||
|
border-bottom-color: var(--waline-border-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-header label {
|
||||||
|
color: var(--waline-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-header input {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-editor {
|
||||||
|
background: var(--waline-bg-color-light) !important;
|
||||||
|
border-radius: var(--waline-btn-radius) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-editor:focus {
|
||||||
|
background: var(--waline-bg-color-hover) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 按钮样式 ========== */
|
||||||
|
.wl-btn {
|
||||||
|
border-radius: var(--waline-btn-radius) !important;
|
||||||
|
font-size: 0.875em !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-btn:hover {
|
||||||
|
border-color: var(--waline-theme-color) !important;
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
background: var(--waline-bg-color-light) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-btn.primary {
|
||||||
|
background: linear-gradient(135deg, #8B5CF6, #EC4899) !important;
|
||||||
|
border: none !important;
|
||||||
|
color: white !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-btn.primary:hover {
|
||||||
|
background: linear-gradient(135deg, #7C3AED, #DB2777) !important;
|
||||||
|
border: none !important;
|
||||||
|
color: white !important;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 头部标签页 ========== */
|
||||||
|
.wl-header label {
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-header label:hover {
|
||||||
|
background: var(--waline-bg-color-light) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 评论卡片样式 ========== */
|
||||||
|
.wl-card {
|
||||||
|
border-bottom-color: var(--waline-border-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-card:first-child {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-nick {
|
||||||
|
color: var(--waline-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-time {
|
||||||
|
color: var(--waline-info-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-content {
|
||||||
|
color: var(--waline-color) !important;
|
||||||
|
line-height: 1.8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 徽章样式 ========== */
|
||||||
|
.wl-badge {
|
||||||
|
background: linear-gradient(135deg, #8B5CF6, #EC4899) !important;
|
||||||
|
border: none !important;
|
||||||
|
color: white !important;
|
||||||
|
font-size: 0.7em !important;
|
||||||
|
padding: 2px 8px !important;
|
||||||
|
border-radius: 9999px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 操作按钮 ========== */
|
||||||
|
.wl-action {
|
||||||
|
color: var(--waline-light-grey) !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-action:hover {
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-action.active {
|
||||||
|
color: var(--waline-active-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 评论操作 ========== */
|
||||||
|
.wl-delete:hover,
|
||||||
|
.wl-like:hover,
|
||||||
|
.wl-reply:hover,
|
||||||
|
.wl-edit:hover {
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-delete.active,
|
||||||
|
.wl-like.active,
|
||||||
|
.wl-reply.active,
|
||||||
|
.wl-edit.active {
|
||||||
|
color: var(--waline-active-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 排序按钮 ========== */
|
||||||
|
.wl-sort li {
|
||||||
|
color: var(--waline-info-color) !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-sort li:hover {
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-sort li.active {
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 表情弹窗 ========== */
|
||||||
|
.wl-emoji-popup {
|
||||||
|
border-radius: var(--waline-border-radius) !important;
|
||||||
|
box-shadow: var(--waline-box-shadow) !important;
|
||||||
|
background: var(--waline-bg-color) !important;
|
||||||
|
border: 1px solid var(--waline-border-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-emoji-popup .wl-tab.active {
|
||||||
|
background: var(--waline-bg-color-light) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-emoji-popup button:hover {
|
||||||
|
background: var(--waline-bg-color-hover) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== GIF 弹窗 ========== */
|
||||||
|
.wl-gif-popup {
|
||||||
|
border-radius: var(--waline-border-radius) !important;
|
||||||
|
box-shadow: var(--waline-box-shadow) !important;
|
||||||
|
background: var(--waline-bg-color) !important;
|
||||||
|
border: 1px solid var(--waline-border-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 评论统计 ========== */
|
||||||
|
.wl-count {
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
font-size: 1.5em !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 空状态 ========== */
|
||||||
|
.wl-empty {
|
||||||
|
color: var(--waline-info-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 头像样式 ========== */
|
||||||
|
.wl-avatar {
|
||||||
|
border-radius: var(--waline-avatar-radius) !important;
|
||||||
|
border: 2px solid var(--waline-border-color) !important;
|
||||||
|
box-shadow: var(--waline-box-shadow) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 回复引用框 ========== */
|
||||||
|
.wl-quote {
|
||||||
|
border-left-color: var(--waline-border-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 预览区域 ========== */
|
||||||
|
.wl-preview .wl-content {
|
||||||
|
background: var(--waline-bg-color-light) !important;
|
||||||
|
border-radius: var(--waline-btn-radius) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 反应区域 ========== */
|
||||||
|
.wl-reaction-title {
|
||||||
|
color: var(--waline-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-reaction-item.active .wl-reaction-text {
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-reaction-votes {
|
||||||
|
border-color: var(--waline-theme-color) !important;
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-reaction-item.active .wl-reaction-votes {
|
||||||
|
background: var(--waline-theme-color) !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 加载动画 ========== */
|
||||||
|
.wl-loading svg {
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 滚动条样式 ========== */
|
||||||
|
[data-waline] ::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-waline] ::-webkit-scrollbar-track-piece {
|
||||||
|
background: var(--waline-bg-color-light);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-waline] ::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--waline-theme-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-waline] ::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--waline-active-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 链接样式 ========== */
|
||||||
|
[data-waline] a {
|
||||||
|
color: var(--waline-theme-color) !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-waline] a:hover {
|
||||||
|
color: var(--waline-active-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 代码块样式 ========== */
|
||||||
|
.wl-content pre,
|
||||||
|
.wl-content pre[class*="language-"] {
|
||||||
|
background: var(--waline-code-bg-color) !important;
|
||||||
|
border-radius: var(--waline-btn-radius) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 移动端适配 ========== */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.wl-panel {
|
||||||
|
border-radius: var(--radius-md, 0.5rem) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-btn {
|
||||||
|
font-size: 0.8em !important;
|
||||||
|
padding: 0.4em 0.8em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wl-editor {
|
||||||
|
min-height: 6em !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user