Compare commits

...

32 commits

Author SHA1 Message Date
Ayo
d8a38b60e3 1.3.88 2026-06-10 12:00:34 +02:00
Ayo
1ae9325ace feat: link to blog prod 2026-06-10 11:46:22 +02:00
Ayo
73ecdbe4d8 1.3.87 2026-06-08 11:15:40 +02:00
Ayo
bd65162c70 style: dotted bg for whole page 2026-06-08 11:15:21 +02:00
Ayo
fb93eb7574 1.3.86 2026-06-07 22:26:02 +02:00
Ayo
ed4b091cf1 refactor: remove unneeded style 2026-06-07 22:25:54 +02:00
Ayo
778328d984 1.3.85 2026-06-07 22:25:30 +02:00
Ayo
44e6fe6722 style: dotted bg everywhere 2026-06-07 22:25:03 +02:00
Ayo
271a92c7b3 1.3.84 2026-06-07 22:21:55 +02:00
Ayo
d79e51f1ce style: dotted background 2026-06-07 22:21:38 +02:00
Ayo
cdc9d091e3 1.3.83 2026-06-05 19:27:59 +02:00
Ayo
ef5c186345 feat: use elk.zone 2026-06-05 19:27:43 +02:00
Ayo
8c2e355bfb 1.3.82 2026-06-05 17:16:55 +02:00
Ayo
a9dc107176 feat: status-indicator on now-label 2026-06-05 17:16:29 +02:00
Ayo
ec7442da30 1.3.81 2026-06-05 12:24:39 +02:00
Ayo
7a674694a7 1.3.80 2026-06-05 12:16:50 +02:00
Ayo
d8768998e2 chore(deps): add sharp 2026-06-05 12:16:28 +02:00
Ayo
2f39f3d62d 1.3.79 2026-06-05 12:14:36 +02:00
Ayo
28a57aca9a chore: update packageManager 2026-06-05 12:14:22 +02:00
Ayo
e77351e5dd refactor: trying copilot edits 2026-06-05 12:13:13 +02:00
Ayo
fd1d015a18 chore(pgp): format 2026-06-05 12:13:13 +02:00
Ayo
f2bbfbf1b4 chore: add test config and instructions 2026-06-05 12:13:13 +02:00
Ayo
4860085aef chore: update lint and format scripts 2026-06-05 12:13:13 +02:00
Ayo
e3be0e92cb feat: update mastodon to webtoo.ls profile 2026-06-05 12:12:29 +02:00
Ayo
1dbd3d662c 1.3.78 2026-05-31 18:48:18 +02:00
Ayo
199f3d1429 fix: links to legacy blog 2026-05-31 18:47:57 +02:00
Ayo
74a3a71090 1.3.77 2026-05-31 18:41:01 +02:00
Ayo
7966746711 feat(pgp): copy & download buttons 2026-05-31 18:40:50 +02:00
Ayo
7e0380a324 1.3.76 2026-05-31 17:04:22 +02:00
Ayo
7921721425 feat(pgp): concise description 2026-05-31 17:04:11 +02:00
Ayo
5fa6e68b37 1.3.75 2026-05-31 17:00:38 +02:00
Ayo
a71eb0f975 feat: add 'encryption' purpose for pgp key 2026-05-31 16:28:29 +02:00
10 changed files with 127 additions and 51 deletions

View file

@ -22,13 +22,30 @@ $ pnpm i
## Commands ## Commands
| Command | Action | | Command | Action |
| ------------------- | ---------------------------------------------- | | ----------------------------- | ---------------------------------------------- |
| `pnpm run dev` | start dev server | | `pnpm run dev` | start dev server |
| `pnpm run build` | generate static files to `dist` directory | | `pnpm run build` | generate static files to `dist` directory |
| `pnpm run deploy` | upload to my server | | `pnpm run deploy` | upload to my server |
| `pnpm run prep:now` | back up and clear current `now page` constants | | `pnpm run prep:now` | back up and clear current `now page` constants |
| `pnpm run patch:build:deploy` | increment version, build, then upload | | `pnpm run patch:build:deploy` | increment version, build, then upload |
## Testing
This project uses Vitest for unit tests. The test script is defined in `package.json` as `vitest run .`.
Run tests locally with pnpm (recommended):
```bash
# install dependencies (if you haven't already)
pnpm i
# run tests once
pnpm test
# run Vitest in interactive/watch mode
pnpm exec vitest
```
## Deployment ## Deployment

View file

@ -1,7 +1,7 @@
{ {
"name": "@ayco/personal-website", "name": "@ayco/personal-website",
"type": "module", "type": "module",
"version": "1.3.74", "version": "1.3.88",
"private": true, "private": true,
"scripts": { "scripts": {
"astro": "astro", "astro": "astro",
@ -11,8 +11,9 @@
"preview": "astro preview", "preview": "astro preview",
"lint": "eslint . --config eslint.config.mjs --cache", "lint": "eslint . --config eslint.config.mjs --cache",
"lint:fix": "eslint . --config eslint.config.mjs --fix", "lint:fix": "eslint . --config eslint.config.mjs --fix",
"format": "prettier . --write", "fmt": "prettier . --config prettier.config.mjs --check",
"check": "npm run format && npm run lint", "fmt:fix": "prettier . --config prettier.config.mjs --write",
"check": "npm run fmt && npm run lint",
"deploy": "eval $(grep '^HOST' .env) && scp -r dist ayo@$HOST:~/ayco.io-flask", "deploy": "eval $(grep '^HOST' .env) && scp -r dist ayo@$HOST:~/ayco.io-flask",
"patch:build:deploy": "npm version patch && npm run build && npm run deploy", "patch:build:deploy": "npm version patch && npm run build && npm run deploy",
"pbd": "npm run patch:build:deploy", "pbd": "npm run patch:build:deploy",
@ -51,6 +52,7 @@
"rehype-stringify": "^10.0.1", "rehype-stringify": "^10.0.1",
"remark-parse": "^11.0.0", "remark-parse": "^11.0.0",
"remark-rehype": "^11.1.2", "remark-rehype": "^11.1.2",
"sharp": "^0.34.5",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.59.3", "typescript-eslint": "^8.59.3",
@ -61,14 +63,14 @@
}, },
"lint-staged": { "lint-staged": {
"*.{js,mjs,astro,ts}": [ "*.{js,mjs,astro,ts}": [
"prettier --write", "prettier . --config prettier.config.mjs --write",
"eslint --fix" "eslint . --config eslint.config.mjs --fix"
], ],
"*.json": [ "*.json": [
"prettier --write" "prettier . --config prettier.config.mjs --write"
] ]
}, },
"packageManager": "pnpm@11.2.2", "packageManager": "pnpm@11.5.2+sha512.71c631e382066efc25625d5cf029075de07b61b37f6e27350fbd84b1bda5864c8c1967adc280776b45c30a715c0359a3be08fef42d5bb09e2b99029979692916",
"dependencies": { "dependencies": {
"@ayo-run/status-indicator": "^2.1.2", "@ayo-run/status-indicator": "^2.1.2",
"web-component-base": "^4.1.2" "web-component-base": "^4.1.2"

View file

@ -96,6 +96,9 @@ importers:
remark-rehype: remark-rehype:
specifier: ^11.1.2 specifier: ^11.1.2
version: 11.1.2 version: 11.1.2
sharp:
specifier: ^0.34.5
version: 0.34.5
tslib: tslib:
specifier: ^2.8.1 specifier: ^2.8.1
version: 2.8.1 version: 2.8.1
@ -3255,8 +3258,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@img/colour@1.1.0': '@img/colour@1.1.0': {}
optional: true
'@img/sharp-darwin-arm64@0.34.5': '@img/sharp-darwin-arm64@0.34.5':
optionalDependencies: optionalDependencies:
@ -4122,8 +4124,7 @@ snapshots:
destr@2.0.5: {} destr@2.0.5: {}
detect-libc@2.1.2: detect-libc@2.1.2: {}
optional: true
devalue@5.8.1: {} devalue@5.8.1: {}
@ -5775,7 +5776,6 @@ snapshots:
'@img/sharp-win32-arm64': 0.34.5 '@img/sharp-win32-arm64': 0.34.5
'@img/sharp-win32-ia32': 0.34.5 '@img/sharp-win32-ia32': 0.34.5
'@img/sharp-win32-x64': 0.34.5 '@img/sharp-win32-x64': 0.34.5
optional: true
shebang-command@2.0.0: shebang-command@2.0.0:
dependencies: dependencies:

View file

@ -57,7 +57,7 @@ export const footerLinks: Link[] = [
}, },
{ {
text: 'Mastodon', text: 'Mastodon',
url: 'https://main.elk.zone/social.ayco.io/@ayo', url: 'https://elk.zone/m.webtoo.ls/@ayo',
icon: 'mastodon', icon: 'mastodon',
}, },
{ {

View file

@ -15,7 +15,7 @@ import { getImage } from 'astro:assets'
// fetch mastodon account // fetch mastodon account
const response = await fetch( const response = await fetch(
'https://social.ayco.io/api/v1/accounts/lookup?acct=ayo' 'https://m.webtoo.ls/api/v1/accounts/lookup?acct=ayo'
) )
const data = await response.json() const data = await response.json()
const { avatar } = data const { avatar } = data
@ -51,13 +51,28 @@ const ogFileType = 'image/png'
font-size: var(--font-size-base); font-size: var(--font-size-base);
color: var(--text-color-dark); color: var(--text-color-dark);
background-color: var(--text-color-light); background-color: var(--text-color-light);
background-image: radial-gradient(
circle,
hsl(var(--dot-grid-light)) 1px,
transparent 1px
);
background-size: 24px 24px;
background-position: -24px -24px;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
html, html,
body, body,
* { * {
background: var(--bg-darker); background-color: var(--bg-darker);
color: var(--text-color-light); color: var(--text-color-light);
background-image: radial-gradient(
circle,
hsl(var(--dot-grid-dark)) 1px,
transparent 1px
);
} }
} }

View file

@ -26,4 +26,7 @@
--bg-dark: #343a40; --bg-dark: #343a40;
--bg-darker: #212529; --bg-darker: #212529;
--bg-darkest: #000; --bg-darkest: #000;
--dot-grid-light: 214 32% 82%;
--dot-grid-dark: 215 25% 25%;
} }

View file

@ -8,7 +8,7 @@ import { Picture } from 'astro:assets'
// fetch mastodon account // fetch mastodon account
const response = await fetch( const response = await fetch(
'https://social.ayco.io/api/v1/accounts/lookup?acct=ayo' 'https://m.webtoo.ls/api/v1/accounts/lookup?acct=ayo'
) )
const data = await response.json() const data = await response.json()
const { avatar, note } = data const { avatar, note } = data
@ -38,13 +38,15 @@ const avatarSize = 150
</h1> </h1>
<a href="/now" class="now-wrapper action primary"> <a href="/now" class="now-wrapper action primary">
<span class="now-label">now</span> <span class="now-label">
<status-indicator status="active" pulse> now </status-indicator>
</span>
<span class="status">{now.title}</span> <span class="status">{now.title}</span>
</a> </a>
</div> </div>
</div> </div>
</section> </section>
<main> <main class=".dot-grid">
<section class="introduction-section"> <section class="introduction-section">
<p> <p>
I care about the <em>Web</em>, and I love to <em>create</em> stuff to <em I care about the <em>Web</em>, and I love to <em>create</em> stuff to <em
@ -93,6 +95,7 @@ const avatarSize = 150
&.primary { &.primary {
border: 1px solid rgba(255, 255, 255, 0.2); border: 1px solid rgba(255, 255, 255, 0.2);
border-style: dotted;
border-radius: 40px; border-radius: 40px;
} }
} }

