this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Rough implementation of a sidebar navList

- Add a path to /navList.json to add it to the navigation
- Add a <Nav /> component to the page you want

- Clicking "Open" opens the nav with light dismiss (will add an X later)
- Sidebar slides in and out on left
- Can open on default

- Made the /blog heading not sticky

+167 -12
+56
src/components/generic/Nav.astro
··· 1 + --- 2 + import type { nav } from "@/content.config"; 3 + import NavEntry from "./NavEntry.astro"; 4 + 5 + interface Props { 6 + startOpen?: boolean; 7 + current: string; 8 + data: nav[]; 9 + } 10 + 11 + const { data, startOpen = false, current } = Astro.props; 12 + --- 13 + 14 + <button popovertarget="nav">Open</button> 15 + <dialog closedby="any" open={startOpen} id="nav" popover> 16 + <h1>{current}</h1> 17 + {(<NavEntry {data} />)} 18 + </dialog> 19 + 20 + <style> 21 + dialog { 22 + color: white; 23 + 24 + width: min(50vw, 20rem); 25 + height: 100vh; 26 + 27 + background: black; 28 + border: none; 29 + 30 + position: absolute; 31 + transition: 32 + left 0.2s, 33 + display 0.2s allow-discrete; 34 + 35 + &:popover-open { 36 + /* Post-Entry (Normal) State */ 37 + left: 0; 38 + 39 + /* Pre-Entry State */ 40 + @starting-style { 41 + left: -100%; 42 + } 43 + } 44 + 45 + /* Exiting State */ 46 + &:not(:popover-open) { 47 + left: -100%; 48 + } 49 + } 50 + 51 + /* STUPID ISSUE */ 52 + :global(::backdrop) { 53 + background: #00000080; 54 + backdrop-filter: blur(0.5rem); 55 + } 56 + </style>
+32
src/components/generic/NavEntry.astro
··· 1 + --- 2 + import type { nav } from "@/content.config"; 3 + 4 + interface Props { 5 + data: nav[]; 6 + } 7 + 8 + const { data } = Astro.props; 9 + --- 10 + 11 + <ul class="nav-ul"> 12 + { 13 + data.map((x) => 14 + x.children && x.children.length > 0 ? ( 15 + <li> 16 + <details> 17 + <summary> 18 + <a href={x.slug}>{x.name}</a> 19 + </summary> 20 + {x.children && x.children.length > 0 ? ( 21 + <Astro.self data={x.children} /> 22 + ) : null} 23 + </details> 24 + </li> 25 + ) : ( 26 + <li> 27 + <a href={x.slug}>{x.name}</a> 28 + </li> 29 + ) 30 + ) 31 + } 32 + </ul>
+22 -4
src/content.config.ts
··· 1 1 import { defineCollection, z } from "astro:content"; 2 - import { glob } from "astro/loaders"; 2 + import { file, glob } from "astro/loaders"; 3 3 4 4 const blog = defineCollection({ 5 5 loader: glob({ pattern: "**/*.md", base: "./src/posts" }), ··· 24 24 loader: glob({ pattern: "**/*.mdx", base: "./src/posts" }), 25 25 schema: z.object({ 26 26 title: z.string(), 27 - }) 28 - }) 27 + }), 28 + }); 29 29 30 - export const collections = { blog, blogMdx }; 30 + const baseNav = z.object({ 31 + slug: z.string(), 32 + name: z.string(), 33 + }); 34 + 35 + export type nav = z.infer<typeof baseNav> & { 36 + children?: nav[]; 37 + }; 38 + 39 + const navSchema: z.ZodType<nav> = baseNav.extend({ 40 + children: z.lazy(() => navSchema.array()), 41 + }); 42 + 43 + const nav = defineCollection({ 44 + loader: file("src/navList.json"), 45 + schema: navSchema, 46 + }); 47 + 48 + export const collections = { blog, blogMdx, nav };
+28
src/navList.json
··· 1 + [ 2 + { 3 + "slug": "/", 4 + "name": "Home", 5 + "children": [] 6 + }, 7 + { 8 + "slug": "/blog", 9 + "name": "Blog", 10 + "children": [] 11 + }, 12 + { 13 + "slug": "/testing", 14 + "name": "Testing", 15 + "children": [ 16 + { 17 + "slug": "/123", 18 + "name": "123", 19 + "children": [] 20 + }, 21 + { 22 + "slug": "/maoii", 23 + "name": "Me!", 24 + "children": [] 25 + } 26 + ] 27 + } 28 + ]
+29 -8
src/pages/blog/index.astro
··· 2 2 import Base from "@/Base.astro"; 3 3 import Post from "@/components/blog/Post.astro"; 4 4 import Background from "@/components/blog/Background.astro"; 5 + import Nav from "@/components/generic/Nav.astro"; 5 6 6 7 import Rss from "@/assets/rss.svg"; 7 8 ··· 9 10 import { blog } from "@/config"; 10 11 11 12 const posts = await getCollection("blog"); 13 + const nav = await getCollection("nav").then((x) => x.map((x) => x.data)); 12 14 --- 13 15 14 16 <style> 15 17 a:has(svg) { 16 18 background-color: orange; 17 19 display: inline-block; 18 - height: 1em; 20 + height: 2em; 19 21 aspect-ratio: 1; 20 - padding: 0.1em; 22 + padding: 0.2em; 21 23 border-radius: 0.5rem; 22 24 23 25 & svg { 24 - width: 0.8em; 26 + width: 1.6em; 25 27 aspect-ratio: 1; 26 28 } 27 29 } 28 30 29 - h1 { 31 + heading { 32 + font-size: 1.6rem; 30 33 margin-bottom: var(--y-gap); 31 34 color: white; 35 + 36 + position: fixed; 37 + top: 0; 38 + width: 100%; 39 + z-index: 999; 40 + padding: 0.5rem 1.5rem; 41 + display: flex; 42 + align-items: center; 43 + justify-content: space-between; 44 + 45 + & .gap { 46 + width: 100%; 47 + } 48 + } 49 + 50 + .top-offset { 51 + height: 16rem; 32 52 } 33 53 </style> 34 54 35 55 <Base title="Blog"> 36 56 <Background /> 37 57 <main> 38 - <h1 style={`--y-gap: ${blog.post.yGap}rem`}> 39 - Blog 58 + <heading style={`--y-gap: ${blog.post.yGap}rem`}> 59 + <Nav data={nav} current="Blog" /> 60 + 40 61 <a href="/rss.xml" aria-label="Rss Feed"> 41 - <Rss width=".8em" height=".8em" /> 62 + <Rss width="1.6em" height="1.6em" /> 42 63 </a> 43 - </h1> 64 + </heading> 44 65 45 66 { 46 67 posts.map((x, i) => (