chore: layout
This commit is contained in:
parent
b9561ad2d0
commit
230dca64ca
27 changed files with 446 additions and 339 deletions
|
@ -8,10 +8,19 @@ import remarkEmoji from 'remark-emoji'
|
|||
import remarkMath from 'remark-math'
|
||||
import remarkToc from 'remark-toc'
|
||||
|
||||
import react from '@astrojs/react'
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: 'https://astro-micro-academic.vercel.app',
|
||||
integrations: [tailwind(), sitemap(), mdx()],
|
||||
integrations: [
|
||||
tailwind({
|
||||
applyBaseStyles: false,
|
||||
}),
|
||||
sitemap(),
|
||||
mdx(),
|
||||
react(),
|
||||
],
|
||||
markdown: {
|
||||
shikiConfig: {
|
||||
theme: 'css-variables',
|
||||
|
@ -19,5 +28,11 @@ export default defineConfig({
|
|||
rehypePlugins: [rehypeHeadingIds, rehypeKatex],
|
||||
remarkPlugins: [remarkToc, remarkMath, remarkEmoji],
|
||||
},
|
||||
server: { port: 1234, host: true },
|
||||
server: {
|
||||
port: 1234,
|
||||
host: true,
|
||||
},
|
||||
devToolbar: {
|
||||
enabled: false,
|
||||
},
|
||||
})
|
||||
|
|
20
components.json
Normal file
20
components.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.ts",
|
||||
"css": "src/styles/global.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
}
|
||||
}
|
208
package-lock.json
generated
208
package-lock.json
generated
|
@ -11,20 +11,29 @@
|
|||
"@astrojs/check": "^0.7.0",
|
||||
"@astrojs/markdown-remark": "^5.2.0",
|
||||
"@astrojs/mdx": "^3.1.2",
|
||||
"@astrojs/react": "^3.6.2",
|
||||
"@astrojs/rss": "^4.0.7",
|
||||
"@astrojs/sitemap": "^3.1.6",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@fontsource/geist-mono": "^5.0.3",
|
||||
"@fontsource/geist-sans": "^5.0.3",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"astro": "^4.11.3",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.439.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"rehype-katex": "^7.0.0",
|
||||
"remark-emoji": "^5.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"remark-toc": "^9.0.0",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwind-merge": "^2.5.2",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -222,6 +231,24 @@
|
|||
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/react": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/react/-/react-3.6.2.tgz",
|
||||
"integrity": "sha512-fK29lYI7zK/KG4ZBy956x4dmauZcZ18osFkuyGa8r3gmmCQa2NZ9XNu9WaVYEUm0j89f4Gii4tbxLoyM8nk2MA==",
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"ultrahtml": "^1.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.50 || ^18.0.21",
|
||||
"@types/react-dom": "^17.0.17 || ^18.0.6",
|
||||
"react": "^17.0.2 || ^18.0.0 || ^19.0.0-beta",
|
||||
"react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0-beta"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/rss": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-4.0.7.tgz",
|
||||
|
@ -593,6 +620,34 @@
|
|||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-jsx-self": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz",
|
||||
"integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-jsx-source": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz",
|
||||
"integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
|
||||
|
@ -1705,6 +1760,14 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-icons": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz",
|
||||
"integrity": "sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.x || ^17.x || ^18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz",
|
||||
|
@ -2082,6 +2145,28 @@
|
|||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
||||
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz",
|
||||
"integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "18.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz",
|
||||
"integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/sax": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz",
|
||||
|
@ -2108,6 +2193,24 @@
|
|||
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz",
|
||||
"integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.24.5",
|
||||
"@babel/plugin-transform-react-jsx-self": "^7.24.5",
|
||||
"@babel/plugin-transform-react-jsx-source": "^7.24.1",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"react-refresh": "^0.14.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^4.2.0 || ^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/kit": {
|
||||
"version": "2.4.0-alpha.15",
|
||||
"resolved": "https://registry.npmjs.org/@volar/kit/-/kit-2.4.0-alpha.15.tgz",
|
||||
|
@ -2832,6 +2935,25 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/class-variance-authority": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz",
|
||||
"integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==",
|
||||
"dependencies": {
|
||||
"clsx": "2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://joebell.co.uk"
|
||||
}
|
||||
},
|
||||
"node_modules/class-variance-authority/node_modules/clsx": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
|
||||
"integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-boxes": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz",
|
||||
|
@ -2980,7 +3102,6 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
@ -3121,6 +3242,11 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
||||
|
@ -4619,6 +4745,17 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
|
@ -4628,6 +4765,14 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/lucide-react": {
|
||||
"version": "0.439.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.439.0.tgz",
|
||||
"integrity": "sha512-PafSWvDTpxdtNEndS2HIHxcNAbd54OaqSYJO90/b63rab2HWYqDbH194j0i82ZFdWOAcf0AHinRykXRRK2PJbw==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.10",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz",
|
||||
|
@ -6693,6 +6838,37 @@
|
|||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.14.2",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
|
@ -7161,6 +7337,14 @@
|
|||
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/section-matter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
|
||||
|
@ -7586,10 +7770,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.4.0.tgz",
|
||||
"integrity": "sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==",
|
||||
"license": "MIT",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz",
|
||||
"integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/dcastil"
|
||||
|
@ -7632,6 +7815,14 @@
|
|||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss-animate": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz",
|
||||
"integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==",
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=3.0.0 || insiders"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss/node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
|
@ -7801,6 +7992,11 @@
|
|||
"semver": "^7.3.8"
|
||||
}
|
||||
},
|
||||
"node_modules/ultrahtml": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.3.tgz",
|
||||
"integrity": "sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg=="
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
|
|
11
package.json
11
package.json
|
@ -15,20 +15,29 @@
|
|||
"@astrojs/check": "^0.7.0",
|
||||
"@astrojs/markdown-remark": "^5.2.0",
|
||||
"@astrojs/mdx": "^3.1.2",
|
||||
"@astrojs/react": "^3.6.2",
|
||||
"@astrojs/rss": "^4.0.7",
|
||||
"@astrojs/sitemap": "^3.1.6",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@fontsource/geist-mono": "^5.0.3",
|
||||
"@fontsource/geist-sans": "^5.0.3",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"astro": "^4.11.3",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.439.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"rehype-katex": "^7.0.0",
|
||||
"remark-emoji": "^5.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"remark-toc": "^9.0.0",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwind-merge": "^2.5.2",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
---
|
||||
|
||||
<div class="mx-auto max-w-screen-md px-3"><slot /></div>
|
||||
<div class="mx-auto max-w-screen-md"><slot /></div>
|
||||
|
|
|
@ -5,7 +5,7 @@ import BackToTop from '@components/BackToTop.astro'
|
|||
import SocialIcons from './SocialIcons.astro'
|
||||
---
|
||||
|
||||
<footer class="animate">
|
||||
<footer>
|
||||
<Container>
|
||||
<div class="my-2 flex justify-between">
|
||||
<SocialIcons icon_size={'text-xl'} />
|
||||
|
@ -16,78 +16,6 @@ import SocialIcons from './SocialIcons.astro'
|
|||
© {new Date().getFullYear()} • {SITE.TITLE} 👀<br />
|
||||
Built with Astro
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
<button
|
||||
id="light-theme-button"
|
||||
aria-label="Light theme"
|
||||
class="group flex size-9 items-center justify-center rounded border border-black/15 hover:bg-black/5 focus-visible:bg-black/5 dark:border-white/20 dark:hover:bg-white/5 dark:focus-visible:bg-white/5"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="transition-colors duration-300 ease-in-out group-hover:animate-pulse group-hover:stroke-black group-focus-visible:animate-pulse group-focus-visible:stroke-black group-hover:dark:stroke-white dark:group-focus-visible:stroke-white"
|
||||
>
|
||||
<circle cx="12" cy="12" r="5"></circle>
|
||||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
id="dark-theme-button"
|
||||
aria-label="Dark theme"
|
||||
class="group flex size-9 items-center justify-center rounded border border-black/15 hover:bg-black/5 focus-visible:bg-black/5 dark:border-white/20 dark:hover:bg-white/5 dark:focus-visible:bg-white/5"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="transition-colors duration-300 ease-in-out group-hover:animate-pulse group-hover:stroke-black group-focus-visible:animate-pulse group-focus-visible:stroke-black group-hover:dark:stroke-white dark:group-focus-visible:stroke-white"
|
||||
>
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
id="system-theme-button"
|
||||
aria-label="System theme"
|
||||
class="group flex size-9 items-center justify-center rounded border border-black/15 hover:bg-black/5 focus-visible:bg-black/5 dark:border-white/20 dark:hover:bg-white/5 dark:focus-visible:bg-white/5"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="transition-colors duration-300 ease-in-out group-hover:animate-pulse group-hover:stroke-black group-focus-visible:animate-pulse group-focus-visible:stroke-black group-hover:dark:stroke-white dark:group-focus-visible:stroke-white"
|
||||
>
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
|
||||
<line x1="8" y1="21" x2="16" y2="21"></line>
|
||||
<line x1="12" y1="17" x2="12" y2="21"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</footer>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
import '../styles/global.css'
|
||||
import { ViewTransitions } from 'astro:transitions'
|
||||
|
||||
import '@fontsource/geist-sans'
|
||||
import '@fontsource/geist-mono'
|
||||
|
@ -16,46 +15,31 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site)
|
|||
const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props
|
||||
---
|
||||
|
||||
<!-- Global Metadata -->
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link
|
||||
rel="icon"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🍄</text></svg>"
|
||||
/>
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href={canonicalURL} />
|
||||
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>{title}</title>
|
||||
<meta name="title" content={title} />
|
||||
<meta name="description" content={description} />
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={Astro.url} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={new URL(image, Astro.url)} />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content={Astro.url} />
|
||||
<meta property="twitter:title" content={title} />
|
||||
<meta property="twitter:description" content={description} />
|
||||
<meta property="twitter:image" content={new URL(image, Astro.url)} />
|
||||
|
||||
<ViewTransitions />
|
||||
|
||||
<script is:inline>
|
||||
function init() {
|
||||
preloadTheme()
|
||||
onScroll()
|
||||
animate()
|
||||
updateThemeButtons()
|
||||
addCopyCodeButtons()
|
||||
|
||||
const backToTop = document.getElementById('back-to-top')
|
||||
|
@ -64,77 +48,9 @@ const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props
|
|||
const backToPrev = document.getElementById('back-to-prev')
|
||||
backToPrev?.addEventListener('click', () => window.history.back())
|
||||
|
||||
const lightThemeButton = document.getElementById('light-theme-button')
|
||||
lightThemeButton?.addEventListener('click', () => {
|
||||
localStorage.setItem('theme', 'light')
|
||||
toggleTheme(false)
|
||||
updateThemeButtons()
|
||||
})
|
||||
|
||||
const darkThemeButton = document.getElementById('dark-theme-button')
|
||||
darkThemeButton?.addEventListener('click', () => {
|
||||
localStorage.setItem('theme', 'dark')
|
||||
toggleTheme(true)
|
||||
updateThemeButtons()
|
||||
})
|
||||
|
||||
const systemThemeButton = document.getElementById('system-theme-button')
|
||||
systemThemeButton?.addEventListener('click', () => {
|
||||
localStorage.setItem('theme', 'system')
|
||||
toggleTheme(window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
updateThemeButtons()
|
||||
})
|
||||
|
||||
window
|
||||
.matchMedia('(prefers-color-scheme: dark)')
|
||||
.addEventListener('change', (event) => {
|
||||
if (localStorage.theme === 'system') {
|
||||
toggleTheme(event.matches)
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener('scroll', onScroll)
|
||||
}
|
||||
|
||||
function updateThemeButtons() {
|
||||
const theme = localStorage.getItem('theme')
|
||||
const lightThemeButton = document.getElementById('light-theme-button')
|
||||
const darkThemeButton = document.getElementById('dark-theme-button')
|
||||
const systemThemeButton = document.getElementById('system-theme-button')
|
||||
|
||||
function removeActiveButtonTheme(button) {
|
||||
button?.classList.remove('bg-black/5')
|
||||
button?.classList.remove('dark:bg-white/5')
|
||||
}
|
||||
|
||||
function addActiveButtonTheme(button) {
|
||||
button?.classList.add('bg-black/5')
|
||||
button?.classList.add('dark:bg-white/5')
|
||||
}
|
||||
|
||||
removeActiveButtonTheme(lightThemeButton)
|
||||
removeActiveButtonTheme(darkThemeButton)
|
||||
removeActiveButtonTheme(systemThemeButton)
|
||||
|
||||
if (theme === 'light') {
|
||||
addActiveButtonTheme(lightThemeButton)
|
||||
} else if (theme === 'dark') {
|
||||
addActiveButtonTheme(darkThemeButton)
|
||||
} else {
|
||||
addActiveButtonTheme(systemThemeButton)
|
||||
}
|
||||
}
|
||||
|
||||
function animate() {
|
||||
const animateElements = document.querySelectorAll('.animate')
|
||||
|
||||
animateElements.forEach((element, index) => {
|
||||
setTimeout(() => {
|
||||
element.classList.add('show')
|
||||
}, index * 100)
|
||||
})
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
if (window.scrollY > 0) {
|
||||
document.documentElement.classList.add('scrolled')
|
||||
|
@ -151,44 +67,6 @@ const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props
|
|||
})
|
||||
}
|
||||
|
||||
function toggleTheme(dark) {
|
||||
const css = document.createElement('style')
|
||||
|
||||
css.appendChild(
|
||||
document.createTextNode(
|
||||
`* {
|
||||
-webkit-transition: none !important;
|
||||
-moz-transition: none !important;
|
||||
-o-transition: none !important;
|
||||
-ms-transition: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
`,
|
||||
),
|
||||
)
|
||||
|
||||
document.head.appendChild(css)
|
||||
|
||||
if (dark) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
|
||||
window.getComputedStyle(css).opacity
|
||||
document.head.removeChild(css)
|
||||
}
|
||||
|
||||
function preloadTheme() {
|
||||
const userTheme = localStorage.theme
|
||||
|
||||
if (userTheme === 'light' || userTheme === 'dark') {
|
||||
toggleTheme(true) // set default to dark theme
|
||||
} else {
|
||||
toggleTheme(window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
}
|
||||
}
|
||||
|
||||
function addCopyCodeButtons() {
|
||||
let copyButtonLabel = '📋'
|
||||
let codeBlocks = Array.from(document.querySelectorAll('pre'))
|
||||
|
@ -228,5 +106,4 @@ const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props
|
|||
|
||||
document.addEventListener('DOMContentLoaded', () => init())
|
||||
document.addEventListener('astro:after-swap', () => init())
|
||||
preloadTheme()
|
||||
</script>
|
||||
|
|
|
@ -2,33 +2,30 @@
|
|||
import Container from '@components/Container.astro'
|
||||
import Link from '@components/Link.astro'
|
||||
import { SITE } from '@consts'
|
||||
|
||||
const items = [
|
||||
{ href: '/blog', label: 'blog' },
|
||||
{ href: '/authors', label: 'authors' },
|
||||
{ href: '/about', label: 'about' },
|
||||
{ href: '/tags', label: 'tags' },
|
||||
]
|
||||
---
|
||||
|
||||
<header transition:persist>
|
||||
<header class="sticky top-0 z-10" transition:persist>
|
||||
<Container>
|
||||
<div class="flex flex-wrap justify-between gap-y-2">
|
||||
<div class="flex items-center justify-between py-4">
|
||||
<Link href="/" underline={false}>
|
||||
<div class="font-semibold">
|
||||
{SITE.TITLE} 🍄
|
||||
</div>
|
||||
{SITE.TITLE}<span class="ml-1">🍄</span>
|
||||
</Link>
|
||||
<nav class="flex items-center gap-1 text-sm">
|
||||
<Link href="/blog">blog</Link>
|
||||
<span>
|
||||
{`/`}
|
||||
</span>
|
||||
<Link href="/authors">authors</Link>
|
||||
<span>
|
||||
{`/`}
|
||||
</span>
|
||||
<Link href="/about">about</Link>
|
||||
<span>
|
||||
{`/`}
|
||||
</span>
|
||||
<Link href="/tags">tags</Link>
|
||||
<span>
|
||||
{`/`}
|
||||
</span>
|
||||
<nav class="flex items-center space-x-1 text-sm">
|
||||
{
|
||||
items.map((item, index) => (
|
||||
<>
|
||||
<Link href={item.href}>{item.label}</Link>
|
||||
{index < items.length - 1 && <span class="text-gray-400">/</span>}
|
||||
</>
|
||||
))
|
||||
}
|
||||
</nav>
|
||||
</div>
|
||||
</Container>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { Image } from "astro:assets";
|
||||
import type { CollectionEntry } from 'astro:content'
|
||||
import { Image } from 'astro:assets'
|
||||
|
||||
type Props = {
|
||||
member: CollectionEntry<"authors">;
|
||||
};
|
||||
member: CollectionEntry<'authors'>
|
||||
}
|
||||
|
||||
const { member } = Astro.props;
|
||||
const { name, avatar, bio } = member.data;
|
||||
const { member } = Astro.props
|
||||
const { name, avatar, bio } = member.data
|
||||
---
|
||||
|
||||
<div
|
||||
class="animate not-prose flex flex-col sm:flex-row size-full sm:items-center gap-4 overflow-hidden rounded-xl border border-foreground bg-background p-6 hover:bg-secondary"
|
||||
class="not-prose flex size-full flex-col gap-4 overflow-hidden rounded-xl border border-foreground bg-background p-6 hover:bg-secondary sm:flex-row sm:items-center"
|
||||
>
|
||||
<Image
|
||||
src={avatar}
|
||||
|
|
|
@ -27,10 +27,7 @@ function buildToc(headings: Heading[]) {
|
|||
}
|
||||
---
|
||||
|
||||
<details
|
||||
open
|
||||
class="animate rounded-lg border border-black/15 dark:border-white/20"
|
||||
>
|
||||
<details open class="rounded-lg border border-black/15 dark:border-white/20">
|
||||
<summary>Table of Contents</summary>
|
||||
<nav class="">
|
||||
<ul class="py-3">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: "enscribe"
|
||||
avatar: "https://gravatar.com/avatar/9bfdc4ec972793cf05cb91efce5f4aaaec2a0da1bf4ec34dad0913f1d845faf6.webp?size=256"
|
||||
bio: "d(-_-)b"
|
||||
website: "https://enscribe.dev"
|
||||
twitter: "enscry"
|
||||
github: "jktrn"
|
||||
---
|
||||
name: 'enscribe'
|
||||
avatar: 'https://gravatar.com/avatar/9bfdc4ec972793cf05cb91efce5f4aaaec2a0da1bf4ec34dad0913f1d845faf6.webp?size=256'
|
||||
bio: 'd(-_-)b'
|
||||
website: 'https://enscribe.dev'
|
||||
twitter: 'enscry'
|
||||
github: 'jktrn'
|
||||
---
|
||||
|
|
|
@ -62,7 +62,7 @@ When developing you can continue to use `npm run dev` and Pagefind will use the
|
|||
|
||||
## UI enhancements 🎨
|
||||
|
||||
- Elements are styled and animate on focus
|
||||
- Elements are styled and on focus
|
||||
- Increased contrast in light mode
|
||||
- Active theme is indicated by theme buttons
|
||||
- Separate syntax highlight themes for light and dark mode
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { defineCollection, reference, z } from "astro:content";
|
||||
import { defineCollection, reference, z } from 'astro:content'
|
||||
|
||||
const blog = defineCollection({
|
||||
type: "content",
|
||||
type: 'content',
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
|
@ -9,12 +9,12 @@ const blog = defineCollection({
|
|||
draft: z.boolean().optional(),
|
||||
|
||||
tags: z.array(z.string()).optional(),
|
||||
author: z.union([reference("authors"), z.string()]).optional(),
|
||||
author: z.union([reference('authors'), z.string()]).optional(),
|
||||
}),
|
||||
});
|
||||
})
|
||||
|
||||
const authors = defineCollection({
|
||||
type: "content",
|
||||
type: 'content',
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
avatar: z.string().url(),
|
||||
|
@ -26,6 +26,6 @@ const authors = defineCollection({
|
|||
mail: z.string().email().optional(),
|
||||
discord: z.string().optional(),
|
||||
}),
|
||||
});
|
||||
})
|
||||
|
||||
export const collections = { blog, authors };
|
||||
export const collections = { blog, authors }
|
||||
|
|
|
@ -4,6 +4,7 @@ import Header from '@components/Header.astro'
|
|||
import Footer from '@components/Footer.astro'
|
||||
import { SITE } from '@consts'
|
||||
import '../styles/katex.css'
|
||||
import { ViewTransitions } from 'astro:transitions'
|
||||
|
||||
type Props = {
|
||||
title: string
|
||||
|
@ -17,10 +18,13 @@ const { title, description } = Astro.props
|
|||
<html lang="en">
|
||||
<head>
|
||||
<Head title={`${title} | ${SITE.TITLE}`} description={description} />
|
||||
<ViewTransitions />
|
||||
</head>
|
||||
<body>
|
||||
<body
|
||||
class="box-border flex h-fit min-h-screen flex-col px-4 font-sans antialiased"
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<main class="flex-grow">
|
||||
<slot />
|
||||
</main>
|
||||
<Footer />
|
||||
|
|
|
@ -9,10 +9,10 @@ import { SITE } from '@consts'
|
|||
<Layout title="404" description={SITE.DESCRIPTION}>
|
||||
<Container>
|
||||
<div class="mt-16 grid place-items-center gap-3">
|
||||
<h4 class="animate text-2xl font-semibold text-black dark:text-white">
|
||||
<h4 class="text-2xl font-semibold text-black dark:text-white">
|
||||
404: Page not found
|
||||
</h4>
|
||||
<span class="animate">
|
||||
<span>
|
||||
<BackToPrevious href="/">Go to home page</BackToPrevious>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -8,8 +8,8 @@ import { Image } from 'astro:assets'
|
|||
<Layout title="About" description="About">
|
||||
<Container>
|
||||
<div class="space-y-10">
|
||||
<div class="animate font-semibold text-black dark:text-white">About</div>
|
||||
<section class="animate not-prose flex flex-col gap-4 text-justify">
|
||||
<div class="font-semibold text-black dark:text-white">About</div>
|
||||
<section class="not-prose flex flex-col gap-4 text-justify">
|
||||
<p class="text-justify">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores porro
|
||||
hic minima incidunt explicabo obcaecati consectetur consequuntur at
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
---
|
||||
import { type CollectionEntry, getCollection, getEntry } from "astro:content";
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import MemberCard from "@components/MemberCard.astro";
|
||||
import { type CollectionEntry, getCollection, getEntry } from 'astro:content'
|
||||
import Layout from '@layouts/Layout.astro'
|
||||
import MemberCard from '@components/MemberCard.astro'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const authors = await getCollection("authors");
|
||||
const authors = await getCollection('authors')
|
||||
return authors.map((member) => ({
|
||||
params: { slug: member.slug },
|
||||
props: { member },
|
||||
}));
|
||||
}))
|
||||
}
|
||||
|
||||
type Props = {
|
||||
member: CollectionEntry<"authors">;
|
||||
};
|
||||
member: CollectionEntry<'authors'>
|
||||
}
|
||||
|
||||
const { member } = Astro.props;
|
||||
const { member } = Astro.props
|
||||
|
||||
const allPosts = await getCollection("blog");
|
||||
const allPosts = await getCollection('blog')
|
||||
const memberPosts = allPosts
|
||||
.filter((post) => {
|
||||
if (typeof post.data.author === 'string') {
|
||||
return post.data.author === member.data.name && !post.data.draft;
|
||||
return post.data.author === member.data.name && !post.data.draft
|
||||
} else if (post.data.author && 'slug' in post.data.author) {
|
||||
return post.data.author.slug === member.slug && !post.data.draft;
|
||||
return post.data.author.slug === member.slug && !post.data.draft
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
})
|
||||
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
|
||||
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
|
||||
---
|
||||
|
||||
<Layout
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import MemberCard from "@components/MemberCard.astro";
|
||||
import { getCollection } from 'astro:content'
|
||||
import Layout from '@layouts/Layout.astro'
|
||||
import MemberCard from '@components/MemberCard.astro'
|
||||
|
||||
const authors = await getCollection("authors");
|
||||
const authors = await getCollection('authors')
|
||||
---
|
||||
|
||||
<Layout title="authors" description="authors">
|
||||
<section>
|
||||
<ul
|
||||
class="animate not-prose grid grid-cols-1 gap-4 lg:grid-cols-2 xl:grid-cols-3"
|
||||
>
|
||||
<ul class="not-prose grid grid-cols-1 gap-4 lg:grid-cols-2 xl:grid-cols-3">
|
||||
{
|
||||
authors.map((member) => (
|
||||
<li>
|
||||
|
|
|
@ -53,7 +53,7 @@ const { Content, headings } = await post.render()
|
|||
<BackToPrevious href="/blog">Back to blog</BackToPrevious>
|
||||
</div>
|
||||
<div class="my-10 space-y-4">
|
||||
<div class="animate flex items-center gap-1.5">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="font-base text-sm">
|
||||
<FormattedDate date={post.data.date} />
|
||||
</div>
|
||||
|
@ -62,7 +62,7 @@ const { Content, headings } = await post.render()
|
|||
{readingTime(post.body)}
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="animate text-4xl font-semibold text-black dark:text-white">
|
||||
<h1 class="text-4xl font-semibold text-black dark:text-white">
|
||||
{post.data.title}
|
||||
</h1>
|
||||
<div class="font-base text-sm">
|
||||
|
|
|
@ -30,7 +30,7 @@ const years = Object.keys(posts).sort((a, b) => parseInt(b) - parseInt(a))
|
|||
<div class="space-y-4">
|
||||
{
|
||||
years.map((year) => (
|
||||
<section class="animate space-y-4">
|
||||
<section class="space-y-4">
|
||||
<div class="font-semibold text-black dark:text-white">{year}</div>
|
||||
<div>
|
||||
<ul class="not-prose flex flex-col gap-4">
|
||||
|
|
|
@ -16,7 +16,7 @@ const blog = (await getCollection('blog'))
|
|||
|
||||
<Layout title="Home" description="Home">
|
||||
<Container>
|
||||
<section class="animate space-y-6">
|
||||
<section class="space-y-6">
|
||||
<div class="flex flex-wrap items-center justify-between gap-y-2">
|
||||
<h2 class="font-semibold text-black dark:text-white">Latest posts</h2>
|
||||
<Link href="/blog"> See all posts </Link>
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import rss from '@astrojs/rss'
|
||||
import { SITE } from '@consts'
|
||||
import { getCollection } from 'astro:content'
|
||||
import type { APIContext } from 'astro'
|
||||
import { getCollection } from 'astro:content'
|
||||
|
||||
export async function GET(context: APIContext) {
|
||||
try {
|
||||
const blog = (await getCollection('blog')).filter(
|
||||
(post) => !post.data.draft
|
||||
(post) => !post.data.draft,
|
||||
)
|
||||
|
||||
// Filter posts by tag 'rss-feed'
|
||||
const filteredBlogs = blog.filter(
|
||||
(post) => post.data.tags && post.data.tags.includes('rss-feed')
|
||||
(post) => post.data.tags && post.data.tags.includes('rss-feed'),
|
||||
)
|
||||
|
||||
// Sort posts by date
|
||||
const items = [...filteredBlogs].sort(
|
||||
(a, b) =>
|
||||
new Date(b.data.date).valueOf() - new Date(a.data.date).valueOf()
|
||||
new Date(b.data.date).valueOf() - new Date(a.data.date).valueOf(),
|
||||
)
|
||||
|
||||
// Return RSS feed
|
||||
|
|
|
@ -36,7 +36,7 @@ export async function getStaticPaths() {
|
|||
>
|
||||
<Container>
|
||||
<div class="space-y-10">
|
||||
<div class="animate font-semibold text-black dark:text-white">
|
||||
<div class="font-semibold text-black dark:text-white">
|
||||
Tag: <span
|
||||
class="mx-2 rounded-full bg-orange-300 px-3 py-2 transition-colors duration-300 ease-in-out hover:bg-cyan-200 dark:bg-orange-500 dark:hover:bg-cyan-500"
|
||||
>#{tag}</span
|
||||
|
@ -45,7 +45,7 @@ export async function getStaticPaths() {
|
|||
<div class="space-y-4">
|
||||
{
|
||||
posts.map((post) => (
|
||||
<section class="animate space-y-4">
|
||||
<section class="space-y-4">
|
||||
<div>
|
||||
<ul class="not-prose flex flex-col gap-4">
|
||||
<li>
|
||||
|
|
|
@ -14,7 +14,7 @@ const tags = blog
|
|||
<Layout title="Tags" description="Tags">
|
||||
<Container>
|
||||
<div class="space-y-10">
|
||||
<div class="animate font-semibold text-black dark:text-white">Tags</div>
|
||||
<div class="font-semibold text-black dark:text-white">Tags</div>
|
||||
<ul class="flex flex-wrap">
|
||||
{
|
||||
tags.map((tag) => (
|
||||
|
|
|
@ -2,42 +2,6 @@
|
|||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
html {
|
||||
overflow-y: auto;
|
||||
color-scheme: light;
|
||||
scroll-padding-top: 100px;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
@apply size-full;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply font-sans antialiased;
|
||||
@apply flex flex-col;
|
||||
@apply bg-neutral-300 dark:bg-slate-900;
|
||||
@apply text-black/75 dark:text-white/75;
|
||||
}
|
||||
|
||||
header {
|
||||
@apply fixed left-0 right-0 top-0 z-50 py-6;
|
||||
@apply bg-neutral-100/75 dark:bg-neutral-900/75;
|
||||
@apply saturate-200 backdrop-blur-sm;
|
||||
}
|
||||
|
||||
main {
|
||||
@apply flex-1 py-32;
|
||||
}
|
||||
|
||||
footer {
|
||||
@apply py-6 text-sm;
|
||||
}
|
||||
|
||||
article {
|
||||
@apply prose prose-neutral max-w-full dark:prose-invert prose-img:mx-auto prose-img:my-auto;
|
||||
@apply prose-headings:font-semibold;
|
||||
|
@ -61,15 +25,6 @@ article {
|
|||
scrollbar-color: #1e293b #0f172a;
|
||||
}
|
||||
|
||||
.animate {
|
||||
@apply -translate-y-3 opacity-0;
|
||||
@apply transition-all duration-300 ease-out;
|
||||
}
|
||||
|
||||
.animate.show {
|
||||
@apply translate-y-0 opacity-100;
|
||||
}
|
||||
|
||||
html #back-to-top {
|
||||
@apply pointer-events-none opacity-0;
|
||||
}
|
||||
|
@ -123,3 +78,65 @@ pre {
|
|||
.copy-code:active {
|
||||
@apply scale-90 transition-transform;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 3.9%;
|
||||
--primary: 0 0% 9%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 0 0% 96.1%;
|
||||
--secondary-foreground: 0 0% 9%;
|
||||
--muted: 0 0% 96.1%;
|
||||
--muted-foreground: 0 0% 45.1%;
|
||||
--accent: 0 0% 96.1%;
|
||||
--accent-foreground: 0 0% 9%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 89.8%;
|
||||
--input: 0 0% 89.8%;
|
||||
--ring: 0 0% 3.9%;
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
.dark {
|
||||
--background: 0 0% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 0 0% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 0 0% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 0 0% 9%;
|
||||
--secondary: 0 0% 14.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 14.9%;
|
||||
--muted-foreground: 0 0% 63.9%;
|
||||
--accent: 0 0% 14.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 14.9%;
|
||||
--input: 0 0% 14.9%;
|
||||
--ring: 0 0% 83.1%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { Config } from 'tailwindcss'
|
|||
import defaultTheme from 'tailwindcss/defaultTheme'
|
||||
|
||||
const config: Config = {
|
||||
darkMode: 'class',
|
||||
darkMode: ['class', 'class'],
|
||||
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
|
||||
theme: {
|
||||
extend: {
|
||||
|
@ -10,9 +10,56 @@ const config: Config = {
|
|||
sans: ['Geist Sans', ...defaultTheme.fontFamily.sans],
|
||||
mono: ['Geist Mono', ...defaultTheme.fontFamily.mono],
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)',
|
||||
},
|
||||
colors: {
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))',
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))',
|
||||
},
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))',
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))',
|
||||
},
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
chart: {
|
||||
'1': 'hsl(var(--chart-1))',
|
||||
'2': 'hsl(var(--chart-2))',
|
||||
'3': 'hsl(var(--chart-3))',
|
||||
'4': 'hsl(var(--chart-4))',
|
||||
'5': 'hsl(var(--chart-5))',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require('@tailwindcss/typography')],
|
||||
plugins: [require('@tailwindcss/typography'), require('tailwindcss-animate')],
|
||||
}
|
||||
|
||||
export default config
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "react"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue