OwO
This commit is contained in:
parent
95869d08ae
commit
ab5fd681b6
|
|
@ -4,14 +4,14 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>88x31 Buttons | Clove Twilight</title>
|
<title>Clove Twilight</title>
|
||||||
<link rel="stylesheet" href="/css/main.css">
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
<!-- SEO Meta Tags -->
|
||||||
<meta name="description" content="The 88x31 buttons featured across c.stupid.cat">
|
<meta name="description" content="A collection of the 88x31 pixel buttons featured across Clove Twilight's site — grab one and link back.">
|
||||||
<meta name="keywords" content="Portfolio, Personal, Developer, 88x31, buttons">
|
<meta name="keywords" content="Clove Twilight, c.stupid.cat, 88x31, buttons, web buttons, personal">
|
||||||
<meta name="author" content="doughmination">
|
<meta name="author" content="doughmination">
|
||||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<link rel="canonical" href="https://c.stupid.cat/88x31">
|
<link rel="canonical" href="https://c.stupid.cat/88x31">
|
||||||
|
|
||||||
<!-- Alternate for mobile -->
|
<!-- Alternate for mobile -->
|
||||||
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat">
|
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat/88x31">
|
||||||
|
|
||||||
<!-- Theme Color -->
|
<!-- Theme Color -->
|
||||||
<meta name="theme-color" content="#f5c2e7">
|
<meta name="theme-color" content="#f5c2e7">
|
||||||
|
|
@ -27,8 +27,8 @@
|
||||||
<!-- Open Graph / Discord / Facebook -->
|
<!-- Open Graph / Discord / Facebook -->
|
||||||
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta property="og:site_name" content="c.stupid.cat">
|
<meta property="og:site_name" content="c.stupid.cat">
|
||||||
<meta property="og:title" content="88x31 Buttons | Clove Twilight">
|
<meta property="og:title" content="Clove Twilight">
|
||||||
<meta property="og:description" content="The 88x31 buttons featured across c.stupid.cat">
|
<meta property="og:description" content="A collection of the 88x31 pixel buttons featured across Clove Twilight's site — grab one and link back.">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://c.stupid.cat/88x31">
|
<meta property="og:url" content="https://c.stupid.cat/88x31">
|
||||||
<meta property="og:locale" content="en_GB">
|
<meta property="og:locale" content="en_GB">
|
||||||
|
|
@ -36,8 +36,8 @@
|
||||||
<!-- Twitter Card -->
|
<!-- Twitter Card -->
|
||||||
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta name="twitter:card" content="summary">
|
<meta name="twitter:card" content="summary">
|
||||||
<meta name="twitter:title" content="88x31 Buttons | Clove Twilight">
|
<meta name="twitter:title" content="Clove Twilight">
|
||||||
<meta name="twitter:description" content="The 88x31 buttons featured across c.stupid.cat">
|
<meta name="twitter:description" content="A collection of the 88x31 pixel buttons featured across Clove Twilight's site — grab one and link back.">
|
||||||
|
|
||||||
<!-- Prefetch other pages for faster navigation -->
|
<!-- Prefetch other pages for faster navigation -->
|
||||||
<link rel="prefetch" href="/">
|
<link rel="prefetch" href="/">
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 110 KiB |
|
|
@ -0,0 +1,49 @@
|
||||||
|
# /assets/selfies
|
||||||
|
|
||||||
|
Drop your selfie image files in this folder, then list them in `selfies.json`.
|
||||||
|
The gallery at `/selfies` is rendered from that manifest by `/js/selfies.js`.
|
||||||
|
|
||||||
|
## Adding a selfie
|
||||||
|
|
||||||
|
1. Put the image file in this folder, e.g. `assets/selfies/2026-06-clove.jpg`.
|
||||||
|
2. Add an entry to `selfies.json`. **The list is shown newest-first — put the
|
||||||
|
newest selfie at the top.**
|
||||||
|
|
||||||
|
`selfies.json` is a plain JSON array. Each entry can be either:
|
||||||
|
|
||||||
|
- **a filename string** (no caption, alt text auto-generated):
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"2026-06-clove.jpg",
|
||||||
|
"2026-05-night-out.png"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
- **or an object** with optional `caption` and `alt`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{ "src": "2026-06-clove.jpg", "caption": "golden hour ☀️", "alt": "Clove smiling in a sunlit park" },
|
||||||
|
{ "src": "2026-05-night-out.png", "caption": "night out 💃" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
You can mix both styles in the same list.
|
||||||
|
|
||||||
|
## Fields
|
||||||
|
|
||||||
|
- **`src`** (required) — the image. A bare filename resolves to
|
||||||
|
`/assets/selfies/<filename>`. You can also give a full path (`/assets/...`)
|
||||||
|
or an absolute URL (`https://...`).
|
||||||
|
- **`caption`** (optional) — short text shown **under the thumbnail and under
|
||||||
|
the enlarged photo in the lightbox**. Leave it out for no caption.
|
||||||
|
- **`alt`** (optional) — accessibility text for screen readers only (not shown
|
||||||
|
on screen). If omitted, it falls back to the caption, then to a generic
|
||||||
|
"Selfie N of Clove Twilight".
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Common web formats work: `.jpg`, `.jpeg`, `.png`, `.gif`, `.webp`, `.avif`.
|
||||||
|
- Until you add at least one entry, the page shows a friendly "no selfies yet"
|
||||||
|
message.
|
||||||
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
|
|
@ -0,0 +1,3 @@
|
||||||
|
[
|
||||||
|
{ "src": "image.png", "alt": "Selfie of Clove Twilight", "caption": "Selfie taken after I fully moved into uni ✨" }
|
||||||
|
]
|
||||||
|
|
@ -13,14 +13,14 @@
|
||||||
<link rel="preconnect" href="https://cdn.discordapp.com">
|
<link rel="preconnect" href="https://cdn.discordapp.com">
|
||||||
<link rel="dns-prefetch" href="https://cdn.discordapp.com">
|
<link rel="dns-prefetch" href="https://cdn.discordapp.com">
|
||||||
|
|
||||||
<title>Cool People</title>
|
<title>Clove Twilight</title>
|
||||||
<link rel="stylesheet" href="/css/main.css">
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
<!-- SEO Meta Tags -->
|
||||||
<meta name="description" content="Home for Clove Twilight">
|
<meta name="description" content="Cool people Clove Twilight knows — friends, mutuals, and creators worth checking out, with links to their sites.">
|
||||||
<meta name="keywords" content="Portfolio, Personal, Developer">
|
<meta name="keywords" content="Clove Twilight, c.stupid.cat, friends, cool people, mutuals, links">
|
||||||
<meta name="author" content="doughmination">
|
<meta name="author" content="doughmination">
|
||||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
<link rel="canonical" href="https://c.stupid.cat/cool-people">
|
<link rel="canonical" href="https://c.stupid.cat/cool-people">
|
||||||
|
|
||||||
<!-- Alternate for mobile -->
|
<!-- Alternate for mobile -->
|
||||||
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat">
|
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat/cool-people">
|
||||||
|
|
||||||
<!-- Theme Color -->
|
<!-- Theme Color -->
|
||||||
<meta name="theme-color" content="#f5c2e7">
|
<meta name="theme-color" content="#f5c2e7">
|
||||||
|
|
@ -36,8 +36,8 @@
|
||||||
<!-- Open Graph / Discord / Facebook -->
|
<!-- Open Graph / Discord / Facebook -->
|
||||||
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta property="og:site_name" content="c.stupid.cat">
|
<meta property="og:site_name" content="c.stupid.cat">
|
||||||
<meta property="og:title" content="Cool People | Clove Twilight">
|
<meta property="og:title" content="Clove Twilight">
|
||||||
<meta property="og:description" content="Cool people Clove knows!">
|
<meta property="og:description" content="Cool people Clove Twilight knows — friends, mutuals, and creators worth checking out, with links to their sites.">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://c.stupid.cat/cool-people">
|
<meta property="og:url" content="https://c.stupid.cat/cool-people">
|
||||||
<meta property="og:locale" content="en_GB">
|
<meta property="og:locale" content="en_GB">
|
||||||
|
|
@ -45,8 +45,9 @@
|
||||||
<!-- Twitter Card -->
|
<!-- Twitter Card -->
|
||||||
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta name="twitter:card" content="summary">
|
<meta name="twitter:card" content="summary">
|
||||||
<meta name="twitter:title" content="Cool People | Clove Twilight">
|
<meta name="twitter:title" content="Clove Twilight">
|
||||||
<meta name="twitter:description" content="Cool people Clove knows!">
|
<meta name="twitter:description" content="Cool people Clove Twilight knows — friends, mutuals, and creators worth checking out, with links to their sites.">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.friends-disclaimer {
|
.friends-disclaimer {
|
||||||
margin: 2.5rem auto 0;
|
margin: 2.5rem auto 0;
|
||||||
|
|
|
||||||
242
css/main.css
242
css/main.css
|
|
@ -3838,3 +3838,245 @@ body:has(.presence-stage) {
|
||||||
color: var(--subtext-0);
|
color: var(--subtext-0);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
14. Selfies page
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
/* Let the gallery scroll (the default layout locks the viewport). Keyed on
|
||||||
|
the wrapper class so it scrolls even before selfies.js injects the grid —
|
||||||
|
mirrors the .friends-wrap rule used by the cool-people page. */
|
||||||
|
html:has(.selfies-wrap),
|
||||||
|
body:has(.selfies-wrap) {
|
||||||
|
height: auto;
|
||||||
|
min-height: 100dvh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
body:has(.selfies-wrap) {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
body:has(.selfies-wrap) .hub {
|
||||||
|
max-width: 960px;
|
||||||
|
}
|
||||||
|
body:has(.selfies-wrap) .hub-header {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selfie-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||||
|
gap: 0.9rem;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
padding-bottom: 4.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selfie-thumb {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 1px solid var(--surface-1);
|
||||||
|
border-radius: 14px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: var(--surface-0);
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
display: block;
|
||||||
|
transition: transform 0.15s ease, border-color 0.15s ease,
|
||||||
|
box-shadow 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selfie-thumb img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selfie-thumb:hover,
|
||||||
|
.selfie-thumb:focus-visible {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
border-color: rgb(var(--accent-rgb));
|
||||||
|
box-shadow: 0 6px 20px rgba(var(--accent-rgb), 0.22);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selfie-empty {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--subtext-0);
|
||||||
|
font-style: italic;
|
||||||
|
padding: 3rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Lightbox ---- */
|
||||||
|
.lightbox {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 1.5rem;
|
||||||
|
background: color-mix(in srgb, var(--crust) 86%, transparent);
|
||||||
|
-webkit-backdrop-filter: blur(6px);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox.is-open {
|
||||||
|
animation: lightbox-fade 0.18s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes lightbox-fade {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-img {
|
||||||
|
max-width: min(92vw, 1100px);
|
||||||
|
max-height: 86vh;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 2px solid rgba(var(--accent-rgb), 0.55);
|
||||||
|
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-close,
|
||||||
|
.lightbox-nav {
|
||||||
|
position: fixed;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 1px solid var(--surface-1);
|
||||||
|
background: color-mix(in srgb, var(--surface-0) 85%, transparent);
|
||||||
|
color: var(--text);
|
||||||
|
border-radius: 999px;
|
||||||
|
line-height: 1;
|
||||||
|
transition: background 0.15s ease, border-color 0.15s ease,
|
||||||
|
transform 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-close:hover,
|
||||||
|
.lightbox-nav:hover,
|
||||||
|
.lightbox-close:focus-visible,
|
||||||
|
.lightbox-nav:focus-visible {
|
||||||
|
background: var(--surface-1);
|
||||||
|
border-color: rgb(var(--accent-rgb));
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-close {
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
width: 2.6rem;
|
||||||
|
height: 2.6rem;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-nav {
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-nav:hover {
|
||||||
|
transform: translateY(-50%) scale(1.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-prev {
|
||||||
|
left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-next {
|
||||||
|
right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-nav[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Freeze the page behind the lightbox while it's open */
|
||||||
|
body.lightbox-open {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.selfie-thumb,
|
||||||
|
.lightbox-close,
|
||||||
|
.lightbox-nav {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
.lightbox.is-open {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
.lightbox-nav:hover {
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.selfie-grid {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
|
||||||
|
gap: 0.6rem;
|
||||||
|
}
|
||||||
|
.lightbox-nav {
|
||||||
|
width: 2.6rem;
|
||||||
|
height: 2.6rem;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Captions (thumbnails + lightbox) ---- */
|
||||||
|
.selfie-item {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selfie-caption {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.35;
|
||||||
|
color: var(--subtext-0);
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-figure {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.8rem;
|
||||||
|
max-width: min(92vw, 1100px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* leave room beneath the image for the caption line */
|
||||||
|
.lightbox-img {
|
||||||
|
max-height: 80vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-caption {
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
max-width: min(92vw, 1100px);
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-caption[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,14 @@
|
||||||
<link rel="preconnect" href="https://wakatime.com">
|
<link rel="preconnect" href="https://wakatime.com">
|
||||||
<link rel="dns-prefetch" href="https://wakatime.com">
|
<link rel="dns-prefetch" href="https://wakatime.com">
|
||||||
|
|
||||||
<title>Clove Twilight - Dev Info</title>
|
<title>Clove Twilight</title>
|
||||||
<link rel="stylesheet" href="/css/main.css">
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
<!-- SEO Meta Tags -->
|
||||||
<meta name="description" content="What Clove has been coding lately, tracked by dev-info">
|
<meta name="description" content="What Clove Twilight has been coding lately — a live contribution heatmap and WakaTime coding stats.">
|
||||||
<meta name="keywords" content="Portfolio, Personal, Developer, dev-info, Dev Info">
|
<meta name="keywords" content="Clove Twilight, c.stupid.cat, dev info, coding stats, WakaTime, contributions, developer">
|
||||||
<meta name="author" content="doughmination">
|
<meta name="author" content="doughmination">
|
||||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
|
|
@ -34,8 +34,8 @@
|
||||||
<!-- Open Graph / Discord / Facebook -->
|
<!-- Open Graph / Discord / Facebook -->
|
||||||
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta property="og:site_name" content="c.stupid.cat">
|
<meta property="og:site_name" content="c.stupid.cat">
|
||||||
<meta property="og:title" content="Clove Twilight | Dev Info">
|
<meta property="og:title" content="Clove Twilight">
|
||||||
<meta property="og:description" content="What Clove has been coding lately, tracked by dev-info">
|
<meta property="og:description" content="What Clove Twilight has been coding lately — a live contribution heatmap and WakaTime coding stats.">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://c.stupid.cat/dev-info">
|
<meta property="og:url" content="https://c.stupid.cat/dev-info">
|
||||||
<meta property="og:locale" content="en_GB">
|
<meta property="og:locale" content="en_GB">
|
||||||
|
|
@ -43,8 +43,8 @@
|
||||||
<!-- Twitter Card -->
|
<!-- Twitter Card -->
|
||||||
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta name="twitter:card" content="summary">
|
<meta name="twitter:card" content="summary">
|
||||||
<meta name="twitter:title" content="Clove Twilight | Dev Info">
|
<meta name="twitter:title" content="Clove Twilight">
|
||||||
<meta name="twitter:description" content="What Clove has been coding lately, tracked by dev-info">
|
<meta name="twitter:description" content="What Clove Twilight has been coding lately — a live contribution heatmap and WakaTime coding stats.">
|
||||||
|
|
||||||
<!-- Prefetch other pages for faster navigation -->
|
<!-- Prefetch other pages for faster navigation -->
|
||||||
<link rel="prefetch" href="/">
|
<link rel="prefetch" href="/">
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@
|
||||||
<link rel="preconnect" href="https://cdn.discordapp.com">
|
<link rel="preconnect" href="https://cdn.discordapp.com">
|
||||||
<link rel="dns-prefetch" href="https://cdn.discordapp.com">
|
<link rel="dns-prefetch" href="https://cdn.discordapp.com">
|
||||||
|
|
||||||
<title>Clove Twilight - Discord</title>
|
<title>Clove Twilight</title>
|
||||||
<link rel="stylesheet" href="/css/main.css">
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
<!-- SEO Meta Tags -->
|
||||||
<meta name="description" content="Clove Twilight's live Discord presence — status, activity, and what fae is up to right now.">
|
<meta name="description" content="Clove Twilight's live Discord presence — current status, activity, and what fae is up to right now.">
|
||||||
<meta name="keywords" content="Portfolio, Personal, Developer, Discord, presence, Lanyard">
|
<meta name="keywords" content="Clove Twilight, c.stupid.cat, Discord, presence, status, Lanyard">
|
||||||
<meta name="author" content="doughmination">
|
<meta name="author" content="doughmination">
|
||||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
|
|
@ -36,8 +36,8 @@
|
||||||
<!-- Open Graph / Discord / Facebook -->
|
<!-- Open Graph / Discord / Facebook -->
|
||||||
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta property="og:site_name" content="c.stupid.cat">
|
<meta property="og:site_name" content="c.stupid.cat">
|
||||||
<meta property="og:title" content="Clove Twilight | Discord">
|
<meta property="og:title" content="Clove Twilight">
|
||||||
<meta property="og:description" content="Clove Twilight's live Discord presence — status, activity, and what fae is up to right now.">
|
<meta property="og:description" content="Clove Twilight's live Discord presence — current status, activity, and what fae is up to right now.">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://c.stupid.cat/discord">
|
<meta property="og:url" content="https://c.stupid.cat/discord">
|
||||||
<meta property="og:locale" content="en_GB">
|
<meta property="og:locale" content="en_GB">
|
||||||
|
|
@ -45,8 +45,8 @@
|
||||||
<!-- Twitter Card -->
|
<!-- Twitter Card -->
|
||||||
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta name="twitter:card" content="summary">
|
<meta name="twitter:card" content="summary">
|
||||||
<meta name="twitter:title" content="Clove Twilight | Discord">
|
<meta name="twitter:title" content="Clove Twilight">
|
||||||
<meta name="twitter:description" content="Clove Twilight's live Discord presence — status, activity, and what fae is up to right now.">
|
<meta name="twitter:description" content="Clove Twilight's live Discord presence — current status, activity, and what fae is up to right now.">
|
||||||
|
|
||||||
<!-- Prefetch other pages for faster navigation -->
|
<!-- Prefetch other pages for faster navigation -->
|
||||||
<link rel="prefetch" href="/">
|
<link rel="prefetch" href="/">
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,14 @@
|
||||||
<link rel="preconnect" href="https://challenges.cloudflare.com">
|
<link rel="preconnect" href="https://challenges.cloudflare.com">
|
||||||
<link rel="dns-prefetch" href="https://challenges.cloudflare.com">
|
<link rel="dns-prefetch" href="https://challenges.cloudflare.com">
|
||||||
|
|
||||||
<title>Guestbook</title>
|
<title>Clove Twilight</title>
|
||||||
<link rel="stylesheet" href="/css/main.css">
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
<!-- SEO Meta Tags -->
|
||||||
<meta name="description" content="Sign Clove's guestbook">
|
<meta name="description" content="Sign Clove Twilight's guestbook — leave a message and say hello.">
|
||||||
<meta name="keywords" content="Guestbook, Personal, Developer">
|
<meta name="keywords" content="Clove Twilight, c.stupid.cat, guestbook, messages, sign">
|
||||||
<meta name="author" content="doughmination">
|
<meta name="author" content="doughmination">
|
||||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
<link rel="canonical" href="https://c.stupid.cat/guestbook">
|
<link rel="canonical" href="https://c.stupid.cat/guestbook">
|
||||||
|
|
||||||
<!-- Alternate for mobile -->
|
<!-- Alternate for mobile -->
|
||||||
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat">
|
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat/guestbook">
|
||||||
|
|
||||||
<!-- Theme Color -->
|
<!-- Theme Color -->
|
||||||
<meta name="theme-color" content="#f5c2e7">
|
<meta name="theme-color" content="#f5c2e7">
|
||||||
|
|
@ -34,8 +34,8 @@
|
||||||
<!-- Open Graph / Discord / Facebook -->
|
<!-- Open Graph / Discord / Facebook -->
|
||||||
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta property="og:site_name" content="c.stupid.cat">
|
<meta property="og:site_name" content="c.stupid.cat">
|
||||||
<meta property="og:title" content="Guestbook | Clove Twilight">
|
<meta property="og:title" content="Clove Twilight">
|
||||||
<meta property="og:description" content="Leave a message in Clove's guestbook!">
|
<meta property="og:description" content="Sign Clove Twilight's guestbook — leave a message and say hello.">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://c.stupid.cat/guestbook">
|
<meta property="og:url" content="https://c.stupid.cat/guestbook">
|
||||||
<meta property="og:locale" content="en_GB">
|
<meta property="og:locale" content="en_GB">
|
||||||
|
|
@ -43,8 +43,8 @@
|
||||||
<!-- Twitter Card -->
|
<!-- Twitter Card -->
|
||||||
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta name="twitter:card" content="summary">
|
<meta name="twitter:card" content="summary">
|
||||||
<meta name="twitter:title" content="Guestbook | Clove Twilight">
|
<meta name="twitter:title" content="Clove Twilight">
|
||||||
<meta name="twitter:description" content="Leave a message in Clove's guestbook!">
|
<meta name="twitter:description" content="Sign Clove Twilight's guestbook — leave a message and say hello.">
|
||||||
|
|
||||||
<!-- Prefetch other pages for faster navigation -->
|
<!-- Prefetch other pages for faster navigation -->
|
||||||
<link rel="prefetch" href="/">
|
<link rel="prefetch" href="/">
|
||||||
|
|
|
||||||
14
index.html
14
index.html
|
|
@ -11,14 +11,14 @@
|
||||||
<link rel="preconnect" href="https://abacus.jasoncameron.dev" crossorigin>
|
<link rel="preconnect" href="https://abacus.jasoncameron.dev" crossorigin>
|
||||||
<link rel="dns-prefetch" href="https://abacus.jasoncameron.dev">
|
<link rel="dns-prefetch" href="https://abacus.jasoncameron.dev">
|
||||||
|
|
||||||
<title>Clove Twilight - Home</title>
|
<title>Clove Twilight</title>
|
||||||
<link rel="stylesheet" href="/css/main.css">
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
<!-- SEO Meta Tags -->
|
||||||
<meta name="description" content="Home for Clove Twilight">
|
<meta name="description" content="The homepage and hub for everything Clove Twilight — projects, music, Discord presence, dev stats, and more.">
|
||||||
<meta name="keywords" content="Portfolio, Personal, Developer">
|
<meta name="keywords" content="Clove Twilight, c.stupid.cat, portfolio, personal, developer, homepage">
|
||||||
<meta name="author" content="doughmination">
|
<meta name="author" content="doughmination">
|
||||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
|
|
@ -34,8 +34,8 @@
|
||||||
<!-- Open Graph / Discord / Facebook -->
|
<!-- Open Graph / Discord / Facebook -->
|
||||||
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta property="og:site_name" content="c.stupid.cat">
|
<meta property="og:site_name" content="c.stupid.cat">
|
||||||
<meta property="og:title" content="Clove Twilight | Home">
|
<meta property="og:title" content="Clove Twilight">
|
||||||
<meta property="og:description" content="Home for Clove Twilight">
|
<meta property="og:description" content="The homepage and hub for everything Clove Twilight — projects, music, Discord presence, dev stats, and more.">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://c.stupid.cat">
|
<meta property="og:url" content="https://c.stupid.cat">
|
||||||
<meta property="og:locale" content="en_GB">
|
<meta property="og:locale" content="en_GB">
|
||||||
|
|
@ -43,8 +43,8 @@
|
||||||
<!-- Twitter Card -->
|
<!-- Twitter Card -->
|
||||||
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta name="twitter:card" content="summary">
|
<meta name="twitter:card" content="summary">
|
||||||
<meta name="twitter:title" content="Clove Twilight | Home">
|
<meta name="twitter:title" content="Clove Twilight">
|
||||||
<meta name="twitter:description" content="Home for Clove Twilight">
|
<meta name="twitter:description" content="The homepage and hub for everything Clove Twilight — projects, music, Discord presence, dev stats, and more.">
|
||||||
|
|
||||||
<!-- Prefetch other pages for faster navigation -->
|
<!-- Prefetch other pages for faster navigation -->
|
||||||
<link rel="prefetch" href="/cool-people">
|
<link rel="prefetch" href="/cool-people">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,203 @@
|
||||||
|
/* ============================================================
|
||||||
|
selfies.js — renders the /selfies gallery from a manifest
|
||||||
|
Manifest: /assets/selfies/selfies.json
|
||||||
|
- array of filename strings, or { "src", "alt", "caption" } objects
|
||||||
|
- shown in list order (newest first = top of the list)
|
||||||
|
"alt" is for screen readers; "caption" (optional) is shown on the page.
|
||||||
|
Click any thumbnail to open it full-size in a lightbox.
|
||||||
|
============================================================ */
|
||||||
|
(function selfies() {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const MANIFEST = "/assets/selfies/selfies.json";
|
||||||
|
const FOLDER = "/assets/selfies/";
|
||||||
|
const root = document.getElementById("selfies-root");
|
||||||
|
if (!root) return;
|
||||||
|
|
||||||
|
const reduceMotion = window.matchMedia(
|
||||||
|
"(prefers-reduced-motion: reduce)"
|
||||||
|
).matches;
|
||||||
|
|
||||||
|
/* ---------- helpers ---------- */
|
||||||
|
// Resolve a manifest src to a usable URL.
|
||||||
|
function resolveSrc(s) {
|
||||||
|
if (typeof s !== "string") return "";
|
||||||
|
s = s.trim();
|
||||||
|
if (/^https?:\/\//i.test(s) || s.startsWith("/")) return s;
|
||||||
|
return FOLDER + s.replace(/^\.?\//, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalise a manifest entry into { src, alt, caption } or null if unusable.
|
||||||
|
function normalize(entry, i) {
|
||||||
|
let raw = "";
|
||||||
|
let alt = "";
|
||||||
|
let caption = "";
|
||||||
|
if (typeof entry === "string") {
|
||||||
|
raw = entry;
|
||||||
|
} else if (entry && typeof entry === "object" && entry.src) {
|
||||||
|
raw = entry.src;
|
||||||
|
alt = typeof entry.alt === "string" ? entry.alt : "";
|
||||||
|
caption = typeof entry.caption === "string" ? entry.caption.trim() : "";
|
||||||
|
}
|
||||||
|
if (typeof raw !== "string" || !raw.trim()) return null;
|
||||||
|
const src = resolveSrc(raw);
|
||||||
|
if (!src) return null;
|
||||||
|
if (!alt) alt = caption || "Selfie " + (i + 1) + " of Clove Twilight";
|
||||||
|
return { src, alt, caption };
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMessage(text) {
|
||||||
|
root.innerHTML = "";
|
||||||
|
const p = document.createElement("p");
|
||||||
|
p.className = "selfie-empty";
|
||||||
|
p.textContent = text;
|
||||||
|
root.appendChild(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- lightbox ---------- */
|
||||||
|
let items = [];
|
||||||
|
let current = 0;
|
||||||
|
let lastFocus = null;
|
||||||
|
|
||||||
|
const lb = document.createElement("div");
|
||||||
|
lb.className = "lightbox";
|
||||||
|
lb.hidden = true;
|
||||||
|
lb.setAttribute("role", "dialog");
|
||||||
|
lb.setAttribute("aria-modal", "true");
|
||||||
|
lb.setAttribute("aria-label", "Selfie viewer");
|
||||||
|
lb.innerHTML =
|
||||||
|
'<button class="lightbox-close" type="button" aria-label="Close (Esc)">×</button>' +
|
||||||
|
'<button class="lightbox-nav lightbox-prev" type="button" aria-label="Previous selfie">‹</button>' +
|
||||||
|
'<figure class="lightbox-figure">' +
|
||||||
|
'<img class="lightbox-img" alt="">' +
|
||||||
|
'<figcaption class="lightbox-caption" hidden></figcaption>' +
|
||||||
|
"</figure>" +
|
||||||
|
'<button class="lightbox-nav lightbox-next" type="button" aria-label="Next selfie">›</button>';
|
||||||
|
document.body.appendChild(lb);
|
||||||
|
|
||||||
|
const lbImg = lb.querySelector(".lightbox-img");
|
||||||
|
const lbCap = lb.querySelector(".lightbox-caption");
|
||||||
|
const btnClose = lb.querySelector(".lightbox-close");
|
||||||
|
const btnPrev = lb.querySelector(".lightbox-prev");
|
||||||
|
const btnNext = lb.querySelector(".lightbox-next");
|
||||||
|
|
||||||
|
function preload(i) {
|
||||||
|
if (i < 0 || i >= items.length) return;
|
||||||
|
const img = new Image();
|
||||||
|
img.src = items[i].src;
|
||||||
|
}
|
||||||
|
|
||||||
|
function render(i) {
|
||||||
|
current = (i + items.length) % items.length; // wrap around
|
||||||
|
const it = items[current];
|
||||||
|
lbImg.src = it.src;
|
||||||
|
lbImg.alt = it.alt;
|
||||||
|
if (it.caption) {
|
||||||
|
lbCap.textContent = it.caption;
|
||||||
|
lbCap.hidden = false;
|
||||||
|
} else {
|
||||||
|
lbCap.textContent = "";
|
||||||
|
lbCap.hidden = true;
|
||||||
|
}
|
||||||
|
const multiple = items.length > 1;
|
||||||
|
btnPrev.hidden = !multiple;
|
||||||
|
btnNext.hidden = !multiple;
|
||||||
|
if (multiple) {
|
||||||
|
preload(current + 1);
|
||||||
|
preload(current - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function open(i) {
|
||||||
|
lastFocus = document.activeElement;
|
||||||
|
render(i);
|
||||||
|
lb.hidden = false;
|
||||||
|
if (!reduceMotion) lb.classList.add("is-open");
|
||||||
|
document.body.classList.add("lightbox-open");
|
||||||
|
btnClose.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
lb.hidden = true;
|
||||||
|
lb.classList.remove("is-open");
|
||||||
|
document.body.classList.remove("lightbox-open");
|
||||||
|
lbImg.removeAttribute("src");
|
||||||
|
if (lastFocus && typeof lastFocus.focus === "function") lastFocus.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
const next = () => render(current + 1);
|
||||||
|
const prev = () => render(current - 1);
|
||||||
|
|
||||||
|
btnClose.addEventListener("click", close);
|
||||||
|
btnNext.addEventListener("click", next);
|
||||||
|
btnPrev.addEventListener("click", prev);
|
||||||
|
// Click on the dim backdrop (but not the image/caption or buttons) closes.
|
||||||
|
lb.addEventListener("click", (e) => {
|
||||||
|
if (e.target === lb) close();
|
||||||
|
});
|
||||||
|
document.addEventListener("keydown", (e) => {
|
||||||
|
if (lb.hidden) return;
|
||||||
|
if (e.key === "Escape") close();
|
||||||
|
else if (e.key === "ArrowRight") next();
|
||||||
|
else if (e.key === "ArrowLeft") prev();
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ---------- grid ---------- */
|
||||||
|
function buildGrid(list) {
|
||||||
|
root.innerHTML = "";
|
||||||
|
const frag = document.createDocumentFragment();
|
||||||
|
list.forEach((it, i) => {
|
||||||
|
const fig = document.createElement("figure");
|
||||||
|
fig.className = "selfie-item";
|
||||||
|
|
||||||
|
const btn = document.createElement("button");
|
||||||
|
btn.type = "button";
|
||||||
|
btn.className = "selfie-thumb";
|
||||||
|
btn.setAttribute("aria-label", "Open " + (it.caption || it.alt));
|
||||||
|
|
||||||
|
const img = document.createElement("img");
|
||||||
|
img.src = it.src;
|
||||||
|
img.alt = it.alt;
|
||||||
|
img.loading = i < 4 ? "eager" : "lazy";
|
||||||
|
img.decoding = "async";
|
||||||
|
// If an image fails to load, drop its tile so the grid stays clean.
|
||||||
|
img.addEventListener("error", () => fig.remove());
|
||||||
|
|
||||||
|
btn.appendChild(img);
|
||||||
|
btn.addEventListener("click", () => open(i));
|
||||||
|
fig.appendChild(btn);
|
||||||
|
|
||||||
|
if (it.caption) {
|
||||||
|
const cap = document.createElement("figcaption");
|
||||||
|
cap.className = "selfie-caption";
|
||||||
|
cap.textContent = it.caption;
|
||||||
|
fig.appendChild(cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
frag.appendChild(fig);
|
||||||
|
});
|
||||||
|
root.appendChild(frag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- load ---------- */
|
||||||
|
root.setAttribute("aria-busy", "true");
|
||||||
|
fetch(MANIFEST, { cache: "no-cache" })
|
||||||
|
.then((r) => {
|
||||||
|
if (!r.ok) throw new Error("manifest " + r.status);
|
||||||
|
return r.json();
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
if (!Array.isArray(data)) throw new Error("manifest is not an array");
|
||||||
|
items = data.map(normalize).filter(Boolean);
|
||||||
|
if (!items.length) {
|
||||||
|
showMessage("No selfies yet — check back soon! 📸");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buildGrid(items);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Could not load selfies:", err);
|
||||||
|
showMessage("Couldn't load the selfies right now.");
|
||||||
|
})
|
||||||
|
.finally(() => root.removeAttribute("aria-busy"));
|
||||||
|
})();
|
||||||
|
|
@ -11,27 +11,41 @@
|
||||||
<link rel="preconnect" href="https://lyrics.lanyard.cafe" crossorigin>
|
<link rel="preconnect" href="https://lyrics.lanyard.cafe" crossorigin>
|
||||||
<link rel="dns-prefetch" href="https://lyrics.lanyard.cafe">
|
<link rel="dns-prefetch" href="https://lyrics.lanyard.cafe">
|
||||||
|
|
||||||
<title>Music · Clove Twilight</title>
|
<title>Clove Twilight</title>
|
||||||
<link rel="stylesheet" href="/css/main.css">
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
<!-- SEO Meta Tags -->
|
||||||
<meta name="description" content="What Clove Twilight is listening to — live now-playing, synced lyrics, and recent plays.">
|
<meta name="description" content="What Clove Twilight is listening to — live now-playing track, synced lyrics, and recent plays from Last.fm.">
|
||||||
|
<meta name="keywords" content="Clove Twilight, c.stupid.cat, music, now playing, Last.fm, lyrics, scrobbles">
|
||||||
<meta name="author" content="doughmination">
|
<meta name="author" content="doughmination">
|
||||||
<meta name="robots" content="index, follow">
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
|
<!-- Canonical URL -->
|
||||||
<link rel="canonical" href="https://c.stupid.cat/music">
|
<link rel="canonical" href="https://c.stupid.cat/music">
|
||||||
|
|
||||||
|
<!-- Alternate for mobile -->
|
||||||
|
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat/music">
|
||||||
|
|
||||||
|
<!-- Theme Color -->
|
||||||
<meta name="theme-color" content="#f5c2e7">
|
<meta name="theme-color" content="#f5c2e7">
|
||||||
|
|
||||||
<!-- Open Graph -->
|
<!-- Open Graph / Discord / Facebook -->
|
||||||
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta property="og:site_name" content="c.stupid.cat">
|
<meta property="og:site_name" content="c.stupid.cat">
|
||||||
<meta property="og:title" content="Music · Clove Twilight">
|
<meta property="og:title" content="Clove Twilight">
|
||||||
<meta property="og:description" content="Live now-playing, synced lyrics, and recent plays.">
|
<meta property="og:description" content="What Clove Twilight is listening to — live now-playing track, synced lyrics, and recent plays from Last.fm.">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://c.stupid.cat/music">
|
<meta property="og:url" content="https://c.stupid.cat/music">
|
||||||
<meta property="og:locale" content="en_GB">
|
<meta property="og:locale" content="en_GB">
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta name="twitter:title" content="Clove Twilight">
|
||||||
|
<meta name="twitter:description" content="What Clove Twilight is listening to — live now-playing track, synced lyrics, and recent plays from Last.fm.">
|
||||||
|
|
||||||
<!-- Prefetch other pages for faster navigation -->
|
<!-- Prefetch other pages for faster navigation -->
|
||||||
<link rel="prefetch" href="/">
|
<link rel="prefetch" href="/">
|
||||||
<link rel="prefetch" href="/cool-people">
|
<link rel="prefetch" href="/cool-people">
|
||||||
|
|
|
||||||
|
|
@ -4,22 +4,22 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Clove Twilight - Projects</title>
|
<title>Clove Twilight</title>
|
||||||
<link rel="stylesheet" href="/css/main.css">
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
<!-- SEO Meta Tags -->
|
||||||
<meta name="description" content="Find all the Projects Clove contributes on actively">
|
<meta name="description" content="Explore the projects Clove Twilight actively builds and contributes to, from web apps to Discord bots.">
|
||||||
<meta name="keywords" content="Portfolio, Personal, Developer">
|
<meta name="keywords" content="Clove Twilight, c.stupid.cat, projects, portfolio, developer, open source">
|
||||||
<meta name="author" content="doughmination">
|
<meta name="author" content="doughmination">
|
||||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
<!-- Canonical URL -->
|
<!-- Canonical URL -->
|
||||||
<link rel="canonical" href="https://c.stupid.cat">
|
<link rel="canonical" href="https://c.stupid.cat/projects">
|
||||||
|
|
||||||
<!-- Alternate for mobile -->
|
<!-- Alternate for mobile -->
|
||||||
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat">
|
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat/projects">
|
||||||
|
|
||||||
<!-- Theme Color -->
|
<!-- Theme Color -->
|
||||||
<meta name="theme-color" content="#f5c2e7">
|
<meta name="theme-color" content="#f5c2e7">
|
||||||
|
|
@ -27,17 +27,17 @@
|
||||||
<!-- Open Graph / Discord / Facebook -->
|
<!-- Open Graph / Discord / Facebook -->
|
||||||
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta property="og:site_name" content="c.stupid.cat">
|
<meta property="og:site_name" content="c.stupid.cat">
|
||||||
<meta property="og:title" content="Clove Twilight | Projects">
|
<meta property="og:title" content="Clove Twilight">
|
||||||
<meta property="og:description" content="Find all the Projects Clove contributes on actively">
|
<meta property="og:description" content="Explore the projects Clove Twilight actively builds and contributes to, from web apps to Discord bots.">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://c.stupid.cat">
|
<meta property="og:url" content="https://c.stupid.cat/projects">
|
||||||
<meta property="og:locale" content="en_GB">
|
<meta property="og:locale" content="en_GB">
|
||||||
|
|
||||||
<!-- Twitter Card -->
|
<!-- Twitter Card -->
|
||||||
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
<meta name="twitter:card" content="summary">
|
<meta name="twitter:card" content="summary">
|
||||||
<meta name="twitter:title" content="Clove Twilight | Discord Bot">
|
<meta name="twitter:title" content="Clove Twilight">
|
||||||
<meta name="twitter:description" content="Find all the Projects Clove contributes on actively">
|
<meta name="twitter:description" content="Explore the projects Clove Twilight actively builds and contributes to, from web apps to Discord bots.">
|
||||||
|
|
||||||
<!-- Prefetch other pages for faster navigation -->
|
<!-- Prefetch other pages for faster navigation -->
|
||||||
<link rel="prefetch" href="/">
|
<link rel="prefetch" href="/">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<title>Clove Twilight</title>
|
||||||
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
|
<script>try { var f = localStorage.getItem('ctpFlavor'); document.documentElement.setAttribute('data-flavor', ['mocha', 'macchiato', 'frappe', 'latte'].indexOf(f) >= 0 ? f : 'mocha'); } catch (e) { document.documentElement.setAttribute('data-flavor', 'mocha'); }</script>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg">
|
||||||
|
|
||||||
|
<!-- SEO Meta Tags -->
|
||||||
|
<meta name="description" content="Browse a gallery of selfies from Clove Twilight.">
|
||||||
|
<meta name="keywords" content="Clove Twilight, c.stupid.cat, selfies, photos, gallery, personal">
|
||||||
|
<meta name="author" content="doughmination">
|
||||||
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
|
<!-- Canonical URL -->
|
||||||
|
<link rel="canonical" href="https://c.stupid.cat/selfies">
|
||||||
|
|
||||||
|
<!-- Alternate for mobile -->
|
||||||
|
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://c.stupid.cat/selfies">
|
||||||
|
|
||||||
|
<!-- Theme Color -->
|
||||||
|
<meta name="theme-color" content="#f5c2e7">
|
||||||
|
|
||||||
|
<!-- Open Graph / Discord / Facebook -->
|
||||||
|
<meta property="og:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
|
<meta property="og:site_name" content="c.stupid.cat">
|
||||||
|
<meta property="og:title" content="Clove Twilight">
|
||||||
|
<meta property="og:description" content="Browse a gallery of selfies from Clove Twilight.">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:url" content="https://c.stupid.cat/selfies">
|
||||||
|
<meta property="og:locale" content="en_GB">
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:image" content="https://c.stupid.cat/assets/favicon/favicon.png">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta name="twitter:title" content="Clove Twilight">
|
||||||
|
<meta name="twitter:description" content="Browse a gallery of selfies from Clove Twilight.">
|
||||||
|
|
||||||
|
<!-- Prefetch other pages for faster navigation -->
|
||||||
|
<link rel="prefetch" href="/">
|
||||||
|
<link rel="prefetch" href="/cool-people">
|
||||||
|
<link rel="prefetch" href="/dev-info">
|
||||||
|
<link rel="prefetch" href="/discord">
|
||||||
|
<link rel="prefetch" href="/projects">
|
||||||
|
<link rel="prefetch" href="/music">
|
||||||
|
<link rel="prefetch" href="/88x31">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header class="nav">
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a class="nav-link" data-href="/">Home</a>
|
||||||
|
<a class="nav-link" data-href="/cool-people">Cool People</a>
|
||||||
|
<a class="nav-link" data-href="/dev-info">Dev Info</a>
|
||||||
|
<a class="nav-link" data-href="/discord">Discord</a>
|
||||||
|
<a class="nav-link" data-href="/projects">Projects</a>
|
||||||
|
<a class="nav-link" data-href="/music">Music</a>
|
||||||
|
<a class="nav-link" data-href="/88x31">88x31</a>
|
||||||
|
<a class="nav-link" data-href="/guestbook">Guestbook</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="hub selfies-wrap">
|
||||||
|
<header class="hub-header">
|
||||||
|
<h1>Selfies</h1>
|
||||||
|
<p class="tagline">A gallery of my selfies — tap any photo to view it full size</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Thumbnails are rendered by selfies.js from /assets/selfies/selfies.json -->
|
||||||
|
<div id="selfies-root" class="selfie-grid" aria-label="Selfies gallery"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/js/core.js" data-cat="/assets/oneko/classics/classic.png"></script>
|
||||||
|
<script src="/js/selfies.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue