diff options
| -rw-r--r-- | www-2/content/posts/nspawn.md | 16 | ||||
| -rw-r--r-- | www-2/src/components/ArticlePreview.astro | 27 | ||||
| -rw-r--r-- | www-2/src/components/ArticlePreviewList.astro | 35 | ||||
| -rw-r--r-- | www-2/src/content.config.ts | 4 | ||||
| -rw-r--r-- | www-2/src/layouts/ArticlePage.astro | 14 | ||||
| -rw-r--r-- | www-2/src/layouts/ListPage.astro | 23 | ||||
| -rw-r--r-- | www-2/src/layouts/PageBase.astro | 242 | ||||
| -rw-r--r-- | www-2/src/pages/[...id].astro | 4 | ||||
| -rw-r--r-- | www-2/src/pages/index.astro | 19 | ||||
| -rw-r--r-- | www-2/src/pages/posts.astro | 11 |
10 files changed, 230 insertions, 165 deletions
diff --git a/www-2/content/posts/nspawn.md b/www-2/content/posts/nspawn.md index 866cf96..33501b4 100644 --- a/www-2/content/posts/nspawn.md +++ b/www-2/content/posts/nspawn.md @@ -66,21 +66,21 @@ its package manager. For Debian-based distributions, it's `debootstrap`. If your OS uses a different package manager ecosystem, the target distribution's one and its keyrings (which might reside somewhere else) have to be installed first. -```bash-session +```shellsession # pacman -S debootstrap debian-archive-keyring ubuntu-keyring ``` Regular directories work perfectly as root filesystems, but other directory-like things should work, too, such as `btrfs` subvolume. -```bash-session +```shellsession # btrfs subvolume create /var/lib/machines/[name] ``` Now, run `debootstrap` to create a minimal filesystem. Update the command with the target distribution's codename and one of its mirrors you select. -```bash-session +```shellsession # debootstrap --include=dbus,libpam-systemd,libnss-systemd [codename] \ /var/lib/machines/[name] [mirror] ``` @@ -125,14 +125,14 @@ further. Otherwise, you can use `systemd-nspawn` directly to enter the VM and run commands inside it. `--resolv-conf=bind-host` binds the host's `/etc/resolv.conf` file to make the network work. -```bash-session +```shellsession # systemd-nspawn --resolv-conf=bind-host -D /var/lib/machines/[name] ``` Now, inside the VM, you can do whatever you like. In my configuration, a correct user must be created manually. -```bash-session +```shellsession # apt install locales lsb-release sudo \ nano vim less man bash-completion curl wget \ build-essential git @@ -175,14 +175,14 @@ deb https://mirrors.ustc.edu.cn/ubuntu/ focal-security main restricted universe The following command starts a new shell session for the specified user inside the VM, where you can run commands and perform tasks. -```bash-session +```shellsession # machinectl shell [user]@[name] ``` Another way is to use `login` command to enter the *login console*. From there, you can log in as a user to start a shell session. -```bash-session +```shellsession # machinectl login [name] ``` @@ -197,7 +197,7 @@ If the VM's filesystem is a `btrfs` subvolume, native `btrfs` snapshots can be used here. Before creating a snapshot, you should power off the VM to avoid archiving runtime files. -```bash-session +```shellsession # machinectl poweroff [name] # btrfs subvolume snapshot /var/lib/machines/[name] \ /var/lib/machines/btrfs-snapshots/[name]/[snapshot-name] diff --git a/www-2/src/components/ArticlePreview.astro b/www-2/src/components/ArticlePreview.astro index 3301ad2..bce8b50 100644 --- a/www-2/src/components/ArticlePreview.astro +++ b/www-2/src/components/ArticlePreview.astro @@ -1,22 +1,25 @@ --- -interface Props { - title: string; - date: string; - url: string; - content: string; +import type { CollectionEntry } from "astro:content"; + +export type Props = { + article: CollectionEntry<"articles">; headerElement?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "h7"; -} +}; -const { title, date, url, content, headerElement = "h2" } = Astro.props; +const { + article: { + id, + data: { title, date }, + }, + headerElement = "h2", +} = Astro.props; const H = headerElement; --- <section class="article-preview"> - <span class="date">{date}</span> - <H class="title"><a href={url}>{title}</a></H> - <p class="content"> - {content} - </p> + <span class="date">{date.toLocaleString()}</span> + <H class="title"><a href={id}>{title}</a></H> + <p class="content">aaa</p> <p>... <a class="mono-link" href="{{ .link }}">Read more</a></p> </section> diff --git a/www-2/src/components/ArticlePreviewList.astro b/www-2/src/components/ArticlePreviewList.astro new file mode 100644 index 0000000..abe54f2 --- /dev/null +++ b/www-2/src/components/ArticlePreviewList.astro @@ -0,0 +1,35 @@ +--- +import ArticlePreview, { + type Props as ArticlePreviewProps, +} from "./ArticlePreview.astro"; + +type Props = { + articles: ArticlePreviewProps["article"][]; +} & Omit<ArticlePreviewProps, "article">; + +export type { Props }; + +const { articles, ...otherProps } = Astro.props; +--- + +{ + articles.length > 0 && ( + <ArticlePreview article={articles[0]} {...otherProps} /> + ) +} + +{ + articles.slice(1).map((a) => ( + <> + <hr class="article-preview-hr" /> + <ArticlePreview article={a} {...otherProps} /> + </> + )) +} + +<style> + hr.article-preview-hr { + border: none; + border-top: 1.5px dashed currentColor; + } +</style> diff --git a/www-2/src/content.config.ts b/www-2/src/content.config.ts index f309aa5..f8a3aa1 100644 --- a/www-2/src/content.config.ts +++ b/www-2/src/content.config.ts @@ -2,7 +2,7 @@ import { defineCollection } from "astro:content"; import { glob } from "astro/loaders"; import { z } from "astro/zod"; -const blogs = defineCollection({ +const articles = defineCollection({ loader: glob({ pattern: "**/*.md", base: "./content" }), schema: z.object({ title: z.string(), @@ -14,4 +14,4 @@ const blogs = defineCollection({ }), }); -export const collections = { blogs }; +export const collections = { articles }; diff --git a/www-2/src/layouts/ArticlePage.astro b/www-2/src/layouts/ArticlePage.astro index b6ea5d0..669681e 100644 --- a/www-2/src/layouts/ArticlePage.astro +++ b/www-2/src/layouts/ArticlePage.astro @@ -1,23 +1,17 @@ --- +import type { CollectionEntry } from "astro:content"; + import PageBase from "./PageBase.astro"; import Nav from "../components/Nav.astro"; -interface Props { - id: string; - data: { - title: string; - date: Date; - lastmod?: Date; - }; -} +type Props = Pick<CollectionEntry<"articles">, "id" | "data">; const { - id, data: { title, date, lastmod }, } = Astro.props; --- -<PageBase> +<PageBase title={title}> <Nav /> <h1 class="post-title">{title}</h1> <hr /> diff --git a/www-2/src/layouts/ListPage.astro b/www-2/src/layouts/ListPage.astro new file mode 100644 index 0000000..708df26 --- /dev/null +++ b/www-2/src/layouts/ListPage.astro @@ -0,0 +1,23 @@ +--- +import PageBase from "./PageBase.astro"; +import Nav from "../components/Nav.astro"; +import ArticlePreviewList, { + type Props as ArticlePreviewListProps, +} from "../components/ArticlePreviewList.astro"; + +interface Props { + title: string; + articles: ArticlePreviewListProps["articles"]; +} + +const { title, articles } = Astro.props; +--- + +<PageBase title={title}> + <Nav /> + <h1>{title}</h1> + <hr /> + <ArticlePreviewList articles={articles} headerElement="h2" /> +</PageBase> + +<style></style> diff --git a/www-2/src/layouts/PageBase.astro b/www-2/src/layouts/PageBase.astro index e6e0e1e..83073ca 100644 --- a/www-2/src/layouts/PageBase.astro +++ b/www-2/src/layouts/PageBase.astro @@ -1,3 +1,11 @@ +--- +interface Props { + title: string; +} + +const { title } = Astro.props; +--- + <!doctype html> <html lang="en"> <head> @@ -5,7 +13,7 @@ <meta name="viewport" content="width=device-width" /> <link rel="icon" href="/favicon.ico" /> <meta name="generator" content={Astro.generator} /> - <title>Astro Basics</title> + <title>{title}</title> </head> <body> <article id="main-article"> @@ -41,141 +49,141 @@ </html> <style is:global> -html { - width: 100%; - --body-fg-color: unset; - --body-bg-color: unset; - --table-border-color: black; - --toast-fg-color: white; - --toast-bg-color: black; - --code-fg-color: var(--body-fg-color); - --code-bg-color: #eff1f5; -} + html { + width: 100%; + --body-fg-color: unset; + --body-bg-color: unset; + --table-border-color: black; + --toast-fg-color: white; + --toast-bg-color: black; + --code-fg-color: var(--body-fg-color); + --code-bg-color: #eff1f5; + } -* { - box-sizing: border-box; -} + * { + box-sizing: border-box; + } -body { - width: 100%; - margin: 0; - color: var(--body-fg-color); - background-color: var(--body-bg-color); -} + body { + width: 100%; + margin: 0; + color: var(--body-fg-color); + background-color: var(--body-bg-color); + } -/* https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements#specifying_a_uniform_font_size_for_h1 */ -h1 { - margin-block: 0.67em; - font-size: 2em; -} + /* https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements#specifying_a_uniform_font_size_for_h1 */ + h1 { + margin-block: 0.67em; + font-size: 2em; + } -.mono { - font-family: monospace; -} + .mono { + font-family: monospace; + } -a.mono-link, -.mono-link a, -.mono-link .fake-link { - font-family: monospace; -} + a.mono-link, + .mono-link a, + .mono-link .fake-link { + font-family: monospace; + } -div.mono-container { - font-family: monospace; - margin-block: 1rem; -} + div.mono-container { + font-family: monospace; + margin-block: 1rem; + } -table { - border-collapse: collapse; + table { + border-collapse: collapse; - &, :is(td,th) { - padding: 0.2em 0.4em; - border: 1px solid var(--table-border-color); - } -} + &, + :is(td, th) { + padding: 0.2em 0.4em; + border: 1px solid var(--table-border-color); + } + } -.toast { - font-size: large; - font-family: monospace; - color: var(--toast-fg-color); - background-color: var(--toast-bg-color); - padding: 0.5em 0.3em; - border-radius: 6px; - - position: fixed; - z-index: 1; - top: 4px; - left: 50vw; - transform: translateX(-50%); -} + .toast { + font-size: large; + font-family: monospace; + color: var(--toast-fg-color); + background-color: var(--toast-bg-color); + padding: 0.5em 0.3em; + border-radius: 6px; + + position: fixed; + z-index: 1; + top: 4px; + left: 50vw; + transform: translateX(-50%); + } -.chroma { - overflow-x: auto; - padding-left: 1px; - padding-right: 4px; - border-radius: 6px; -} + .chroma { + overflow-x: auto; + padding-left: 1px; + padding-right: 4px; + border-radius: 6px; + } -nav { - font-size: large; -} + nav { + font-size: large; + } -#main-article { - position: relative; - left: 50%; - transform: translateX(-50%); - max-width: 880px; - padding: 0 1em; - margin-top: 1em; -} + #main-article { + position: relative; + left: 50%; + transform: translateX(-50%); + max-width: 880px; + padding: 0 1em; + margin-top: 1em; + } -#license a { - font-family: initial; - text-decoration: none; -} + #license a { + font-family: initial; + text-decoration: none; + } -#license-text { - font-family: monospace; - text-decoration: initial; -} + #license-text { + font-family: monospace; + text-decoration: initial; + } -#license-img-container img { - height: 1em; - vertical-align: middle; -} + #license-img-container img { + height: 1em; + vertical-align: middle; + } -.link-group { - margin-block-end: 1em; + .link-group { + margin-block-end: 1em; - > .link-group-title { - font-size: 1.1em; - margin-block-end: 5px; - } + > .link-group-title { + font-size: 1.1em; + margin-block-end: 5px; + } - > .link-group-list { - border-inline-start: solid 1px hsl(0, 0%, 25%); - padding-inline-start: 8px; + > .link-group-list { + border-inline-start: solid 1px hsl(0, 0%, 25%); + padding-inline-start: 8px; - > .link-group-item::before { - content: "- "; + > .link-group-item::before { + content: "- "; + } + } } - } -} - -html[data-theme="dark"] { - --body-fg-color: white; - --body-bg-color: black; - --table-border-color: hsl(0, 0%, 25%); - --toast-fg-color: var(--body-bg-color); - --toast-bg-color: var(--body-fg-color); - --code-bg-color: #1e1e2e; - - & a:link { - color:#34ffd9; - } - - & a:visited { - color:#abcac4; - } -} + html[data-theme="dark"] { + --body-fg-color: white; + --body-bg-color: black; + --table-border-color: hsl(0, 0%, 25%); + --toast-fg-color: var(--body-bg-color); + --toast-bg-color: var(--body-fg-color); + --code-bg-color: #1e1e2e; + + & a:link { + color: #34ffd9; + } + + & a:visited { + color: #abcac4; + } + } </style> diff --git a/www-2/src/pages/[...id].astro b/www-2/src/pages/[...id].astro index b3c5b40..bbaed88 100644 --- a/www-2/src/pages/[...id].astro +++ b/www-2/src/pages/[...id].astro @@ -4,8 +4,8 @@ import { getCollection, render } from "astro:content"; import ArticlePage from "../layouts/ArticlePage.astro"; export async function getStaticPaths() { - const posts = await getCollection("blogs"); - return posts.map((post) => ({ + const articles = await getCollection("articles"); + return articles.map((post) => ({ params: { id: post.id }, props: { post }, })); diff --git a/www-2/src/pages/index.astro b/www-2/src/pages/index.astro index 4007037..c8687c4 100644 --- a/www-2/src/pages/index.astro +++ b/www-2/src/pages/index.astro @@ -1,16 +1,16 @@ --- -import { getCollection, render } from "astro:content"; +import { getCollection } from "astro:content"; import PageBase from "../layouts/PageBase.astro"; import Friend from "../components/Friend.astro"; -import ArticlePreview from "../components/ArticlePreview.astro"; +import ArticlePreviewList from "../components/ArticlePreviewList.astro"; const posts = ( - await getCollection("blogs", ({ id }) => id.startsWith("posts/")) + await getCollection("articles", ({ id }) => id.startsWith("posts/")) ).slice(0, 3); --- -<PageBase> +<PageBase title="crupest's home"> <img id="avatar" src="/avatar.png" alt="My avatar" width="80" height="80" /> <h1 id="title">Hello! This is <code>crupest</code> !</h1> <hr /> @@ -38,16 +38,7 @@ const posts = ( <hr /> <section id="recent-posts"> <h2>Recent Posts <a class="mono-link" href="/posts">(all)</a></h2> - { - posts.map((post) => ( - <ArticlePreview - title={post.data.title} - date={post.data.date.toLocaleString()} - url={"/posts/" + post.id} - content="" - /> - )) - } + <ArticlePreviewList articles={posts} headerElement="h3" /> </section> <hr /> <section> diff --git a/www-2/src/pages/posts.astro b/www-2/src/pages/posts.astro new file mode 100644 index 0000000..b4c6189 --- /dev/null +++ b/www-2/src/pages/posts.astro @@ -0,0 +1,11 @@ +--- +import { getCollection } from "astro:content"; + +import ListPage from "../layouts/ListPage.astro"; + +const posts = await getCollection("articles", ({ id }) => + id.startsWith("posts/"), +); +--- + +<ListPage title="Posts" articles={posts} /> |