View file

@ -4,7 +4,7 @@ import Footer from '../components/Footer.astro'
const title = 'PGP public key' const title = 'PGP public key'
const description = const description =
'Use to verify my digitally signed content like emails and files' 'Use to verify my digital signature or to encrypt messages intended only for me.'
--- ---
<Layout title={"Ayo's " + title} description={description}> <Layout title={"Ayo's " + title} description={description}>
@ -13,7 +13,12 @@ const description =
<p>{description}</p> <p>{description}</p>
<div class="key-block" role="region" aria-labelledby="public-key"> <div class="key-block" role="region" aria-labelledby="public-key">
<button class="copy-btn" aria-label="Copy key to clipboard">Copy</button> <div class="btn-wrapper">
<button class="copy-btn btn" aria-label="Copy key to clipboard"
>Copy</button
>
<a href="/publickey.asc" class="btn">Download</a>
</div>
<pre <pre
id="public-key"><code> id="public-key"><code>
-----BEGIN PGP PUBLIC KEY BLOCK----- -----BEGIN PGP PUBLIC KEY BLOCK-----
@ -31,32 +36,42 @@ AP0YLC768PFTBm9CM5T1BE0xjJ7s4dZSrVoI4n8RSe1nCA==
-----END PGP PUBLIC KEY BLOCK----- -----END PGP PUBLIC KEY BLOCK-----
</code></pre> </code></pre>
</div> </div>
<p>Expiry Date: 2027-05-30</p>
<p> <p>
<a href="/publickey.asc" class="download-link"> Download key (asc) </a> Fingerprint: <code>17F1 3D5E 8FF7 372B 1354 5C38 65E6 BF64 1529 3C65</code
>
</p> </p>
<p>This key will expire on: 2027-05-30</p>
<p></p>
</main> </main>
<Footer /> <Footer />
</Layout> </Layout>
<script> <script>
/* Clipboard copy logic */ /* Clipboard copy logic */
document.querySelector('.copy-btn').addEventListener('click', async () => { const copyBtn = document.querySelector('.copy-btn')
const keyText = document.querySelector('#public-key code').innerText.trim() if (copyBtn) {
try { copyBtn.addEventListener('click', async () => {
await navigator.clipboard.writeText(keyText) const keyText = (
const btn = document.querySelector('.copy-btn') document.querySelector('#public-key code') as HTMLElement
const original = btn.textContent )?.innerText.trim()
btn.textContent = 'Copied!' if (!keyText) return
setTimeout(() => { try {
btn.textContent = original await navigator.clipboard.writeText(keyText)
}, 2000) const btn = document.querySelector('.copy-btn')
} catch (err) { if (btn) {
console.error('Copy failed', err) const original = btn.textContent
alert('Unable to copy the key. Please copy it manually.') btn.textContent = 'Copied!'
} setTimeout(() => {
}) btn.textContent = original
}, 2000)
}
} catch (err) {
console.error('Copy failed', err)
alert('Unable to copy the key. Please copy it manually.')
}
})
}
</script> </script>
<style> <style>
@ -83,11 +98,16 @@ AP0YLC768PFTBm9CM5T1BE0xjJ7s4dZSrVoI4n8RSe1nCA==
display: block; display: block;
} }
/* Copy button */ /* buttons */
.copy-btn { .btn-wrapper {
position: absolute; position: absolute;
top: 0.5rem; top: 0.5rem;
right: 0.5rem; right: 0.5rem;
}
.btn {
display: inline-block;
position: relative;
background: var(--color-brand-blue-1); background: var(--color-brand-blue-1);
color: #fff; color: #fff;
border: none; border: none;
@ -97,14 +117,15 @@ AP0YLC768PFTBm9CM5T1BE0xjJ7s4dZSrVoI4n8RSe1nCA==
cursor: pointer; cursor: pointer;
opacity: 0.9; opacity: 0.9;
transition: opacity 0.2s; transition: opacity 0.2s;
text-decoration: none;
} }
.copy-btn:hover, .btn:hover,
.copy-btn:focus { .btn:focus {
opacity: 1; opacity: 1;
} }
.copy-btn:focus { .btn:focus {
outline: 2px solid #0056b3; outline: 2px solid #0056b3;
outline-offset: 2px; outline-offset: 2px;
} }

View file

@ -11,7 +11,8 @@ import Card from '../components/Card.astro'
<main> <main>
<h1><span class="text-gradient">Hobby Projects</span></h1> <h1><span class="text-gradient">Hobby Projects</span></h1>
<p> <p>
See more of my previous projects at <a href="https://ayos.blog">my blog</a See more of my previous projects at <a href="https://ayos.blog/projects"
>my blog</a
>. >.
</p> </p>
<ul> <ul>

14
vitest.config.ts Normal file
View file

@ -0,0 +1,14 @@
import { defineConfig } from 'vitest/config'
// Exclude generated files and heavy folders from the watcher to avoid
// continuous re-runs when build output or other tools touch files.
export default defineConfig({
test: {
globals: true,
environment: 'node',
exclude: ['dist/**', 'public/**', 'node_modules/**'],
},
watch: {
exclude: ['dist/**', 'public/**', 'node_modules/**', '.git/**'],
},
})