Compare commits
10 commits
c1a329103a
...
f177bb3857
| Author | SHA1 | Date | |
|---|---|---|---|
| f177bb3857 | |||
| 98c35dabc5 | |||
| 39bb755f1e | |||
| a3b0b838c7 | |||
| 6f537de9e6 | |||
| 35ac6a7ae1 | |||
| 8e539ffc0f | |||
| e56608c81e | |||
| 2dbadd360f | |||
| 9dbaf7c321 |
53
.forgejo/workflows/deploy.yml
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
name: deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- src/**/*
|
||||||
|
- public/**/*
|
||||||
|
- .forgejo/workflows/deploy.yml
|
||||||
|
- astro.config.mjs
|
||||||
|
- tsconfig.json
|
||||||
|
- package.json
|
||||||
|
- bun.lock
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: trixie
|
||||||
|
env:
|
||||||
|
TERM: dumb
|
||||||
|
NIX_INSTALLER_INIT: "none"
|
||||||
|
NIX_INSTALLER_NO_CONFIRM: "true"
|
||||||
|
NIX_INSTALLER_ENABLE_FLAKES: "true"
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: https://code.forgejo.org/actions/checkout@v6.0.1
|
||||||
|
- name: Setup lix toolchain
|
||||||
|
run: curl -sL https://install.lix.systems/lix | sh -s -- install linux
|
||||||
|
- name: Install bun dependencies
|
||||||
|
run: nix develop -c bun install --frozen-lockfile
|
||||||
|
- name: Build static files for website
|
||||||
|
run: nix develop -c bun run build
|
||||||
|
- name: Upload static files
|
||||||
|
uses: https://code.forgejo.org/forgejo/upload-artifact@v5
|
||||||
|
with:
|
||||||
|
name: website-${{ forge.sha }}
|
||||||
|
retention-days: 1
|
||||||
|
path: dist
|
||||||
|
deploy:
|
||||||
|
needs: [build]
|
||||||
|
runs-on: trixie
|
||||||
|
env: { TERM: "dumb" }
|
||||||
|
container: { image: "node:current" }
|
||||||
|
steps:
|
||||||
|
- name: Download static files
|
||||||
|
uses: https://code.forgejo.org/forgejo/download-artifact@v7
|
||||||
|
with: { name: "website-${{ forge.sha }}", path: "dist" }
|
||||||
|
- name: Deploy website to cloudflare
|
||||||
|
uses: https://github.com/cloudflare/wrangler-action@v3.14.1
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
command: pages deploy dist --project-name=website
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
stages:
|
|
||||||
- build
|
|
||||||
- deploy
|
|
||||||
|
|
||||||
workflow:
|
|
||||||
rules:
|
|
||||||
- changes:
|
|
||||||
- src/**/*
|
|
||||||
- public/**/*
|
|
||||||
- astro.config.mjs
|
|
||||||
- .gitlab-ci.yml
|
|
||||||
- tsconfig.json
|
|
||||||
- package.json
|
|
||||||
- flake.lock
|
|
||||||
- flake.nix
|
|
||||||
- bun.lock
|
|
||||||
|
|
||||||
build:
|
|
||||||
stage: build
|
|
||||||
image: alpine:edge
|
|
||||||
variables:
|
|
||||||
TERM: "dumb"
|
|
||||||
NIX_INSTALLER_NO_CONFIRM: "true"
|
|
||||||
NIX_INSTALLER_ENABLE_FLAKES: "true"
|
|
||||||
before_script:
|
|
||||||
- apk add --no-cache curl bash git xz
|
|
||||||
- curl -sL https://install.lix.systems/lix | sh -s -- install linux --init none
|
|
||||||
- source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
|
|
||||||
script:
|
|
||||||
- nix develop -c bun install
|
|
||||||
- nix develop -c bun run build
|
|
||||||
artifacts:
|
|
||||||
name: website-$CI_COMMIT_SHA
|
|
||||||
expire_in: 1 day
|
|
||||||
paths: [dist]
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
stage: deploy
|
|
||||||
image: node:alpine
|
|
||||||
needs: [build]
|
|
||||||
script: npx wrangler pages deploy dist --project-name=website
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Website
|
# website ![license] ![status]
|
||||||
|
|
||||||
The source code of my personal website and blog, made using the [Astro] static
|
The source code of my personal website and blog, made using the [Astro] static
|
||||||
site generator.
|
site generator.
|
||||||
|
|
@ -13,6 +13,9 @@ Due to the nature of the content in this repository, it uses multiple licenses.
|
||||||
|
|
||||||
All files that are in this repository must follow these licenses.
|
All files that are in this repository must follow these licenses.
|
||||||
|
|
||||||
|
[status]: https://badge.hanna.lol/build/hanna/website/main
|
||||||
|
[license]: https://badge.hanna.lol/license/MPL-2.0
|
||||||
|
|
||||||
[astro]: https://astro.build
|
[astro]: https://astro.build
|
||||||
[mpl-2.0]: https://choosealicense.com/licenses/mpl-2.0
|
[mpl-2.0]: https://choosealicense.com/licenses/mpl-2.0
|
||||||
[cc by-nc-nd 4.0]: https://creativecommons.org/licenses/by-nc-nd/4.0
|
[cc by-nc-nd 4.0]: https://creativecommons.org/licenses/by-nc-nd/4.0
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,7 @@ import mdx from '@astrojs/mdx';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [mdx()],
|
integrations: [mdx()],
|
||||||
|
image: {
|
||||||
|
service: { entrypoint: 'astro/assets/services/noop' },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
6
flake.lock
generated
|
|
@ -21,11 +21,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765903799,
|
"lastModified": 1766025857,
|
||||||
"narHash": "sha256-1wbl0y7U8TvSHxDWME7o92bIspfuhjVaTOs27r54uc4=",
|
"narHash": "sha256-Lav5jJazCW4mdg1iHcROpuXqmM94BWJvabLFWaJVJp0=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e8d16d2186d6ed9f047eb30948e97e7e01886d10",
|
"rev": "def3da69945bbe338c373fddad5a1bb49cf199ce",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-calendar-icon lucide-calendar"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 338 B |
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-smile-plus-icon lucide-smile-plus"><path d="M22 11v1a10 10 0 1 1-9-10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" x2="9.01" y1="9" y2="9"/><line x1="15" x2="15.01" y1="9" y2="9"/><path d="M16 5h6"/><path d="M19 2v6"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 424 B |
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mail-icon lucide-mail"><path d="m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7"/><rect x="2" y="4" width="20" height="16" rx="2"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 324 B |
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-user-icon lucide-file-user"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/><path d="M16 22a4 4 0 0 0-8 0"/><circle cx="12" cy="15" r="3"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 454 B |
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-gamepad-directional-icon lucide-gamepad-directional"><path d="M11.146 15.854a1.207 1.207 0 0 1 1.708 0l1.56 1.56A2 2 0 0 1 15 18.828V21a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1v-2.172a2 2 0 0 1 .586-1.414z"/><path d="M18.828 15a2 2 0 0 1-1.414-.586l-1.56-1.56a1.207 1.207 0 0 1 0-1.708l1.56-1.56A2 2 0 0 1 18.828 9H21a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1z"/><path d="M6.586 14.414A2 2 0 0 1 5.172 15H3a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h2.172a2 2 0 0 1 1.414.586l1.56 1.56a1.207 1.207 0 0 1 0 1.708z"/><path d="M9 3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2.172a2 2 0 0 1-.586 1.414l-1.56 1.56a1.207 1.207 0 0 1-1.708 0l-1.56-1.56A2 2 0 0 1 9 5.172z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 822 B |
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-gitlab-icon lucide-gitlab"><path d="m22 13.29-3.33-10a.42.42 0 0 0-.14-.18.38.38 0 0 0-.22-.11.39.39 0 0 0-.23.07.42.42 0 0 0-.14.18l-2.26 6.67H8.32L6.1 3.26a.42.42 0 0 0-.1-.18.38.38 0 0 0-.26-.08.39.39 0 0 0-.23.07.42.42 0 0 0-.14.18L2 13.29a.74.74 0 0 0 .27.83L12 21l9.69-6.88a.71.71 0 0 0 .31-.83Z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 505 B |
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-heart-icon lucide-heart"><path d="M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 387 B |
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user-lock-icon lucide-user-lock"><circle cx="10" cy="7" r="4"/><path d="M10.3 15H7a4 4 0 0 0-4 4v2"/><path d="M15 15.5V14a2 2 0 0 1 4 0v1.5"/><rect width="8" height="5" x="13" y="16" rx=".899"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 395 B |
|
Before Width: | Height: | Size: 255 KiB After Width: | Height: | Size: 255 KiB |
1
src/images/calendar.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-calendar-icon lucide-calendar"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
|
||||||
|
After Width: | Height: | Size: 346 B |
1
src/images/emoji.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-smile-plus-icon lucide-smile-plus"><path d="M22 11v1a10 10 0 1 1-9-10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" x2="9.01" y1="9" y2="9"/><line x1="15" x2="15.01" y1="9" y2="9"/><path d="M16 5h6"/><path d="M19 2v6"/></svg>
|
||||||
|
After Width: | Height: | Size: 432 B |
1
src/images/envelope.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mail-icon lucide-mail"><path d="m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7"/><rect x="2" y="4" width="20" height="16" rx="2"/></svg>
|
||||||
|
After Width: | Height: | Size: 332 B |
1
src/images/file-user.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-user-icon lucide-file-user"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/><path d="M16 22a4 4 0 0 0-8 0"/><circle cx="12" cy="15" r="3"/></svg>
|
||||||
|
After Width: | Height: | Size: 462 B |
1
src/images/games.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-gamepad-directional-icon lucide-gamepad-directional"><path d="M11.146 15.854a1.207 1.207 0 0 1 1.708 0l1.56 1.56A2 2 0 0 1 15 18.828V21a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1v-2.172a2 2 0 0 1 .586-1.414z"/><path d="M18.828 15a2 2 0 0 1-1.414-.586l-1.56-1.56a1.207 1.207 0 0 1 0-1.708l1.56-1.56A2 2 0 0 1 18.828 9H21a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1z"/><path d="M6.586 14.414A2 2 0 0 1 5.172 15H3a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h2.172a2 2 0 0 1 1.414.586l1.56 1.56a1.207 1.207 0 0 1 0 1.708z"/><path d="M9 3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2.172a2 2 0 0 1-.586 1.414l-1.56 1.56a1.207 1.207 0 0 1-1.708 0l-1.56-1.56A2 2 0 0 1 9 5.172z"/></svg>
|
||||||
|
After Width: | Height: | Size: 830 B |
1
src/images/git-branch.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-git-branch-icon lucide-git-branch"><line x1="6" x2="6" y1="3" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
|
||||||
|
After Width: | Height: | Size: 371 B |
1
src/images/heart.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-heart-icon lucide-heart"><path d="M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"/></svg>
|
||||||
|
After Width: | Height: | Size: 395 B |
1
src/images/user-lock.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user-lock-icon lucide-user-lock"><circle cx="10" cy="7" r="4"/><path d="M10.3 15H7a4 4 0 0 0-4 4v2"/><path d="M15 15.5V14a2 2 0 0 1 4 0v1.5"/><rect width="8" height="5" x="13" y="16" rx=".899"/></svg>
|
||||||
|
After Width: | Height: | Size: 403 B |
|
|
@ -8,6 +8,7 @@ const { title, desc } = Astro.props;
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
<meta name="description" content={desc}>
|
<meta name="description" content={desc}>
|
||||||
|
<meta name="theme-color" content="#2986cc">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg">
|
||||||
<link rel="stylesheet" href="/css/global.css">
|
<link rel="stylesheet" href="/css/global.css">
|
||||||
|
|
@ -16,13 +17,13 @@ const { title, desc } = Astro.props;
|
||||||
<body>
|
<body>
|
||||||
<div class="navbar">
|
<div class="navbar">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<h1><a href="/">Hanna Rose</a></h1>
|
<h1><a draggable="false" href="/">Hanna Rose</a></h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<ul class="pages">
|
<ul class="pages">
|
||||||
<li><a href="/">Home</a></li>
|
<li><a draggable="false" href="/">Home</a></li>
|
||||||
<li><a href="/blog">Blog</a></li>
|
<li><a draggable="false" href="/blog">Blog</a></li>
|
||||||
<li><a href="https://liberapay.com/hqnna">Donate</a></li>
|
<li><a draggable="false" href="https://liberapay.com/hqnna">Donate</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,12 @@ export async function getStaticPaths() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const fmtDate = (date) => new Date(date).toLocaleString('en-US', {
|
const fmtDate = (date: Date) =>
|
||||||
month: '2-digit',
|
new Date(date).toLocaleString('en-US', {
|
||||||
day: '2-digit',
|
month: '2-digit',
|
||||||
year: 'numeric'
|
day: '2-digit',
|
||||||
});
|
year: 'numeric',
|
||||||
|
});
|
||||||
|
|
||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
const { Content, headings } = await post.render();
|
const { Content, headings } = await post.render();
|
||||||
|
|
@ -31,27 +32,33 @@ const { Content, headings } = await post.render();
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<details class="toc" open>
|
<div class="sidebar">
|
||||||
<summary>Table of Contents</summary>
|
<details class="toc" open>
|
||||||
<ul>
|
<summary>Table of Contents</summary>
|
||||||
{headings.filter(h => h.depth > 1 && h.depth < 4).map(h => (
|
<ul>
|
||||||
<li class={`depth-${h.depth}`}>
|
{headings.filter(h => h.depth > 1 && h.depth < 4).map(h => (
|
||||||
<a href={`#${h.slug}`}>{h.text}</a>
|
<li class={`depth-${h.depth}`}>
|
||||||
</li>
|
<a draggable="false" href={`#${h.slug}`}>{h.text}</a>
|
||||||
))}
|
</li>
|
||||||
</ul>
|
))}
|
||||||
</details>
|
</ul>
|
||||||
|
</details>
|
||||||
|
<p class="copyright">
|
||||||
|
This blog post is licensed under
|
||||||
|
<a draggable="false" href="https://creativecommons.org/licenses/by-nc-nd/4.0/">
|
||||||
|
CC BY-NC-ND 4.0</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<section class="article">
|
<section class="article">
|
||||||
<Content />
|
<Content />
|
||||||
<p class="copyright">
|
|
||||||
This article is licensed under the
|
|
||||||
<a href="https://creativecommons.org/licenses/by-nc-nd/4.0/">
|
|
||||||
CC BY-NC-ND 4.0
|
|
||||||
</a>
|
|
||||||
license.
|
|
||||||
</p>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<p class="copyright mobile">
|
||||||
|
This blog post is licensed under
|
||||||
|
<a draggable="false" href="https://creativecommons.org/licenses/by-nc-nd/4.0/">
|
||||||
|
CC BY-NC-ND 4.0</a>.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Page>
|
</Page>
|
||||||
|
|
||||||
|
|
@ -102,16 +109,63 @@ const { Content, headings } = await post.render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc {
|
.sidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: max(20px, calc(50% - 24rem - 300px));
|
left: max(20px, calc(50% - 24rem - 300px));
|
||||||
max-height: calc(100vh - 140px);
|
max-height: calc(100vh - 140px);
|
||||||
|
width: 250px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
& > .copyright {
|
||||||
|
color: rgba(194, 200, 204, 0.4);
|
||||||
|
padding-top: var(--space-sm);
|
||||||
|
font-size: 10px;
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
color: var(--text-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1400px) {
|
||||||
|
position: relative;
|
||||||
|
max-height: none;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
& > .copyright {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright.mobile {
|
||||||
|
display: none;
|
||||||
|
color: rgba(194, 200, 204, 0.4);
|
||||||
|
font-size: 10px;
|
||||||
|
border-top: 1px solid rgba(194, 200, 204, 0.1);
|
||||||
|
padding-top: 8px;
|
||||||
|
margin-top: var(--space-sm);
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
color: var(--text-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1400px) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc {
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
padding: var(--space-sm);
|
padding: var(--space-sm);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
width: 250px;
|
flex: 1;
|
||||||
|
max-height: calc(100vh - 200px);
|
||||||
|
|
||||||
& summary {
|
& summary {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
@ -147,7 +201,6 @@ const { Content, headings } = await post.render();
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
display: block;
|
display: block;
|
||||||
padding: 2px 0;
|
padding: 2px 0;
|
||||||
transition: color 0.2s;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
@ -171,12 +224,9 @@ const { Content, headings } = await post.render();
|
||||||
|
|
||||||
@media only screen and (max-width: 1400px) {
|
@media only screen and (max-width: 1400px) {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
position: relative;
|
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
max-height: none;
|
max-height: none;
|
||||||
width: calc(100% - 22px);
|
flex: none;
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
|
|
||||||
&:not([open]) {
|
&:not([open]) {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
@ -330,7 +380,8 @@ const { Content, headings } = await post.render();
|
||||||
text-decoration-color: transparent;
|
text-decoration-color: transparent;
|
||||||
text-underline-offset: 2px;
|
text-underline-offset: 2px;
|
||||||
color: var(--accent-blue);
|
color: var(--accent-blue);
|
||||||
transition: text-decoration-color 0.25s ease-out;
|
-webkit-user-drag: none;
|
||||||
|
user-drag: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
& :global(a:hover) {
|
& :global(a:hover) {
|
||||||
|
|
@ -399,17 +450,5 @@ const { Content, headings } = await post.render();
|
||||||
& :global(blockquote p) {
|
& :global(blockquote p) {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > .copyright {
|
|
||||||
border-top: 1px solid rgba(194, 200, 204, 0.1);
|
|
||||||
color: rgba(194, 200, 204, 0.4);
|
|
||||||
padding-top: 8px;
|
|
||||||
font-size: 10px;
|
|
||||||
|
|
||||||
& > a {
|
|
||||||
color: var(--text-muted);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,25 @@
|
||||||
---
|
---
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
|
import CalendarIcon from '../../images/calendar.svg';
|
||||||
import Page from '../../layouts/Page.astro';
|
import Page from '../../layouts/Page.astro';
|
||||||
|
|
||||||
const posts = (await getCollection('posts'))
|
const posts = (await getCollection('posts'))
|
||||||
.filter(post => !post.data.draft)
|
.filter((post) => !post.data.draft)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const firstDate = new Date(a.data.date).valueOf();
|
const firstDate = new Date(a.data.date).valueOf();
|
||||||
const secondDate = new Date(b.data.date).valueOf();
|
const secondDate = new Date(b.data.date).valueOf();
|
||||||
return secondDate - firstDate;
|
return secondDate - firstDate;
|
||||||
});
|
});
|
||||||
|
|
||||||
const fmtDate = (date) => new Date(date).toLocaleString('en-US', {
|
const fmtDate = (date: Date) =>
|
||||||
month: '2-digit',
|
new Date(date).toLocaleString('en-US', {
|
||||||
day: '2-digit',
|
month: '2-digit',
|
||||||
year: 'numeric'
|
day: '2-digit',
|
||||||
});
|
year: 'numeric',
|
||||||
|
});
|
||||||
---
|
---
|
||||||
|
|
||||||
<Page title="Blog" desc="">
|
<Page title="Blog" desc="A list of all the blog posts I've written">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<section>
|
<section>
|
||||||
<h1>Here be dragons.</h1>
|
<h1>Here be dragons.</h1>
|
||||||
|
|
@ -31,11 +33,11 @@ const fmtDate = (date) => new Date(date).toLocaleString('en-US', {
|
||||||
<section>
|
<section>
|
||||||
<ul class="posts">
|
<ul class="posts">
|
||||||
{posts.map((post) => (
|
{posts.map((post) => (
|
||||||
<li><a href={`/blog/${post.slug}`}>
|
<li><a draggable="false" href={`/blog/${post.slug}`}>
|
||||||
<div class="metadata">
|
<div class="metadata">
|
||||||
<h1>{post.data.title}</h1>
|
<h1>{post.data.title}</h1>
|
||||||
<p>
|
<p>
|
||||||
<img src="/img/calendar.svg" alt="calendar icon">
|
<CalendarIcon class="icon" />
|
||||||
{fmtDate(post.data.date)}
|
{fmtDate(post.data.date)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -127,9 +129,10 @@ const fmtDate = (date) => new Date(date).toLocaleString('en-US', {
|
||||||
max-height: 23px;
|
max-height: 23px;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
|
|
||||||
& > img {
|
& > .icon {
|
||||||
margin-right: var(--space-xs);
|
margin-right: var(--space-xs);
|
||||||
height: 12px;
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,52 @@
|
||||||
---
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
import Page from '../layouts/Page.astro';
|
import Page from '../layouts/Page.astro';
|
||||||
|
|
||||||
|
import Avatar from '../images/avatar.png';
|
||||||
|
import EmojiIcon from '../images/emoji.svg';
|
||||||
|
import EnvelopeIcon from '../images/envelope.svg';
|
||||||
|
import FileUserIcon from '../images/file-user.svg';
|
||||||
|
import UserLockIcon from '../images/user-lock.svg';
|
||||||
|
import GitBranchIcon from '../images/git-branch.svg';
|
||||||
|
import GamesIcon from '../images/games.svg';
|
||||||
|
import HeartIcon from '../images/heart.svg';
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
{
|
{
|
||||||
name: 'GitLab',
|
name: 'GitDab',
|
||||||
icon: 'gitlab',
|
icon: GitBranchIcon,
|
||||||
url: 'https://gitlab.com/hqnna',
|
url: 'https://gitdab.com/hanna',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Emojis',
|
name: 'Emojis',
|
||||||
icon: 'emoji',
|
icon: EmojiIcon,
|
||||||
url: 'https://discord.gg/qZQmTM5Skk',
|
url: 'https://discord.gg/qZQmTM5Skk',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Steam',
|
name: 'Steam',
|
||||||
icon: 'games',
|
icon: GamesIcon,
|
||||||
url: 'https://steamcommunity.com/id/sapphicdoll',
|
url: 'https://steamcommunity.com/id/sapphicdoll',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'GPG Key',
|
name: 'GPG Key',
|
||||||
icon: 'user-lock',
|
icon: UserLockIcon,
|
||||||
url: '/files/key.txt',
|
url: '/files/key.txt',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Resume',
|
name: 'Resume',
|
||||||
icon: 'file-user',
|
icon: FileUserIcon,
|
||||||
url: '/files/resume.pdf',
|
url: '/files/resume.pdf',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Contact',
|
name: 'Contact',
|
||||||
icon: 'envelope',
|
icon: EnvelopeIcon,
|
||||||
url: 'mailto:me@hanna.lol',
|
url: 'mailto:me@hanna.lol',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Donate',
|
name: 'Donate',
|
||||||
icon: 'heart',
|
icon: HeartIcon,
|
||||||
url: 'https://liberapay.com/hqnna',
|
url: 'https://liberapay.com/hqnna',
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -46,15 +56,15 @@ const links = [
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<img src="/img/avatar.png" alt="avatar">
|
<Image src={Avatar} alt="avatar" loading="eager" />
|
||||||
<div class="about">
|
<div class="about">
|
||||||
<h1>Hanna Rose</h1>
|
<h1>Hanna Rose</h1>
|
||||||
<h2>Just your average software engineer</h2>
|
<h2>Just your average software engineer</h2>
|
||||||
<ul class="socials">
|
<ul class="socials">
|
||||||
{links.map(link => (
|
{links.map(link => (
|
||||||
<li>
|
<li>
|
||||||
<a draggable="false" href={link.url}>
|
<a draggable="false" href={link.url} aria-label={link.name}>
|
||||||
<img src={`/img/${link.icon}.svg`} alt={`${link.name} icon`}>
|
<link.icon class="icon" />
|
||||||
<span class="label">{link.name}</span>
|
<span class="label">{link.name}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -67,6 +77,10 @@ const links = [
|
||||||
</Page>
|
</Page>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
html > body {
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.background {
|
.background {
|
||||||
background-image: url("/img/background.jpg");
|
background-image: url("/img/background.jpg");
|
||||||
background-position: center;
|
background-position: center;
|
||||||
|
|
@ -87,7 +101,7 @@ const links = [
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
@media only screen and (max-width: 800px) {
|
||||||
padding-top: 24px;
|
padding-top: 20px;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +198,7 @@ const links = [
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|
||||||
& img {
|
& .icon {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,16 +207,8 @@ const links = [
|
||||||
border-color: var(--accent-blue);
|
border-color: var(--accent-blue);
|
||||||
color: var(--accent-blue);
|
color: var(--accent-blue);
|
||||||
|
|
||||||
& img {
|
& .icon {
|
||||||
filter:
|
stroke: var(--accent-blue);
|
||||||
brightness(0)
|
|
||||||
saturate(100%)
|
|
||||||
invert(70%)
|
|
||||||
sepia(37%)
|
|
||||||
saturate(4975%)
|
|
||||||
hue-rotate(200deg)
|
|
||||||
brightness(106%)
|
|
||||||
contrast(101%);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||