chore: cleanup, shadcn
This commit is contained in:
parent
230dca64ca
commit
ea68d4f02f
38 changed files with 1073 additions and 1378 deletions
668
package-lock.json
generated
668
package-lock.json
generated
|
@ -17,7 +17,9 @@
|
|||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@fontsource/geist-mono": "^5.0.3",
|
||||
"@fontsource/geist-sans": "^5.0.3",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"astro": "^4.11.3",
|
||||
|
@ -1130,6 +1132,40 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz",
|
||||
"integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==",
|
||||
"dependencies": {
|
||||
"@floating-ui/utils": "^0.2.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "1.6.10",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz",
|
||||
"integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.6.0",
|
||||
"@floating-ui/utils": "^0.2.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/react-dom": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz",
|
||||
"integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/utils": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz",
|
||||
"integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA=="
|
||||
},
|
||||
"node_modules/@fontsource/geist-mono": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/geist-mono/-/geist-mono-5.0.3.tgz",
|
||||
|
@ -1760,6 +1796,192 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz",
|
||||
"integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA=="
|
||||
},
|
||||
"node_modules/@radix-ui/react-arrow": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz",
|
||||
"integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collection": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz",
|
||||
"integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.0",
|
||||
"@radix-ui/react-context": "1.1.0",
|
||||
"@radix-ui/react-primitive": "2.0.0",
|
||||
"@radix-ui/react-slot": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
|
||||
"integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-context": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz",
|
||||
"integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-direction": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
|
||||
"integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz",
|
||||
"integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.0",
|
||||
"@radix-ui/react-compose-refs": "1.1.0",
|
||||
"@radix-ui/react-primitive": "2.0.0",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-escape-keydown": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dropdown-menu": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz",
|
||||
"integrity": "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.0",
|
||||
"@radix-ui/react-compose-refs": "1.1.0",
|
||||
"@radix-ui/react-context": "1.1.0",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
"@radix-ui/react-menu": "2.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.0",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-guards": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz",
|
||||
"integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-scope": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz",
|
||||
"integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.0",
|
||||
"@radix-ui/react-primitive": "2.0.0",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"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",
|
||||
|
@ -1768,6 +1990,309 @@
|
|||
"react": "^16.x || ^17.x || ^18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-id": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
|
||||
"integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-menu": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.1.tgz",
|
||||
"integrity": "sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.0",
|
||||
"@radix-ui/react-collection": "1.1.0",
|
||||
"@radix-ui/react-compose-refs": "1.1.0",
|
||||
"@radix-ui/react-context": "1.1.0",
|
||||
"@radix-ui/react-direction": "1.1.0",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.0",
|
||||
"@radix-ui/react-focus-guards": "1.1.0",
|
||||
"@radix-ui/react-focus-scope": "1.1.0",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
"@radix-ui/react-popper": "1.2.0",
|
||||
"@radix-ui/react-portal": "1.1.1",
|
||||
"@radix-ui/react-presence": "1.1.0",
|
||||
"@radix-ui/react-primitive": "2.0.0",
|
||||
"@radix-ui/react-roving-focus": "1.1.0",
|
||||
"@radix-ui/react-slot": "1.1.0",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"aria-hidden": "^1.1.1",
|
||||
"react-remove-scroll": "2.5.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popper": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz",
|
||||
"integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^2.0.0",
|
||||
"@radix-ui/react-arrow": "1.1.0",
|
||||
"@radix-ui/react-compose-refs": "1.1.0",
|
||||
"@radix-ui/react-context": "1.1.0",
|
||||
"@radix-ui/react-primitive": "2.0.0",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0",
|
||||
"@radix-ui/react-use-rect": "1.1.0",
|
||||
"@radix-ui/react-use-size": "1.1.0",
|
||||
"@radix-ui/rect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-portal": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz",
|
||||
"integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.0.0",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-presence": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz",
|
||||
"integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.0",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
|
||||
"integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-roving-focus": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz",
|
||||
"integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.0",
|
||||
"@radix-ui/react-collection": "1.1.0",
|
||||
"@radix-ui/react-compose-refs": "1.1.0",
|
||||
"@radix-ui/react-context": "1.1.0",
|
||||
"@radix-ui/react-direction": "1.1.0",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
"@radix-ui/react-primitive": "2.0.0",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
|
||||
"integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-callback-ref": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
|
||||
"integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-controllable-state": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
|
||||
"integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-escape-keydown": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
|
||||
"integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-layout-effect": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",
|
||||
"integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-rect": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz",
|
||||
"integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==",
|
||||
"dependencies": {
|
||||
"@radix-ui/rect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-size": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz",
|
||||
"integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/rect": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",
|
||||
"integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg=="
|
||||
},
|
||||
"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",
|
||||
|
@ -2444,6 +2969,17 @@
|
|||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/aria-hidden": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz",
|
||||
"integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/aria-query": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
||||
|
@ -3296,6 +3832,11 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-node-es": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
|
||||
},
|
||||
"node_modules/deterministic-object-hash": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz",
|
||||
|
@ -3792,6 +4333,14 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/get-nonce": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
||||
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
|
||||
|
@ -4242,6 +4791,14 @@
|
|||
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-alphabetical": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
|
||||
|
@ -6869,6 +7426,73 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz",
|
||||
"integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==",
|
||||
"dependencies": {
|
||||
"react-remove-scroll-bar": "^2.3.4",
|
||||
"react-style-singleton": "^2.2.1",
|
||||
"tslib": "^2.1.0",
|
||||
"use-callback-ref": "^1.3.0",
|
||||
"use-sidecar": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll-bar": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz",
|
||||
"integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==",
|
||||
"dependencies": {
|
||||
"react-style-singleton": "^2.2.1",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-style-singleton": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
|
||||
"integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
|
||||
"dependencies": {
|
||||
"get-nonce": "^1.0.0",
|
||||
"invariant": "^2.2.4",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
|
@ -7949,8 +8573,7 @@
|
|||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
|
||||
"license": "0BSD",
|
||||
"optional": true
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "2.19.0",
|
||||
|
@ -8196,6 +8819,47 @@
|
|||
"browserslist": ">= 4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-callback-ref": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz",
|
||||
"integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/use-sidecar": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
|
||||
"integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==",
|
||||
"dependencies": {
|
||||
"detect-node-es": "^1.1.0",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@fontsource/geist-mono": "^5.0.3",
|
||||
"@fontsource/geist-sans": "^5.0.3",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"astro": "^4.11.3",
|
||||
|
|
|
@ -12,7 +12,7 @@ const { entry } = Astro.props as {
|
|||
|
||||
<a
|
||||
href={`/${entry.collection}/${entry.slug}`}
|
||||
class="not-prose group relative flex flex-nowrap rounded-lg border border-black/15 px-4 py-3 pr-10 transition-colors duration-300 ease-in-out hover:bg-black/5 hover:text-black focus-visible:bg-black/5 focus-visible:text-black dark:border-white/20 dark:hover:bg-white/5 dark:hover:text-white dark:focus-visible:bg-white/5 dark:focus-visible:text-white"
|
||||
class="not-prose group relative flex flex-nowrap rounded-lg border px-4 py-3 pr-10 transition-colors duration-300 ease-in-out"
|
||||
>
|
||||
<div class="flex flex-1 flex-col truncate">
|
||||
<div class="font-semibold">
|
||||
|
@ -32,11 +32,11 @@ const { entry } = Astro.props as {
|
|||
y1="12"
|
||||
x2="19"
|
||||
y2="12"
|
||||
class="translate-x-3 scale-x-0 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-hover:scale-x-100 group-focus-visible:translate-x-0 group-focus-visible:scale-x-100"
|
||||
class="translate-x-3 scale-x-0 transition-transform duration-300 ease-in-out group-focus-visible:translate-x-0 group-focus-visible:scale-x-100"
|
||||
></line>
|
||||
<polyline
|
||||
points="12 5 19 12 12 19"
|
||||
class="-translate-x-1 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-focus-visible:translate-x-0"
|
||||
class="-translate-x-1 transition-transform duration-300 ease-in-out group-focus-visible:translate-x-0"
|
||||
></polyline>
|
||||
</svg>
|
||||
</a>
|
||||
|
|
|
@ -8,7 +8,7 @@ const { href } = Astro.props
|
|||
|
||||
<a
|
||||
href={href}
|
||||
class="not-prose group relative flex w-fit flex-nowrap rounded border border-black/15 py-1.5 pl-7 pr-3 transition-colors duration-300 ease-in-out hover:bg-black/5 hover:text-black focus-visible:bg-black/5 focus-visible:text-black dark:border-white/20 dark:hover:bg-white/5 dark:hover:text-white dark:focus-visible:bg-white/5 dark:focus-visible:text-white"
|
||||
class="not-prose group relative flex w-fit flex-nowrap rounded border py-1.5 pl-7 pr-3 transition-colors duration-300 ease-in-out"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -20,11 +20,11 @@ const { href } = Astro.props
|
|||
y1="12"
|
||||
x2="19"
|
||||
y2="12"
|
||||
class="translate-x-2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-hover:scale-x-100 group-focus-visible:translate-x-0 group-focus-visible:scale-x-100"
|
||||
class="translate-x-2 scale-x-0 transition-transform duration-300 ease-in-out"
|
||||
></line>
|
||||
<polyline
|
||||
points="12 5 5 12 12 19"
|
||||
class="translate-x-1 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-focus-visible:translate-x-0"
|
||||
class="translate-x-1 transition-transform duration-300 ease-in-out"
|
||||
></polyline>
|
||||
</svg>
|
||||
<div class="text-sm">
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
|
||||
---
|
||||
|
||||
<button
|
||||
id="back-to-top"
|
||||
class="group relative flex w-fit flex-nowrap rounded border border-black/15 py-1.5 pl-8 pr-3 transition-colors duration-300 ease-in-out hover:bg-black/5 hover:text-black focus-visible:bg-black/5 focus-visible:text-black dark:border-white/20 dark:hover:bg-white/5 dark:hover:text-white dark:focus-visible:bg-white/5 dark:focus-visible:text-white"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
class="absolute left-2 top-1/2 size-4 -translate-y-1/2 rotate-90 fill-none stroke-current stroke-2"
|
||||
>
|
||||
<line
|
||||
x1="5"
|
||||
y1="12"
|
||||
x2="19"
|
||||
y2="12"
|
||||
class="translate-x-2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-hover:scale-x-100 group-focus-visible:translate-x-0 group-focus-visible:scale-x-100"
|
||||
></line>
|
||||
<polyline
|
||||
points="12 5 5 12 12 19"
|
||||
class="translate-x-1 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-focus-visible:translate-x-0"
|
||||
></polyline>
|
||||
</svg>
|
||||
<div class="text-sm">Back to top</div>
|
||||
</button>
|
|
@ -1,44 +0,0 @@
|
|||
---
|
||||
interface Component {
|
||||
type: 'default' | 'info' | 'warning' | 'error'
|
||||
}
|
||||
|
||||
const { type = 'default' } = Astro.props
|
||||
|
||||
let emoji = '💡'
|
||||
|
||||
if (type === 'info') {
|
||||
emoji = 'ℹ️'
|
||||
} else if (type === 'warning') {
|
||||
emoji = '⚠️'
|
||||
} else if (type === 'error') {
|
||||
emoji = '🚨'
|
||||
}
|
||||
---
|
||||
|
||||
<div class={`not-prose callout callout-${type}`}>
|
||||
<span class="emoji pointer-events-none select-none">{emoji}</span>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.callout {
|
||||
@apply relative my-4 flex rounded border border-orange-800 bg-orange-100 p-3 text-orange-950 dark:border-orange-200/20 dark:bg-orange-950/20 dark:text-orange-200;
|
||||
}
|
||||
|
||||
.emoji {
|
||||
@apply pr-3 text-xl;
|
||||
}
|
||||
|
||||
.callout-info {
|
||||
@apply border-blue-800 bg-blue-100 text-blue-950 dark:border-blue-200/20 dark:bg-blue-950/20 dark:text-blue-200;
|
||||
}
|
||||
|
||||
.callout-warning {
|
||||
@apply border-yellow-800 bg-yellow-100 text-yellow-950 dark:border-yellow-200/20 dark:bg-yellow-950/20 dark:text-yellow-200;
|
||||
}
|
||||
|
||||
.callout-error {
|
||||
@apply border-red-800 bg-red-100 text-red-950 dark:border-red-200/20 dark:bg-red-950/20 dark:text-red-200;
|
||||
}
|
||||
</style>
|
|
@ -1,21 +1,17 @@
|
|||
---
|
||||
import Container from '@components/Container.astro'
|
||||
import { SITE } from '@consts'
|
||||
import BackToTop from '@components/BackToTop.astro'
|
||||
import SocialIcons from './SocialIcons.astro'
|
||||
import { ModeToggle } from '@components/ui/mode-toggle'
|
||||
---
|
||||
|
||||
<footer>
|
||||
<footer class="py-8">
|
||||
<Container>
|
||||
<div class="my-2 flex justify-between">
|
||||
<SocialIcons icon_size={'text-xl'} />
|
||||
<BackToTop />
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
© {new Date().getFullYear()} • {SITE.TITLE} 👀<br />
|
||||
Built with Astro
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center space-x-4">
|
||||
<ModeToggle client:load />
|
||||
<p class="text-sm text-muted-foreground">© {new Date().getFullYear()} All rights reserved.</p>
|
||||
</div>
|
||||
<SocialIcons />
|
||||
</div>
|
||||
</Container>
|
||||
</footer>
|
||||
|
|
|
@ -4,6 +4,8 @@ import '../styles/global.css'
|
|||
import '@fontsource/geist-sans'
|
||||
import '@fontsource/geist-mono'
|
||||
|
||||
import { ViewTransitions } from 'astro:transitions'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
description: string
|
||||
|
@ -37,73 +39,40 @@ const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props
|
|||
<meta property="twitter:description" content={description} />
|
||||
<meta property="twitter:image" content={new URL(image, Astro.url)} />
|
||||
|
||||
<ViewTransitions />
|
||||
|
||||
<script is:inline>
|
||||
function init() {
|
||||
onScroll()
|
||||
addCopyCodeButtons()
|
||||
|
||||
const backToTop = document.getElementById('back-to-top')
|
||||
backToTop?.addEventListener('click', (event) => scrollToTop(event))
|
||||
|
||||
const backToPrev = document.getElementById('back-to-prev')
|
||||
backToPrev?.addEventListener('click', () => window.history.back())
|
||||
|
||||
document.addEventListener('scroll', onScroll)
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
if (window.scrollY > 0) {
|
||||
document.documentElement.classList.add('scrolled')
|
||||
} else {
|
||||
document.documentElement.classList.remove('scrolled')
|
||||
function setDarkMode(document) {
|
||||
const getThemePreference = () => {
|
||||
if (
|
||||
typeof localStorage !== 'undefined' &&
|
||||
localStorage.getItem('theme')
|
||||
) {
|
||||
return localStorage.getItem('theme')
|
||||
}
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? 'dark'
|
||||
: 'theme-light'
|
||||
}
|
||||
}
|
||||
const isDark = getThemePreference() === 'dark'
|
||||
document.documentElement.classList[isDark ? 'add' : 'remove']('dark')
|
||||
|
||||
function scrollToTop(event) {
|
||||
event.preventDefault()
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth',
|
||||
})
|
||||
}
|
||||
|
||||
function addCopyCodeButtons() {
|
||||
let copyButtonLabel = '📋'
|
||||
let codeBlocks = Array.from(document.querySelectorAll('pre'))
|
||||
|
||||
async function copyCode(codeBlock, copyButton) {
|
||||
const codeText = codeBlock.innerText
|
||||
const buttonText = copyButton.innerText
|
||||
const textToCopy = codeText.replace(buttonText, '')
|
||||
|
||||
await navigator.clipboard.writeText(textToCopy)
|
||||
copyButton.innerText = '✅'
|
||||
|
||||
setTimeout(() => {
|
||||
copyButton.innerText = copyButtonLabel
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
for (let codeBlock of codeBlocks) {
|
||||
const wrapper = document.createElement('div')
|
||||
wrapper.style.position = 'relative'
|
||||
|
||||
const copyButton = document.createElement('button')
|
||||
copyButton.innerText = copyButtonLabel
|
||||
copyButton.classList = 'copy-code'
|
||||
|
||||
codeBlock.setAttribute('tabindex', '0')
|
||||
codeBlock.appendChild(copyButton)
|
||||
|
||||
codeBlock.parentNode.insertBefore(wrapper, codeBlock)
|
||||
wrapper.appendChild(codeBlock)
|
||||
|
||||
copyButton?.addEventListener('click', async () => {
|
||||
await copyCode(codeBlock, copyButton)
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
const observer = new MutationObserver(() => {
|
||||
const isDark = document.documentElement.classList.contains('dark')
|
||||
localStorage.setItem('theme', isDark ? 'dark' : 'theme-light')
|
||||
})
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class'],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => init())
|
||||
document.addEventListener('astro:after-swap', () => init())
|
||||
setDarkMode(document)
|
||||
|
||||
document.addEventListener('astro:before-swap', (ev) => {
|
||||
// Pass the incoming document to set the theme on it
|
||||
setDarkMode(ev.newDocument)
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -15,7 +15,7 @@ const { href, external, underline = true, group = false, ...rest } = Astro.props
|
|||
href={href}
|
||||
target={external ? '_blank' : '_self'}
|
||||
class={cn(
|
||||
'inline-block decoration-black/30 hover:decoration-black/50 focus-visible:decoration-black/50 dark:decoration-white/30 dark:hover:decoration-white/50 dark:focus-visible:decoration-white/50 hover:text-cyan-500 focus-visible:text-black dark:hover:text-orange-500 dark:focus-visible:text-white transition-colors duration-300 ease-in-out',
|
||||
'inline-block transition-colors duration-300 ease-in-out',
|
||||
underline && 'underline underline-offset-[3px]',
|
||||
group && 'group',
|
||||
)}
|
||||
|
|
|
@ -11,7 +11,7 @@ const { name, avatar, bio } = member.data
|
|||
---
|
||||
|
||||
<div
|
||||
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"
|
||||
class="not-prose flex size-full flex-col gap-4 overflow-hidden rounded-xl border p-6 hover:bg-secondary sm:flex-row sm:items-center"
|
||||
>
|
||||
<Image
|
||||
src={avatar}
|
||||
|
|
|
@ -7,7 +7,7 @@ const { prevPost, nextPost } = Astro.props
|
|||
prevPost?.slug ? (
|
||||
<a
|
||||
href={`/blog/${prevPost?.slug}`}
|
||||
class="group relative flex flex-nowrap rounded-lg border border-black/15 px-4 py-3 pl-10 no-underline transition-colors duration-300 ease-in-out hover:bg-black/5 hover:text-black focus-visible:bg-black/5 focus-visible:text-black dark:border-white/20 dark:hover:bg-white/5 dark:hover:text-white dark:focus-visible:bg-white/5 dark:focus-visible:text-white"
|
||||
class="group relative flex flex-nowrap rounded-lg border px-4 py-3 pl-10 no-underline transition-colors duration-300 ease-in-out"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -19,11 +19,11 @@ const { prevPost, nextPost } = Astro.props
|
|||
y1="12"
|
||||
x2="19"
|
||||
y2="12"
|
||||
class="translate-x-3 scale-x-0 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-hover:scale-x-100 group-focus-visible:translate-x-0 group-focus-visible:scale-x-100"
|
||||
class="translate-x-3 scale-x-0 transition-transform duration-300 ease-in-out"
|
||||
/>
|
||||
<polyline
|
||||
points="12 5 5 12 12 19"
|
||||
class="translate-x-1 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-focus-visible:translate-x-0"
|
||||
class="translate-x-1 transition-transform duration-300 ease-in-out"
|
||||
/>
|
||||
</svg>
|
||||
<div class="flex items-center text-sm">{prevPost?.data.title}</div>
|
||||
|
@ -37,7 +37,7 @@ const { prevPost, nextPost } = Astro.props
|
|||
nextPost?.slug ? (
|
||||
<a
|
||||
href={`/blog/${nextPost?.slug}`}
|
||||
class="group relative flex flex-grow flex-row-reverse flex-nowrap rounded-lg border border-black/15 px-4 py-4 pr-10 no-underline transition-colors duration-300 ease-in-out hover:bg-black/5 hover:text-black focus-visible:bg-black/5 focus-visible:text-black dark:border-white/20 dark:hover:bg-white/5 dark:hover:text-white dark:focus-visible:bg-white/5 dark:focus-visible:text-white"
|
||||
class="group relative flex flex-grow flex-row-reverse flex-nowrap rounded-lg border px-4 py-4 pr-10 no-underline transition-colors duration-300 ease-in-out"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -49,11 +49,11 @@ const { prevPost, nextPost } = Astro.props
|
|||
y1="12"
|
||||
x2="19"
|
||||
y2="12"
|
||||
class="translate-x-3 scale-x-0 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-hover:scale-x-100 group-focus-visible:translate-x-0 group-focus-visible:scale-x-100"
|
||||
class="translate-x-3 scale-x-0 transition-transform duration-300 ease-in-out"
|
||||
/>
|
||||
<polyline
|
||||
points="12 5 19 12 12 19"
|
||||
class="-translate-x-1 transition-transform duration-300 ease-in-out group-hover:translate-x-0 group-focus-visible:translate-x-0"
|
||||
class="-translate-x-1 transition-transform duration-300 ease-in-out"
|
||||
/>
|
||||
</svg>
|
||||
<div class="flex items-center text-sm">{nextPost?.data.title}</div>
|
||||
|
|
|
@ -13,7 +13,7 @@ const { URL, icon, icon_size } = Astro.props
|
|||
<a
|
||||
href={URL}
|
||||
target={'_blank'}
|
||||
class={`inline-block ${icon_size} decoration-black/30 dark:decoration-white/30 hover:decoration-black/50 focus-visible:decoration-black/50 dark:hover:decoration-white/50 dark:focus-visible:decoration-white/50 text-current hover:text-cyan-500 focus-visible:text-black dark:hover:text-orange-500 dark:focus-visible:text-white transition-colors duration-300 ease-in-out`}
|
||||
class={`inline-block ${icon_size}`}
|
||||
>
|
||||
<i class={`bi bi-${icon}`}></i>
|
||||
</a>
|
||||
|
|
|
@ -1,23 +1,14 @@
|
|||
---
|
||||
import SocialIcon from '@components/SocialIcon.astro'
|
||||
import { Twitter, Github, Linkedin, Mail, GraduationCap, Rss } from 'lucide-react'
|
||||
import { SITE } from '@consts'
|
||||
|
||||
export interface Props {
|
||||
icon_size: string
|
||||
}
|
||||
|
||||
const { icon_size } = Astro.props
|
||||
---
|
||||
|
||||
<ul class="not-prose flex flex-wrap gap-2">
|
||||
<SocialIcon icon_size={icon_size} URL="#" icon="twitter-x" />
|
||||
<SocialIcon icon_size={icon_size} URL="#" icon="github" />
|
||||
<SocialIcon icon_size={icon_size} URL="#" icon="linkedin" />
|
||||
<SocialIcon icon_size={icon_size} URL="#" icon="envelope-fill" />
|
||||
<SocialIcon icon_size={icon_size} URL="#" icon="mortarboard-fill" />
|
||||
<SocialIcon
|
||||
icon_size={icon_size}
|
||||
URL={`${SITE.SITEURL}/rss.xml`}
|
||||
icon="rss-fill"
|
||||
/>
|
||||
<a href="#" class="inline-block"><Twitter /></a>
|
||||
<a href="#" class="inline-block"><Github /></a>
|
||||
<a href="#" class="inline-block"><Linkedin /></a>
|
||||
<a href="#" class="inline-block"><Mail /></a>
|
||||
<a href="#" class="inline-block"><GraduationCap /></a>
|
||||
<a href={`${SITE.SITEURL}/rss.xml`} class="inline-block"><Rss /></a>
|
||||
</ul>
|
||||
|
|
|
@ -27,9 +27,9 @@ function buildToc(headings: Heading[]) {
|
|||
}
|
||||
---
|
||||
|
||||
<details open class="rounded-lg border border-black/15 dark:border-white/20">
|
||||
<details open class="rounded-lg border">
|
||||
<summary>Table of Contents</summary>
|
||||
<nav class="">
|
||||
<nav>
|
||||
<ul class="py-3">
|
||||
{toc.map((heading) => <TableOfContentsHeading heading={heading} />)}
|
||||
</ul>
|
||||
|
@ -40,12 +40,4 @@ function buildToc(headings: Heading[]) {
|
|||
summary {
|
||||
@apply cursor-pointer rounded-t-lg px-3 py-1.5 font-medium transition-colors;
|
||||
}
|
||||
|
||||
summary:hover {
|
||||
@apply bg-black/5 dark:bg-white/5;
|
||||
}
|
||||
|
||||
details[open] summary {
|
||||
@apply bg-black/5 dark:bg-white/5;
|
||||
}
|
||||
</style>
|
||||
|
|
57
src/components/ui/button.tsx
Normal file
57
src/components/ui/button.tsx
Normal file
|
@ -0,0 +1,57 @@
|
|||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
|
||||
export { Button, buttonVariants }
|
203
src/components/ui/dropdown-menu.tsx
Normal file
203
src/components/ui/dropdown-menu.tsx
Normal file
|
@ -0,0 +1,203 @@
|
|||
import * as React from "react"
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import {
|
||||
CheckIcon,
|
||||
ChevronRightIcon,
|
||||
DotFilledIcon,
|
||||
} from "@radix-ui/react-icons"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root
|
||||
|
||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
|
||||
|
||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group
|
||||
|
||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
|
||||
|
||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
||||
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRightIcon className="ml-auto h-4 w-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
))
|
||||
DropdownMenuSubTrigger.displayName =
|
||||
DropdownMenuPrimitive.SubTrigger.displayName
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSubContent.displayName =
|
||||
DropdownMenuPrimitive.SubContent.displayName
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
))
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
||||
|
||||
const DropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
||||
|
||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||
>(({ className, children, checked, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<CheckIcon className="h-4 w-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
))
|
||||
DropdownMenuCheckboxItem.displayName =
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<DotFilledIcon className="h-4 w-4 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
))
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
||||
|
||||
const DropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
||||
|
||||
const DropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
||||
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
}
|
52
src/components/ui/mode-toggle.tsx
Normal file
52
src/components/ui/mode-toggle.tsx
Normal file
|
@ -0,0 +1,52 @@
|
|||
import * as React from "react"
|
||||
import { Moon, Sun } from "lucide-react"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
|
||||
export function ModeToggle() {
|
||||
const [theme, setThemeState] = React.useState<
|
||||
"theme-light" | "dark" | "system"
|
||||
>("theme-light")
|
||||
|
||||
React.useEffect(() => {
|
||||
const isDarkMode = document.documentElement.classList.contains("dark")
|
||||
setThemeState(isDarkMode ? "dark" : "theme-light")
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
const isDark =
|
||||
theme === "dark" ||
|
||||
(theme === "system" &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
document.documentElement.classList[isDark ? "add" : "remove"]("dark")
|
||||
}, [theme])
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => setThemeState("theme-light")}>
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setThemeState("dark")}>
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setThemeState("system")}>
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
---
|
||||
title: '[Tutorial] Getting started with Astro-Micro-Academics'
|
||||
description: 'Hit the ground running.'
|
||||
date: '2024-07-26'
|
||||
tags: ['guide', 'tutorial']
|
||||
---
|
||||
|
||||
:exclamation: Also refer to [Old] posts to see examples and changes. Some changes are removed in this version, which are marked.
|
||||
|
||||
## Install Astro-Micro-Academics
|
||||
|
||||
Clone the [repository](https://github.com/jingwu2121/astro-micro-academic).
|
||||
|
||||
```sh
|
||||
git clone https://github.com/jingwu2121/astro-micro-academic.git
|
||||
```
|
||||
|
||||
```sh
|
||||
cd astro-micro-academic
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i
|
||||
```
|
||||
|
||||
Run local server
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Update the Homepage
|
||||
|
||||
Update your home page in `src/pages/index.astro`.
|
||||
|
||||
## CV & About
|
||||
|
||||
Update your CV and About page in `src/pages/cv.astro` and `src/pages/about.astro`.
|
||||
|
||||
```ts
|
||||
const works = [
|
||||
{
|
||||
company: 'Company A',
|
||||
time: '2022-Present',
|
||||
job_title: 'Research Scientist',
|
||||
location: 'London, UK',
|
||||
description: 'Your Notes about the job',
|
||||
},
|
||||
{
|
||||
company: 'Company A',
|
||||
time: '2022-Present',
|
||||
job_title: 'Research Scientist',
|
||||
location: 'London, UK',
|
||||
description: 'Your Notes about the job',
|
||||
},
|
||||
]
|
||||
const educations = [
|
||||
{
|
||||
school: 'University 1',
|
||||
time: '2022-Present',
|
||||
job_title: 'BEng in Electronic Information Engineering',
|
||||
location: 'London, UK',
|
||||
description: 'Your Notes about the study',
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
## Social Links
|
||||
|
||||
Update the social links in `src/components/SocialIcons.astro`, simply replace the `URL`.
|
||||
|
||||
## Publications metadata
|
||||
|
||||
Metadata is required for each post. Add a new `publication.md` to automartically add a publication on the website. Publications are sorted by date.
|
||||
|
||||
```astro
|
||||
---
|
||||
title: 'Diffusion Models Beat GANs on Image Synthesis'
|
||||
description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Molestias earum quod quo repellat blanditiis est iste eos dolorem! Voluptatibus corporis totam sed unde est iusto neque iure natus adipisci omnis.'
|
||||
date: '2024-07-26'
|
||||
authors: 'John B*, Jon A*, Frank C, John B, Jon A, Frank C'
|
||||
paperURL: 'Paper: https://astro-sphere-demo.vercel.app'
|
||||
codeURL: 'Code: '
|
||||
webURL: 'Web: https://github.com/markhorn-dev/astro-sphere'
|
||||
dataURL: 'Data: https://github.com/markhorn-dev/astro-sphere'
|
||||
img: '/rupert-cat.gif'
|
||||
imgAlt: 'Paper Teaser'
|
||||
pub: 'ECCV2024'
|
||||
---
|
||||
```
|
||||
|
||||
| Field | Req | Type | Remarks |
|
||||
| :--------------------------------- | :-- | :----- | :--------------------------------------------------------------------------------------------------------------- |
|
||||
| title | Yes | string | Title of the content. Used in SEO and RSS. |
|
||||
| description | Yes | string | Description of the content. Used in SEO and RSS. |
|
||||
| date | Yes | string | Must be a valid date string (able to be parsed). |
|
||||
| authors | Yes | string | A string seperated by comma. |
|
||||
| paperURL, codeURL, webURL, dataURL | Yes | string | A string seperated by ": ". If you don't have a link to add, leave the link part blank, e.g. `codeURL: "Code: "` |
|
||||
| img | Yes | string | Path to teaser image. |
|
||||
| imgAlt | Yes | string | Description of the image. |
|
||||
| pub | Yes | string | The conference or journal |
|
||||
|
||||
## Blog metadata
|
||||
|
||||
Metadata is required for each post.
|
||||
|
||||
```astro
|
||||
---
|
||||
title: 'Blog Collection'
|
||||
description: 'How to add posts to the blog.'
|
||||
date: '2024-03-21'
|
||||
tags: ['guide', 'tutorial']
|
||||
draft: false
|
||||
---
|
||||
```
|
||||
|
||||
| Field | Req | Type | Remarks |
|
||||
| :---------- | :-- | :------ | :----------------------------------------------- |
|
||||
| title | Yes | string | Title of the content. Used in SEO and RSS. |
|
||||
| description | Yes | string | Description of the content. Used in SEO and RSS. |
|
||||
| date | Yes | string | Must be a valid date string (able to be parsed). |
|
||||
| tags | Yes | list | A list of strings |
|
||||
| draft | No | boolean | If draft: true, content will not be published. |
|
||||
|
||||
## Customize the website metadata and set up RSS
|
||||
|
||||
To change the website metadata, edit `src/consts.ts`.
|
||||
|
||||
```ts
|
||||
// src/consts.ts
|
||||
|
||||
export const SITE: Site = {
|
||||
TITLE: 'Astro Micro Academics',
|
||||
DESCRIPTION: 'Astro Micro Academics is for academic user.',
|
||||
EMAIL: 'youremial@gmail.com',
|
||||
NUM_POSTS_ON_HOMEPAGE: 2,
|
||||
NUM_PUBLICATIONS_ON_HOMEPAGE: 3,
|
||||
SITEURL: 'https://astro-micro-academic.vercel.app', // Update here to link the RSS icon to your website RSS
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Req | Description |
|
||||
| :--------------- | :-- | :--------------------------------------------------- |
|
||||
| TITLE | Yes | Displayed in header and footer. Used in SEO and RSS. |
|
||||
| DESCRIPTION | Yes | Used in SEO and RSS. |
|
||||
| EMAIL | Yes | Displayed in contact section. |
|
||||
| NUM_POSTS | Yes | Limit number of posts on home page. |
|
||||
| NUM_PUBLICATIONS | Yes | Limit number of research on home page. |
|
||||
| SITEURL | Yes | Your website URL |
|
||||
|
||||
### RSS Post
|
||||
|
||||
Please tag the post of RSS feed with tag `"rss-feed"`, other posts are not included in the RSS.
|
||||
|
||||
---
|
||||
|
||||
## Custom metadata for highlighted author in your paper
|
||||
|
||||
```ts
|
||||
// src/consts.ts
|
||||
|
||||
export const HIGHLIGHTAUTHOR = 'John B'
|
||||
```
|
||||
|
||||
## Customize metadata for individual pages
|
||||
|
||||
```ts
|
||||
// src/consts.ts
|
||||
|
||||
export const HOME: Metadata = {
|
||||
TITLE: 'Home',
|
||||
DESCRIPTION: 'Astro Micro is an accessible theme for Astro.',
|
||||
}
|
||||
|
||||
export const BLOG: Metadata = {
|
||||
TITLE: 'Blog',
|
||||
DESCRIPTION: 'A collection of articles on topics I am passionate about.',
|
||||
}
|
||||
|
||||
export const RESEARCH: Metadata = {
|
||||
TITLE: 'Publications',
|
||||
DESCRIPTION:
|
||||
'A collection of my publications with links to paper, repositories and live demos.',
|
||||
}
|
||||
|
||||
export const CV: Metadata = {
|
||||
TITLE: 'CV',
|
||||
DESCRIPTION: 'your cv',
|
||||
}
|
||||
|
||||
export const TAGS: Metadata = {
|
||||
TITLE: 'TAGS',
|
||||
DESCRIPTION: 'blog tag filter',
|
||||
}
|
||||
|
||||
export const ABOUT: Metadata = {
|
||||
TITLE: 'ABOUT',
|
||||
DESCRIPTION: 'A self-intro',
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Req | Description |
|
||||
| :---------- | :-- | :--------------------------------------------- |
|
||||
| TITLE | Yes | Displayed in browser tab. Used in SEO and RSS. |
|
||||
| DESCRIPTION | Yes | Used in SEO and RSS. |
|
||||
|
||||
---
|
||||
|
||||
## Deploy the site
|
||||
|
||||
To set up RSS and Giscus, it's easier if the site is deployed and has a URL for you to use. Instantly deploy to Vercel or Netlify by clicking the buttons below.
|
||||
|
||||
<div class="flex gap-2">
|
||||
<a target="_blank" aria-label="Deploy with Vercel" href="https://vercel.com/new/clone?repository-url=https://github.com/trevortylerlee/astro-micro">
|
||||
<img src="/deploy_vercel.svg" />
|
||||
</a>
|
||||
<a target="_blank" aria-label="Deploy with Netlify" href="https://app.netlify.com/start/deploy?repository=https://github.com/trevortylerlee/astro-micro">
|
||||
<img src="/deploy_netlify.svg" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
To deploy manually see [Astro's docs](https://docs.astro.build/en/guides/deploy/).
|
||||
|
||||
To deploy to Github, see [here](https://docs.astro.build/en/guides/deploy/github/).
|
||||
|
||||
## Set up Giscus (from Astro Micro)
|
||||
|
||||
Follow the steps at [giscus.app](https://giscus.app). Once you get your custom Giscus script from that site, go to `Giscus.astro` and replace that script with your own.
|
||||
|
||||
```js
|
||||
// src/components/Giscus.astro
|
||||
|
||||
<script
|
||||
is:inline
|
||||
src="https://giscus.app/client.js"
|
||||
data-repo="trevortylerlee/astro-micro"
|
||||
data-repo-id="R_kgDOL_6l9Q"
|
||||
data-category="Announcements"
|
||||
data-category-id="DIC_kwDOL_6l9c4Cfk55"
|
||||
data-mapping="pathname"
|
||||
data-strict="0"
|
||||
data-reactions-enabled="1"
|
||||
data-emit-metadata="0"
|
||||
data-input-position="top"
|
||||
data-theme="preferred_color_scheme"
|
||||
data-lang="en"
|
||||
data-loading="lazy"
|
||||
crossorigin="anonymous"
|
||||
async
|
||||
></script>
|
||||
```
|
||||
|
||||
To change the Giscus themes used, edit the `setGiscusTheme` function in `Head.astro`.
|
||||
|
||||
```js
|
||||
// src/components/Head.astro
|
||||
|
||||
const setGiscusTheme = () => {
|
||||
const giscus = document.querySelector('.giscus-frame')
|
||||
|
||||
const isDark = document.documentElement.classList.contains('dark')
|
||||
|
||||
if (giscus) {
|
||||
const url = new URL(giscus.src)
|
||||
// Change "dark" and "light" to other Giscus themes
|
||||
url.searchParams.set('theme', isDark ? 'dark' : 'light')
|
||||
giscus.src = url.toString()
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,105 +0,0 @@
|
|||
---
|
||||
title: '[Old] Everything new in Astro Micro'
|
||||
description: 'Features, enhancements, and changes.'
|
||||
date: '2024-05-09'
|
||||
tags: ['astro-micro']
|
||||
---
|
||||
|
||||
import Callout from '@/components/Callout.astro'
|
||||
|
||||
---
|
||||
|
||||
## Pagefind search 🔎
|
||||
|
||||
[Pagefind](https://pagefind.app) is a search library for static websites. Micro uses [Sergey Shishkin's](https://github.com/shishkin) [astro-pagefind](https://github.com/shishkin/astro-pagefind) integration. This integration simplifies development and does not require any changes to the default build script.
|
||||
|
||||
Press <kbd>/</kbd> or <kbd>CTRL</kbd> + <kbd>K</kbd> to open the search dialog. For Mac users, <kbd>⌘</kbd> + <kbd>K</kbd> can also be used. To dismiss the search dialog, press <kbd>Esc</kbd> or click on an area outside the component.
|
||||
|
||||
### Build and develop
|
||||
|
||||
<Callout type="error">
|
||||
The site **must** be built at least once so Pagefind can index the content.
|
||||
</Callout>
|
||||
|
||||
```bash
|
||||
# Pagefind must index the site to function
|
||||
npm run build
|
||||
```
|
||||
|
||||
When developing you can continue to use `npm run dev` and Pagefind will use the index from the last available build.
|
||||
|
||||
---
|
||||
|
||||
## Giscus comments 💬
|
||||
|
||||
[Giscus](https://giscus.app) leverages Github discussions to act as a comments system. To get Giscus working on your own website, see [here](/blog/01-getting-started#deploy-the-site).
|
||||
|
||||
---
|
||||
|
||||
## Callout component 🆕
|
||||
|
||||
<Callout>
|
||||
Adipisicing et officia reprehenderit fugiat occaecat cupidatat exercitation
|
||||
labore consequat ullamco nostrud non.
|
||||
</Callout>
|
||||
|
||||
<Callout type="info">
|
||||
Adipisicing et officia reprehenderit fugiat occaecat cupidatat exercitation
|
||||
labore consequat ullamco nostrud non.
|
||||
</Callout>
|
||||
|
||||
<Callout type="warning">
|
||||
Adipisicing et officia reprehenderit fugiat occaecat cupidatat exercitation
|
||||
labore consequat ullamco nostrud non.
|
||||
</Callout>
|
||||
|
||||
<Callout type="error">
|
||||
Adipisicing et officia reprehenderit fugiat occaecat cupidatat exercitation
|
||||
labore consequat ullamco nostrud non.
|
||||
</Callout>
|
||||
|
||||
---
|
||||
|
||||
## UI enhancements 🎨
|
||||
|
||||
- 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
|
||||
- Code blocks have a copy button
|
||||
- Add pagination to the bottom of blog posts
|
||||
- Create 404 page
|
||||
- Add ToC component to posts
|
||||
|
||||
---
|
||||
|
||||
## Other changes
|
||||
|
||||
- Change fonts to Geist Sans and Geist Mono
|
||||
- Switch base color from "stone" to "neutral"
|
||||
- Change formatted date to use "long" option for month
|
||||
- Minor spacing changes throughout
|
||||
- Remove "work" collection and components
|
||||
- If desired, you can get the code from [Astro Nano](https://github.com/markhorn-dev/astro-nano)
|
||||
- Slightly increased link decoration offset
|
||||
- Slightly sped-up animations
|
||||
- Reversed animation
|
||||
- Ensure posts use an h1 tag for post titles
|
||||
- Tweaked typography
|
||||
|
||||
---
|
||||
|
||||
## Issues ⚠️
|
||||
|
||||
### Active issues
|
||||
|
||||
- [PostNavigation.astro is broken when deployed with Cloudflare Pages](https://github.com/trevortylerlee/astro-micro/issues/39)
|
||||
|
||||
### Closed issues
|
||||
|
||||
- Fixed by [blopker](https://github.com/blopker): [Pagefind requires a refresh to function when ViewTransitions is enabled](https://github.com/trevortylerlee/astro-micro/issues/7)
|
||||
- Fixed by [blopker](https://github.com/blopker): [ToC links are obscured by Header when scrolled to](https://github.com/trevortylerlee/astro-micro/issues/4)
|
||||
- Fixed by [cgranier](https://github.com/cgranier): [Pagination links advance by slug/folder](https://github.com/trevortylerlee/astro-micro/issues/26)
|
||||
- Fixed by [cgranier](https://github.com/cgranier): [Hides Table of Contents when there are no headings](https://github.com/trevortylerlee/astro-micro/pull/30)
|
||||
- Fixed by [arastoonet](https://github.com/arastoonet): [Fix typo in README](https://github.com/trevortylerlee/astro-micro/pull/19)
|
||||
- Fixed by [luciancah](https://github.com/luciancah): [Prevent Pagefind from double-indexing results](https://github.com/trevortylerlee/astro-micro/issues/40)
|
|
@ -1,181 +0,0 @@
|
|||
---
|
||||
title: '[Old] Getting started with Astro-Micro'
|
||||
description: 'Hit the ground running.'
|
||||
date: '2024-03-22'
|
||||
tags: ['guide', 'start']
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## Install astro-micro
|
||||
|
||||
Clone the [Astro Micro repository](https://github.com/trevortylerlee/astro-micro.git).
|
||||
|
||||
```sh
|
||||
git clone https://github.com/trevortylerlee/astro-micro.git my-astro-micro
|
||||
```
|
||||
|
||||
```sh
|
||||
cd my-astro-micro
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i
|
||||
```
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Customize the website metadata
|
||||
|
||||
To change the website metadata, edit `src/consts.ts`.
|
||||
|
||||
```ts
|
||||
// src/consts.ts
|
||||
|
||||
export const SITE: Site = {
|
||||
NAME: 'Astro Micro',
|
||||
DESCRIPTION: 'Astro Micro is an accessible theme for Astro.',
|
||||
EMAIL: 'trevortylerlee@gmail.com',
|
||||
NUM_POSTS_ON_HOMEPAGE: 3,
|
||||
NUM_PUBLICATIONS_ON_HOMEPAGE: 3,
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Req | Description |
|
||||
| :--------------- | :-- | :--------------------------------------------------- |
|
||||
| TITLE | Yes | Displayed in header and footer. Used in SEO and RSS. |
|
||||
| DESCRIPTION | Yes | Used in SEO and RSS. |
|
||||
| EMAIL | Yes | Displayed in contact section. |
|
||||
| NUM_POSTS | Yes | Limit number of posts on home page. |
|
||||
| NUM_PUBLICATIONS | Yes | Limit number of research on home page. |
|
||||
|
||||
---
|
||||
|
||||
## Customize metadata for individual pages
|
||||
|
||||
```ts
|
||||
// src/consts.ts
|
||||
|
||||
export const ABOUT: Metadata = {
|
||||
TITLE: 'About',
|
||||
DESCRIPTION: 'Astro Micro is a fork of Astro Nano.',
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Req | Description |
|
||||
| :---------- | :-- | :--------------------------------------------- |
|
||||
| TITLE | Yes | Displayed in browser tab. Used in SEO and RSS. |
|
||||
| DESCRIPTION | Yes | Used in SEO and RSS. |
|
||||
|
||||
---
|
||||
|
||||
## ~~Add your social media links~~ Removed in Micro Academics
|
||||
|
||||
```ts
|
||||
// src/consts.ts
|
||||
|
||||
export const SOCIALS: Socials = [
|
||||
{
|
||||
NAME: 'twitter-x',
|
||||
HREF: 'https://twitter.com/boogerbuttcheeks',
|
||||
},
|
||||
{
|
||||
NAME: 'github',
|
||||
HREF: 'https://github.com/trevortylerlee',
|
||||
},
|
||||
{
|
||||
NAME: 'linkedin',
|
||||
HREF: 'https://www.linkedin.com/in/trevortylerlee',
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
| Field | Req | Description |
|
||||
| :---- | :-- | :-------------------------------------- |
|
||||
| NAME | Yes | Displayed in contact section as a link. |
|
||||
| HREF | Yes | External url to social media profile. |
|
||||
|
||||
## Deploy the site
|
||||
|
||||
To set up RSS and Giscus, it's easier if the site is deployed and has a URL for you to use. Instantly deploy to Vercel or Netlify by clicking the buttons below.
|
||||
|
||||
<div class="flex gap-2">
|
||||
<a target="_blank" aria-label="Deploy with Vercel" href="https://vercel.com/new/clone?repository-url=https://github.com/trevortylerlee/astro-micro">
|
||||
<img src="/deploy_vercel.svg" />
|
||||
</a>
|
||||
<a target="_blank" aria-label="Deploy with Netlify" href="https://app.netlify.com/start/deploy?repository=https://github.com/trevortylerlee/astro-micro">
|
||||
<img src="/deploy_netlify.svg" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
To deploy manually see [Astro's docs](https://docs.astro.build/en/guides/deploy/).
|
||||
|
||||
## ~~Set up RSS~~ New config in Astro Micro Academics
|
||||
|
||||
Change the `site` option to the deployed site's URL.
|
||||
|
||||
```js
|
||||
// astro.config.mjs
|
||||
|
||||
export default defineConfig({
|
||||
site: 'https://astro-micro.vercel.app',
|
||||
integrations: [tailwind(), sitemap(), mdx(), pagefind()],
|
||||
markdown: {
|
||||
shikiConfig: {
|
||||
theme: 'css-variables',
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Set up Giscus
|
||||
|
||||
Follow the steps at [giscus.app](https://giscus.app). Once you get your custom Giscus script from that site, go to `Giscus.astro` and replace that script with your own.
|
||||
|
||||
```js
|
||||
// src/components/Giscus.astro
|
||||
|
||||
<script
|
||||
is:inline
|
||||
src="https://giscus.app/client.js"
|
||||
data-repo="trevortylerlee/astro-micro"
|
||||
data-repo-id="R_kgDOL_6l9Q"
|
||||
data-category="Announcements"
|
||||
data-category-id="DIC_kwDOL_6l9c4Cfk55"
|
||||
data-mapping="pathname"
|
||||
data-strict="0"
|
||||
data-reactions-enabled="1"
|
||||
data-emit-metadata="0"
|
||||
data-input-position="top"
|
||||
data-theme="preferred_color_scheme"
|
||||
data-lang="en"
|
||||
data-loading="lazy"
|
||||
crossorigin="anonymous"
|
||||
async
|
||||
></script>
|
||||
```
|
||||
|
||||
To change the Giscus themes used, edit the `setGiscusTheme` function in `Head.astro`.
|
||||
|
||||
```js
|
||||
// src/components/Head.astro
|
||||
|
||||
const setGiscusTheme = () => {
|
||||
const giscus = document.querySelector('.giscus-frame')
|
||||
|
||||
const isDark = document.documentElement.classList.contains('dark')
|
||||
|
||||
if (giscus) {
|
||||
const url = new URL(giscus.src)
|
||||
// Change "dark" and "light" to other Giscus themes
|
||||
url.searchParams.set('theme', isDark ? 'dark' : 'light')
|
||||
giscus.src = url.toString()
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,63 +0,0 @@
|
|||
---
|
||||
title: '[Old] Blog Collection'
|
||||
description: 'How to add posts to the blog.'
|
||||
date: '2024-03-21'
|
||||
tags: ['aa']
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## Working with the `blog` collection:
|
||||
|
||||
The `blog` collection is found in `src/content/blog`.
|
||||
|
||||
```
|
||||
📁 /src/content/blog
|
||||
└── 📁 post-1
|
||||
└── 📄 index.md
|
||||
└── 📁 post-2
|
||||
└── 📄 index.mdx
|
||||
```
|
||||
|
||||
In the above example, two blog posts will be generated with the folder name representing the slug.
|
||||
|
||||
- `https://example.com/blog/post-1`
|
||||
- `https://example.com/blog/post-2`
|
||||
|
||||
---
|
||||
|
||||
## Provide metadata
|
||||
|
||||
Metadata is required for each post.
|
||||
|
||||
```astro
|
||||
---
|
||||
title: 'Blog Collection'
|
||||
description: 'How to add posts to the blog.'
|
||||
date: '2024-03-21'
|
||||
draft: false
|
||||
---
|
||||
```
|
||||
|
||||
| Field | Req | Type | Remarks |
|
||||
| :---------- | :-- | :------ | :----------------------------------------------- |
|
||||
| title | Yes | string | Title of the content. Used in SEO and RSS. |
|
||||
| description | Yes | string | Description of the content. Used in SEO and RSS. |
|
||||
| date | Yes | string | Must be a valid date string (able to be parsed). |
|
||||
| draft | No | boolean | If draft: true, content will not be published. |
|
||||
|
||||
---
|
||||
|
||||
All that's left to do is write the content under the metadata.
|
||||
|
||||
```astro
|
||||
---
|
||||
title: 'Blog Collection'
|
||||
description: 'How to add posts to the blog.'
|
||||
date: '2024-03-21'
|
||||
draft: false
|
||||
---
|
||||
|
||||
## Working with the blog collection
|
||||
<!-- content -->
|
||||
```
|
|
@ -1,398 +0,0 @@
|
|||
---
|
||||
title: '[Old] Markdown syntax guide'
|
||||
description: 'Get started writing content in Markdown.'
|
||||
date: '2024-03-17'
|
||||
---
|
||||
|
||||
import Callout from '@/components/Callout.astro'
|
||||
|
||||
---
|
||||
|
||||
## Headings
|
||||
|
||||
To create headings, use hash symbols (#) followed by a space. The number of hash symbols indicates the heading level.
|
||||
|
||||
<Callout>
|
||||
Use `h2` tags instead of `h1` tags in the post. Too many `h1` tags on a single
|
||||
page can impact SEO. The post title serves as the `h1`.
|
||||
</Callout>
|
||||
|
||||
```md
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
#### Heading 4
|
||||
|
||||
##### Heading 5
|
||||
|
||||
###### Heading 6
|
||||
```
|
||||
|
||||
<h1>Heading 1</h1>
|
||||
<h2>Heading 2</h2>
|
||||
<h3>Heading 3</h3>
|
||||
<h4>Heading 4</h4>
|
||||
<h5>Heading 5</h5>
|
||||
<h6>Heading 6</h6>
|
||||
|
||||
---
|
||||
|
||||
## Paragraphs
|
||||
|
||||
To create paragraphs, use a blank line to separate one or more lines of text.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```md
|
||||
<!-- empty line -->
|
||||
I love Star Wars.
|
||||
<!-- empty line -->
|
||||
My favourite is Episode III – Revenge of the Sith.
|
||||
<!-- empty line -->
|
||||
```
|
||||
|
||||
I love Star Wars.
|
||||
|
||||
My favourite is Episode III – Revenge of the Sith.
|
||||
|
||||
---
|
||||
|
||||
## Italic
|
||||
|
||||
Use one asterisk \(\*\) or underscore \(\_\) to italicize text.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```md
|
||||
I *love* Star Wars.
|
||||
My _favourite_ is Episode III – Revenge of the Sith.
|
||||
```
|
||||
|
||||
I _love_ Star Wars.
|
||||
My _favourite_ is Episode III – Revenge of the Sith.
|
||||
|
||||
---
|
||||
|
||||
## Bold
|
||||
|
||||
Use two asterisks \(\*\) or underscores \(\_\) to bold text.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```md
|
||||
I **love** Star Wars.
|
||||
My __favourite__ is Episode III – Revenge of the Sith.
|
||||
```
|
||||
|
||||
I **love** Star Wars.
|
||||
My **favourite** is Episode III – Revenge of the Sith.
|
||||
|
||||
---
|
||||
|
||||
## Italic and Bold
|
||||
|
||||
Use three asterisks \(\*\) or underscores \(\_\) to both bold and italicize text.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```md
|
||||
I ***love*** Star Wars.
|
||||
My ___favourite___ is Episode III – Revenge of the Sith.
|
||||
```
|
||||
|
||||
I **_love_** Star Wars.
|
||||
My **_favourite_** is Episode III – Revenge of the Sith.
|
||||
|
||||
---
|
||||
|
||||
## Horizontal Rule
|
||||
|
||||
Use three hyphens \(\-\), asterisks \(\*\), or underscores \(\_\) to create a horizontal rule.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```md
|
||||
<!-- empty line -->
|
||||
---
|
||||
<!-- empty line -->
|
||||
***
|
||||
<!-- empty line -->
|
||||
___
|
||||
<!-- empty line -->
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## Links
|
||||
|
||||
To create a link, the link text in brackets \(\[\]\) and then follow it immediately with the URL in parentheses \(\(\)\).
|
||||
|
||||
```md
|
||||
Micro is a fork of [astro-nano](https://github.com/markhorn-dev/astro-nano).
|
||||
```
|
||||
|
||||
Micro is a fork of [astro-nano](https://github.com/markhorn-dev/astro-nano).
|
||||
|
||||
---
|
||||
|
||||
## Ordered Lists
|
||||
|
||||
To create an ordered list, add line items with numbers followed by periods. Use an indent to create a nested list.
|
||||
|
||||
```md
|
||||
1. Item 1
|
||||
2. Item 2
|
||||
1. Sub item 1
|
||||
2. Sub item 2
|
||||
3. Item 3
|
||||
```
|
||||
|
||||
1. Item 1
|
||||
2. Item 2
|
||||
1. Sub item 1
|
||||
2. Sub item 2
|
||||
3. Item 3
|
||||
|
||||
---
|
||||
|
||||
## Unordered List
|
||||
|
||||
To create an unordered list, add a hyphen \(\-\), an asterisk \(\*\), or a plus sign \(\+\) in front of line items. Don't mix. Use an indent to create a nested list.
|
||||
|
||||
```md
|
||||
- Item 1
|
||||
- Item 2
|
||||
- Sub item 1
|
||||
- Sub item 2
|
||||
- Item 3
|
||||
```
|
||||
|
||||
- Item 1
|
||||
- Item 2
|
||||
- Sub item 1
|
||||
- Sub item 2
|
||||
- Item 3
|
||||
|
||||
---
|
||||
|
||||
## Images
|
||||
|
||||
To add an image, add an exclamation mark (!), followed by alt text in brackets ([]), and the path or URL to the image asset in parentheses.
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
### Relative
|
||||
|
||||
Use the `` pattern relative to the same folder as the markdown file. Notice the period.
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||

|
||||
|
||||
### Public Image
|
||||
|
||||
Use the `` pattern relative to the public folder. No period.
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||

|
||||
|
||||
### External Image
|
||||
|
||||
Use the `` pattern.
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Blockquotes
|
||||
|
||||
To add a blockquote add the greater-than character \(\>\) before a paragraph. For multi-line blockquotes, add additional greater-than character for each line and include an empty spacer line.
|
||||
|
||||
```md
|
||||
> So this is how liberty dies...
|
||||
>
|
||||
> with thunderous applause.
|
||||
```
|
||||
|
||||
> So this is how liberty dies...
|
||||
>
|
||||
> with thunderous applause.
|
||||
|
||||
---
|
||||
|
||||
## Strikethrough
|
||||
|
||||
Use a tilde \(\~\) symbol to strikethrough text.
|
||||
|
||||
```md
|
||||
~I don't like sand.~ It's coarse and rough and irritating.
|
||||
```
|
||||
|
||||
~I don't like sand.~ It's coarse and rough and irritating.
|
||||
|
||||
---
|
||||
|
||||
## Subscript
|
||||
|
||||
Use the `<sub>` tag to denote subscript.
|
||||
|
||||
```md
|
||||
H<sub>2</sub>O
|
||||
```
|
||||
|
||||
H<sub>2</sub>O
|
||||
|
||||
---
|
||||
|
||||
## Superscript
|
||||
|
||||
Use the `<sup>` tag to denote superscript.
|
||||
|
||||
```md
|
||||
E=mc<sup>2</sup>
|
||||
```
|
||||
|
||||
E=mc<sup>2</sup>
|
||||
|
||||
---
|
||||
|
||||
## Keyboard
|
||||
|
||||
Use the `<kbd>` tag to denote keys on the keyboard.
|
||||
|
||||
```md
|
||||
<kbd>CTRL</kbd> + <kbd>ALT</kbd> + <kbd>Delete</kbd>
|
||||
```
|
||||
|
||||
<kbd>CTRL</kbd> + <kbd>ALT</kbd> + <kbd>Delete</kbd>
|
||||
|
||||
---
|
||||
|
||||
## Abbreviate
|
||||
|
||||
Use the `<abbr>` tag to denote abbreviation.
|
||||
|
||||
```md
|
||||
<abbr title="Graphics Interchange Format">GIF</abbr>
|
||||
```
|
||||
|
||||
<abbr title="Graphics Interchange Format">GIF</abbr>
|
||||
|
||||
---
|
||||
|
||||
### Highlight
|
||||
|
||||
Use the `<mark>` tag to denote highlighted text.
|
||||
|
||||
```md
|
||||
Do or do not. <mark>There is no try.</mark>
|
||||
```
|
||||
|
||||
Do or do not. <mark>There is no try.</mark>
|
||||
|
||||
---
|
||||
|
||||
## Task Lists
|
||||
|
||||
Combine a list with square brackets ([]) representing a checkbox. Typing `x` inside the brackets marks the task as complete.
|
||||
|
||||
```md
|
||||
- [x] Build a lightsaber
|
||||
- [ ] Pass the Jedi Trials
|
||||
- [ ] Train a padawan
|
||||
```
|
||||
|
||||
- [x] Build a lightsaber
|
||||
- [ ] Pass the Jedi Trials
|
||||
- [ ] Train a padawan
|
||||
|
||||
---
|
||||
|
||||
## Tables
|
||||
|
||||
Use three or more hyphens (-) for the column headers and use pipes (|) to separate each column. You can align text in the columns to the left, right, or center by adding a colon (:) to the left, right, or on both side of the hyphens.
|
||||
|
||||
```md
|
||||
| Item | Count |
|
||||
| :----- | ----: |
|
||||
| X-Wing | 1 |
|
||||
| Y-Wing | 2 |
|
||||
| A-Wing | 3 |
|
||||
```
|
||||
|
||||
| Item | Count |
|
||||
| :----- | ----: |
|
||||
| X-Wing | 1 |
|
||||
| Y-Wing | 2 |
|
||||
| A-Wing | 3 |
|
||||
|
||||
---
|
||||
|
||||
## Footnotes
|
||||
|
||||
Add a caret (^) and an identifier inside brackets \(\[\^1\]\). Identifiers can be numbers or words but can't contain spaces or tabs.
|
||||
|
||||
```md
|
||||
Here's a footnote, [^1] and here's another one. [^2]
|
||||
[^1]: This is the first footnote.
|
||||
[^2]: This is the second footnote.
|
||||
```
|
||||
|
||||
Here's a footnote, [^1] and here's another one. [^2]
|
||||
[^1]: This is the first footnote.
|
||||
[^2]: This is the second footnote.
|
||||
|
||||
See the bottom of this page to view the footnotes.
|
||||
|
||||
---
|
||||
|
||||
## Code
|
||||
|
||||
To denote a word or phrase as code, enclose it in backticks (`).
|
||||
|
||||
```md
|
||||
`package.json`
|
||||
```
|
||||
|
||||
`package.json`
|
||||
|
||||
---
|
||||
|
||||
## Code Blocks
|
||||
|
||||
Denote a code block by wrapping a section of valid code in triple backticks (`). To enable syntax highlighting, type the shorthand symbol for the language after the first three backticks. [Reference for shorthand symbols](https://shiki.style/languages).
|
||||
|
||||
````
|
||||
```js
|
||||
function hello() {
|
||||
console.log("hello world");
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
```js
|
||||
function hello() {
|
||||
console.log('hello world')
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Refer to [markdownguide.org](https://www.markdownguide.org/) for best practices as well as extended syntax.
|
||||
|
||||
---
|
Binary file not shown.
Before Width: | Height: | Size: 203 KiB |
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
|
||||
---
|
||||
|
||||
<button
|
||||
onclick="alert(`You clicked the button!`)"
|
||||
class="border border-black/10 p-2 transition-colors duration-300 ease-in-out hover:bg-black/5 dark:border-white/10 dark:hover:bg-white/10"
|
||||
>
|
||||
Relative Button
|
||||
</button>
|
|
@ -1,71 +0,0 @@
|
|||
---
|
||||
title: '[Old] MDX syntax guide'
|
||||
description: 'Use interactive components in Markdown.'
|
||||
date: '2024-03-16'
|
||||
---
|
||||
|
||||
import Callout from '@/components/Callout.astro'
|
||||
|
||||
---
|
||||
|
||||
MDX is an extension of Markdown with the ability to import `.astro`,
|
||||
`.jsx`, `.tsx` and other framework components you have integrated.
|
||||
|
||||
This guide covers the basics of MDX syntax and how to use it, as well as a few examples.
|
||||
|
||||
## Example 1
|
||||
|
||||
Importing a component from the `/components` directory.
|
||||
|
||||
This component accepts a Javascript date object and format it as a string.
|
||||
|
||||
```astro
|
||||
import DateComp from "../../../components/FormattedDate.astro";
|
||||
|
||||
<DateComp date={new Date()} />
|
||||
```
|
||||
|
||||
import FormattedDate from '../../../components/FormattedDate.astro'
|
||||
|
||||
<FormattedDate date={new Date()} />
|
||||
|
||||
---
|
||||
|
||||
## Example 2
|
||||
|
||||
Importing a component from a relative path to your content.
|
||||
|
||||
This component displays an alert when the button is clicked.
|
||||
|
||||
```astro
|
||||
import RelativeComponent from "./component.astro";
|
||||
|
||||
<RelativeComponent />
|
||||
```
|
||||
|
||||
import RelativeComponent from './component.astro'
|
||||
|
||||
<RelativeComponent />
|
||||
|
||||
---
|
||||
|
||||
By default Micro has zero frameworks installed. If you install a framework, components of that framework can be used in MDX files.
|
||||
|
||||
<Callout>
|
||||
Don't forget to use [client
|
||||
directives](https://docs.astro.build/en/reference/directives-reference/#client-directives)
|
||||
to make framework components interactive.
|
||||
</Callout>
|
||||
|
||||
```astro
|
||||
<ReactComponent client:load />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## More Links
|
||||
|
||||
- [MDX Syntax Documentation](https://mdxjs.com/docs/what-is-mdx)
|
||||
- [Astro Framework Integrations](https://docs.astro.build/en/guides/integrations-guide)
|
||||
- [Astro Usage Documentation](https://docs.astro.build/en/guides/markdown-content/#markdown-and-mdx-pages)
|
||||
- [Client Directives](https://docs.astro.build/en/reference/directives-reference/#client-directives)
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
title: '[Old] Year sorting example'
|
||||
description: 'Nano groups posts by year.'
|
||||
date: '2023-12-31'
|
||||
---
|
||||
|
||||
This post is to demonstrate the year sorting capabilities.
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
title: '[Old] Draft example'
|
||||
description: 'Setting draft flag to true to hide this post.'
|
||||
date: '2022-12-31'
|
||||
draft: false
|
||||
---
|
||||
|
||||
This post also demonstrates the year sorting capabilities.
|
||||
|
||||
Try setting this file's metadata to `draft: true`.
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
title: '[Old] Chronological pagination example'
|
||||
description: 'Pagination works regardless of folder name.'
|
||||
date: '2024-03-21'
|
||||
draft: false
|
||||
---
|
||||
|
||||
This post should show up in proper chronological order even though its folder comes last in the `content/blog` directory.
|
||||
|
||||
The `Previous Post` and `Next Post` buttons under each blog post should also keep the proper chronological order, based on the frontmatter `date` field.
|
|
@ -4,7 +4,6 @@ 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
|
||||
|
@ -18,10 +17,9 @@ const { title, description } = Astro.props
|
|||
<html lang="en">
|
||||
<head>
|
||||
<Head title={`${title} | ${SITE.TITLE}`} description={description} />
|
||||
<ViewTransitions />
|
||||
</head>
|
||||
<body
|
||||
class="box-border flex h-fit min-h-screen flex-col px-4 font-sans antialiased"
|
||||
class="box-border flex h-fit min-h-screen flex-col px-4 font-sans bg-background text-foreground antialiased"
|
||||
>
|
||||
<Header />
|
||||
<main class="flex-grow">
|
||||
|
|
|
@ -9,7 +9,7 @@ import { SITE } from '@consts'
|
|||
<Layout title="404" description={SITE.DESCRIPTION}>
|
||||
<Container>
|
||||
<div class="mt-16 grid place-items-center gap-3">
|
||||
<h4 class="text-2xl font-semibold text-black dark:text-white">
|
||||
<h4 class="text-2xl font-semibold">
|
||||
404: Page not found
|
||||
</h4>
|
||||
<span>
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Image } from 'astro:assets'
|
|||
<Layout title="About" description="About">
|
||||
<Container>
|
||||
<div class="space-y-10">
|
||||
<div class="font-semibold text-black dark:text-white">About</div>
|
||||
<div class="font-semibold">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
|
||||
|
@ -26,7 +26,7 @@ import { Image } from 'astro:assets'
|
|||
<div class="flex flex-col justify-center md:flex-row">
|
||||
<div class="my-10 text-center">
|
||||
<div
|
||||
class="h-[250px] w-[350px] -rotate-6 overflow-hidden rounded-xl bg-neutral-300 object-cover"
|
||||
class="h-[250px] w-[350px] -rotate-6 overflow-hidden rounded-xl object-cover"
|
||||
>
|
||||
<Image
|
||||
src={'/astro-nano.png'}
|
||||
|
@ -42,7 +42,7 @@ import { Image } from 'astro:assets'
|
|||
</div>
|
||||
<div class="mx-10 my-10 text-center">
|
||||
<div
|
||||
class="mx-auto h-[250px] w-[150px] rotate-6 rounded-xl bg-neutral-300 object-cover sm:ml-auto"
|
||||
class="mx-auto h-[250px] w-[150px] rotate-6 rounded-xl object-cover sm:ml-auto"
|
||||
>
|
||||
<Image
|
||||
src={'/astro-micro.jpg'}
|
||||
|
|
|
@ -62,7 +62,7 @@ const { Content, headings } = await post.render()
|
|||
{readingTime(post.body)}
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="text-4xl font-semibold text-black dark:text-white">
|
||||
<h1 class="text-4xl font-semibold">
|
||||
{post.data.title}
|
||||
</h1>
|
||||
<div class="font-base text-sm">
|
||||
|
@ -72,7 +72,7 @@ const { Content, headings } = await post.render()
|
|||
<div class="my-1 inline-block">
|
||||
<a
|
||||
href={`/tags/${tag}`}
|
||||
class="mx-1 rounded-full bg-orange-300 px-2 py-1 transition-colors duration-300 ease-in-out hover:bg-cyan-200 dark:bg-orange-500 dark:hover:bg-cyan-500"
|
||||
class="mx-1 rounded-full px-2 py-1 transition-colors duration-300 ease-in-out"
|
||||
>
|
||||
#{tag}
|
||||
</a>
|
||||
|
@ -85,7 +85,7 @@ const { Content, headings } = await post.render()
|
|||
</div>
|
||||
</div>
|
||||
{headings.length > 0 && <TableOfContents headings={headings} />}
|
||||
<article class="animate">
|
||||
<article class="prose prose-neutral max-w-full dark:prose-invert prose-img:mx-auto prose-img:my-auto">
|
||||
<Content />
|
||||
<div class="mt-24">
|
||||
<PostNavigation prevPost={prevPost} nextPost={nextPost} />
|
||||
|
|
|
@ -31,7 +31,7 @@ const years = Object.keys(posts).sort((a, b) => parseInt(b) - parseInt(a))
|
|||
{
|
||||
years.map((year) => (
|
||||
<section class="space-y-4">
|
||||
<div class="font-semibold text-black dark:text-white">{year}</div>
|
||||
<div class="font-semibold">{year}</div>
|
||||
<div>
|
||||
<ul class="not-prose flex flex-col gap-4">
|
||||
{posts[year].map((post) => (
|
||||
|
|
|
@ -7,6 +7,7 @@ import Link from '@components/Link.astro'
|
|||
import { getCollection } from 'astro:content'
|
||||
import type { CollectionEntry } from 'astro:content'
|
||||
import SocialIcons from '@components/SocialIcons.astro'
|
||||
import { ModeToggle } from '@components/ui/mode-toggle'
|
||||
|
||||
const blog = (await getCollection('blog'))
|
||||
.filter((post) => !post.data.draft)
|
||||
|
@ -17,8 +18,9 @@ const blog = (await getCollection('blog'))
|
|||
<Layout title="Home" description="Home">
|
||||
<Container>
|
||||
<section class="space-y-6">
|
||||
<ModeToggle client:load />
|
||||
<div class="flex flex-wrap items-center justify-between gap-y-2">
|
||||
<h2 class="font-semibold text-black dark:text-white">Latest posts</h2>
|
||||
<h2 class="font-semibold">Latest posts</h2>
|
||||
<Link href="/blog"> See all posts </Link>
|
||||
</div>
|
||||
<ul class="not-prose flex flex-col gap-4">
|
||||
|
|
|
@ -36,9 +36,9 @@ export async function getStaticPaths() {
|
|||
>
|
||||
<Container>
|
||||
<div class="space-y-10">
|
||||
<div class="font-semibold text-black dark:text-white">
|
||||
<div class="font-semibold">
|
||||
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"
|
||||
class="mx-2 rounded-full px-3 py-2 transition-colors duration-300 ease-in-out"
|
||||
>#{tag}</span
|
||||
>
|
||||
</div>
|
||||
|
|
|
@ -14,14 +14,14 @@ const tags = blog
|
|||
<Layout title="Tags" description="Tags">
|
||||
<Container>
|
||||
<div class="space-y-10">
|
||||
<div class="font-semibold text-black dark:text-white">Tags</div>
|
||||
<div class="font-semibold">Tags</div>
|
||||
<ul class="flex flex-wrap">
|
||||
{
|
||||
tags.map((tag) => (
|
||||
<li class="my-3">
|
||||
<a
|
||||
href={`/tags/${tag}`}
|
||||
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"
|
||||
class="mx-2 rounded-full px-3 py-2 transition-colors duration-300 ease-in-out"
|
||||
>
|
||||
#{tag}
|
||||
</a>
|
||||
|
|
|
@ -2,42 +2,6 @@
|
|||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
article {
|
||||
@apply prose prose-neutral max-w-full dark:prose-invert prose-img:mx-auto prose-img:my-auto;
|
||||
@apply prose-headings:font-semibold;
|
||||
@apply prose-headings:text-black prose-headings:dark:text-white;
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
article a {
|
||||
@apply font-sans text-current underline underline-offset-[3px];
|
||||
@apply decoration-black/30 dark:decoration-white/30;
|
||||
@apply transition-colors duration-300 ease-in-out;
|
||||
}
|
||||
article a:hover {
|
||||
@apply text-black dark:text-white;
|
||||
@apply decoration-black/50 dark:decoration-white/50;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll_bar {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #1e293b #0f172a;
|
||||
}
|
||||
|
||||
html #back-to-top {
|
||||
@apply pointer-events-none opacity-0;
|
||||
}
|
||||
|
||||
html.scrolled #back-to-top {
|
||||
@apply pointer-events-auto opacity-100;
|
||||
}
|
||||
|
||||
/* shiki config */
|
||||
pre {
|
||||
@apply border border-black/15 py-5 dark:border-white/20;
|
||||
}
|
||||
|
||||
:root {
|
||||
--astro-code-color-text: #09090b;
|
||||
--astro-code-color-background: #fafafa;
|
||||
|
@ -66,19 +30,6 @@ pre {
|
|||
--astro-code-token-link: #8d85ff;
|
||||
}
|
||||
|
||||
/* copy code button on codeblocks */
|
||||
.copy-code {
|
||||
@apply absolute right-3 top-3 grid size-9 place-content-center rounded border border-black/15 bg-neutral-100 text-center duration-300 ease-in-out dark:border-white/20 dark:bg-neutral-900;
|
||||
}
|
||||
|
||||
.copy-code:hover {
|
||||
@apply bg-[#E9E9E9] transition-colors dark:bg-[#232323];
|
||||
}
|
||||
|
||||
.copy-code:active {
|
||||
@apply scale-90 transition-transform;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
|
@ -139,4 +90,18 @@ pre {
|
|||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
|
||||
html {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.disable-transitions * {
|
||||
@apply !transition-none;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ import type { Config } from 'tailwindcss'
|
|||
import defaultTheme from 'tailwindcss/defaultTheme'
|
||||
|
||||
const config: Config = {
|
||||
darkMode: ['class', 'class'],
|
||||
darkMode: ['selector'],
|
||||
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
|
||||
theme: {
|
||||
extend: {
|
||||
|
|
Loading…
Add table
Reference in a new issue