├── .gitignore
├── .prettierrc.mjs
├── .vscode
├── extensions.json
└── launch.json
├── LICENSE
├── README.md
├── astro.config.mjs
├── package-lock.json
├── package.json
├── public
├── astro-micro-lighthouse.jpg
├── astro-micro.jpg
├── astro-nano-lighthouse.jpg
├── astro-nano.png
├── astro-sphere-lighthouse.jpg
├── astro-sphere.jpg
├── blog-placeholder-1.jpg
├── deploy_netlify.svg
├── deploy_vercel.svg
├── favicon.ico
├── lighthouse-nano.jpg
├── lighthouse-sphere.jpg
├── pagefind
│ ├── fragment
│ │ ├── en_26435e5.pf_fragment
│ │ ├── en_2a5e6b1.pf_fragment
│ │ ├── en_2fed8eb.pf_fragment
│ │ ├── en_3131981.pf_fragment
│ │ ├── en_3923b3d.pf_fragment
│ │ ├── en_3ccfc4e.pf_fragment
│ │ ├── en_3ec1c2b.pf_fragment
│ │ ├── en_42f73b1.pf_fragment
│ │ ├── en_4885cf2.pf_fragment
│ │ ├── en_4cc991a.pf_fragment
│ │ ├── en_4f7e69c.pf_fragment
│ │ ├── en_51fdb47.pf_fragment
│ │ ├── en_54fba64.pf_fragment
│ │ ├── en_6935ba6.pf_fragment
│ │ ├── en_6ee846f.pf_fragment
│ │ ├── en_7a47df9.pf_fragment
│ │ ├── en_7cbffcd.pf_fragment
│ │ ├── en_8826d47.pf_fragment
│ │ ├── en_a1fb37a.pf_fragment
│ │ ├── en_a3eb135.pf_fragment
│ │ ├── en_ad42bb6.pf_fragment
│ │ ├── en_bbc53aa.pf_fragment
│ │ ├── en_cf248be.pf_fragment
│ │ ├── en_cf8ecb3.pf_fragment
│ │ ├── en_fbe187d.pf_fragment
│ │ └── en_fefcc58.pf_fragment
│ ├── index
│ │ ├── en_8739159.pf_index
│ │ └── en_d0dad81.pf_index
│ ├── pagefind-entry.json
│ ├── pagefind-highlight.js
│ ├── pagefind-modular-ui.css
│ ├── pagefind-modular-ui.js
│ ├── pagefind-ui.css
│ ├── pagefind-ui.js
│ ├── pagefind.en_2e70f624f4.pf_meta
│ ├── pagefind.en_3fd8bd6252.pf_meta
│ ├── pagefind.en_45ddb13fe8.pf_meta
│ ├── pagefind.js
│ ├── wasm.en.pagefind
│ └── wasm.unknown.pagefind
└── y-wing.jpeg
├── src
├── components
│ ├── ArrowCard.astro
│ ├── BackToPrevious.astro
│ ├── BackToTop.astro
│ ├── Callout.astro
│ ├── Container.astro
│ ├── Footer.astro
│ ├── FormattedDate.astro
│ ├── Giscus.astro
│ ├── Head.astro
│ ├── Header.astro
│ ├── Link.astro
│ ├── PageFind.astro
│ ├── PostNavigation.astro
│ ├── TableOfContents.astro
│ ├── TableOfContentsHeading.astro
│ └── TagCloud.astro
├── consts.ts
├── content.config.ts
├── content
│ ├── blog
│ │ ├── 00-micro-changelog
│ │ │ └── index.mdx
│ │ ├── 01-getting-started
│ │ │ └── index.md
│ │ ├── 02-blog-collection
│ │ │ └── index.md
│ │ ├── 03-projects-collection
│ │ │ └── index.md
│ │ ├── 04-markdown-syntax
│ │ │ ├── index.mdx
│ │ │ └── x-wing.jpeg
│ │ ├── 05-mdx-syntax
│ │ │ ├── component.astro
│ │ │ └── index.mdx
│ │ ├── 06-year-sorting-example
│ │ │ └── index.md
│ │ ├── 07-draft-example
│ │ │ └── index.md
│ │ └── 08-prev-next-order-example
│ │ │ └── index.md
│ └── projects
│ │ ├── project-1
│ │ └── index.md
│ │ ├── project-2
│ │ └── index.md
│ │ └── project-3
│ │ └── index.md
├── layouts
│ └── Layout.astro
├── lib
│ └── utils.ts
├── pages
│ ├── 404.astro
│ ├── blog
│ │ ├── [...id].astro
│ │ └── index.astro
│ ├── index.astro
│ ├── projects
│ │ ├── [...id].astro
│ │ └── index.astro
│ ├── rss.xml.js
│ └── tags
│ │ ├── [...id].astro
│ │ └── index.astro
├── styles
│ └── global.css
└── types.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | # generated types
4 | .astro/
5 |
6 | # dependencies
7 | node_modules/
8 |
9 | # logs
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
23 | # jetbrains setting folder
24 | .idea/
25 |
--------------------------------------------------------------------------------
/.prettierrc.mjs:
--------------------------------------------------------------------------------
1 | // .prettierrc.mjs
2 | /** @type {import("prettier").Config} */
3 | export default {
4 | plugins: ["prettier-plugin-astro", "prettier-plugin-tailwindcss"],
5 | overrides: [
6 | {
7 | files: "*.astro",
8 | options: {
9 | parser: "astro",
10 | },
11 | },
12 | ],
13 | };
14 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["astro-build.astro-vscode"],
3 | "unwantedRecommendations": []
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "command": "./node_modules/.bin/astro dev",
6 | "name": "Development server",
7 | "request": "launch",
8 | "type": "node-terminal"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Trevor Lee
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Introducing [Astro Micro 🔬](https://astro-micro.vercel.app/)
2 |
3 | Astro Micro is an accessible theme for Astro. It's a fork of [Mark Horn's](https://github.com/markhorn-dev) popular theme [Astro Nano](https://astro-nano-demo.vercel.app/). Like Nano, Micro comes with zero frameworks installed.
4 |
5 | Micro adds features like [Pagefind](https://pagefind.app) for search, [Giscus](https://giscus.app) for comments, and more. For a full list of changes, see this [blog post](https://astro-micro.vercel.app/blog/00-micro-changelog).
6 |
7 | Micro still comes with everything great about Nano — full type safety, a sitemap, an RSS feed, and Markdown + MDX support. Styled with TailwindCSS and preconfigured with system, light, and dark themes.
8 |
9 | ---
10 |
11 | 
12 |
--------------------------------------------------------------------------------
/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "astro/config";
2 | import sitemap from "@astrojs/sitemap";
3 | import mdx from "@astrojs/mdx";
4 | import pagefind from "astro-pagefind";
5 | import tailwindcss from "@tailwindcss/vite";
6 |
7 | // https://astro.build/config
8 | export default defineConfig({
9 | site: "https://astro-micro.vercel.app",
10 | integrations: [sitemap(), mdx(), pagefind()],
11 | vite: {
12 | plugins: [tailwindcss()],
13 | },
14 | markdown: {
15 | shikiConfig: {
16 | theme: "css-variables",
17 | },
18 | },
19 | });
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astro-micro",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro check && astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "@astrojs/check": "^0.9.4",
14 | "@astrojs/mdx": "^4.2.6",
15 | "@astrojs/rss": "^4.0.11",
16 | "@astrojs/sitemap": "^3.4.0",
17 | "@fontsource/geist-mono": "^5.2.6",
18 | "@fontsource/geist-sans": "^5.2.5",
19 | "@tailwindcss/vite": "^4.1.6",
20 | "astro": "^5.7.13",
21 | "astro-pagefind": "^1.8.3",
22 | "clsx": "^2.1.1",
23 | "tailwind-merge": "^3.3.0",
24 | "tailwindcss": "^4.1.6",
25 | "typescript": "^5.8.3"
26 | },
27 | "devDependencies": {
28 | "@tailwindcss/typography": "^0.5.16",
29 | "pagefind": "^1.3.0",
30 | "prettier": "^3.5.3",
31 | "prettier-plugin-astro": "^0.14.1",
32 | "prettier-plugin-tailwindcss": "^0.6.11"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/public/astro-micro-lighthouse.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/astro-micro-lighthouse.jpg
--------------------------------------------------------------------------------
/public/astro-micro.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/astro-micro.jpg
--------------------------------------------------------------------------------
/public/astro-nano-lighthouse.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/astro-nano-lighthouse.jpg
--------------------------------------------------------------------------------
/public/astro-nano.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/astro-nano.png
--------------------------------------------------------------------------------
/public/astro-sphere-lighthouse.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/astro-sphere-lighthouse.jpg
--------------------------------------------------------------------------------
/public/astro-sphere.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/astro-sphere.jpg
--------------------------------------------------------------------------------
/public/blog-placeholder-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/blog-placeholder-1.jpg
--------------------------------------------------------------------------------
/public/deploy_netlify.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/public/deploy_vercel.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/favicon.ico
--------------------------------------------------------------------------------
/public/lighthouse-nano.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/lighthouse-nano.jpg
--------------------------------------------------------------------------------
/public/lighthouse-sphere.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/lighthouse-sphere.jpg
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_26435e5.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_26435e5.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_2a5e6b1.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_2a5e6b1.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_2fed8eb.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_2fed8eb.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_3131981.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_3131981.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_3923b3d.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_3923b3d.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_3ccfc4e.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_3ccfc4e.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_3ec1c2b.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_3ec1c2b.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_42f73b1.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_42f73b1.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_4885cf2.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_4885cf2.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_4cc991a.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_4cc991a.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_4f7e69c.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_4f7e69c.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_51fdb47.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_51fdb47.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_54fba64.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_54fba64.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_6935ba6.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_6935ba6.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_6ee846f.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_6ee846f.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_7a47df9.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_7a47df9.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_7cbffcd.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_7cbffcd.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_8826d47.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_8826d47.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_a1fb37a.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_a1fb37a.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_a3eb135.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_a3eb135.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_ad42bb6.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_ad42bb6.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_bbc53aa.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_bbc53aa.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_cf248be.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_cf248be.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_cf8ecb3.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_cf8ecb3.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_fbe187d.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_fbe187d.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/fragment/en_fefcc58.pf_fragment:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/fragment/en_fefcc58.pf_fragment
--------------------------------------------------------------------------------
/public/pagefind/index/en_8739159.pf_index:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/index/en_8739159.pf_index
--------------------------------------------------------------------------------
/public/pagefind/index/en_d0dad81.pf_index:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/index/en_d0dad81.pf_index
--------------------------------------------------------------------------------
/public/pagefind/pagefind-entry.json:
--------------------------------------------------------------------------------
1 | {"version":"1.1.0","languages":{"en":{"hash":"en_45ddb13fe8","wasm":"en","page_count":13}}}
--------------------------------------------------------------------------------
/public/pagefind/pagefind-modular-ui.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --pagefind-ui-scale: 0.8;
3 | --pagefind-ui-primary: #034AD8;
4 | --pagefind-ui-fade: #707070;
5 | --pagefind-ui-text: #393939;
6 | --pagefind-ui-background: #ffffff;
7 | --pagefind-ui-border: #eeeeee;
8 | --pagefind-ui-tag: #eeeeee;
9 | --pagefind-ui-border-width: 2px;
10 | --pagefind-ui-border-radius: 8px;
11 | --pagefind-ui-image-border-radius: 8px;
12 | --pagefind-ui-image-box-ratio: 3 / 2;
13 | --pagefind-ui-font: system, -apple-system, ".SFNSText-Regular",
14 | "San Francisco", "Roboto", "Segoe UI", "Helvetica Neue",
15 | "Lucida Grande", sans-serif;
16 | }
17 |
18 | [data-pfmod-hidden] {
19 | display: none !important;
20 | }
21 |
22 | [data-pfmod-suppressed] {
23 | opacity: 0 !important;
24 | pointer-events: none !important;
25 | }
26 |
27 | [data-pfmod-sr-hidden] {
28 | -webkit-clip: rect(0 0 0 0) !important;
29 | clip: rect(0 0 0 0) !important;
30 | -webkit-clip-path: inset(100%) !important;
31 | clip-path: inset(100%) !important;
32 | height: 1px !important;
33 | overflow: hidden !important;
34 | overflow: clip !important;
35 | position: absolute !important;
36 | white-space: nowrap !important;
37 | width: 1px !important;
38 | }
39 |
40 | [data-pfmod-loading] {
41 | color: var(--pagefind-ui-text);
42 | background-color: var(--pagefind-ui-text);
43 | border-radius: var(--pagefind-ui-border-radius);
44 | opacity: 0.1;
45 | pointer-events: none;
46 | }
47 |
48 | /* Input */
49 |
50 | .pagefind-modular-input-wrapper {
51 | position: relative;
52 | }
53 |
54 | .pagefind-modular-input-wrapper::before {
55 | background-color: var(--pagefind-ui-text);
56 | width: calc(18px * var(--pagefind-ui-scale));
57 | height: calc(18px * var(--pagefind-ui-scale));
58 | top: calc(23px * var(--pagefind-ui-scale));
59 | left: calc(20px * var(--pagefind-ui-scale));
60 | content: "";
61 | position: absolute;
62 | display: block;
63 | opacity: 0.7;
64 | -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.7549 11.255H11.9649L11.6849 10.985C12.6649 9.845 13.2549 8.365 13.2549 6.755C13.2549 3.165 10.3449 0.255005 6.75488 0.255005C3.16488 0.255005 0.254883 3.165 0.254883 6.755C0.254883 10.345 3.16488 13.255 6.75488 13.255C8.36488 13.255 9.84488 12.665 10.9849 11.685L11.2549 11.965V12.755L16.2549 17.745L17.7449 16.255L12.7549 11.255ZM6.75488 11.255C4.26488 11.255 2.25488 9.245 2.25488 6.755C2.25488 4.26501 4.26488 2.255 6.75488 2.255C9.24488 2.255 11.2549 4.26501 11.2549 6.755C11.2549 9.245 9.24488 11.255 6.75488 11.255Z' fill='%23000000'/%3E%3C/svg%3E%0A");
65 | mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.7549 11.255H11.9649L11.6849 10.985C12.6649 9.845 13.2549 8.365 13.2549 6.755C13.2549 3.165 10.3449 0.255005 6.75488 0.255005C3.16488 0.255005 0.254883 3.165 0.254883 6.755C0.254883 10.345 3.16488 13.255 6.75488 13.255C8.36488 13.255 9.84488 12.665 10.9849 11.685L11.2549 11.965V12.755L16.2549 17.745L17.7449 16.255L12.7549 11.255ZM6.75488 11.255C4.26488 11.255 2.25488 9.245 2.25488 6.755C2.25488 4.26501 4.26488 2.255 6.75488 2.255C9.24488 2.255 11.2549 4.26501 11.2549 6.755C11.2549 9.245 9.24488 11.255 6.75488 11.255Z' fill='%23000000'/%3E%3C/svg%3E%0A");
66 | -webkit-mask-size: 100%;
67 | mask-size: 100%;
68 | z-index: 9;
69 | pointer-events: none;
70 | }
71 |
72 | .pagefind-modular-input {
73 | height: calc(64px * var(--pagefind-ui-scale));
74 | padding: 0 calc(70px * var(--pagefind-ui-scale)) 0 calc(54px * var(--pagefind-ui-scale));
75 | background-color: var(--pagefind-ui-background);
76 | border: var(--pagefind-ui-border-width) solid var(--pagefind-ui-border);
77 | border-radius: var(--pagefind-ui-border-radius);
78 | font-size: calc(21px * var(--pagefind-ui-scale));
79 | position: relative;
80 | appearance: none;
81 | -webkit-appearance: none;
82 | display: flex;
83 | width: 100%;
84 | box-sizing: border-box;
85 | font-weight: 700;
86 | }
87 |
88 | .pagefind-modular-input::placeholder {
89 | opacity: 0.2;
90 | }
91 |
92 | .pagefind-modular-input-clear {
93 | position: absolute;
94 | top: calc(2px * var(--pagefind-ui-scale));
95 | right: calc(2px * var(--pagefind-ui-scale));
96 | height: calc(60px * var(--pagefind-ui-scale));
97 | border-radius: var(--pagefind-ui-border-radius);
98 | padding: 0 calc(15px * var(--pagefind-ui-scale)) 0 calc(2px * var(--pagefind-ui-scale));
99 | color: var(--pagefind-ui-text);
100 | font-size: calc(14px * var(--pagefind-ui-scale));
101 | cursor: pointer;
102 | background-color: var(--pagefind-ui-background);
103 | border: none;
104 | appearance: none;
105 | }
106 |
107 | /* ResultList */
108 |
109 | .pagefind-modular-list-result {
110 | list-style-type: none;
111 | display: flex;
112 | align-items: flex-start;
113 | gap: min(calc(40px * var(--pagefind-ui-scale)), 3%);
114 | padding: calc(30px * var(--pagefind-ui-scale)) 0 calc(40px * var(--pagefind-ui-scale));
115 | border-top: solid var(--pagefind-ui-border-width) var(--pagefind-ui-border);
116 | }
117 |
118 | .pagefind-modular-list-result:last-of-type {
119 | border-bottom: solid var(--pagefind-ui-border-width) var(--pagefind-ui-border);
120 | }
121 |
122 | .pagefind-modular-list-thumb {
123 | width: min(30%,
124 | calc((30% - (100px * var(--pagefind-ui-scale))) * 100000));
125 | max-width: calc(120px * var(--pagefind-ui-scale));
126 | margin-top: calc(10px * var(--pagefind-ui-scale));
127 | aspect-ratio: var(--pagefind-ui-image-box-ratio);
128 | position: relative;
129 | }
130 |
131 | .pagefind-modular-list-image {
132 | display: block;
133 | position: absolute;
134 | left: 50%;
135 | transform: translateX(-50%);
136 | font-size: 0;
137 | width: auto;
138 | height: auto;
139 | max-width: 100%;
140 | max-height: 100%;
141 | border-radius: var(--pagefind-ui-image-border-radius);
142 | }
143 |
144 | .pagefind-modular-list-inner {
145 | flex: 1;
146 | display: flex;
147 | flex-direction: column;
148 | align-items: flex-start;
149 | margin-top: calc(10px * var(--pagefind-ui-scale));
150 | }
151 |
152 | .pagefind-modular-list-title {
153 | display: inline-block;
154 | font-weight: 700;
155 | font-size: calc(21px * var(--pagefind-ui-scale));
156 | margin-top: 0;
157 | margin-bottom: 0;
158 | }
159 |
160 | .pagefind-modular-list-link {
161 | color: var(--pagefind-ui-text);
162 | text-decoration: none;
163 | }
164 |
165 | .pagefind-modular-list-link:hover {
166 | text-decoration: underline;
167 | }
168 |
169 | .pagefind-modular-list-excerpt {
170 | display: inline-block;
171 | font-weight: 400;
172 | font-size: calc(16px * var(--pagefind-ui-scale));
173 | margin-top: calc(4px * var(--pagefind-ui-scale));
174 | margin-bottom: 0;
175 | min-width: calc(250px * var(--pagefind-ui-scale));
176 | }
177 |
178 | /* FilterPills */
179 |
180 | .pagefind-modular-filter-pills-wrapper {
181 | overflow-x: scroll;
182 | padding: 15px 0;
183 | }
184 |
185 | .pagefind-modular-filter-pills {
186 | display: flex;
187 | gap: 6px;
188 | }
189 |
190 | .pagefind-modular-filter-pill {
191 | display: flex;
192 | justify-content: center;
193 | align-items: center;
194 | border: none;
195 | appearance: none;
196 | padding: 0 calc(24px * var(--pagefind-ui-scale));
197 | background-color: var(--pagefind-ui-background);
198 | color: var(--pagefind-ui-fade);
199 | border: var(--pagefind-ui-border-width) solid var(--pagefind-ui-border);
200 | border-radius: calc(25px * var(--pagefind-ui-scale));
201 | font-size: calc(18px * var(--pagefind-ui-scale));
202 | height: calc(50px * var(--pagefind-ui-scale));
203 | cursor: pointer;
204 | white-space: nowrap;
205 | }
206 |
207 | .pagefind-modular-filter-pill:hover {
208 | border-color: var(--pagefind-ui-primary);
209 | }
210 |
211 | .pagefind-modular-filter-pill[aria-pressed="true"] {
212 | border-color: var(--pagefind-ui-primary);
213 | color: var(--pagefind-ui-primary);
214 | }
--------------------------------------------------------------------------------
/public/pagefind/pagefind-modular-ui.js:
--------------------------------------------------------------------------------
1 | (()=>{var b=Object.defineProperty;var w=(i,e)=>{for(var t in e)b(i,t,{get:e[t],enumerable:!0})};var f={};w(f,{FilterPills:()=>h,Input:()=>l,Instance:()=>p,ResultList:()=>a,Summary:()=>o});var r=class i{constructor(e){this.element=document.createElement(e)}id(e){return this.element.id=e,this}class(e){return this.element.classList.add(e),this}attrs(e){for(let[t,s]of Object.entries(e))this.element.setAttribute(t,s);return this}text(e){return this.element.innerText=e,this}html(e){return this.element.innerHTML=e,this}handle(e,t){return this.element.addEventListener(e,t),this}addTo(e){return e instanceof i?e.element.appendChild(this.element):e.appendChild(this.element),this.element}};var T=async(i=100)=>new Promise(e=>setTimeout(e,i)),l=class{constructor(e={}){if(this.inputEl=null,this.clearEl=null,this.instance=null,this.searchID=0,this.debounceTimeoutMs=e.debounceTimeoutMs??300,e.inputElement){if(e.containerElement){console.warn("[Pagefind Input component]: inputElement and containerElement both supplied. Ignoring the container option.");return}this.initExisting(e.inputElement)}else if(e.containerElement)this.initContainer(e.containerElement);else{console.error("[Pagefind Input component]: No selector supplied for containerElement or inputElement");return}this.inputEl.addEventListener("input",async t=>{if(this.instance&&typeof t?.target?.value=="string"){this.updateState(t.target.value);let s=++this.searchID;if(await T(this.debounceTimeoutMs),s!==this.searchID)return null;this.instance?.triggerSearch(t.target.value)}}),this.inputEl.addEventListener("keydown",t=>{t.key==="Escape"&&(++this.searchID,this.inputEl.value="",this.instance?.triggerSearch(""),this.updateState("")),t.key==="Enter"&&t.preventDefault()}),this.inputEl.addEventListener("focus",()=>{this.instance?.triggerLoad()})}initContainer(e){let t=document.querySelector(e);if(!t){console.error(`[Pagefind Input component]: No container found for ${e} selector`);return}if(t.tagName==="INPUT")console.warn(`[Pagefind Input component]: Encountered input element for ${e} when a container was expected`),console.warn("[Pagefind Input component]: Treating containerElement option as inputElement and proceeding"),this.initExisting(e);else{t.innerHTML="";let s=0;for(;document.querySelector(`#pfmod-input-${s}`);)s+=1;let n=new r("form").class("pagefind-modular-input-wrapper").attrs({role:"search","aria-label":"Search this site",action:"javascript:void(0);"});new r("label").attrs({for:`pfmod-input-${s}`,"data-pfmod-sr-hidden":"true"}).text("Search this site").addTo(n),this.inputEl=new r("input").id(`pfmod-input-${s}`).class("pagefind-modular-input").attrs({autocapitalize:"none",enterkeyhint:"search"}).addTo(n),this.clearEl=new r("button").class("pagefind-modular-input-clear").attrs({"data-pfmod-suppressed":"true"}).text("Clear").handle("click",()=>{this.inputEl.value="",this.instance.triggerSearch(""),this.updateState("")}).addTo(n),n.addTo(t)}}initExisting(e){let t=document.querySelector(e);if(!t){console.error(`[Pagefind Input component]: No input element found for ${e} selector`);return}if(t.tagName!=="INPUT"){console.error(`[Pagefind Input component]: Expected ${e} to be an element`);return}this.inputEl=t}updateState(e){this.clearEl&&(e&&e?.length?this.clearEl.removeAttribute("data-pfmod-suppressed"):this.clearEl.setAttribute("data-pfmod-suppressed","true"))}register(e){this.instance=e,this.instance.on("search",(t,s)=>{this.inputEl&&document.activeElement!==this.inputEl&&(this.inputEl.value=t,this.updateState(t))})}focus(){this.inputEl&&this.inputEl.focus()}};var g=i=>{if(i instanceof Element)return[i];if(Array.isArray(i)&&i.every(e=>e instanceof Element))return i;if(typeof i=="string"||i instanceof String){let e=document.createElement("div");return e.innerHTML=i,[...e.childNodes]}else return console.error(`[Pagefind ResultList component]: Expected template function to return an HTML element or string, got ${typeof i}`),[]},v=()=>{let i=(e=30)=>". ".repeat(Math.floor(10+Math.random()*e));return`
2 |
3 |
4 |
${i(30)}
5 |
${i(40)}
6 |
7 | `},y=i=>{let e=new r("li").class("pagefind-modular-list-result"),t=new r("div").class("pagefind-modular-list-thumb").addTo(e);i?.meta?.image&&new r("img").class("pagefind-modular-list-image").attrs({src:i.meta.image,alt:i.meta.image_alt||i.meta.title}).addTo(t);let s=new r("div").class("pagefind-modular-list-inner").addTo(e),n=new r("p").class("pagefind-modular-list-title").addTo(s);return new r("a").class("pagefind-modular-list-link").text(i.meta?.title).attrs({href:i.meta?.url||i.url}).addTo(n),new r("p").class("pagefind-modular-list-excerpt").html(i.excerpt).addTo(s),e.element},E=i=>{if(!(i instanceof HTMLElement))return null;let e=window.getComputedStyle(i).overflowY;return e!=="visible"&&e!=="hidden"?i:E(i.parentNode)},d=class{constructor(e={}){this.rawResult=e.result,this.placeholderNodes=e.placeholderNodes,this.resultFn=e.resultFn,this.intersectionEl=e.intersectionEl,this.result=null,this.waitForIntersection()}waitForIntersection(){if(!this.placeholderNodes?.length)return;let e={root:this.intersectionEl,rootMargin:"0px",threshold:.01};new IntersectionObserver((s,n)=>{this.result===null&&s?.[0]?.isIntersecting&&(this.load(),n.disconnect())},e).observe(this.placeholderNodes[0])}async load(){if(!this.placeholderNodes?.length)return;this.result=await this.rawResult.data();let e=this.resultFn(this.result),t=g(e);for(;this.placeholderNodes.length>1;)this.placeholderNodes.pop().remove();this.placeholderNodes[0].replaceWith(...t)}},a=class{constructor(e){if(this.intersectionEl=document.body,this.containerEl=null,this.results=[],this.placeholderTemplate=e.placeholderTemplate??v,this.resultTemplate=e.resultTemplate??y,e.containerElement)this.initContainer(e.containerElement);else{console.error("[Pagefind ResultList component]: No selector supplied for containerElement");return}}initContainer(e){let t=document.querySelector(e);if(!t){console.error(`[Pagefind ResultList component]: No container found for ${e} selector`);return}this.containerEl=t}append(e){for(let t of e)this.containerEl.appendChild(t)}register(e){e.on("results",t=>{this.containerEl&&(this.containerEl.innerHTML="",this.intersectionEl=E(this.containerEl),this.results=t.results.map(s=>{let n=g(this.placeholderTemplate());return this.append(n),new d({result:s,placeholderNodes:n,resultFn:this.resultTemplate,intersectionEl:this.intersectionEl})}))}),e.on("loading",()=>{this.containerEl&&(this.containerEl.innerHTML="")})}};var o=class{constructor(e={}){if(this.containerEl=null,this.defaultMessage=e.defaultMessage??"",this.term="",e.containerElement)this.initContainer(e.containerElement);else{console.error("[Pagefind Summary component]: No selector supplied for containerElement");return}}initContainer(e){let t=document.querySelector(e);if(!t){console.error(`[Pagefind Summary component]: No container found for ${e} selector`);return}this.containerEl=t,this.containerEl.innerText=this.defaultMessage}register(e){e.on("search",(t,s)=>{this.term=t}),e.on("results",t=>{if(!this.containerEl||!t)return;if(!this.term){this.containerEl.innerText=this.defaultMessage;return}let s=t?.results?.length??0;this.containerEl.innerText=`${s} result${s===1?"":"s"} for ${this.term}`}),e.on("loading",()=>{this.containerEl&&(this.containerEl.innerText=`Searching for ${this.term}...`)})}};var h=class{constructor(e={}){if(this.instance=null,this.wrapper=null,this.pillContainer=null,this.available={},this.selected=["All"],this.total=0,this.filterMemo="",this.filter=e.filter,this.ordering=e.ordering??null,this.alwaysShow=e.alwaysShow??!1,this.selectMultiple=e.selectMultiple??!1,!this.filter?.length){console.error("[Pagefind FilterPills component]: No filter option supplied, nothing to display");return}if(e.containerElement)this.initContainer(e.containerElement);else{console.error("[Pagefind FilterPills component]: No selector supplied for containerElement");return}}initContainer(e){let t=document.querySelector(e);if(!t){console.error(`[Pagefind FilterPills component]: No container found for ${e} selector`);return}t.innerHTML="";let s=`pagefind_modular_filter_pills_${this.filter}`,n=new r("div").class("pagefind-modular-filter-pills-wrapper").attrs({role:"group","aria-labelledby":s});this.alwaysShow||n.attrs({"data-pfmod-hidden":!0}),new r("div").id(s).class("pagefind-modular-filter-pills-label").attrs({"data-pfmod-sr-hidden":!0}).text(`Filter results by ${this.filter}`).addTo(n),this.pillContainer=new r("div").class("pagefind-modular-filter-pills").addTo(n),this.wrapper=n.addTo(t)}update(){let e=this.available.map(t=>t[0]).join("~");e==this.filterMemo?this.updateExisting():(this.renderNew(),this.filterMemo=e)}pushFilters(){let e=this.selected.filter(t=>t!=="All");this.instance.triggerFilter(this.filter,e)}pillInner(e,t){return this.total?`${e} (${t}) `:`${e} `}renderNew(){this.available.forEach(([e,t])=>{new r("button").class("pagefind-modular-filter-pill").html(this.pillInner(e,t)).attrs({"aria-pressed":this.selected.includes(e),type:"button"}).handle("click",()=>{e==="All"?this.selected=["All"]:this.selected.includes(e)?this.selected=this.selected.filter(s=>s!==e):this.selectMultiple?this.selected.push(e):this.selected=[e],this.selected?.length?this.selected?.length>1&&(this.selected=this.selected.filter(s=>s!=="All")):this.selected=["All"],this.update(),this.pushFilters()}).addTo(this.pillContainer)})}updateExisting(){let e=[...this.pillContainer.childNodes];this.available.forEach(([t,s],n)=>{e[n].innerHTML=this.pillInner(t,s),e[n].setAttribute("aria-pressed",this.selected.includes(t))})}register(e){this.instance=e,this.instance.on("filters",t=>{if(!this.pillContainer)return;this.selectMultiple?t=t.available:t=t.total;let s=t[this.filter];if(!s){console.warn(`[Pagefind FilterPills component]: No possible values found for the ${this.filter} filter`);return}this.available=Object.entries(s),Array.isArray(this.ordering)?this.available.sort((n,c)=>{let m=this.ordering.indexOf(n[0]),_=this.ordering.indexOf(c[0]);return(m===-1?1/0:m)-(_===-1?1/0:_)}):this.available.sort((n,c)=>n[0].localeCompare(c[0])),this.available.unshift(["All",this.total]),this.update()}),e.on("results",t=>{this.pillContainer&&(this.total=t?.unfilteredResultCount||0,this.available?.[0]?.[0]==="All"&&(this.available[0][1]=this.total),this.total||this.alwaysShow?this.wrapper.removeAttribute("data-pfmod-hidden"):this.wrapper.setAttribute("data-pfmod-hidden","true"),this.update())})}};var F=async(i=50)=>await new Promise(e=>setTimeout(e,i)),u;try{u=new URL(document.currentScript.src).pathname.match(/^(.*\/)(?:pagefind-)?modular-ui.js.*$/)[1]}catch{u="/pagefind/"}var p=class{constructor(e={}){this.__pagefind__=null,this.__initializing__=null,this.__searchID__=0,this.__hooks__={search:[],filters:[],loading:[],results:[]},this.components=[],this.searchTerm="",this.searchFilters={},this.searchResult={},this.availableFilters=null,this.totalFilters=null,this.options={bundlePath:e.bundlePath??u,mergeIndex:e.mergeIndex??[]},delete e.bundlePath,delete e.resetStyles,delete e.processResult,delete e.processTerm,delete e.debounceTimeoutMs,delete e.mergeIndex,delete e.translations,this.pagefindOptions=e}add(e){e?.register?.(this),this.components.push(e)}on(e,t){if(!this.__hooks__[e]){let s=Object.keys(this.__hooks__).join(", ");console.error(`[Pagefind Composable]: Unknown event type ${e}. Supported events: [${s}]`);return}if(typeof t!="function"){console.error(`[Pagefind Composable]: Expected callback to be a function, received ${typeof t}`);return}this.__hooks__[e].push(t)}triggerLoad(){this.__load__()}triggerSearch(e){this.searchTerm=e,this.__dispatch__("search",e,this.searchFilters),this.__search__(e,this.searchFilters)}triggerSearchWithFilters(e,t){this.searchTerm=e,this.searchFilters=t,this.__dispatch__("search",e,t),this.__search__(e,t)}triggerFilters(e){this.searchFilters=e,this.__dispatch__("search",this.searchTerm,e),this.__search__(this.searchTerm,e)}triggerFilter(e,t){this.searchFilters=this.searchFilters||{},this.searchFilters[e]=t,this.__dispatch__("search",this.searchTerm,this.searchFilters),this.__search__(this.searchTerm,this.searchFilters)}__dispatch__(e,...t){this.__hooks__[e]?.forEach(s=>s?.(...t))}async __clear__(){this.__dispatch__("results",{results:[],unfilteredTotalCount:0}),this.availableFilters=await this.__pagefind__.filters(),this.totalFilters=this.availableFilters,this.__dispatch__("filters",{available:this.availableFilters,total:this.totalFilters})}async __search__(e,t){this.__dispatch__("loading"),await this.__load__();let s=++this.__searchID__;if(!e||!e.length)return this.__clear__();let n=await this.__pagefind__.search(e,{filters:t});n&&this.__searchID__===s&&(n.filters&&Object.keys(n.filters)?.length&&(this.availableFilters=n.filters,this.totalFilters=n.totalFilters,this.__dispatch__("filters",{available:this.availableFilters,total:this.totalFilters})),this.searchResult=n,this.__dispatch__("results",this.searchResult))}async __load__(){if(this.__initializing__){for(;!this.__pagefind__;)await F(50);return}if(this.__initializing__=!0,!this.__pagefind__){let e;try{e=await import(`${this.options.bundlePath}pagefind.js`)}catch(t){console.error(t),console.error([`Pagefind couldn't be loaded from ${this.options.bundlePath}pagefind.js`,"You can configure this by passing a bundlePath option to PagefindComposable Instance",`[DEBUG: Loaded from ${document?.currentScript?.src??"no known script location"}]`].join(`
8 | `))}await e.options(this.pagefindOptions||{});for(let t of this.options.mergeIndex){if(!t.bundlePath)throw new Error("mergeIndex requires a bundlePath parameter");let s=t.bundlePath;delete t.bundlePath,await e.mergeIndex(s,t)}this.__pagefind__=e}this.availableFilters=await this.__pagefind__.filters(),this.totalFilters=this.availableFilters,this.__dispatch__("filters",{available:this.availableFilters,total:this.totalFilters})}};window.PagefindModularUI=f;})();
9 |
--------------------------------------------------------------------------------
/public/pagefind/pagefind-ui.css:
--------------------------------------------------------------------------------
1 | .pagefind-ui__result.svelte-j9e30.svelte-j9e30{list-style-type:none;display:flex;align-items:flex-start;gap:min(calc(40px * var(--pagefind-ui-scale)),3%);padding:calc(30px * var(--pagefind-ui-scale)) 0 calc(40px * var(--pagefind-ui-scale));border-top:solid var(--pagefind-ui-border-width) var(--pagefind-ui-border)}.pagefind-ui__result.svelte-j9e30.svelte-j9e30:last-of-type{border-bottom:solid var(--pagefind-ui-border-width) var(--pagefind-ui-border)}.pagefind-ui__result-thumb.svelte-j9e30.svelte-j9e30{width:min(30%,calc((30% - (100px * var(--pagefind-ui-scale))) * 100000));max-width:calc(120px * var(--pagefind-ui-scale));margin-top:calc(10px * var(--pagefind-ui-scale));aspect-ratio:var(--pagefind-ui-image-box-ratio);position:relative}.pagefind-ui__result-image.svelte-j9e30.svelte-j9e30{display:block;position:absolute;left:50%;transform:translate(-50%);font-size:0;width:auto;height:auto;max-width:100%;max-height:100%;border-radius:var(--pagefind-ui-image-border-radius)}.pagefind-ui__result-inner.svelte-j9e30.svelte-j9e30{flex:1;display:flex;flex-direction:column;align-items:flex-start;margin-top:calc(10px * var(--pagefind-ui-scale))}.pagefind-ui__result-title.svelte-j9e30.svelte-j9e30{display:inline-block;font-weight:700;font-size:calc(21px * var(--pagefind-ui-scale));margin-top:0;margin-bottom:0}.pagefind-ui__result-title.svelte-j9e30 .pagefind-ui__result-link.svelte-j9e30{color:var(--pagefind-ui-text);text-decoration:none}.pagefind-ui__result-title.svelte-j9e30 .pagefind-ui__result-link.svelte-j9e30:hover{text-decoration:underline}.pagefind-ui__result-excerpt.svelte-j9e30.svelte-j9e30{display:inline-block;font-weight:400;font-size:calc(16px * var(--pagefind-ui-scale));margin-top:calc(4px * var(--pagefind-ui-scale));margin-bottom:0;min-width:calc(250px * var(--pagefind-ui-scale))}.pagefind-ui__loading.svelte-j9e30.svelte-j9e30{color:var(--pagefind-ui-text);background-color:var(--pagefind-ui-text);border-radius:var(--pagefind-ui-border-radius);opacity:.1;pointer-events:none}.pagefind-ui__result-tags.svelte-j9e30.svelte-j9e30{list-style-type:none;padding:0;display:flex;gap:calc(20px * var(--pagefind-ui-scale));flex-wrap:wrap;margin-top:calc(20px * var(--pagefind-ui-scale))}.pagefind-ui__result-tag.svelte-j9e30.svelte-j9e30{padding:calc(4px * var(--pagefind-ui-scale)) calc(8px * var(--pagefind-ui-scale));font-size:calc(14px * var(--pagefind-ui-scale));border-radius:var(--pagefind-ui-border-radius);background-color:var(--pagefind-ui-tag)}.pagefind-ui__result.svelte-4xnkmf.svelte-4xnkmf{list-style-type:none;display:flex;align-items:flex-start;gap:min(calc(40px * var(--pagefind-ui-scale)),3%);padding:calc(30px * var(--pagefind-ui-scale)) 0 calc(40px * var(--pagefind-ui-scale));border-top:solid var(--pagefind-ui-border-width) var(--pagefind-ui-border)}.pagefind-ui__result.svelte-4xnkmf.svelte-4xnkmf:last-of-type{border-bottom:solid var(--pagefind-ui-border-width) var(--pagefind-ui-border)}.pagefind-ui__result-nested.svelte-4xnkmf.svelte-4xnkmf{display:flex;flex-direction:column;padding-left:calc(20px * var(--pagefind-ui-scale))}.pagefind-ui__result-nested.svelte-4xnkmf.svelte-4xnkmf:first-of-type{padding-top:calc(10px * var(--pagefind-ui-scale))}.pagefind-ui__result-nested.svelte-4xnkmf .pagefind-ui__result-link.svelte-4xnkmf{font-size:.9em;position:relative}.pagefind-ui__result-nested.svelte-4xnkmf .pagefind-ui__result-link.svelte-4xnkmf:before{content:"\2937 ";position:absolute;top:0;right:calc(100% + .1em)}.pagefind-ui__result-thumb.svelte-4xnkmf.svelte-4xnkmf{width:min(30%,calc((30% - (100px * var(--pagefind-ui-scale))) * 100000));max-width:calc(120px * var(--pagefind-ui-scale));margin-top:calc(10px * var(--pagefind-ui-scale));aspect-ratio:var(--pagefind-ui-image-box-ratio);position:relative}.pagefind-ui__result-image.svelte-4xnkmf.svelte-4xnkmf{display:block;position:absolute;left:50%;transform:translate(-50%);font-size:0;width:auto;height:auto;max-width:100%;max-height:100%;border-radius:var(--pagefind-ui-image-border-radius)}.pagefind-ui__result-inner.svelte-4xnkmf.svelte-4xnkmf{flex:1;display:flex;flex-direction:column;align-items:flex-start;margin-top:calc(10px * var(--pagefind-ui-scale))}.pagefind-ui__result-title.svelte-4xnkmf.svelte-4xnkmf{display:inline-block;font-weight:700;font-size:calc(21px * var(--pagefind-ui-scale));margin-top:0;margin-bottom:0}.pagefind-ui__result-title.svelte-4xnkmf .pagefind-ui__result-link.svelte-4xnkmf{color:var(--pagefind-ui-text);text-decoration:none}.pagefind-ui__result-title.svelte-4xnkmf .pagefind-ui__result-link.svelte-4xnkmf:hover{text-decoration:underline}.pagefind-ui__result-excerpt.svelte-4xnkmf.svelte-4xnkmf{display:inline-block;font-weight:400;font-size:calc(16px * var(--pagefind-ui-scale));margin-top:calc(4px * var(--pagefind-ui-scale));margin-bottom:0;min-width:calc(250px * var(--pagefind-ui-scale))}.pagefind-ui__loading.svelte-4xnkmf.svelte-4xnkmf{color:var(--pagefind-ui-text);background-color:var(--pagefind-ui-text);border-radius:var(--pagefind-ui-border-radius);opacity:.1;pointer-events:none}.pagefind-ui__result-tags.svelte-4xnkmf.svelte-4xnkmf{list-style-type:none;padding:0;display:flex;gap:calc(20px * var(--pagefind-ui-scale));flex-wrap:wrap;margin-top:calc(20px * var(--pagefind-ui-scale))}.pagefind-ui__result-tag.svelte-4xnkmf.svelte-4xnkmf{padding:calc(4px * var(--pagefind-ui-scale)) calc(8px * var(--pagefind-ui-scale));font-size:calc(14px * var(--pagefind-ui-scale));border-radius:var(--pagefind-ui-border-radius);background-color:var(--pagefind-ui-tag)}legend.svelte-1v2r7ls.svelte-1v2r7ls{position:absolute;clip:rect(0 0 0 0)}.pagefind-ui__filter-panel.svelte-1v2r7ls.svelte-1v2r7ls{min-width:min(calc(260px * var(--pagefind-ui-scale)),100%);flex:1;display:flex;flex-direction:column;margin-top:calc(20px * var(--pagefind-ui-scale))}.pagefind-ui__filter-group.svelte-1v2r7ls.svelte-1v2r7ls{border:0;padding:0}.pagefind-ui__filter-block.svelte-1v2r7ls.svelte-1v2r7ls{padding:0;display:block;border-bottom:solid calc(2px * var(--pagefind-ui-scale)) var(--pagefind-ui-border);padding:calc(20px * var(--pagefind-ui-scale)) 0}.pagefind-ui__filter-name.svelte-1v2r7ls.svelte-1v2r7ls{font-size:calc(16px * var(--pagefind-ui-scale));position:relative;display:flex;align-items:center;list-style:none;font-weight:700;cursor:pointer;height:calc(24px * var(--pagefind-ui-scale))}.pagefind-ui__filter-name.svelte-1v2r7ls.svelte-1v2r7ls::-webkit-details-marker{display:none}.pagefind-ui__filter-name.svelte-1v2r7ls.svelte-1v2r7ls:after{position:absolute;content:"";right:calc(6px * var(--pagefind-ui-scale));top:50%;width:calc(8px * var(--pagefind-ui-scale));height:calc(8px * var(--pagefind-ui-scale));border:solid calc(2px * var(--pagefind-ui-scale)) currentColor;border-right:0;border-top:0;transform:translateY(-70%) rotate(-45deg)}.pagefind-ui__filter-block[open].svelte-1v2r7ls .pagefind-ui__filter-name.svelte-1v2r7ls:after{transform:translateY(-70%) rotate(-225deg)}.pagefind-ui__filter-group.svelte-1v2r7ls.svelte-1v2r7ls{display:flex;flex-direction:column;gap:calc(20px * var(--pagefind-ui-scale));padding-top:calc(30px * var(--pagefind-ui-scale))}.pagefind-ui__filter-value.svelte-1v2r7ls.svelte-1v2r7ls{position:relative;display:flex;align-items:center;gap:calc(8px * var(--pagefind-ui-scale))}.pagefind-ui__filter-value.svelte-1v2r7ls.svelte-1v2r7ls:before{position:absolute;content:"";top:50%;left:calc(8px * var(--pagefind-ui-scale));width:0px;height:0px;border:solid 1px #fff;opacity:0;transform:translate(calc(4.5px * var(--pagefind-ui-scale) * -1),calc(.8px * var(--pagefind-ui-scale))) skew(-5deg) rotate(-45deg);transform-origin:top left;border-top:0;border-right:0;pointer-events:none}.pagefind-ui__filter-value.pagefind-ui__filter-value--checked.svelte-1v2r7ls.svelte-1v2r7ls:before{opacity:1;width:calc(9px * var(--pagefind-ui-scale));height:calc(4px * var(--pagefind-ui-scale));transition:width .1s ease-out .1s,height .1s ease-in}.pagefind-ui__filter-checkbox.svelte-1v2r7ls.svelte-1v2r7ls{margin:0;width:calc(16px * var(--pagefind-ui-scale));height:calc(16px * var(--pagefind-ui-scale));border:solid 1px var(--pagefind-ui-border);appearance:none;-webkit-appearance:none;border-radius:calc(var(--pagefind-ui-border-radius) / 2);background-color:var(--pagefind-ui-background);cursor:pointer}.pagefind-ui__filter-checkbox.svelte-1v2r7ls.svelte-1v2r7ls:checked{background-color:var(--pagefind-ui-primary);border:solid 1px var(--pagefind-ui-primary)}.pagefind-ui__filter-label.svelte-1v2r7ls.svelte-1v2r7ls{cursor:pointer;font-size:calc(16px * var(--pagefind-ui-scale));font-weight:400}.pagefind-ui--reset *:where(:not(html,iframe,canvas,img,svg,video):not(svg *,symbol *)){all:unset;display:revert;outline:revert}.pagefind-ui--reset *,.pagefind-ui--reset *:before,.pagefind-ui--reset *:after{box-sizing:border-box}.pagefind-ui--reset a,.pagefind-ui--reset button{cursor:revert}.pagefind-ui--reset ol,.pagefind-ui--reset ul,.pagefind-ui--reset menu{list-style:none}.pagefind-ui--reset img{max-width:100%}.pagefind-ui--reset table{border-collapse:collapse}.pagefind-ui--reset input,.pagefind-ui--reset textarea{-webkit-user-select:auto}.pagefind-ui--reset textarea{white-space:revert}.pagefind-ui--reset meter{-webkit-appearance:revert;appearance:revert}.pagefind-ui--reset ::placeholder{color:unset}.pagefind-ui--reset :where([hidden]){display:none}.pagefind-ui--reset :where([contenteditable]:not([contenteditable="false"])){-moz-user-modify:read-write;-webkit-user-modify:read-write;overflow-wrap:break-word;-webkit-line-break:after-white-space;-webkit-user-select:auto}.pagefind-ui--reset :where([draggable="true"]){-webkit-user-drag:element}.pagefind-ui--reset mark{all:revert}:root{--pagefind-ui-scale:.8;--pagefind-ui-primary:#393939;--pagefind-ui-text:#393939;--pagefind-ui-background:#ffffff;--pagefind-ui-border:#eeeeee;--pagefind-ui-tag:#eeeeee;--pagefind-ui-border-width:2px;--pagefind-ui-border-radius:8px;--pagefind-ui-image-border-radius:8px;--pagefind-ui-image-box-ratio:3 / 2;--pagefind-ui-font:system, -apple-system, "BlinkMacSystemFont", ".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif}.pagefind-ui.svelte-e9gkc3{width:100%;color:var(--pagefind-ui-text);font-family:var(--pagefind-ui-font)}.pagefind-ui__hidden.svelte-e9gkc3{display:none!important}.pagefind-ui__suppressed.svelte-e9gkc3{opacity:0;pointer-events:none}.pagefind-ui__form.svelte-e9gkc3{position:relative}.pagefind-ui__form.svelte-e9gkc3:before{background-color:var(--pagefind-ui-text);width:calc(18px * var(--pagefind-ui-scale));height:calc(18px * var(--pagefind-ui-scale));top:calc(23px * var(--pagefind-ui-scale));left:calc(20px * var(--pagefind-ui-scale));content:"";position:absolute;display:block;opacity:.7;-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.7549 11.255H11.9649L11.6849 10.985C12.6649 9.845 13.2549 8.365 13.2549 6.755C13.2549 3.165 10.3449 0.255005 6.75488 0.255005C3.16488 0.255005 0.254883 3.165 0.254883 6.755C0.254883 10.345 3.16488 13.255 6.75488 13.255C8.36488 13.255 9.84488 12.665 10.9849 11.685L11.2549 11.965V12.755L16.2549 17.745L17.7449 16.255L12.7549 11.255ZM6.75488 11.255C4.26488 11.255 2.25488 9.245 2.25488 6.755C2.25488 4.26501 4.26488 2.255 6.75488 2.255C9.24488 2.255 11.2549 4.26501 11.2549 6.755C11.2549 9.245 9.24488 11.255 6.75488 11.255Z' fill='%23000000'/%3E%3C/svg%3E%0A");mask-image:url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.7549 11.255H11.9649L11.6849 10.985C12.6649 9.845 13.2549 8.365 13.2549 6.755C13.2549 3.165 10.3449 0.255005 6.75488 0.255005C3.16488 0.255005 0.254883 3.165 0.254883 6.755C0.254883 10.345 3.16488 13.255 6.75488 13.255C8.36488 13.255 9.84488 12.665 10.9849 11.685L11.2549 11.965V12.755L16.2549 17.745L17.7449 16.255L12.7549 11.255ZM6.75488 11.255C4.26488 11.255 2.25488 9.245 2.25488 6.755C2.25488 4.26501 4.26488 2.255 6.75488 2.255C9.24488 2.255 11.2549 4.26501 11.2549 6.755C11.2549 9.245 9.24488 11.255 6.75488 11.255Z' fill='%23000000'/%3E%3C/svg%3E%0A");-webkit-mask-size:100%;mask-size:100%;z-index:9;pointer-events:none}.pagefind-ui__search-input.svelte-e9gkc3{height:calc(64px * var(--pagefind-ui-scale));padding:0 calc(70px * var(--pagefind-ui-scale)) 0 calc(54px * var(--pagefind-ui-scale));background-color:var(--pagefind-ui-background);border:var(--pagefind-ui-border-width) solid var(--pagefind-ui-border);border-radius:var(--pagefind-ui-border-radius);font-size:calc(21px * var(--pagefind-ui-scale));position:relative;appearance:none;-webkit-appearance:none;display:flex;width:100%;box-sizing:border-box;font-weight:700}.pagefind-ui__search-input.svelte-e9gkc3::placeholder{opacity:.2}.pagefind-ui__search-clear.svelte-e9gkc3{position:absolute;top:calc(3px * var(--pagefind-ui-scale));right:calc(3px * var(--pagefind-ui-scale));height:calc(58px * var(--pagefind-ui-scale));padding:0 calc(15px * var(--pagefind-ui-scale)) 0 calc(2px * var(--pagefind-ui-scale));color:var(--pagefind-ui-text);font-size:calc(14px * var(--pagefind-ui-scale));cursor:pointer;background-color:var(--pagefind-ui-background);border-radius:var(--pagefind-ui-border-radius)}.pagefind-ui__drawer.svelte-e9gkc3{gap:calc(60px * var(--pagefind-ui-scale));display:flex;flex-direction:row;flex-wrap:wrap}.pagefind-ui__results-area.svelte-e9gkc3{min-width:min(calc(400px * var(--pagefind-ui-scale)),100%);flex:1000;margin-top:calc(20px * var(--pagefind-ui-scale))}.pagefind-ui__results.svelte-e9gkc3{padding:0}.pagefind-ui__message.svelte-e9gkc3{box-sizing:content-box;font-size:calc(16px * var(--pagefind-ui-scale));height:calc(24px * var(--pagefind-ui-scale));padding:calc(20px * var(--pagefind-ui-scale)) 0;display:flex;align-items:center;font-weight:700;margin-top:0}.pagefind-ui__button.svelte-e9gkc3{margin-top:calc(40px * var(--pagefind-ui-scale));border:var(--pagefind-ui-border-width) solid var(--pagefind-ui-border);border-radius:var(--pagefind-ui-border-radius);height:calc(48px * var(--pagefind-ui-scale));padding:0 calc(12px * var(--pagefind-ui-scale));font-size:calc(16px * var(--pagefind-ui-scale));color:var(--pagefind-ui-primary);background:var(--pagefind-ui-background);width:100%;text-align:center;font-weight:700;cursor:pointer}.pagefind-ui__button.svelte-e9gkc3:hover{border-color:var(--pagefind-ui-primary);color:var(--pagefind-ui-primary);background:var(--pagefind-ui-background)}
2 |
--------------------------------------------------------------------------------
/public/pagefind/pagefind.en_2e70f624f4.pf_meta:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/pagefind.en_2e70f624f4.pf_meta
--------------------------------------------------------------------------------
/public/pagefind/pagefind.en_3fd8bd6252.pf_meta:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/pagefind.en_3fd8bd6252.pf_meta
--------------------------------------------------------------------------------
/public/pagefind/pagefind.en_45ddb13fe8.pf_meta:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/pagefind.en_45ddb13fe8.pf_meta
--------------------------------------------------------------------------------
/public/pagefind/pagefind.js:
--------------------------------------------------------------------------------
1 | const pagefind_version="1.1.0";let wasm_bindgen;(function(){const __exports={};let script_src;if(typeof document!=='undefined'&&document.currentScript!==null){script_src=new URL("UNHANDLED",location.href).toString()}let wasm=undefined;let cachedUint8Memory0=null;function getUint8Memory0(){if(cachedUint8Memory0===null||cachedUint8Memory0.byteLength===0){cachedUint8Memory0=new Uint8Array(wasm.memory.buffer)}return cachedUint8Memory0}let WASM_VECTOR_LEN=0;function passArray8ToWasm0(arg,malloc){const ptr=malloc(arg.length*1,1)>>>0;getUint8Memory0().set(arg,ptr/1);WASM_VECTOR_LEN=arg.length;return ptr}__exports.init_pagefind=function(metadata_bytes){const ptr0=passArray8ToWasm0(metadata_bytes,wasm.__wbindgen_malloc);const len0=WASM_VECTOR_LEN;const ret=wasm.init_pagefind(ptr0,len0);return ret>>>0};const cachedTextEncoder=(typeof TextEncoder!=='undefined'?new TextEncoder('utf-8'):{encode:()=>{throw Error('TextEncoder not available')}});const encodeString=(typeof cachedTextEncoder.encodeInto==='function'?function(arg,view){return cachedTextEncoder.encodeInto(arg,view)}:function(arg,view){const buf=cachedTextEncoder.encode(arg);view.set(buf);return{read:arg.length,written:buf.length}});function passStringToWasm0(arg,malloc,realloc){if(realloc===undefined){const buf=cachedTextEncoder.encode(arg);const ptr=malloc(buf.length,1)>>>0;getUint8Memory0().subarray(ptr,ptr+buf.length).set(buf);WASM_VECTOR_LEN=buf.length;return ptr}let len=arg.length;let ptr=malloc(len,1)>>>0;const mem=getUint8Memory0();let offset=0;for(;offset0x7F)break;mem[ptr+offset]=code}if(offset!==len){if(offset!==0){arg=arg.slice(offset)}ptr=realloc(ptr,len,len=offset+arg.length*3,1)>>>0;const view=getUint8Memory0().subarray(ptr+offset,ptr+len);const ret=encodeString(arg,view);offset+=ret.written;ptr=realloc(ptr,len,offset,1)>>>0}WASM_VECTOR_LEN=offset;return ptr}__exports.set_ranking_weights=function(ptr,weights){const ptr0=passStringToWasm0(weights,wasm.__wbindgen_malloc,wasm.__wbindgen_realloc);const len0=WASM_VECTOR_LEN;const ret=wasm.set_ranking_weights(ptr,ptr0,len0);return ret>>>0};__exports.load_index_chunk=function(ptr,chunk_bytes){const ptr0=passArray8ToWasm0(chunk_bytes,wasm.__wbindgen_malloc);const len0=WASM_VECTOR_LEN;const ret=wasm.load_index_chunk(ptr,ptr0,len0);return ret>>>0};__exports.load_filter_chunk=function(ptr,chunk_bytes){const ptr0=passArray8ToWasm0(chunk_bytes,wasm.__wbindgen_malloc);const len0=WASM_VECTOR_LEN;const ret=wasm.load_filter_chunk(ptr,ptr0,len0);return ret>>>0};__exports.add_synthetic_filter=function(ptr,filter){const ptr0=passStringToWasm0(filter,wasm.__wbindgen_malloc,wasm.__wbindgen_realloc);const len0=WASM_VECTOR_LEN;const ret=wasm.add_synthetic_filter(ptr,ptr0,len0);return ret>>>0};let cachedInt32Memory0=null;function getInt32Memory0(){if(cachedInt32Memory0===null||cachedInt32Memory0.byteLength===0){cachedInt32Memory0=new Int32Array(wasm.memory.buffer)}return cachedInt32Memory0}const cachedTextDecoder=(typeof TextDecoder!=='undefined'?new TextDecoder('utf-8',{ignoreBOM:true,fatal:true}):{decode:()=>{throw Error('TextDecoder not available')}});if(typeof TextDecoder!=='undefined'){cachedTextDecoder.decode()};function getStringFromWasm0(ptr,len){ptr=ptr>>>0;return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr,ptr+len))}__exports.request_indexes=function(ptr,query){let deferred2_0;let deferred2_1;try{const retptr=wasm.__wbindgen_add_to_stack_pointer(-16);const ptr0=passStringToWasm0(query,wasm.__wbindgen_malloc,wasm.__wbindgen_realloc);const len0=WASM_VECTOR_LEN;wasm.request_indexes(retptr,ptr,ptr0,len0);var r0=getInt32Memory0()[retptr/4+0];var r1=getInt32Memory0()[retptr/4+1];deferred2_0=r0;deferred2_1=r1;return getStringFromWasm0(r0,r1)}finally{wasm.__wbindgen_add_to_stack_pointer(16);wasm.__wbindgen_free(deferred2_0,deferred2_1,1)}};__exports.request_filter_indexes=function(ptr,filters){let deferred2_0;let deferred2_1;try{const retptr=wasm.__wbindgen_add_to_stack_pointer(-16);const ptr0=passStringToWasm0(filters,wasm.__wbindgen_malloc,wasm.__wbindgen_realloc);const len0=WASM_VECTOR_LEN;wasm.request_filter_indexes(retptr,ptr,ptr0,len0);var r0=getInt32Memory0()[retptr/4+0];var r1=getInt32Memory0()[retptr/4+1];deferred2_0=r0;deferred2_1=r1;return getStringFromWasm0(r0,r1)}finally{wasm.__wbindgen_add_to_stack_pointer(16);wasm.__wbindgen_free(deferred2_0,deferred2_1,1)}};__exports.request_all_filter_indexes=function(ptr){let deferred1_0;let deferred1_1;try{const retptr=wasm.__wbindgen_add_to_stack_pointer(-16);wasm.request_all_filter_indexes(retptr,ptr);var r0=getInt32Memory0()[retptr/4+0];var r1=getInt32Memory0()[retptr/4+1];deferred1_0=r0;deferred1_1=r1;return getStringFromWasm0(r0,r1)}finally{wasm.__wbindgen_add_to_stack_pointer(16);wasm.__wbindgen_free(deferred1_0,deferred1_1,1)}};__exports.filters=function(ptr){let deferred1_0;let deferred1_1;try{const retptr=wasm.__wbindgen_add_to_stack_pointer(-16);wasm.filters(retptr,ptr);var r0=getInt32Memory0()[retptr/4+0];var r1=getInt32Memory0()[retptr/4+1];deferred1_0=r0;deferred1_1=r1;return getStringFromWasm0(r0,r1)}finally{wasm.__wbindgen_add_to_stack_pointer(16);wasm.__wbindgen_free(deferred1_0,deferred1_1,1)}};__exports.search=function(ptr,query,filter,sort,exact){let deferred4_0;let deferred4_1;try{const retptr=wasm.__wbindgen_add_to_stack_pointer(-16);const ptr0=passStringToWasm0(query,wasm.__wbindgen_malloc,wasm.__wbindgen_realloc);const len0=WASM_VECTOR_LEN;const ptr1=passStringToWasm0(filter,wasm.__wbindgen_malloc,wasm.__wbindgen_realloc);const len1=WASM_VECTOR_LEN;const ptr2=passStringToWasm0(sort,wasm.__wbindgen_malloc,wasm.__wbindgen_realloc);const len2=WASM_VECTOR_LEN;wasm.search(retptr,ptr,ptr0,len0,ptr1,len1,ptr2,len2,exact);var r0=getInt32Memory0()[retptr/4+0];var r1=getInt32Memory0()[retptr/4+1];deferred4_0=r0;deferred4_1=r1;return getStringFromWasm0(r0,r1)}finally{wasm.__wbindgen_add_to_stack_pointer(16);wasm.__wbindgen_free(deferred4_0,deferred4_1,1)}};async function __wbg_load(module,imports){if(typeof Response==='function'&&module instanceof Response){if(typeof WebAssembly.instantiateStreaming==='function'){try{return await WebAssembly.instantiateStreaming(module,imports)}catch(e){if(module.headers.get('Content-Type')!='application/wasm'){console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",e)}else{throw e}}}const bytes=await module.arrayBuffer();return await WebAssembly.instantiate(bytes,imports)}else{const instance=await WebAssembly.instantiate(module,imports);if(instance instanceof WebAssembly.Instance){return{instance,module}}else{return instance}}}function __wbg_get_imports(){const imports={};imports.wbg={};return imports}function __wbg_init_memory(imports,maybe_memory){}function __wbg_finalize_init(instance,module){wasm=instance.exports;__wbg_init.__wbindgen_wasm_module=module;cachedInt32Memory0=null;cachedUint8Memory0=null;return wasm}function initSync(module){if(wasm!==undefined)return wasm;const imports=__wbg_get_imports();__wbg_init_memory(imports);if(!(module instanceof WebAssembly.Module)){module=new WebAssembly.Module(module)}const instance=new WebAssembly.Instance(module,imports);return __wbg_finalize_init(instance,module)}async function __wbg_init(input){if(wasm!==undefined)return wasm;if(typeof input==='undefined'&&typeof script_src!=='undefined'){input=script_src.replace(/\.js$/,'_bg.wasm')}const imports=__wbg_get_imports();if(typeof input==='string'||(typeof Request==='function'&&input instanceof Request)||(typeof URL==='function'&&input instanceof URL)){input=fetch(input)}__wbg_init_memory(imports);const{instance,module}=await __wbg_load(await input,imports);return __wbg_finalize_init(instance,module)}wasm_bindgen=Object.assign(__wbg_init,{initSync},__exports)})();var u8=Uint8Array;var u16=Uint16Array;var u32=Uint32Array;var fleb=new u8([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]);var fdeb=new u8([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]);var clim=new u8([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]);var freb=function(eb,start){var b=new u16(31);for(var i2=0;i2<31;++i2){b[i2]=start+=1<>>1|(i&21845)<<1;x=(x&52428)>>>2|(x&13107)<<2;x=(x&61680)>>>4|(x&3855)<<4;rev[i]=((x&65280)>>>8|(x&255)<<8)>>>1}var x;var i;var hMap=function(cd,mb,r){var s=cd.length;var i2=0;var l=new u16(mb);for(;i2>>rvb]=sv}}}}else{co=new u16(s);for(i2=0;i2>>15-cd[i2]}}}return co};var flt=new u8(288);for(i=0;i<144;++i)flt[i]=8;var i;for(i=144;i<256;++i)flt[i]=9;var i;for(i=256;i<280;++i)flt[i]=7;var i;for(i=280;i<288;++i)flt[i]=8;var i;var fdt=new u8(32);for(i=0;i<32;++i)fdt[i]=5;var i;var flrm=hMap(flt,9,1);var fdrm=hMap(fdt,5,1);var max=function(a){var m=a[0];for(var i2=1;i2m)m=a[i2]}return m};var bits=function(d,p,m){var o=p/8|0;return(d[o]|d[o+1]<<8)>>(p&7)&m};var bits16=function(d,p){var o=p/8|0;return(d[o]|d[o+1]<<8|d[o+2]<<16)>>(p&7)};var shft=function(p){return(p+7)/8|0};var slc=function(v,s,e){if(s==null||s<0)s=0;if(e==null||e>v.length)e=v.length;var n=new(v.BYTES_PER_ELEMENT==2?u16:v.BYTES_PER_ELEMENT==4?u32:u8)(e-s);n.set(v.subarray(s,e));return n};var ec=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"];var err=function(ind,msg,nt){var e=new Error(msg||ec[ind]);e.code=ind;if(Error.captureStackTrace)Error.captureStackTrace(e,err);if(!nt)throw e;return e};var inflt=function(dat,buf,st){var sl=dat.length;if(!sl||st&&st.f&&!st.l)return buf||new u8(0);var noBuf=!buf||st;var noSt=!st||st.i;if(!st)st={};if(!buf)buf=new u8(sl*3);var cbuf=function(l2){var bl=buf.length;if(l2>bl){var nbuf=new u8(Math.max(bl*2,l2));nbuf.set(buf);buf=nbuf}};var final=st.f||0,pos=st.p||0,bt=st.b||0,lm=st.l,dm=st.d,lbt=st.m,dbt=st.n;var tbts=sl*8;do{if(!lm){final=bits(dat,pos,1);var type=bits(dat,pos+1,3);pos+=3;if(!type){var s=shft(pos)+4,l=dat[s-4]|dat[s-3]<<8,t=s+l;if(t>sl){if(noSt)err(0);break}if(noBuf)cbuf(bt+l);buf.set(dat.subarray(s,t),bt);st.b=bt+=l,st.p=pos=t*8,st.f=final;continue}else if(type==1)lm=flrm,dm=fdrm,lbt=9,dbt=5;else if(type==2){var hLit=bits(dat,pos,31)+257,hcLen=bits(dat,pos+10,15)+4;var tl=hLit+bits(dat,pos+5,31)+1;pos+=14;var ldt=new u8(tl);var clt=new u8(19);for(var i2=0;i2>>4;if(s<16){ldt[i2++]=s}else{var c=0,n=0;if(s==16)n=3+bits(dat,pos,3),pos+=2,c=ldt[i2-1];else if(s==17)n=3+bits(dat,pos,7),pos+=3;else if(s==18)n=11+bits(dat,pos,127),pos+=7;while(n--)ldt[i2++]=c}}var lt=ldt.subarray(0,hLit),dt=ldt.subarray(hLit);lbt=max(lt);dbt=max(dt);lm=hMap(lt,lbt,1);dm=hMap(dt,dbt,1)}else err(1);if(pos>tbts){if(noSt)err(0);break}}if(noBuf)cbuf(bt+131072);var lms=(1<>>4;pos+=c&15;if(pos>tbts){if(noSt)err(0);break}if(!c)err(2);if(sym<256)buf[bt++]=sym;else if(sym==256){lpos=pos,lm=null;break}else{var add=sym-254;if(sym>264){var i2=sym-257,b=fleb[i2];add=bits(dat,pos,(1<>>4;if(!d)err(3);pos+=d&15;var dt=fd[dsym];if(dsym>3){var b=fdeb[dsym];dt+=bits16(dat,pos)&(1<tbts){if(noSt)err(0);break}if(noBuf)cbuf(bt+131072);var end=bt+add;for(;bt>3&1)+(flg>>4&1);zs>0;zs-=!d[st++]);return st+(flg&2)};var gzl=function(d){var l=d.length;return(d[l-4]|d[l-3]<<8|d[l-2]<<16|d[l-1]<<24)>>>0};function gunzipSync(data,out){return inflt(data.subarray(gzs(data),-8),out||new u8(gzl(data)))}var td=typeof TextDecoder!="undefined"&&new TextDecoder();var tds=0;try{td.decode(et,{stream:true});tds=1}catch(e){}var gz_default=gunzipSync;var calculate_excerpt_region=(word_positions,excerpt_length)=>{if(word_positions.length===0){return 0}let words=[];for(const word of word_positions){words[word.location]=words[word.location]||0;words[word.location]+=word.balanced_score}if(words.length<=excerpt_length){return 0}let densest=words.slice(0,excerpt_length).reduce((partialSum,a)=>partialSum+a,0);let working_sum=densest;let densest_at=[0];for(let i2=0;i2densest){densest=working_sum;densest_at=[i2]}else if(working_sum===densest&&densest_at[densest_at.length-1]===i2-1){densest_at.push(i2)}}let midpoint=densest_at[Math.floor(densest_at.length/2)];return midpoint};var build_excerpt=(content,start,length,locations,not_before,not_from)=>{let is_zws_delimited=content.includes("\u200B");let fragment_words=[];if(is_zws_delimited){fragment_words=content.split("\u200B")}else{fragment_words=content.split(/[\r\n\s]+/g)}for(let word of locations){if(fragment_words[word]?.startsWith(``)){continue}fragment_words[word]=`${fragment_words[word]} `}let endcap=not_from??fragment_words.length;let startcap=not_before??0;if(endcap-startcapendcap){start=endcap-length}if(start{const anchors=fragment.anchors.filter((a)=>/h\d/i.test(a.element)&&a.text?.length&&/\S/.test(a.text)).sort((a,b)=>a.location-b.location);const results=[];let current_anchor_position=0;let current_anchor={title:fragment.meta["title"],url:fragment.url,weighted_locations:[],locations:[],excerpt:""};const add_result=(end_range)=>{if(current_anchor.locations.length){const relative_weighted_locations=current_anchor.weighted_locations.map((l)=>{return{weight:l.weight,balanced_score:l.balanced_score,location:l.location-current_anchor_position}});const excerpt_start=calculate_excerpt_region(relative_weighted_locations,desired_excerpt_length)+current_anchor_position;const excerpt_length=end_range?Math.min(end_range-excerpt_start,desired_excerpt_length):desired_excerpt_length;current_anchor.excerpt=build_excerpt(fragment.raw_content??"",excerpt_start,excerpt_length,current_anchor.locations,current_anchor_position,end_range);results.push(current_anchor)}};for(let word of fragment.weighted_locations){if(!anchors.length||word.location=anchors[0].location){next_anchor=anchors.shift()}let anchored_url=fragment.url;try{const url_is_fq=/^((https?:)?\/\/)/.test(anchored_url);if(url_is_fq){let fq_url=new URL(anchored_url);fq_url.hash=next_anchor.id;anchored_url=fq_url.toString()}else{if(!/^\//.test(anchored_url)){anchored_url=`/${anchored_url}`}let fq_url=new URL(`https://example.com${anchored_url}`);fq_url.hash=next_anchor.id;anchored_url=fq_url.toString().replace(/^https:\/\/example.com/,"")}}catch(e){console.error(`Pagefind: Couldn't process ${anchored_url} for a search result`)}current_anchor_position=next_anchor.location;current_anchor={title:next_anchor.text,url:anchored_url,anchor:next_anchor,weighted_locations:[word],locations:[word.location],excerpt:""}}}add_result(anchors[0]?.location);return results};var asyncSleep=async(ms=100)=>{return new Promise((r)=>setTimeout(r,ms))};var PagefindInstance=class{constructor(opts={}){this.version=pagefind_version;this.backend=wasm_bindgen;this.decoder=new TextDecoder("utf-8");this.wasm=null;this.basePath=opts.basePath||"/pagefind/";this.primary=opts.primary||false;if(this.primary&&!opts.basePath){this.initPrimary()}if(/[^\/]$/.test(this.basePath)){this.basePath=`${this.basePath}/`}if(window?.location?.origin&&this.basePath.startsWith(window.location.origin)){this.basePath=this.basePath.replace(window.location.origin,"")}this.baseUrl=opts.baseUrl||this.defaultBaseUrl();if(!/^(\/|https?:\/\/)/.test(this.baseUrl)){this.baseUrl=`/${this.baseUrl}`}this.indexWeight=opts.indexWeight??1;this.excerptLength=opts.excerptLength??30;this.mergeFilter=opts.mergeFilter??{};this.ranking=opts.ranking;this.highlightParam=opts.highlightParam??null;this.loaded_chunks={};this.loaded_filters={};this.loaded_fragments={};this.raw_ptr=null;this.searchMeta=null;this.languages=null}initPrimary(){let derivedBasePath=import.meta.url.match(/^(.*\/)pagefind.js.*$/)?.[1];if(derivedBasePath){this.basePath=derivedBasePath}else{console.warn(["Pagefind couldn't determine the base of the bundle from the import path. Falling back to the default.","Set a basePath option when initialising Pagefind to ignore this message."].join("\n"))}}defaultBaseUrl(){let default_base=this.basePath.match(/^(.*\/)_?pagefind/)?.[1];return default_base||"/"}async options(options2){const opts=["basePath","baseUrl","indexWeight","excerptLength","mergeFilter","highlightParam","ranking"];for(const[k,v]of Object.entries(options2)){if(k==="mergeFilter"){let filters2=this.stringifyFilters(v);let ptr=await this.getPtr();this.raw_ptr=this.backend.add_synthetic_filter(ptr,filters2)}else if(k==="ranking"){await this.set_ranking(options2.ranking)}else if(opts.includes(k)){if(k==="basePath"&&typeof v==="string")this.basePath=v;if(k==="baseUrl"&&typeof v==="string")this.baseUrl=v;if(k==="indexWeight"&&typeof v==="number")this.indexWeight=v;if(k==="excerptLength"&&typeof v==="number")this.excerptLength=v;if(k==="mergeFilter"&&typeof v==="object")this.mergeFilter=v;if(k==="highlightParam"&&typeof v==="string")this.highlightParam=v}else{console.warn(`Unknown Pagefind option ${k}. Allowed options: [${opts.join(", ")}]`)}}}decompress(data,file="unknown file"){if(this.decoder.decode(data.slice(0,12))==="pagefind_dcd"){return data.slice(12)}data=gz_default(data);if(this.decoder.decode(data.slice(0,12))!=="pagefind_dcd"){console.error(`Decompressing ${file} appears to have failed: Missing signature`);return data}return data.slice(12)}async set_ranking(ranking){if(!ranking)return;let rankingWeights={term_similarity:ranking.termSimilarity??null,page_length:ranking.pageLength??null,term_saturation:ranking.termSaturation??null,term_frequency:ranking.termFrequency??null};let ptr=await this.getPtr();this.raw_ptr=this.backend.set_ranking_weights(ptr,JSON.stringify(rankingWeights))}async init(language,opts){await this.loadEntry();let index=this.findIndex(language);let lang_wasm=index.wasm?index.wasm:"unknown";let resources=[this.loadMeta(index.hash)];if(opts.load_wasm===true){resources.push(this.loadWasm(lang_wasm))}await Promise.all(resources);this.raw_ptr=this.backend.init_pagefind(new Uint8Array(this.searchMeta));if(Object.keys(this.mergeFilter)?.length){let filters2=this.stringifyFilters(this.mergeFilter);let ptr=await this.getPtr();this.raw_ptr=this.backend.add_synthetic_filter(ptr,filters2)}if(this.ranking){await this.set_ranking(this.ranking)}}async loadEntry(){try{let entry_response=await fetch(`${this.basePath}pagefind-entry.json?ts=${Date.now()}`);let entry_json=await entry_response.json();this.languages=entry_json.languages;if(entry_json.version!==this.version){if(this.primary){console.warn(["Pagefind JS version doesn't match the version in your search index.",`Pagefind JS: ${this.version}. Pagefind index: ${entry_json.version}`,"If you upgraded Pagefind recently, you likely have a cached pagefind.js file.","If you encounter any search errors, try clearing your cache."].join("\n"))}else{console.warn(["Merging a Pagefind index from a different version than the main Pagefind instance.",`Main Pagefind JS: ${this.version}. Merged index (${this.basePath}): ${entry_json.version}`,"If you encounter any search errors, make sure that both sites are running the same version of Pagefind."].join("\n"))}}}catch(e){console.error(`Failed to load Pagefind metadata:
2 | ${e?.toString()}`);throw new Error("Failed to load Pagefind metadata")}}findIndex(language){if(this.languages){let index=this.languages[language];if(index)return index;index=this.languages[language.split("-")[0]];if(index)return index;let topLang=Object.values(this.languages).sort((a,b)=>b.page_count-a.page_count);if(topLang[0])return topLang[0]}throw new Error("Pagefind Error: No language indexes found.")}async loadMeta(index){try{let compressed_resp=await fetch(`${this.basePath}pagefind.${index}.pf_meta`);let compressed_meta=await compressed_resp.arrayBuffer();this.searchMeta=this.decompress(new Uint8Array(compressed_meta),"Pagefind metadata")}catch(e){console.error(`Failed to load the meta index:
3 | ${e?.toString()}`)}}async loadWasm(language){try{const wasm_url=`${this.basePath}wasm.${language}.pagefind`;let compressed_resp=await fetch(wasm_url);let compressed_wasm=await compressed_resp.arrayBuffer();const final_wasm=this.decompress(new Uint8Array(compressed_wasm),"Pagefind WebAssembly");if(!final_wasm){throw new Error("No WASM after decompression")}this.wasm=await this.backend(final_wasm)}catch(e){console.error(`Failed to load the Pagefind WASM:
4 | ${e?.toString()}`);throw new Error(`Failed to load the Pagefind WASM:
5 | ${e?.toString()}`)}}async _loadGenericChunk(url,method){try{let compressed_resp=await fetch(url);let compressed_chunk=await compressed_resp.arrayBuffer();let chunk=this.decompress(new Uint8Array(compressed_chunk),url);let ptr=await this.getPtr();this.raw_ptr=this.backend[method](ptr,chunk)}catch(e){console.error(`Failed to load the index chunk ${url}:
6 | ${e?.toString()}`)}}async loadChunk(hash){if(!this.loaded_chunks[hash]){const url=`${this.basePath}index/${hash}.pf_index`;this.loaded_chunks[hash]=this._loadGenericChunk(url,"load_index_chunk")}return await this.loaded_chunks[hash]}async loadFilterChunk(hash){if(!this.loaded_filters[hash]){const url=`${this.basePath}filter/${hash}.pf_filter`;this.loaded_filters[hash]=this._loadGenericChunk(url,"load_filter_chunk")}return await this.loaded_filters[hash]}async _loadFragment(hash){let compressed_resp=await fetch(`${this.basePath}fragment/${hash}.pf_fragment`);let compressed_fragment=await compressed_resp.arrayBuffer();let fragment=this.decompress(new Uint8Array(compressed_fragment),`Fragment ${hash}`);return JSON.parse(new TextDecoder().decode(fragment))}async loadFragment(hash,weighted_locations=[],search_term){if(!this.loaded_fragments[hash]){this.loaded_fragments[hash]=this._loadFragment(hash)}let fragment=await this.loaded_fragments[hash];fragment.weighted_locations=weighted_locations;fragment.locations=weighted_locations.map((l)=>l.location);if(!fragment.raw_content){fragment.raw_content=fragment.content.replace(//g,">");fragment.content=fragment.content.replace(/\u200B/g,"")}if(!fragment.raw_url){fragment.raw_url=fragment.url}fragment.url=this.processedUrl(fragment.raw_url,search_term);const excerpt_start=calculate_excerpt_region(weighted_locations,this.excerptLength);fragment.excerpt=build_excerpt(fragment.raw_content,excerpt_start,this.excerptLength,fragment.locations);fragment.sub_results=calculate_sub_results(fragment,this.excerptLength);return fragment}fullUrl(raw){if(/^(https?:)?\/\//.test(raw)){return raw}return`${this.baseUrl}/${raw}`.replace(/\/+/g,"/").replace(/^(https?:\/)/,"$1/")}processedUrl(url,search_term){const normalized=this.fullUrl(url);if(this.highlightParam===null){return normalized}let individual_terms=search_term.split(/\s+/);try{let processed=new URL(normalized);for(const term of individual_terms){processed.searchParams.append(this.highlightParam,term)}return processed.toString()}catch(e){try{let processed=new URL(`https://example.com${normalized}`);for(const term of individual_terms){processed.searchParams.append(this.highlightParam,term)}return processed.toString().replace(/^https:\/\/example\.com/,"")}catch(e2){return normalized}}}async getPtr(){while(this.raw_ptr===null){await asyncSleep(50)}if(!this.raw_ptr){console.error("Pagefind: WASM Error (No pointer)");throw new Error("Pagefind: WASM Error (No pointer)")}return this.raw_ptr}parseFilters(str){let output={};if(!str)return output;for(const block of str.split("__PF_FILTER_DELIM__")){let[filter,values]=block.split(/:(.*)$/);output[filter]={};if(values){for(const valueBlock of values.split("__PF_VALUE_DELIM__")){if(valueBlock){let extract=valueBlock.match(/^(.*):(\d+)$/);if(extract){let[,value,count]=extract;output[filter][value]=parseInt(count)??count}}}}}return output}stringifyFilters(obj={}){return JSON.stringify(obj)}stringifySorts(obj={}){let sorts=Object.entries(obj);for(let[sort,direction]of sorts){if(sorts.length>1){console.warn(`Pagefind was provided multiple sort options in this search, but can only operate on one. Using the ${sort} sort.`)}if(direction!=="asc"&&direction!=="desc"){console.warn(`Pagefind was provided a sort with unknown direction ${direction}. Supported: [asc, desc]`)}return`${sort}:${direction}`}return``}async filters(){let ptr=await this.getPtr();let filters2=this.backend.request_all_filter_indexes(ptr);let filter_chunks=filters2.split(" ").filter((v)=>v).map((chunk)=>this.loadFilterChunk(chunk));await Promise.all([...filter_chunks]);ptr=await this.getPtr();let results=this.backend.filters(ptr);return this.parseFilters(results)}async preload(term,options2={}){await this.search(term,{...options2,preload:true})}async search(term,options2={}){options2={verbose:false,filters:{},sort:{},...options2};const log=(str)=>{if(options2.verbose)console.log(str)};log(`Starting search on ${this.basePath}`);let start=Date.now();let ptr=await this.getPtr();let filter_only=term===null;term=term??"";let exact_search=/^\s*".+"\s*$/.test(term);if(exact_search){log(`Running an exact search`)}term=term.toLowerCase().trim().replace(/[\.`~!@#\$%\^&\*\(\)\{\}\[\]\\\|:;'",<>\/\?\-]/g,"").replace(/\s{2,}/g," ").trim();log(`Normalized search term to ${term}`);if(!term?.length&&!filter_only){return{results:[],unfilteredResultCount:0,filters:{},totalFilters:{},timings:{preload:Date.now()-start,search:Date.now()-start,total:Date.now()-start}}}let sort_list=this.stringifySorts(options2.sort);log(`Stringified sort to ${sort_list}`);const filter_list=this.stringifyFilters(options2.filters);log(`Stringified filters to ${filter_list}`);let index_resp=this.backend.request_indexes(ptr,term);let filter_resp=this.backend.request_filter_indexes(ptr,filter_list);let chunks=index_resp.split(" ").filter((v)=>v).map((chunk)=>this.loadChunk(chunk));let filter_chunks=filter_resp.split(" ").filter((v)=>v).map((chunk)=>this.loadFilterChunk(chunk));await Promise.all([...chunks,...filter_chunks]);log(`Loaded necessary chunks to run search`);if(options2.preload){log(`Preload \u2014 bailing out of search operation now.`);return null}ptr=await this.getPtr();let searchStart=Date.now();let result=this.backend.search(ptr,term,filter_list,sort_list,exact_search);log(`Got the raw search result: ${result}`);let[unfilteredResultCount,all_results,filters2,totalFilters]=result.split(/:([^:]*):(.*)__PF_UNFILTERED_DELIM__(.*)$/);let filterObj=this.parseFilters(filters2);let totalFilterObj=this.parseFilters(totalFilters);log(`Remaining filters: ${JSON.stringify(result)}`);let results=all_results.length?all_results.split(" "):[];let resultsInterface=results.map((result2)=>{let[hash,score,all_locations]=result2.split("@");log(`Processing result:
7 | hash:${hash}
8 | score:${score}
9 | locations:${all_locations}`);let weighted_locations=all_locations.length?all_locations.split(",").map((l)=>{let[weight,balanced_score,location]=l.split(">");return{weight:parseInt(weight)/24,balanced_score:parseFloat(balanced_score),location:parseInt(location)}}):[];let locations=weighted_locations.map((l)=>l.location);return{id:hash,score:parseFloat(score)*this.indexWeight,words:locations,data:async()=>await this.loadFragment(hash,weighted_locations,term)}});const searchTime=Date.now()-searchStart;const realTime=Date.now()-start;log(`Found ${results.length} result${results.length == 1 ? "" : "s"} for "${term}" in ${Date.now() - searchStart}ms (${Date.now() - start}ms realtime)`);return{results:resultsInterface,unfilteredResultCount:parseInt(unfilteredResultCount),filters:filterObj,totalFilters:totalFilterObj,timings:{preload:realTime-searchTime,search:searchTime,total:realTime}}}};var Pagefind=class{constructor(options2={}){this.backend=wasm_bindgen;this.primaryLanguage="unknown";this.searchID=0;this.primary=new PagefindInstance({...options2,primary:true});this.instances=[this.primary];this.init(options2?.language)}async options(options2){await this.primary.options(options2)}async init(overrideLanguage){if(document?.querySelector){const langCode=document.querySelector("html")?.getAttribute("lang")||"unknown";this.primaryLanguage=langCode.toLocaleLowerCase()}await this.primary.init(overrideLanguage?overrideLanguage:this.primaryLanguage,{load_wasm:true})}async mergeIndex(indexPath,options2={}){if(this.primary.basePath.startsWith(indexPath)){console.warn(`Skipping mergeIndex ${indexPath} that appears to be the same as the primary index (${this.primary.basePath})`);return}let newInstance=new PagefindInstance({primary:false,basePath:indexPath});this.instances.push(newInstance);while(this.primary.wasm===null){await asyncSleep(50)}await newInstance.init(options2.language||this.primaryLanguage,{load_wasm:false});delete options2["language"];await newInstance.options(options2)}mergeFilters(filters2){const merged={};for(const searchFilter of filters2){for(const[filterKey,values]of Object.entries(searchFilter)){if(!merged[filterKey]){merged[filterKey]=values;continue}else{const filter=merged[filterKey];for(const[valueKey,count]of Object.entries(values)){filter[valueKey]=(filter[valueKey]||0)+count}}}}return merged}async filters(){let filters2=await Promise.all(this.instances.map((i2)=>i2.filters()));return this.mergeFilters(filters2)}async preload(term,options2={}){await Promise.all(this.instances.map((i2)=>i2.preload(term,options2)))}async debouncedSearch(term,options2,debounceTimeoutMs){const thisSearchID=++this.searchID;this.preload(term,options2);await asyncSleep(debounceTimeoutMs);if(thisSearchID!==this.searchID){return null}const searchResult=await this.search(term,options2);if(thisSearchID!==this.searchID){return null}return searchResult}async search(term,options2={}){let search2=await Promise.all(this.instances.map((i2)=>i2.search(term,options2)));const filters2=this.mergeFilters(search2.map((s)=>s.filters));const totalFilters=this.mergeFilters(search2.map((s)=>s.totalFilters));const results=search2.map((s)=>s.results).flat().sort((a,b)=>b.score-a.score);const timings=search2.map((s)=>s.timings);const unfilteredResultCount=search2.reduce((sum,s)=>sum+s.unfilteredResultCount,0);return{results,unfilteredResultCount,filters:filters2,totalFilters,timings}}};var pagefind=void 0;var initial_options=void 0;var init_pagefind=()=>{if(!pagefind){pagefind=new Pagefind(initial_options??{})}};var options=async(new_options)=>{if(pagefind){await pagefind.options(new_options)}else{initial_options=new_options}};var init=async()=>{init_pagefind()};var destroy=async()=>{pagefind=void 0;initial_options=void 0};var mergeIndex=async(indexPath,options2)=>{init_pagefind();return await pagefind.mergeIndex(indexPath,options2)};var search=async(term,options2)=>{init_pagefind();return await pagefind.search(term,options2)};var debouncedSearch=async(term,options2,debounceTimeoutMs=300)=>{init_pagefind();return await pagefind.debouncedSearch(term,options2,debounceTimeoutMs)};var preload=async(term,options2)=>{init_pagefind();return await pagefind.preload(term,options2)};var filters=async()=>{init_pagefind();return await pagefind.filters()};export{debouncedSearch,destroy,filters,init,mergeIndex,options,preload,search}
--------------------------------------------------------------------------------
/public/pagefind/wasm.en.pagefind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/wasm.en.pagefind
--------------------------------------------------------------------------------
/public/pagefind/wasm.unknown.pagefind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/pagefind/wasm.unknown.pagefind
--------------------------------------------------------------------------------
/public/y-wing.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/public/y-wing.jpeg
--------------------------------------------------------------------------------
/src/components/ArrowCard.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import type { CollectionEntry } from "astro:content";
3 |
4 | type Props = {
5 | entry: CollectionEntry<"blog"> | CollectionEntry<"projects">;
6 | };
7 |
8 | const { entry } = Astro.props as {
9 | entry: CollectionEntry<"blog"> | CollectionEntry<"projects">;
10 | };
11 | ---
12 |
13 |
17 |
18 |
19 | {entry.data.title}
20 |
21 |
22 | {entry.data.description}
23 |
24 |
25 |
30 |
37 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/components/BackToPrevious.astro:
--------------------------------------------------------------------------------
1 | ---
2 | type Props = {
3 | href: string;
4 | };
5 |
6 | const { href } = Astro.props;
7 | ---
8 |
9 |
13 |
18 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/components/BackToTop.astro:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | ---
4 |
5 |
9 |
14 |
21 |
25 |
26 | Back to top
27 |
28 |
--------------------------------------------------------------------------------
/src/components/Callout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | interface Props {
3 | type?: "default" | "info" | "warning" | "error";
4 | }
5 | const { type = "default" } = Astro.props;
6 | let emoji = "💡";
7 | if (type === "info") {
8 | emoji = "ℹ️";
9 | } else if (type === "warning") {
10 | emoji = "⚠️";
11 | } else if (type === "error") {
12 | emoji = "🚨";
13 | }
14 |
15 | const baseClasses = "relative my-4 flex rounded border p-3";
16 | const typeClasses = {
17 | default:
18 | "border-orange-800 bg-orange-100 text-orange-950 dark:border-orange-200/20 dark:bg-orange-950/20 dark:text-orange-200",
19 | info: "border-blue-800 bg-blue-100 text-blue-950 dark:border-blue-200/20 dark:bg-blue-950/20 dark:text-blue-200",
20 | warning:
21 | "border-yellow-800 bg-yellow-100 text-yellow-950 dark:border-yellow-200/20 dark:bg-yellow-950/20 dark:text-yellow-200",
22 | error:
23 | "border-red-800 bg-red-100 text-red-950 dark:border-red-200/20 dark:bg-red-950/20 dark:text-red-200",
24 | };
25 | ---
26 |
27 |
28 | {emoji}
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/components/Container.astro:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | ---
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/components/Footer.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Container from "@components/Container.astro";
3 | import { SITE } from "@consts";
4 | import BackToTop from "@components/BackToTop.astro";
5 | ---
6 |
7 |
8 |
9 |
14 |
15 |
© {new Date().getFullYear()} • {SITE.TITLE} 🔬
16 |
17 |
22 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
50 |
62 |
63 |
64 |
65 |
70 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/components/FormattedDate.astro:
--------------------------------------------------------------------------------
1 | ---
2 | interface Props {
3 | date: Date;
4 | }
5 |
6 | const { date } = Astro.props;
7 | ---
8 |
9 |
10 | {
11 | date.toLocaleDateString("en-US", {
12 | month: "long",
13 | day: "2-digit",
14 | year: "numeric",
15 | })
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/src/components/Giscus.astro:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
--------------------------------------------------------------------------------
/src/components/Head.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import "../styles/global.css";
3 | import { ClientRouter } from "astro:transitions";
4 |
5 | import "@fontsource/geist-sans/100.css";
6 | import "@fontsource/geist-sans/200.css";
7 | import "@fontsource/geist-sans/300.css";
8 | import "@fontsource/geist-sans/400.css";
9 | import "@fontsource/geist-sans/500.css";
10 | import "@fontsource/geist-sans/600.css";
11 | import "@fontsource/geist-sans/700.css";
12 | import "@fontsource/geist-sans/800.css";
13 | import "@fontsource/geist-sans/900.css";
14 | import "@fontsource/geist-mono/100.css";
15 | import "@fontsource/geist-mono/200.css";
16 | import "@fontsource/geist-mono/300.css";
17 | import "@fontsource/geist-mono/400.css";
18 | import "@fontsource/geist-mono/500.css";
19 | import "@fontsource/geist-mono/600.css";
20 | import "@fontsource/geist-mono/700.css";
21 | import "@fontsource/geist-mono/800.css";
22 | import "@fontsource/geist-mono/900.css";
23 |
24 | interface Props {
25 | title: string;
26 | description: string;
27 | image?: string;
28 | }
29 |
30 | const canonicalURL = new URL(Astro.url.pathname, Astro.site);
31 |
32 | const { title, description, image = "/astro-micro.jpg" } = Astro.props;
33 | ---
34 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | {title}
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
268 |
--------------------------------------------------------------------------------
/src/components/Header.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Container from "@components/Container.astro";
3 | import Link from "@components/Link.astro";
4 | import { SITE } from "@consts";
5 | ---
6 |
7 |
8 |
9 |
10 |
11 |
12 | {SITE.TITLE} 🔬
13 |
14 |
15 |
16 | blog
17 |
18 | {`/`}
19 |
20 | projects
21 |
22 | {`/`}
23 |
24 |
29 |
41 | Search
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/components/Link.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { cn } from "@lib/utils";
3 |
4 | type Props = {
5 | href: string;
6 | external?: boolean;
7 | underline?: boolean;
8 | group?: boolean;
9 | };
10 |
11 | const {
12 | href,
13 | external,
14 | underline = true,
15 | group = false,
16 | ...rest
17 | } = Astro.props;
18 | ---
19 |
20 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/components/PageFind.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Search from "astro-pagefind/components/Search";
3 | ---
4 |
5 |
6 |
11 |
15 |
24 |
25 | Press Esc or click anywhere to close
28 |
29 |
30 |
31 |
32 |
33 |
95 |
96 |
133 |
--------------------------------------------------------------------------------
/src/components/PostNavigation.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { prevPost, nextPost } = Astro.props;
3 | ---
4 |
5 |
66 |
--------------------------------------------------------------------------------
/src/components/TableOfContents.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import TableOfContentsHeading from "./TableOfContentsHeading.astro";
3 |
4 | // https://kld.dev/building-table-of-contents/
5 | const { headings } = Astro.props;
6 | const toc = buildToc(headings);
7 |
8 | export interface Heading {
9 | depth: number;
10 | slug: string;
11 | text: string;
12 | }
13 |
14 | function buildToc(headings: Heading[]) {
15 | const toc: Heading[] = [];
16 | const parentHeadings = new Map();
17 | headings.forEach((h) => {
18 | const heading = { ...h, subheadings: [] };
19 | parentHeadings.set(heading.depth, heading);
20 | if (heading.depth === 2) {
21 | toc.push(heading);
22 | } else {
23 | parentHeadings.get(heading.depth - 1).subheadings.push(heading);
24 | }
25 | });
26 | return toc;
27 | }
28 | ---
29 |
30 |
34 | Table of Contents
38 |
39 |
40 | {toc.map((heading) => )}
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/components/TableOfContentsHeading.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import type { Heading } from "./TableOfContents.astro";
3 | import Link from "./Link.astro";
4 |
5 | // https://kld.dev/building-table-of-contents/
6 |
7 | const { heading } = Astro.props;
8 | ---
9 |
10 |
11 |
12 | {heading.text}
13 |
14 | {
15 | heading.subheadings.length > 0 && (
16 |
17 | {heading.subheadings.map((subheading: Heading) => (
18 |
19 | ))}
20 |
21 | )
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/src/components/TagCloud.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { getCollection } from "astro:content";
3 |
4 | const allPosts = await getCollection("blog");
5 | const allTags = allPosts.map((tag) => tag.data.tags).flat();
6 |
7 | console.log(allTags);
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/consts.ts:
--------------------------------------------------------------------------------
1 | import type { Metadata, Site, Socials } from "@types";
2 |
3 | export const SITE: Site = {
4 | TITLE: "Astro Micro",
5 | DESCRIPTION: "Astro Micro is an accessible and lightweight blog.",
6 | EMAIL: "trevortylerlee@gmail.com",
7 | NUM_POSTS_ON_HOMEPAGE: 5,
8 | NUM_PROJECTS_ON_HOMEPAGE: 3,
9 | };
10 |
11 | export const HOME: Metadata = {
12 | TITLE: "Home",
13 | DESCRIPTION: "Astro Micro is an accessible theme for Astro.",
14 | };
15 |
16 | export const BLOG: Metadata = {
17 | TITLE: "Blog",
18 | DESCRIPTION: "A collection of articles on topics I am passionate about.",
19 | };
20 |
21 | export const PROJECTS: Metadata = {
22 | TITLE: "Projects",
23 | DESCRIPTION:
24 | "A collection of my projects with links to repositories and live demos.",
25 | };
26 |
27 | export const SOCIALS: Socials = [
28 | {
29 | NAME: "X (formerly Twitter)",
30 | HREF: "https://twitter.com/boogerbuttcheek",
31 | },
32 | {
33 | NAME: "GitHub",
34 | HREF: "https://github.com/trevortylerlee",
35 | },
36 | {
37 | NAME: "Website",
38 | HREF: "https://trevortylerlee.com",
39 | },
40 | ];
41 |
--------------------------------------------------------------------------------
/src/content.config.ts:
--------------------------------------------------------------------------------
1 | import { defineCollection, z } from "astro:content";
2 | import { glob } from 'astro/loaders';
3 |
4 | const blog = defineCollection({
5 | loader: glob({ pattern: '**/*.{md,mdx}', base: "./src/content/blog" }),
6 | schema: z.object({
7 | title: z.string(),
8 | description: z.string(),
9 | date: z.coerce.date(),
10 | draft: z.boolean().optional(),
11 | tags: z.array(z.string()).optional(),
12 | }),
13 | });
14 |
15 | const projects = defineCollection({
16 | loader: glob({ pattern: '**/*.{md,mdx}', base: "./src/content/projects" }),
17 | schema: z.object({
18 | title: z.string(),
19 | description: z.string(),
20 | date: z.coerce.date(),
21 | draft: z.boolean().optional(),
22 | demoURL: z.string().optional(),
23 | repoURL: z.string().optional(),
24 | }),
25 | });
26 |
27 | export const collections = { blog, projects };
28 |
--------------------------------------------------------------------------------
/src/content/blog/00-micro-changelog/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Everything new in Astro Micro"
3 | description: "Features, enhancements, and changes."
4 | date: "2024-05-09"
5 | ---
6 |
7 | import Callout from "@/components/Callout.astro";
8 |
9 | ---
10 |
11 | ## Pagefind search 🔎
12 |
13 | [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.
14 |
15 | Press / or CTRL + K to open the search dialog. For Mac users, ⌘ + K can also be used. To dismiss the search dialog, press Esc or click on an area outside the component.
16 |
17 | ### Build and develop
18 |
19 |
20 | The site **must** be built at least once so Pagefind can index the content.
21 |
22 |
23 | ```bash
24 | # Pagefind must index the site to function
25 | npm run build
26 | ```
27 |
28 | When developing you can continue to use `npm run dev` and Pagefind will use the index from the last available build.
29 |
30 | ---
31 |
32 | ## Giscus comments 💬
33 |
34 | [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).
35 |
36 | ---
37 |
38 | ## Callout component 🆕
39 |
40 |
41 | Adipisicing et officia reprehenderit fugiat occaecat cupidatat exercitation
42 | labore consequat ullamco nostrud non.
43 |
44 |
45 |
46 | Adipisicing et officia reprehenderit fugiat occaecat cupidatat exercitation
47 | labore consequat ullamco nostrud non.
48 |
49 |
50 |
51 | Adipisicing et officia reprehenderit fugiat occaecat cupidatat exercitation
52 | labore consequat ullamco nostrud non.
53 |
54 |
55 |
56 | Adipisicing et officia reprehenderit fugiat occaecat cupidatat exercitation
57 | labore consequat ullamco nostrud non.
58 |
59 |
60 | ---
61 |
62 | ## UI enhancements 🎨
63 |
64 | - Elements are styled and animate on focus
65 | - Increased contrast in light mode
66 | - Active theme is indicated by theme buttons
67 | - Separate syntax highlight themes for light and dark mode
68 | - Code blocks have a copy button
69 | - Add pagination to the bottom of blog posts
70 | - Create 404 page
71 | - Add ToC component to posts
72 |
73 | ---
74 |
75 | ## Other changes
76 |
77 | - Change fonts to Geist Sans and Geist Mono
78 | - Switch base color from "stone" to "neutral"
79 | - Change formatted date to use "long" option for month
80 | - Minor spacing changes throughout
81 | - Remove "work" collection and components
82 | - If desired, you can get the code from [Astro Nano](https://github.com/markhorn-dev/astro-nano)
83 | - Slightly increased link decoration offset
84 | - Slightly sped-up animations
85 | - Reversed animation
86 | - Ensure posts use an h1 tag for post titles
87 | - Tweaked typography
88 |
89 | ---
90 |
91 | ## Issues ⚠️
92 |
93 | ### Active issues
94 |
95 | No active issues!
96 |
97 | ### Closed issues
98 |
99 | - Fixed by [blopker](https://github.com/blopker): [ToC links are obscured by Header when scrolled to](https://github.com/trevortylerlee/astro-micro/issues/4)
100 | - 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)
101 | - Fixed by [arastoonet](https://github.com/arastoonet): [Fix typo in README](https://github.com/trevortylerlee/astro-micro/pull/19)
102 | - Fixed by [cgranier](https://github.com/cgranier): [Pagination links advance by slug/folder](https://github.com/trevortylerlee/astro-micro/issues/26)
103 | - Fixed by [cgranier](https://github.com/cgranier): [Hides Table of Contents when there are no headings](https://github.com/trevortylerlee/astro-micro/pull/30)
104 | - Fixed: [Giscus does not appear when switching blogs via post navigation](https://github.com/trevortylerlee/astro-micro/issues/32)
105 | - Fixed: [Geist font renders incorrectly on Windows](https://github.com/trevortylerlee/astro-micro/issues/33)
106 | - Fixed: [Pagination fails in Cloudflare Pages](https://github.com/trevortylerlee/astro-micro/issues/39)
107 | - Fixed by [luciancah](https://github.com/luciancah): [Prevent Pagefind from double-indexing results](https://github.com/trevortylerlee/astro-micro/issues/40)
108 | - Fixed by [luciancah](https://github.com/luciancah): [Pagefind should close if a result is clicked](https://github.com/trevortylerlee/astro-micro/issues/43)
109 | - Fixed: [Implement tags](https://github.com/trevortylerlee/astro-micro/issues/70)
110 | - Fixed by [anaxite](https://github.com/anaxite): [Update Astro to 5.0](https://github.com/trevortylerlee/astro-micro/issues/73)
111 | - Fixed by [MoyaF](https://github.com/MoyaF): [Table of Contents links not working](https://github.com/trevortylerlee/astro-micro/issues/75)
112 | - Fixed by [antoniovalentini](https://github.com/antoniovalentini): [Possible bugs due to outdated Astro version 5.0.3](https://github.com/trevortylerlee/astro-micro/issues/78)
113 |
--------------------------------------------------------------------------------
/src/content/blog/01-getting-started/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Getting started"
3 | description: "Hit the ground running."
4 | date: "2024-03-22"
5 | tags:
6 | - tutorial
7 | ---
8 |
9 | ---
10 |
11 | ## Install astro-micro
12 |
13 | Clone the [Astro Micro repository](https://github.com/trevortylerlee/astro-micro.git).
14 |
15 | ```sh
16 | git clone https://github.com/trevortylerlee/astro-micro.git my-astro-micro
17 | ```
18 |
19 | ```sh
20 | cd my-astro-micro
21 | ```
22 |
23 | ```sh
24 | npm i
25 | ```
26 |
27 | ```sh
28 | npm run build
29 | ```
30 |
31 | ```sh
32 | npm run dev
33 | ```
34 |
35 | ## Customize the website metadata
36 |
37 | To change the website metadata, edit `src/consts.ts`.
38 |
39 | ```ts
40 | // src/consts.ts
41 |
42 | export const SITE: Site = {
43 | NAME: "Astro Micro",
44 | DESCRIPTION: "Astro Micro is an accessible theme for Astro.",
45 | EMAIL: "trevortylerlee@gmail.com",
46 | NUM_POSTS_ON_HOMEPAGE: 3,
47 | NUM_PROJECTS_ON_HOMEPAGE: 3,
48 | };
49 | ```
50 |
51 | | Field | Req | Description |
52 | | :----------- | :-- | :--------------------------------------------------- |
53 | | TITLE | Yes | Displayed in header and footer. Used in SEO and RSS. |
54 | | DESCRIPTION | Yes | Used in SEO and RSS. |
55 | | EMAIL | Yes | Displayed in contact section. |
56 | | NUM_POSTS | Yes | Limit number of posts on home page. |
57 | | NUM_PROJECTS | Yes | Limit number of projects on home page. |
58 |
59 | ---
60 |
61 | ## Customize metadata for individual pages
62 |
63 | ```ts
64 | // src/consts.ts
65 |
66 | export const ABOUT: Metadata = {
67 | TITLE: "About",
68 | DESCRIPTION: "Astro Micro is a fork of Astro Nano.",
69 | };
70 | ```
71 |
72 | | Field | Req | Description |
73 | | :---------- | :-- | :--------------------------------------------- |
74 | | TITLE | Yes | Displayed in browser tab. Used in SEO and RSS. |
75 | | DESCRIPTION | Yes | Used in SEO and RSS. |
76 |
77 | ---
78 |
79 | ## Add your social media links
80 |
81 | ```ts
82 | // src/consts.ts
83 |
84 | export const SOCIALS: Socials = [
85 | {
86 | NAME: "twitter-x",
87 | HREF: "https://twitter.com/boogerbuttcheeks",
88 | },
89 | {
90 | NAME: "github",
91 | HREF: "https://github.com/trevortylerlee",
92 | },
93 | {
94 | NAME: "linkedin",
95 | HREF: "https://www.linkedin.com/in/trevortylerlee",
96 | },
97 | ];
98 | ```
99 |
100 | | Field | Req | Description |
101 | | :---- | :-- | :-------------------------------------- |
102 | | NAME | Yes | Displayed in contact section as a link. |
103 | | HREF | Yes | External url to social media profile. |
104 |
105 | ## Deploy the site
106 |
107 | 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.
108 |
109 |
117 |
118 | To deploy manually see [Astro's docs](https://docs.astro.build/en/guides/deploy/).
119 |
120 | ## Set up RSS
121 |
122 | Change the `site` option to the deployed site's URL.
123 |
124 | ```js
125 | // astro.config.mjs
126 |
127 | export default defineConfig({
128 | site: "https://astro-micro.vercel.app",
129 | integrations: [tailwind(), sitemap(), mdx(), pagefind()],
130 | markdown: {
131 | shikiConfig: {
132 | theme: "css-variables",
133 | },
134 | },
135 | });
136 | ```
137 |
138 | ## Set up Giscus
139 |
140 | 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.
141 |
142 | ```js
143 | // src/components/Giscus.astro
144 |
145 |
163 | ```
164 |
165 | To change the Giscus themes used, edit the `setGiscusTheme` function in `Head.astro`.
166 |
167 | ```js
168 | // src/components/Head.astro
169 |
170 | const setGiscusTheme = () => {
171 | const giscus = document.querySelector(".giscus-frame");
172 |
173 | const isDark = document.documentElement.classList.contains("dark");
174 |
175 | if (giscus) {
176 | const url = new URL(giscus.src);
177 | // Change "dark" and "light" to other Giscus themes
178 | url.searchParams.set("theme", isDark ? "dark" : "light");
179 | giscus.src = url.toString();
180 | }
181 | };
182 | ```
183 |
--------------------------------------------------------------------------------
/src/content/blog/02-blog-collection/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Blog Collection"
3 | description: "How to add posts to the blog."
4 | date: "2024-03-21"
5 | tags:
6 | - tutorial
7 | ---
8 |
9 | ---
10 |
11 | ## Working with the `blog` collection:
12 |
13 | The `blog` collection is found in `src/content/blog`.
14 |
15 | ```
16 | 📁 /src/content/blog
17 | └── 📁 post-1
18 | └── 📄 index.md
19 | └── 📁 post-2
20 | └── 📄 index.mdx
21 | ```
22 |
23 | In the above example, two blog posts will be generated with the folder name representing the id.
24 |
25 | - `https://example.com/blog/post-1`
26 | - `https://example.com/blog/post-2`
27 |
28 | ---
29 |
30 | ## Provide metadata
31 |
32 | Metadata is required for each post.
33 |
34 | ```astro
35 | ---
36 | title: "Blog Collection";
37 | description: "How to add posts to the blog.";
38 | date: "2024-03-21";
39 | draft: false;
40 | tags:
41 | - tutorial
42 | ---
43 | ```
44 |
45 | | Field | Req | Type | Remarks |
46 | | :---------- | :-- | :------ | :----------------------------------------------- |
47 | | title | Yes | string | Title of the content. Used in SEO and RSS. |
48 | | description | Yes | string | Description of the content. Used in SEO and RSS. |
49 | | date | Yes | string | Must be a valid date string (able to be parsed). |
50 | | draft | No | boolean | If draft: true, content will not be published. |
51 | | tags | No | string array | Tags to organize content |
52 |
53 | ---
54 |
55 | All that's left to do is write the content under the metadata.
56 |
57 | ```astro
58 | ---
59 | title: "Blog Collection";
60 | description: "How to add posts to the blog.";
61 | date: "2024-03-21";
62 | draft: false;
63 | tags:
64 | - tutorial
65 | ---
66 |
67 | ## Working with the blog collection
68 |
69 | ```
70 |
--------------------------------------------------------------------------------
/src/content/blog/03-projects-collection/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Projects Collection"
3 | description: "How to add projects to your portfolio."
4 | date: "2024-03-20"
5 | tags:
6 | - tutorial
7 | ---
8 |
9 | ---
10 |
11 | ## Working with the `projects` collection
12 |
13 | The `projects` collections is found in `src/content/projects`.
14 |
15 | ```
16 | 📁 /src/content/projects
17 | └── 📁 project-1
18 | └── 📄 index.md
19 | └── 📁 project-2
20 | └── 📄 index.mdx
21 | ```
22 |
23 | In the above example, two project posts will be generated with the folder name representing the id.
24 |
25 | - `https://example.com/projects/project-1`
26 | - `https://example.com/projects/project-2`
27 |
28 | ---
29 |
30 | ## Provide metadata
31 |
32 | ```astro
33 | ---
34 | title: "Astro Micro";
35 | description: "Astro Micro is an accessible theme for Astro.";
36 | date: "2024-03-20";
37 | draft: false;
38 | ---
39 | ```
40 |
41 | | Field | Req | Type | Remarks |
42 | | :---------- | :-- | :------ | :----------------------------------------------- |
43 | | title | Yes | string | Title of the content. Used in SEO and RSS. |
44 | | description | Yes | string | Description of the content. Used in SEO and RSS. |
45 | | date | Yes | string | Must be a valid date string (able to be parsed). |
46 | | draft | No | boolean | If draft: true, content will not be published. |
47 | | demoURL | No | string | Link to live project demo, if available. |
48 | | repoURL | No | string | Link to project repo, if available. |
49 |
50 | ---
51 |
52 | All that's left to do is write the content under the metadata.
53 |
54 | ```astro
55 | ---
56 | title: "Astro Micro";
57 | description: "Astro Micro is an accessible theme for Astro";
58 | date: "2024-03-20";
59 | draft: false;
60 | ---
61 |
62 | ## Astro Micro 🔬
63 |
64 | ```
65 |
--------------------------------------------------------------------------------
/src/content/blog/04-markdown-syntax/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Markdown syntax guide"
3 | description: "Get started writing content in Markdown."
4 | date: "2024-03-17"
5 | tag:
6 | - reference
7 | ---
8 |
9 | import Callout from "@/components/Callout.astro";
10 |
11 | ---
12 |
13 | ## Headings
14 |
15 | To create headings, use hash symbols (#) followed by a space. The number of hash symbols indicates the heading level.
16 |
17 |
18 | Use `h2` tags instead of `h1` tags in the post. Too many `h1` tags on a single
19 | page can impact SEO. The post title serves as the `h1`.
20 |
21 |
22 | ```md
23 | # Heading 1
24 |
25 | ## Heading 2
26 |
27 | ### Heading 3
28 |
29 | #### Heading 4
30 |
31 | ##### Heading 5
32 |
33 | ###### Heading 6
34 | ```
35 |
36 | Heading 1
37 | Heading 2
38 | Heading 3
39 | Heading 4
40 | Heading 5
41 | Heading 6
42 |
43 | ---
44 |
45 | ## Paragraphs
46 |
47 | To create paragraphs, use a blank line to separate one or more lines of text.
48 |
49 | {/* prettier-ignore */}
50 | ```md
51 |
52 | I love Star Wars.
53 |
54 | My favourite is Episode III – Revenge of the Sith.
55 |
56 | ```
57 |
58 | I love Star Wars.
59 |
60 | My favourite is Episode III – Revenge of the Sith.
61 |
62 | ---
63 |
64 | ## Italic
65 |
66 | Use one asterisk \(\*\) or underscore \(\_\) to italicize text.
67 |
68 | {/* prettier-ignore */}
69 | ```md
70 | I *love* Star Wars.
71 | My _favourite_ is Episode III – Revenge of the Sith.
72 | ```
73 |
74 | I _love_ Star Wars.
75 | My _favourite_ is Episode III – Revenge of the Sith.
76 |
77 | ---
78 |
79 | ## Bold
80 |
81 | Use two asterisks \(\*\) or underscores \(\_\) to bold text.
82 |
83 | {/* prettier-ignore */}
84 | ```md
85 | I **love** Star Wars.
86 | My __favourite__ is Episode III – Revenge of the Sith.
87 | ```
88 |
89 | I **love** Star Wars.
90 | My **favourite** is Episode III – Revenge of the Sith.
91 |
92 | ---
93 |
94 | ## Italic and Bold
95 |
96 | Use three asterisks \(\*\) or underscores \(\_\) to both bold and italicize text.
97 |
98 | {/* prettier-ignore */}
99 | ```md
100 | I ***love*** Star Wars.
101 | My ___favourite___ is Episode III – Revenge of the Sith.
102 | ```
103 |
104 | I **_love_** Star Wars.
105 | My **_favourite_** is Episode III – Revenge of the Sith.
106 |
107 | ---
108 |
109 | ## Horizontal Rule
110 |
111 | Use three hyphens \(\-\), asterisks \(\*\), or underscores \(\_\) to create a horizontal rule.
112 |
113 | {/* prettier-ignore */}
114 | ```md
115 |
116 | ---
117 |
118 | ***
119 |
120 | ___
121 |
122 | ```
123 |
124 | ---
125 |
126 | ---
127 |
128 | ---
129 |
130 | ## Links
131 |
132 | To create a link, the link text in brackets \(\[\]\) and then follow it immediately with the URL in parentheses \(\(\)\).
133 |
134 | ```md
135 | Micro is a fork of [astro-nano](https://github.com/markhorn-dev/astro-nano).
136 | ```
137 |
138 | Micro is a fork of [astro-nano](https://github.com/markhorn-dev/astro-nano).
139 |
140 | ---
141 |
142 | ## Ordered Lists
143 |
144 | To create an ordered list, add line items with numbers followed by periods. Use an indent to create a nested list.
145 |
146 | ```md
147 | 1. Item 1
148 | 2. Item 2
149 | 1. Sub item 1
150 | 2. Sub item 2
151 | 3. Item 3
152 | ```
153 |
154 | 1. Item 1
155 | 2. Item 2
156 | 1. Sub item 1
157 | 2. Sub item 2
158 | 3. Item 3
159 |
160 | ---
161 |
162 | ## Unordered List
163 |
164 | 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.
165 |
166 | ```md
167 | - Item 1
168 | - Item 2
169 | - Sub item 1
170 | - Sub item 2
171 | - Item 3
172 | ```
173 |
174 | - Item 1
175 | - Item 2
176 | - Sub item 1
177 | - Sub item 2
178 | - Item 3
179 |
180 | ---
181 |
182 | ## Images
183 |
184 | 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.
185 |
186 | ```md
187 | 
188 | ```
189 |
190 | ### Relative
191 |
192 | Use the `` pattern relative to the same folder as the markdown file. Notice the period.
193 |
194 | ```md
195 | 
196 | ```
197 |
198 | 
199 |
200 | ### Public Image
201 |
202 | Use the `` pattern relative to the public folder. No period.
203 |
204 | ```md
205 | 
206 | ```
207 |
208 | 
209 |
210 | ### External Image
211 |
212 | Use the `` pattern.
213 |
214 | ```md
215 | 
216 | ```
217 |
218 | 
219 |
220 | ---
221 |
222 | ## Blockquotes
223 |
224 | 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.
225 |
226 | ```md
227 | > So this is how liberty dies...
228 | >
229 | > with thunderous applause.
230 | ```
231 |
232 | > So this is how liberty dies...
233 | >
234 | > with thunderous applause.
235 |
236 | ---
237 |
238 | ## Strikethrough
239 |
240 | Use a tilde \(\~\) symbol to strikethrough text.
241 |
242 | ```md
243 | ~I don't like sand.~ It's coarse and rough and irritating.
244 | ```
245 |
246 | ~I don't like sand.~ It's coarse and rough and irritating.
247 |
248 | ---
249 |
250 | ## Subscript
251 |
252 | Use the `` tag to denote subscript.
253 |
254 | ```md
255 | H2 O
256 | ```
257 |
258 | H2 O
259 |
260 | ---
261 |
262 | ## Superscript
263 |
264 | Use the `` tag to denote superscript.
265 |
266 | ```md
267 | E=mc2
268 | ```
269 |
270 | E=mc2
271 |
272 | ---
273 |
274 | ## Keyboard
275 |
276 | Use the `` tag to denote keys on the keyboard.
277 |
278 | ```md
279 | CTRL + ALT + Delete
280 | ```
281 |
282 | CTRL + ALT + Delete
283 |
284 | ---
285 |
286 | ## Abbreviate
287 |
288 | Use the `` tag to denote abbreviation.
289 |
290 | ```md
291 | GIF
292 | ```
293 |
294 | GIF
295 |
296 | ---
297 |
298 | ### Highlight
299 |
300 | Use the `` tag to denote highlighted text.
301 |
302 | ```md
303 | Do or do not. There is no try.
304 | ```
305 |
306 | Do or do not. There is no try.
307 |
308 | ---
309 |
310 | ## Task Lists
311 |
312 | Combine a list with square brackets ([]) representing a checkbox. Typing `x` inside the brackets marks the task as complete.
313 |
314 | ```md
315 | - [x] Build a lightsaber
316 | - [ ] Pass the Jedi Trials
317 | - [ ] Train a padawan
318 | ```
319 |
320 | - [x] Build a lightsaber
321 | - [ ] Pass the Jedi Trials
322 | - [ ] Train a padawan
323 |
324 | ---
325 |
326 | ## Tables
327 |
328 | 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.
329 |
330 | ```md
331 | | Item | Count |
332 | | :----- | ----: |
333 | | X-Wing | 1 |
334 | | Y-Wing | 2 |
335 | | A-Wing | 3 |
336 | ```
337 |
338 | | Item | Count |
339 | | :----- | ----: |
340 | | X-Wing | 1 |
341 | | Y-Wing | 2 |
342 | | A-Wing | 3 |
343 |
344 | ---
345 |
346 | ## Footnotes
347 |
348 | Add a caret (^) and an identifier inside brackets \(\[\^1\]\). Identifiers can be numbers or words but can't contain spaces or tabs.
349 |
350 | ```md
351 | Here's a footnote, [^1] and here's another one. [^2]
352 | [^1]: This is the first footnote.
353 | [^2]: This is the second footnote.
354 | ```
355 |
356 | Here's a footnote, [^1] and here's another one. [^2]
357 | [^1]: This is the first footnote.
358 | [^2]: This is the second footnote.
359 |
360 | See the bottom of this page to view the footnotes.
361 |
362 | ---
363 |
364 | ## Code
365 |
366 | To denote a word or phrase as code, enclose it in backticks (`).
367 |
368 | ```md
369 | `package.json`
370 | ```
371 |
372 | `package.json`
373 |
374 | ---
375 |
376 | ## Code Blocks
377 |
378 | 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).
379 |
380 | ````
381 | ```js
382 | function hello() {
383 | console.log("hello world");
384 | }
385 | ```
386 | ````
387 |
388 | ```js
389 | function hello() {
390 | console.log("hello world");
391 | }
392 | ```
393 |
394 | ---
395 |
396 | ## Conclusion
397 |
398 | Refer to [markdownguide.org](https://www.markdownguide.org/) for best practices as well as extended syntax.
399 |
400 | ---
401 |
--------------------------------------------------------------------------------
/src/content/blog/04-markdown-syntax/x-wing.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trevortylerlee/astro-micro/a1618ee2a3b4761a18f463ff200a48b6d415609a/src/content/blog/04-markdown-syntax/x-wing.jpeg
--------------------------------------------------------------------------------
/src/content/blog/05-mdx-syntax/component.astro:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | ---
4 |
5 |
9 | Relative Button
10 |
11 |
--------------------------------------------------------------------------------
/src/content/blog/05-mdx-syntax/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: "MDX syntax guide"
3 | description: "Use interactive components in Markdown."
4 | date: "2024-03-16"
5 | tags:
6 | - reference
7 | ---
8 |
9 | import Callout from "@/components/Callout.astro";
10 |
11 | ---
12 |
13 | MDX is an extension of Markdown with the ability to import `.astro`,
14 | `.jsx`, `.tsx` and other framework components you have integrated.
15 |
16 | This guide covers the basics of MDX syntax and how to use it, as well as a few examples.
17 |
18 | ## Example 1
19 |
20 | Importing a component from the `/components` directory.
21 |
22 | This component accepts a Javascript date object and format it as a string.
23 |
24 | ```astro
25 | import DateComp from "../../../components/FormattedDate.astro";
26 |
27 |
28 | ```
29 |
30 | import FormattedDate from "../../../components/FormattedDate.astro";
31 |
32 |
33 |
34 | ---
35 |
36 | ## Example 2
37 |
38 | Importing a component from a relative path to your content.
39 |
40 | This component displays an alert when the button is clicked.
41 |
42 | ```astro
43 | import RelativeComponent from "./component.astro";
44 |
45 |
46 | ```
47 |
48 | import RelativeComponent from "./component.astro";
49 |
50 |
51 |
52 | ---
53 |
54 | By default Micro has zero frameworks installed. If you install a framework, components of that framework can be used in MDX files.
55 |
56 |
57 | Don't forget to use [client
58 | directives](https://docs.astro.build/en/reference/directives-reference/#client-directives)
59 | to make framework components interactive.
60 |
61 |
62 | ```astro
63 |
64 | ```
65 |
66 | ---
67 |
68 | ## More Links
69 |
70 | - [MDX Syntax Documentation](https://mdxjs.com/docs/what-is-mdx)
71 | - [Astro Framework Integrations](https://docs.astro.build/en/guides/integrations-guide)
72 | - [Astro Usage Documentation](https://docs.astro.build/en/guides/markdown-content/#markdown-and-mdx-pages)
73 | - [Client Directives](https://docs.astro.build/en/reference/directives-reference/#client-directives)
74 |
--------------------------------------------------------------------------------
/src/content/blog/06-year-sorting-example/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Year sorting example"
3 | description: "Nano groups posts by year."
4 | date: "2023-12-31"
5 | tags:
6 | - example
7 | ---
8 |
9 | This post is to demonstrate the year sorting capabilities.
10 |
--------------------------------------------------------------------------------
/src/content/blog/07-draft-example/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Draft example"
3 | description: "Setting draft flag to true to hide this post."
4 | date: "2022-12-31"
5 | draft: false
6 | tags:
7 | - example
8 | ---
9 |
10 | This post also demonstrates the year sorting capabilities.
11 |
12 | Try setting this file's metadata to `draft: true`.
13 |
--------------------------------------------------------------------------------
/src/content/blog/08-prev-next-order-example/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Chronological pagination example"
3 | description: "Pagination works regardless of folder name."
4 | date: "2024-03-21"
5 | tags:
6 | - example
7 | ---
8 |
9 | This post should show up in proper chronological order even though its folder comes last in the `content/blog` directory.
10 |
11 | The `Previous Post` and `Next Post` buttons under each blog post should also keep the proper chronological order, based on the frontmatter `date` field.
12 |
--------------------------------------------------------------------------------
/src/content/projects/project-1/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Astro Sphere"
3 | description: "Portfolio and blog build with astro."
4 | date: "03/18/2024"
5 | demoURL: "https://astro-sphere-demo.vercel.app"
6 | repoURL: "https://github.com/markhorn-dev/astro-sphere"
7 | ---
8 |
9 | 
10 |
11 | Astro Sphere is a static, minimalist, lightweight, lightning fast portfolio and blog theme based on Mark Horn's personal website.
12 |
13 | It is primarily Astro, Tailwind and Typescript, with a very small amount of SolidJS for stateful components.
14 |
15 | ## 🚀 Deploy your own
16 |
17 |
25 |
26 | ## 📋 Features
27 |
28 | - ✅ 100/100 Lighthouse performance
29 | - ✅ Responsive
30 | - ✅ Accessible
31 | - ✅ SEO-friendly
32 | - ✅ Typesafe
33 | - ✅ Minimal style
34 | - ✅ Light/Dark Theme
35 | - ✅ Animated UI
36 | - ✅ Tailwind styling
37 | - ✅ Auto generated sitemap
38 | - ✅ Auto generated RSS Feed
39 | - ✅ Markdown support
40 | - ✅ MDX Support (components in your markdown)
41 | - ✅ Searchable content (posts and projects)
42 |
43 | ## 💯 Lighthouse score
44 |
45 | 
46 |
47 | ## 🕊️ Lightweight
48 |
49 | All pages under 100kb (including fonts)
50 |
51 | ## ⚡︎ Fast
52 |
53 | Rendered in ~40ms on localhost
54 |
55 | ## 📄 Configuration
56 |
57 | The blog posts on the demo serve as the documentation and configuration.
58 |
59 | ## 💻 Commands
60 |
61 | All commands are run from the root of the project, from a terminal:
62 |
63 | Replace npm with your package manager of choice. `npm`, `pnpm`, `yarn`, `bun`, etc
64 |
65 | | Command | Action |
66 | | :------------------------ | :------------------------------------------------ |
67 | | `npm install` | Installs dependencies |
68 | | `npm run dev` | Starts local dev server at `localhost:4321` |
69 | | `npm run sync` | Generates TypeScript types for all Astro modules. |
70 | | `npm run build` | Build your production site to `./dist/` |
71 | | `npm run preview` | Preview your build locally, before deploying |
72 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
73 | | `npm run astro -- --help` | Get help using the Astro CLI |
74 | | `npm run lint` | Run ESLint |
75 | | `npm run lint:fix` | Auto-fix ESLint issues |
76 |
77 | ## 🏛️ License
78 |
79 | MIT
80 |
--------------------------------------------------------------------------------
/src/content/projects/project-2/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Astro Nano"
3 | description: "Minimal portfolio and blog build with astro and no frameworks."
4 | date: "2024-03-26"
5 | demoURL: "https://astro-nano-demo.vercel.app"
6 | repoURL: "https://github.com/markhorn-dev/astro-nano"
7 | ---
8 |
9 | 
10 |
11 | Astro Nano is a static, minimalist, lightweight, lightning fast portfolio and blog theme.
12 |
13 | Built with Astro, Tailwind and Typescript, and no frameworks.
14 |
15 | It was designed as an even more minimal theme than Mark Horn's popular theme [Astro Sphere](https://github.com/markhorn-dev/astro-sphere)
16 |
17 | ## 🚀 Deploy your own
18 |
19 |
27 |
28 | ## 📋 Features
29 |
30 | - ✅ 100/100 Lighthouse performance
31 | - ✅ Responsive
32 | - ✅ Accessible
33 | - ✅ SEO-friendly
34 | - ✅ Typesafe
35 | - ✅ Minimal style
36 | - ✅ Light/Dark Theme
37 | - ✅ Animated UI
38 | - ✅ Tailwind styling
39 | - ✅ Auto generated sitemap
40 | - ✅ Auto generated RSS Feed
41 | - ✅ Markdown support
42 | - ✅ MDX Support (components in your markdown)
43 |
44 | ## 💯 Lighthouse score
45 |
46 | 
47 |
48 | ## 🕊️ Lightweight
49 |
50 | No frameworks or added bulk
51 |
52 | ## ⚡︎ Fast
53 |
54 | Rendered in ~40ms on localhost
55 |
56 | ## 📄 Configuration
57 |
58 | The blog posts on the demo serve as the documentation and configuration.
59 |
60 | ## 💻 Commands
61 |
62 | All commands are run from the root of the project, from a terminal:
63 |
64 | Replace npm with your package manager of choice. `npm`, `pnpm`, `yarn`, `bun`, etc
65 |
66 | | Command | Action |
67 | | :------------------------ | :------------------------------------------------ |
68 | | `npm install` | Installs dependencies |
69 | | `npm run dev` | Starts local dev server at `localhost:4321` |
70 | | `npm run dev:network` | Starts local dev server on local network |
71 | | `npm run sync` | Generates TypeScript types for all Astro modules. |
72 | | `npm run build` | Build your production site to `./dist/` |
73 | | `npm run preview` | Preview your build locally, before deploying |
74 | | `npm run preview:network` | Preview build on local network |
75 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
76 | | `npm run astro -- --help` | Get help using the Astro CLI |
77 | | `npm run lint` | Run ESLint |
78 | | `npm run lint:fix` | Auto-fix ESLint issues |
79 |
80 | ## 🏛️ License
81 |
82 | MIT
83 |
--------------------------------------------------------------------------------
/src/content/projects/project-3/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Astro Micro"
3 | description: "Astro Micro is an accessible and lightweight blog."
4 | date: "2024-05-26"
5 | demoURL: "https://astro-micro.vercel.app"
6 | repoURL: "https://github.com/trevortylerlee/astro-micro"
7 | ---
8 |
9 | 
10 |
11 | Astro Micro is an accessible theme for Astro. It's a fork of Mark Horn's popular theme Astro Nano. Like Nano, Micro comes with zero frameworks installed.
12 |
13 | Micro adds features like [Pagefind](https://pagefind.app) for search, [Giscus](https://giscus.app) for comments, and more. For a full list of changes, see this [blog post](/blog/00-micro-changelog).
14 |
15 | Micro still comes with everything great about Nano — full type safety, a sitemap, an RSS feed, and Markdown + MDX support. Styled with TailwindCSS and preconfigured with system, light, and dark themes.
16 |
17 | Visit [Astro Micro on Github](https://github.com/trevortylerlee/astro-micro) to get started.
18 |
19 | ## 🚀 Deploy your own
20 |
21 |
29 |
30 | ## 📋 Features
31 |
32 | Everything in [Astro Nano](https://github.com/markhorn-dev/astro-nano) plus:
33 |
34 | - Pagefind search
35 | - Giscus comments
36 | - Callout component
37 | - Table of contents component
38 | - Pagination component
39 | - 404 page
40 |
41 | and [more](/blog/00-micro-changelog).
42 |
43 | ## 💯 Lighthouse score
44 |
45 | 
46 |
--------------------------------------------------------------------------------
/src/layouts/Layout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Head from "@components/Head.astro";
3 | import Header from "@components/Header.astro";
4 | import Footer from "@components/Footer.astro";
5 | import Pagefind from "@components/PageFind.astro";
6 | import { SITE } from "@consts";
7 |
8 | type Props = {
9 | title: string;
10 | description: string;
11 | };
12 |
13 | const { title, description } = Astro.props;
14 | ---
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs));
6 | }
7 |
8 | export function formatDate(date: Date) {
9 | return Intl.DateTimeFormat("en-US", {
10 | year: "numeric",
11 | month: "2-digit",
12 | day: "2-digit",
13 | }).format(date);
14 | }
15 |
16 | export function readingTime(html: string) {
17 | const textOnly = html.replace(/<[^>]+>/g, "");
18 | const wordCount = textOnly.split(/\s+/).length;
19 | const readingTimeMinutes = (wordCount / 200 + 1).toFixed();
20 | return `${readingTimeMinutes} min read`;
21 | }
22 |
--------------------------------------------------------------------------------
/src/pages/404.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "@layouts/Layout.astro";
3 | import Container from "@components/Container.astro";
4 | import BackToPrevious from "@components/BackToPrevious.astro";
5 | import { SITE } from "@consts";
6 | ---
7 |
8 |
9 |
10 |
11 |
12 | 404: Page not found
13 |
14 |
15 | Go to home page
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/pages/blog/[...id].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { type CollectionEntry, getCollection, render } from "astro:content";
3 | import Layout from "@layouts/Layout.astro";
4 | import Container from "@components/Container.astro";
5 | import FormattedDate from "@components/FormattedDate.astro";
6 | import { readingTime } from "@lib/utils";
7 | import BackToPrevious from "@components/BackToPrevious.astro";
8 | import PostNavigation from "@components/PostNavigation.astro";
9 | import TableOfContents from "@components/TableOfContents.astro";
10 | import Giscus from "@components/Giscus.astro";
11 |
12 | export async function getStaticPaths() {
13 | const posts = (await getCollection("blog"))
14 | .filter((post) => !post.data.draft)
15 | .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
16 | return posts.map((post) => ({
17 | params: { id: post.id },
18 | props: post,
19 | }));
20 | }
21 | type Props = CollectionEntry<"blog">;
22 |
23 | const posts = (await getCollection("blog"))
24 | .filter((post) => !post.data.draft)
25 | .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
26 |
27 | function getNextPost() {
28 | let postIndex;
29 | for (const post of posts) {
30 | if (post.id === Astro.params.id) {
31 | postIndex = posts.indexOf(post);
32 | return posts[postIndex + 1];
33 | }
34 | }
35 | }
36 |
37 | function getPrevPost() {
38 | let postIndex;
39 | for (const post of posts) {
40 | if (post.id === Astro.params.id) {
41 | postIndex = posts.indexOf(post);
42 | return posts[postIndex - 1];
43 | }
44 | }
45 | }
46 |
47 | const nextPost = getNextPost();
48 | const prevPost = getPrevPost();
49 |
50 | const post = Astro.props;
51 | const { Content, headings } = await render(post);
52 | ---
53 |
54 |
55 |
56 |
57 | Back to blog
58 |
59 |
60 |
61 |
62 |
63 |
64 | •
65 | {post.body && (
66 |
67 | {readingTime(post.body)}
68 |
69 | )}
70 |
71 |
72 | {post.data.title}
73 |
74 | {
75 | post.data.tags && post.data.tags?.length > 0 ? (
76 |
86 | ) : null
87 | }
88 |
89 | {headings.length > 0 && }
90 |
91 |
92 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/src/pages/blog/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { type CollectionEntry, getCollection } from "astro:content";
3 | import Layout from "@layouts/Layout.astro";
4 | import Container from "@components/Container.astro";
5 | import ArrowCard from "@components/ArrowCard.astro";
6 | import { BLOG } from "@consts";
7 |
8 | const data = (await getCollection("blog"))
9 | .filter((post) => !post.data.draft)
10 | .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
11 |
12 | type Acc = {
13 | [year: string]: CollectionEntry<"blog">[];
14 | };
15 |
16 | const posts = data.reduce((acc: Acc, post) => {
17 | const year = post.data.date.getFullYear().toString();
18 | if (!acc[year]) {
19 | acc[year] = [];
20 | }
21 | acc[year].push(post);
22 | return acc;
23 | }, {});
24 |
25 | const years = Object.keys(posts).sort((a, b) => parseInt(b) - parseInt(a));
26 | ---
27 |
28 |
29 |
30 |
31 |
32 |
33 | {
34 | years.map((year) => (
35 |
36 |
37 | {year}
38 |
39 |
40 |
41 | {posts[year].map((post) => (
42 |
43 |
44 |
45 | ))}
46 |
47 |
48 |
49 | ))
50 | }
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "@layouts/Layout.astro";
3 | import Container from "@components/Container.astro";
4 | import { SITE, HOME, SOCIALS } from "@consts";
5 | import ArrowCard from "@components/ArrowCard.astro";
6 | import Link from "@components/Link.astro";
7 | import { getCollection } from "astro:content";
8 | import type { CollectionEntry } from "astro:content";
9 |
10 | const blog = (await getCollection("blog"))
11 | .filter((post) => !post.data.draft)
12 | .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
13 | .slice(0, SITE.NUM_POSTS_ON_HOMEPAGE);
14 |
15 | const projects: CollectionEntry<"projects">[] = (
16 | await getCollection("projects")
17 | )
18 | .filter((project) => !project.data.draft)
19 | .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
20 | .slice(0, SITE.NUM_PROJECTS_ON_HOMEPAGE);
21 | ---
22 |
23 |
24 |
25 |
26 |
27 | Introducing Astro Micro 🔬
28 |
29 |
30 |
31 |
32 |
33 |
34 | Astro Micro is an accessible theme for Astro. It's a fork of
37 |
38 | Mark Horn's
39 | popular theme Astro Nano. Like Nano, Micro comes with zero frameworks installed.
43 |
44 |
45 | Micro adds features like Pagefind for search, Giscus for comments,
48 | and more. For a full list of changes, see this blog post.
51 |
52 |
53 |
54 |
55 | Micro still comes with everything great about Nano — full type
56 | safety, a sitemap, an RSS feed, and Markdown + MDX support.
57 | Styled with TailwindCSS and preconfigured with system, light,
58 | and dark themes.
59 |
60 |
61 | Visit
62 |
63 | Astro Micro on GitHub
64 |
65 | to fork the repository to get started.
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | Latest posts
75 |
76 | See all posts
77 |
78 |
79 | {
80 | blog.map((post) => (
81 |
82 |
83 |
84 | ))
85 | }
86 |
87 |
88 |
89 |
90 |
91 |
92 | Recent projects
93 |
94 | See all projects
95 |
96 |
97 | {
98 | projects.map((project) => (
99 |
100 |
101 |
102 | ))
103 | }
104 |
105 |
106 |
107 |
108 |
109 | Let's Connect
110 |
111 |
112 |
113 | If you want to get in touch with me about something or just to say
114 | hi, reach out on social media or send me an email.
115 |
116 |
117 |
118 | {
119 | SOCIALS.map((SOCIAL) => (
120 |
121 |
126 | {SOCIAL.NAME}
127 |
128 | {"/"}
129 |
130 | ))
131 | }
132 |
133 |
137 | {SITE.EMAIL}
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/src/pages/projects/[...id].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { type CollectionEntry, getCollection, render } from "astro:content";
3 | import Layout from "@layouts/Layout.astro";
4 | import Container from "@components/Container.astro";
5 | import FormattedDate from "@components/FormattedDate.astro";
6 | import { readingTime } from "@lib/utils";
7 | import BackToPrevious from "@components/BackToPrevious.astro";
8 | import Link from "@components/Link.astro";
9 | import TableOfContents from "@components/TableOfContents.astro";
10 |
11 | export async function getStaticPaths() {
12 | const projects = (await getCollection("projects"))
13 | .filter((post) => !post.data.draft)
14 | .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
15 | return projects.map((project) => ({
16 | params: { id: project.id },
17 | props: project,
18 | }));
19 | }
20 | type Props = CollectionEntry<"projects">;
21 |
22 | const project = Astro.props;
23 | const { Content, headings } = await render(project);
24 | ---
25 |
26 |
27 |
28 |
29 | Back to projects
30 |
31 |
32 |
33 |
34 |
35 |
36 | •
37 | {project.body && (
38 |
39 | {readingTime(project.body)}
40 |
41 | )}
42 |
43 |
44 | {project.data.title}
45 |
46 | {
47 | (project.data.demoURL || project.data.repoURL) && (
48 |
49 | {project.data.demoURL && (
50 |
51 | demo
52 |
53 | )}
54 | {project.data.demoURL && project.data.repoURL && / }
55 | {project.data.repoURL && (
56 |
57 | repo
58 |
59 | )}
60 |
61 | )
62 | }
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/pages/projects/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { getCollection } from "astro:content";
3 | import Layout from "@layouts/Layout.astro";
4 | import Container from "@components/Container.astro";
5 | import ArrowCard from "@components/ArrowCard.astro";
6 | import { PROJECTS } from "@consts";
7 |
8 | const projects = (await getCollection("projects"))
9 | .filter((project) => !project.data.draft)
10 | .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
11 | ---
12 |
13 |
14 |
15 |
16 |
17 |
18 | Projects
19 |
20 |
21 | {
22 | projects.map((project) => (
23 |
24 |
25 |
26 | ))
27 | }
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/pages/rss.xml.js:
--------------------------------------------------------------------------------
1 | import rss from "@astrojs/rss";
2 | import { SITE } from "@consts";
3 | import { getCollection } from "astro:content";
4 |
5 | export async function GET(context) {
6 | const blog = (await getCollection("blog")).filter((post) => !post.data.draft);
7 |
8 | const projects = (await getCollection("projects")).filter(
9 | (project) => !project.data.draft,
10 | );
11 |
12 | const items = [...blog, ...projects].sort(
13 | (a, b) => new Date(b.data.date).valueOf() - new Date(a.data.date).valueOf(),
14 | );
15 |
16 | return rss({
17 | title: SITE.TITLE,
18 | description: SITE.DESCRIPTION,
19 | site: context.site,
20 | items: items.map((item) => ({
21 | title: item.data.title,
22 | description: item.data.description,
23 | pubDate: item.data.date,
24 | link: `/${item.collection}/${item.id}/`,
25 | })),
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/src/pages/tags/[...id].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { getCollection } from "astro:content";
3 | import Layout from "@layouts/Layout.astro";
4 | import Container from "@components/Container.astro";
5 | import ArrowCard from "@components/ArrowCard.astro";
6 | import BackToPrevious from "@components/BackToPrevious.astro";
7 |
8 | export async function getStaticPaths() {
9 | const posts = await getCollection("blog", ({ data }) => !data.draft);
10 |
11 | // Get unique tags
12 | const tags = [...new Set(posts.flatMap((post) => post.data.tags || []))];
13 |
14 | // Create paths for each tag
15 | return tags.map((tag) => ({
16 | params: { id: tag },
17 | props: {
18 | posts: posts.filter((post) => post.data.tags?.includes(tag)),
19 | },
20 | }));
21 | }
22 |
23 | const { id } = Astro.params;
24 | const { posts } = Astro.props;
25 |
26 | // Sort posts by date, most recent first
27 | const sortedPosts = posts.sort(
28 | (a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime(),
29 | );
30 | ---
31 |
32 |
33 |
34 |
35 |
All tags
36 |
37 | Posts tagged with "{id}"
38 |
39 |
40 | {sortedPosts.map((post) => )}
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/pages/tags/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { getCollection } from "astro:content";
3 | import Layout from "@layouts/Layout.astro";
4 | import Container from "@components/Container.astro";
5 |
6 | const posts = await getCollection("blog", ({ data }) => !data.draft);
7 | const tags = [...new Set(posts.flatMap((post) => post.data.tags || []))].sort();
8 | ---
9 |
10 |
11 |
12 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/styles/global.css:
--------------------------------------------------------------------------------
1 | @import 'tailwindcss';
2 |
3 | @plugin '@tailwindcss/typography';
4 |
5 | @custom-variant dark (&:is(.dark *));
6 |
7 | @theme {
8 | --font-sans: Geist Sans, ui-sans-serif, system-ui, sans-serif,
9 | 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
10 | --font-mono: Geist Mono, ui-monospace, SFMono-Regular, Menlo, Monaco,
11 | Consolas, 'Liberation Mono', 'Courier New', monospace;
12 | }
13 |
14 | /*
15 | The default border color has changed to `currentColor` in Tailwind CSS v4,
16 | so we've added these compatibility styles to make sure everything still
17 | looks the same as it did with Tailwind CSS v3.
18 |
19 | If we ever want to remove these styles, we need to add an explicit border
20 | color utility to any element that depends on these defaults.
21 | */
22 | @layer base {
23 | *,
24 | ::after,
25 | ::before,
26 | ::backdrop,
27 | ::file-selector-button {
28 | border-color: var(--color-gray-200, currentColor);
29 | }
30 | }
31 |
32 | @layer utilities {
33 | html {
34 | overflow-y: auto;
35 | color-scheme: light;
36 | scroll-padding-top: 100px;
37 | }
38 |
39 | html.dark {
40 | color-scheme: dark;
41 | }
42 |
43 | html,
44 | body {
45 | @apply size-full;
46 | }
47 |
48 | body {
49 | @apply font-sans antialiased;
50 | @apply flex flex-col;
51 | @apply bg-neutral-100 dark:bg-neutral-900;
52 | @apply text-black/75 dark:text-white/75;
53 | }
54 |
55 | header {
56 | @apply fixed left-0 right-0 top-0 z-50 py-6;
57 | @apply bg-neutral-100/75 dark:bg-neutral-900/75;
58 | @apply saturate-200 backdrop-blur-xs;
59 | }
60 |
61 | main {
62 | @apply flex-1 py-32;
63 | }
64 |
65 | footer {
66 | @apply py-6 text-sm;
67 | }
68 |
69 | article {
70 | @apply prose prose-neutral max-w-full dark:prose-invert prose-img:mx-auto prose-img:my-auto;
71 | @apply prose-headings:font-semibold;
72 | @apply prose-headings:text-black dark:prose-headings:text-white;
73 | }
74 | }
75 |
76 | @layer utilities {
77 | article a {
78 | @apply font-sans text-current underline underline-offset-[3px];
79 | @apply decoration-black/30 dark:decoration-white/30;
80 | @apply transition-colors duration-300 ease-in-out;
81 | }
82 | article a:hover {
83 | @apply text-black dark:text-white;
84 | @apply decoration-black/50 dark:decoration-white/50;
85 | }
86 | }
87 |
88 | .animate {
89 | @apply -translate-y-3 opacity-0;
90 | @apply transition-all duration-300 ease-out;
91 | }
92 |
93 | .animate.show {
94 | @apply translate-y-0 opacity-100;
95 | }
96 |
97 | html #back-to-top {
98 | @apply pointer-events-none opacity-0;
99 | }
100 |
101 | html.scrolled #back-to-top {
102 | @apply pointer-events-auto opacity-100;
103 | }
104 |
105 | /* shiki config */
106 | pre {
107 | @apply border border-black/15 py-5 dark:border-white/20;
108 | }
109 |
110 | :root {
111 | --astro-code-foreground: #09090b;
112 | --astro-code-background: #fafafa;
113 | --astro-code-token-comment: #a19595;
114 | --astro-code-token-keyword: #f47067;
115 | --astro-code-token-string: #00a99a;
116 | --astro-code-token-function: #429996;
117 | --astro-code-token-constant: #2b70c5;
118 | --astro-code-token-parameter: #4e8fdf;
119 | --astro-code-token-string-expression: #ae42a0;
120 | --astro-code-token-punctuation: #8996a3;
121 | --astro-code-token-link: #8d85ff;
122 | }
123 |
124 | .dark {
125 | --astro-code-foreground: #fafafa;
126 | --astro-code-background: #09090b;
127 | --astro-code-token-comment: #a19595;
128 | --astro-code-token-keyword: #f47067;
129 | --astro-code-token-string: #00a99a;
130 | --astro-code-token-function: #6eafad;
131 | --astro-code-token-constant: #b3cceb;
132 | --astro-code-token-parameter: #4e8fdf;
133 | --astro-code-token-string-expression: #bf7db6;
134 | --astro-code-token-punctuation: #8996a3;
135 | --astro-code-token-link: #8d85ff;
136 | }
137 |
138 | /* copy code button on codeblocks */
139 | .copy-code {
140 | @apply absolute right-3 top-3 grid size-9 place-content-center rounded-sm border border-black/15 bg-neutral-100 text-center duration-300 ease-in-out dark:border-white/20 dark:bg-neutral-900;
141 | }
142 |
143 | .copy-code:hover {
144 | @apply bg-[#E9E9E9] transition-colors dark:bg-[#232323];
145 | }
146 |
147 | .copy-code:active {
148 | @apply scale-90 transition-transform;
149 | }
150 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | export type Site = {
2 | TITLE: string;
3 | DESCRIPTION: string;
4 | EMAIL: string;
5 | NUM_POSTS_ON_HOMEPAGE: number;
6 | NUM_PROJECTS_ON_HOMEPAGE: number;
7 | };
8 |
9 | export type Metadata = {
10 | TITLE: string;
11 | DESCRIPTION: string;
12 | };
13 |
14 | export type Socials = {
15 | NAME: string;
16 | HREF: string;
17 | }[];
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict",
3 | "include": [".astro/types.d.ts", "**/*"],
4 | "exclude": ["dist"],
5 | "compilerOptions": {
6 | "strictNullChecks": true,
7 | "baseUrl": ".",
8 | "paths": {
9 | "@*": ["./src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------