Add changelog, some extra cats and some other cool things
This commit is contained in:
parent
c3ee69e918
commit
9c4dfc2912
|
|
@ -0,0 +1,143 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Clove Twilight - Changelog</title>
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="icon" type="image/svg+xml" href="/images/favicon.svg">
|
||||
|
||||
<meta name="description" content="Changelog for clove.is-a.dev" />
|
||||
<meta name="author" content="doughmination" />
|
||||
<meta name="theme-color" content="#f5c2e7" />
|
||||
|
||||
<meta property="og:site_name" content="clove.is-a.dev" />
|
||||
<meta property="og:title" content="Clove Twilight - Changelog" />
|
||||
<meta property="og:description" content="Update history for the site" />
|
||||
<meta property="og:type" content="website" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header class="nav">
|
||||
<nav class="nav-links">
|
||||
<a class="nav-link" data-href="/"><- Homepage</a>
|
||||
<a class="nav-link selected" data-href="/changelog">Changelog</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<a class="now-playing" id="now-playing" target="_blank" rel="noopener" hidden>
|
||||
<img class="np-art" alt="" referrerpolicy="no-referrer">
|
||||
<span class="np-bars" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
|
||||
<span class="np-text">
|
||||
<span class="np-label">Now playing</span>
|
||||
<span class="np-track"></span>
|
||||
<span class="np-artist"></span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a class="version-tag" data-href="/changelog" title="Changelog">v1.4.0</a>
|
||||
|
||||
<main class="hub">
|
||||
<header class="hub-header">
|
||||
<h1>Changelog</h1>
|
||||
<p class="tagline">What's new on clove.is-a.dev</p>
|
||||
</header>
|
||||
|
||||
<section class="changelog" aria-label="Update history">
|
||||
<article class="release">
|
||||
<header class="release-head">
|
||||
<span class="release-version">v1.4.0</span>
|
||||
<time class="release-date">2026-05-30</time>
|
||||
</header>
|
||||
<ul class="release-notes">
|
||||
<li><span class="tag tag-add">Added</span> "Now Playing" widget pulling my latest Last.fm scrobble</li>
|
||||
<li><span class="tag tag-add">Added</span> Secret Cat Modes — click the cat to unlock new looks</li>
|
||||
<li><span class="tag tag-add">Added</span> this changelog + version tag</li>
|
||||
<li><span class="tag tag-change">Changed</span> bottom-left page nav with smooth cross-fade transitions</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="release">
|
||||
<header class="release-head">
|
||||
<span class="release-version">v1.3.0</span>
|
||||
<time class="release-date">2026-05-29</time>
|
||||
</header>
|
||||
<ul class="release-notes">
|
||||
<li><span class="tag tag-add">Added</span> Tech Stack page with palette-themed badges</li>
|
||||
<li><span class="tag tag-change">Changed</span> restructured the project into css/ js/ images/</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="release">
|
||||
<header class="release-head">
|
||||
<span class="release-version">v1.2.0</span>
|
||||
<time class="release-date">2026-05-29</time>
|
||||
</header>
|
||||
<ul class="release-notes">
|
||||
<li><span class="tag tag-add">Added</span> profile picture to the header</li>
|
||||
<li><span class="tag tag-add">Added</span> estrogen-molecule background watermark</li>
|
||||
<li><span class="tag tag-change">Changed</span> moved the system badges into the corner</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="release">
|
||||
<header class="release-head">
|
||||
<span class="release-version">v1.1.0</span>
|
||||
<time class="release-date">2026-05-29</time>
|
||||
</header>
|
||||
<ul class="release-notes">
|
||||
<li><span class="tag tag-add">Added</span> custom domain: clove.is-a.dev</li>
|
||||
<li><span class="tag tag-add">Added</span> git.gay to the links</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="release">
|
||||
<header class="release-head">
|
||||
<span class="release-version">v1.0.0</span>
|
||||
<time class="release-date">2026-05-29</time>
|
||||
</header>
|
||||
<ul class="release-notes">
|
||||
<li><span class="tag tag-add">Added</span> rebuilt the site as a link hub (icon grid, Catppuccin theme)</li>
|
||||
<li><span class="tag tag-add">Added</span> oneko cat + cosmetic system badges</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="release">
|
||||
<header class="release-head">
|
||||
<span class="release-version">v0.1.0</span>
|
||||
<time class="release-date">2026-02-16</time>
|
||||
</header>
|
||||
<ul class="release-notes">
|
||||
<li><span class="tag tag-add">Added</span> initial site — a simple redirect page</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<aside class="badges" aria-label="System badges">
|
||||
<span class="badge">
|
||||
<img class="badge-icon" src="/images/amd.svg" alt="">
|
||||
AMD Purist
|
||||
</span>
|
||||
<span class="badge">
|
||||
<img class="badge-icon" src="/images/arch.svg" alt="">
|
||||
I use arch btw
|
||||
</span>
|
||||
<span class="badge">
|
||||
<img class="badge-icon" src="/images/debian.svg" alt="">
|
||||
Debian Professional
|
||||
</span>
|
||||
<span class="badge">
|
||||
<img class="badge-icon" src="/images/apple.svg" alt="">
|
||||
Apple Ecosystem Enthusiast
|
||||
</span>
|
||||
</aside>
|
||||
|
||||
<script src="/js/cat.js" data-cat="/images/oneko.gif"></script>
|
||||
<script src="/js/nav.js"></script>
|
||||
<script src="/js/now-playing.js"></script>
|
||||
<script src="/js/cat-modes.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
343
css/style.css
343
css/style.css
|
|
@ -271,6 +271,107 @@ body::before {
|
|||
color: var(--pink);
|
||||
}
|
||||
|
||||
/* "Now playing" widget, pinned top-left */
|
||||
.now-playing {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
z-index: 6;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
max-width: 240px;
|
||||
padding: 0.4rem 0.7rem 0.4rem 0.4rem;
|
||||
border-radius: 999px;
|
||||
background: var(--surface-0);
|
||||
border: 1px solid var(--surface-1);
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
transition: transform 0.15s ease, border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.now-playing[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.now-playing:hover {
|
||||
transform: translateY(2px);
|
||||
border-color: var(--pink);
|
||||
}
|
||||
|
||||
.np-art {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Equalizer bars (only animate while live) */
|
||||
.np-bars {
|
||||
display: none;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.now-playing.is-live .np-bars {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.np-bars i {
|
||||
width: 3px;
|
||||
height: 100%;
|
||||
border-radius: 2px;
|
||||
background: var(--pink);
|
||||
transform-origin: bottom;
|
||||
animation: np-eq 0.9s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.np-bars i:nth-child(2) { animation-delay: 0.15s; }
|
||||
.np-bars i:nth-child(3) { animation-delay: 0.3s; }
|
||||
.np-bars i:nth-child(4) { animation-delay: 0.45s; }
|
||||
|
||||
@keyframes np-eq {
|
||||
0%, 100% { transform: scaleY(0.3); }
|
||||
50% { transform: scaleY(1); }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.np-bars i { animation: none; transform: scaleY(0.6); }
|
||||
}
|
||||
|
||||
.np-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.np-label {
|
||||
font-size: 0.6rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--pink);
|
||||
}
|
||||
|
||||
.np-track {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.np-artist {
|
||||
font-size: 0.72rem;
|
||||
color: var(--subtext-0);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Page nav, pinned bottom-left, selected item with a pointer triangle */
|
||||
.nav {
|
||||
position: fixed;
|
||||
|
|
@ -427,3 +528,245 @@ body:has(.tech-stack) .hub {
|
|||
transform: translateY(-2px) scale(1.04);
|
||||
box-shadow: 0 4px 12px rgba(245, 194, 231, 0.25);
|
||||
}
|
||||
|
||||
/* ===== Secret Cat Modes toast ===== */
|
||||
.cat-toast {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
bottom: 4.5rem;
|
||||
transform: translateX(-50%) translateY(8px);
|
||||
z-index: 2147483647;
|
||||
padding: 0.4rem 0.9rem;
|
||||
border-radius: 999px;
|
||||
background: var(--crust);
|
||||
border: 1px solid var(--pink);
|
||||
color: var(--text);
|
||||
font-size: 0.8rem;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.cat-toast.show {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
|
||||
/* ===== Version tag (top-right) ===== */
|
||||
.version-tag {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
z-index: 6;
|
||||
padding: 0.25rem 0.6rem;
|
||||
border-radius: 999px;
|
||||
background: var(--surface-0);
|
||||
border: 1px solid var(--surface-1);
|
||||
color: var(--subtext-0);
|
||||
font-size: 0.72rem;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: color 0.15s ease, border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.version-tag:hover {
|
||||
color: var(--pink);
|
||||
border-color: var(--pink);
|
||||
}
|
||||
|
||||
/* ===== Changelog page ===== */
|
||||
html:has(.changelog),
|
||||
body:has(.changelog) {
|
||||
height: auto;
|
||||
min-height: 100dvh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
body:has(.changelog) {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
body:has(.changelog) .hub {
|
||||
max-width: 540px;
|
||||
}
|
||||
|
||||
.changelog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding-bottom: 4.5rem;
|
||||
}
|
||||
|
||||
.release {
|
||||
background: var(--surface-0);
|
||||
border: 1px solid var(--surface-1);
|
||||
border-radius: 14px;
|
||||
padding: 1rem 1.15rem;
|
||||
}
|
||||
|
||||
.release-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.release-version {
|
||||
font-weight: 700;
|
||||
font-size: 1.05rem;
|
||||
color: var(--pink);
|
||||
}
|
||||
|
||||
.release-date {
|
||||
font-size: 0.78rem;
|
||||
color: var(--subtext-0);
|
||||
}
|
||||
|
||||
.release-notes {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.release-notes li {
|
||||
font-size: 0.88rem;
|
||||
line-height: 1.4;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
margin-right: 0.4rem;
|
||||
padding: 0.05rem 0.45rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
vertical-align: 1px;
|
||||
}
|
||||
|
||||
.tag-add {
|
||||
background: rgba(166, 227, 161, 0.18);
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.tag-change {
|
||||
background: rgba(137, 180, 250, 0.18);
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
/* ===== Cat picker modal ===== */
|
||||
.cat-picker {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 2147483646;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
background: rgba(17, 17, 27, 0.65);
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.cat-picker[hidden] { display: none; }
|
||||
|
||||
.cat-picker-panel {
|
||||
width: min(94vw, 430px);
|
||||
max-height: 82vh;
|
||||
overflow-y: auto;
|
||||
background: var(--base);
|
||||
border: 1px solid var(--surface-1);
|
||||
border-radius: 16px;
|
||||
padding: 1rem;
|
||||
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
.cat-picker-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.85rem;
|
||||
font-weight: 700;
|
||||
color: var(--pink);
|
||||
}
|
||||
|
||||
.cat-picker-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--subtext-0);
|
||||
font-size: 1.35rem;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
.cat-picker-close:hover { color: var(--text); }
|
||||
|
||||
.cat-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.cat-option {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
padding: 0.75rem 0.4rem 0.6rem;
|
||||
border-radius: 12px;
|
||||
background: var(--surface-0);
|
||||
border: 1px solid var(--surface-1);
|
||||
color: var(--text);
|
||||
font-family: inherit;
|
||||
font-size: 0.74rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s ease, border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.cat-option:hover:not(.locked) {
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--pink);
|
||||
}
|
||||
|
||||
.cat-option.current {
|
||||
border-color: var(--pink);
|
||||
box-shadow: inset 0 0 0 1px var(--pink);
|
||||
}
|
||||
|
||||
.cat-option.locked { cursor: default; opacity: 0.75; }
|
||||
|
||||
.cat-preview {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 6px 0 10px;
|
||||
background-repeat: no-repeat;
|
||||
image-rendering: pixelated;
|
||||
transform: scale(1.6);
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.cat-name { font-weight: 500; }
|
||||
|
||||
.cat-lock {
|
||||
font-size: 0.62rem;
|
||||
color: var(--subtext-0);
|
||||
}
|
||||
|
||||
.cat-hint {
|
||||
margin: 0.85rem 0 0;
|
||||
font-size: 0.68rem;
|
||||
color: var(--subtext-0);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width: 420px) {
|
||||
.cat-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
|
|
|
|||
15
index.html
15
index.html
|
|
@ -45,6 +45,19 @@
|
|||
</nav>
|
||||
</header>
|
||||
<a rel="me" href="https://mastodon.social/@doughmination" style="display: none;"></a>
|
||||
|
||||
<a class="now-playing" id="now-playing" target="_blank" rel="noopener" hidden>
|
||||
<img class="np-art" alt="" referrerpolicy="no-referrer">
|
||||
<span class="np-bars" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
|
||||
<span class="np-text">
|
||||
<span class="np-label">Now playing</span>
|
||||
<span class="np-track"></span>
|
||||
<span class="np-artist"></span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a class="version-tag" data-href="/changelog" title="Changelog">v1.4.0</a>
|
||||
|
||||
<main class="hub">
|
||||
<header class="hub-header">
|
||||
<img class="pfp" src="https://cdn.discordapp.com/avatars/1464890289922641993/83c6f674b7bdf901ab7b1e65204795ca.png" alt="Clove Twilight avatar">
|
||||
|
|
@ -190,6 +203,8 @@
|
|||
|
||||
<script src="/js/cat.js" data-cat="/images/oneko.gif"></script>
|
||||
<script src="/js/nav.js"></script>
|
||||
<script src="/js/now-playing.js"></script>
|
||||
<script src="/js/cat-modes.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
const CAT_MODES = [
|
||||
{ name: "Classic", filter: "none" },
|
||||
{ name: "Shadow Cat", filter: "invert(1) drop-shadow(0 0 3px #cba6f7)" },
|
||||
{ name: "Ghost Cat", filter: "grayscale(1) brightness(1.7) opacity(0.55) drop-shadow(0 0 4px #89dceb)" },
|
||||
{ name: "CRT Cat", filter: "invert(48%) sepia(80%) saturate(2000%) hue-rotate(85deg) brightness(0.9) contrast(1.2)" },
|
||||
{ name: "Vaporwave Cat", filter: "invert(60%) sepia(90%) saturate(3000%) hue-rotate(280deg) brightness(0.95)" },
|
||||
{ name: "Gold Cat", filter: "invert(75%) sepia(85%) saturate(1400%) hue-rotate(8deg) brightness(1.0)" },
|
||||
{ name: "Sapphire Cat", filter: "invert(45%) sepia(90%) saturate(2500%) hue-rotate(200deg) brightness(1.0)" },
|
||||
];
|
||||
const UNLOCK_EVERY = 5; // clicks needed to unlock each new mode
|
||||
const SPRITE = "/images/oneko.gif";
|
||||
const IDLE_POS = "-96px -96px"; // idle frame of the sprite sheet
|
||||
|
||||
(function catModes() {
|
||||
const oneko = document.getElementById("oneko");
|
||||
if (!oneko) return;
|
||||
|
||||
oneko.style.pointerEvents = "auto";
|
||||
oneko.style.cursor = "pointer";
|
||||
|
||||
const ls = window.localStorage;
|
||||
let clicks = parseInt(ls.getItem("onekoClicks") || "0", 10);
|
||||
let mode = parseInt(ls.getItem("onekoMode") || "0", 10);
|
||||
|
||||
const unlockedCount = () =>
|
||||
Math.min(CAT_MODES.length, 1 + Math.floor(clicks / UNLOCK_EVERY));
|
||||
const isUnlocked = (i) => i < unlockedCount();
|
||||
const apply = (i) => (oneko.style.filter = CAT_MODES[i].filter);
|
||||
|
||||
/* ---------- picker overlay (no visible trigger — press C to find it) ---------- */
|
||||
const overlay = document.createElement("div");
|
||||
overlay.className = "cat-picker";
|
||||
overlay.hidden = true;
|
||||
overlay.innerHTML = `
|
||||
<div class="cat-picker-panel" role="dialog" aria-label="Choose a cat">
|
||||
<div class="cat-picker-head">
|
||||
<span>Cat collection</span>
|
||||
<button class="cat-picker-close" type="button" aria-label="Close">×</button>
|
||||
</div>
|
||||
<div class="cat-grid"></div>
|
||||
<p class="cat-hint">Some cats are still hidden… · press C to toggle</p>
|
||||
</div>`;
|
||||
document.body.appendChild(overlay);
|
||||
const grid = overlay.querySelector(".cat-grid");
|
||||
|
||||
function renderGrid() {
|
||||
grid.innerHTML = "";
|
||||
CAT_MODES.forEach((c, i) => {
|
||||
const unlocked = isUnlocked(i);
|
||||
const opt = document.createElement(unlocked ? "button" : "div");
|
||||
opt.className =
|
||||
"cat-option" + (unlocked ? "" : " locked") + (i === mode ? " current" : "");
|
||||
if (unlocked) opt.type = "button";
|
||||
const previewFilter = unlocked ? c.filter : "brightness(0) opacity(0.3)";
|
||||
opt.innerHTML = `
|
||||
<span class="cat-preview" style="background-image:url('${SPRITE}');background-position:${IDLE_POS};filter:${previewFilter}"></span>
|
||||
<span class="cat-name">${unlocked ? c.name : "???"}</span>`;
|
||||
if (unlocked) opt.addEventListener("click", () => selectMode(i));
|
||||
grid.appendChild(opt);
|
||||
});
|
||||
}
|
||||
|
||||
function selectMode(i) {
|
||||
mode = i;
|
||||
ls.setItem("onekoMode", String(i));
|
||||
apply(i);
|
||||
renderGrid();
|
||||
}
|
||||
|
||||
const openPicker = () => {
|
||||
renderGrid();
|
||||
overlay.hidden = false;
|
||||
};
|
||||
const closePicker = () => (overlay.hidden = true);
|
||||
const togglePicker = () => (overlay.hidden ? openPicker() : closePicker());
|
||||
|
||||
overlay
|
||||
.querySelector(".cat-picker-close")
|
||||
.addEventListener("click", closePicker);
|
||||
overlay.addEventListener("click", (e) => {
|
||||
if (e.target === overlay) closePicker();
|
||||
});
|
||||
document.addEventListener("keydown", (e) => {
|
||||
// ignore while typing in a field or with modifier keys held
|
||||
const typing = /^(INPUT|TEXTAREA|SELECT)$/.test(document.activeElement?.tagName || "");
|
||||
if (e.key === "Escape" && !overlay.hidden) {
|
||||
closePicker();
|
||||
} else if (
|
||||
(e.key === "c" || e.key === "C") &&
|
||||
!e.ctrlKey && !e.metaKey && !e.altKey && !typing
|
||||
) {
|
||||
togglePicker();
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------- toast ---------- */
|
||||
let toastEl, toastTimer;
|
||||
function toast(msg) {
|
||||
if (!toastEl) {
|
||||
toastEl = document.createElement("div");
|
||||
toastEl.className = "cat-toast";
|
||||
document.body.appendChild(toastEl);
|
||||
}
|
||||
toastEl.textContent = msg;
|
||||
toastEl.classList.remove("show");
|
||||
void toastEl.offsetWidth;
|
||||
toastEl.classList.add("show");
|
||||
clearTimeout(toastTimer);
|
||||
toastTimer = setTimeout(() => toastEl.classList.remove("show"), 1700);
|
||||
}
|
||||
|
||||
/* ---------- init + cat click ---------- */
|
||||
mode = Math.max(0, Math.min(mode, unlockedCount() - 1));
|
||||
apply(mode);
|
||||
|
||||
oneko.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const before = unlockedCount();
|
||||
clicks += 1;
|
||||
ls.setItem("onekoClicks", String(clicks));
|
||||
const after = unlockedCount();
|
||||
|
||||
if (after > before) {
|
||||
mode = after - 1;
|
||||
toast(`✨ Unlocked: ${CAT_MODES[mode].name}!`);
|
||||
} else {
|
||||
mode = (mode + 1) % after;
|
||||
toast(CAT_MODES[mode].name);
|
||||
}
|
||||
|
||||
ls.setItem("onekoMode", String(mode));
|
||||
apply(mode);
|
||||
if (!overlay.hidden) renderGrid();
|
||||
});
|
||||
})();
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
const LASTFM_USER = "Real_AlexTLM";
|
||||
const LASTFM_API_KEY = "768e8bd0d366f4d6c7874740ca6610ad";
|
||||
|
||||
const POLL_MS = 30000; // refresh every 30s
|
||||
|
||||
(function nowPlaying() {
|
||||
const el = document.getElementById("now-playing");
|
||||
if (!el) return;
|
||||
|
||||
// Don't fire until configured (keeps the widget hidden on a fresh clone)
|
||||
if (
|
||||
LASTFM_USER === "YOUR_LASTFM_USERNAME" ||
|
||||
LASTFM_API_KEY === "YOUR_LASTFM_API_KEY"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const artEl = el.querySelector(".np-art");
|
||||
const labelEl = el.querySelector(".np-label");
|
||||
const trackEl = el.querySelector(".np-track");
|
||||
const artistEl = el.querySelector(".np-artist");
|
||||
|
||||
const endpoint =
|
||||
"https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks" +
|
||||
`&user=${encodeURIComponent(LASTFM_USER)}` +
|
||||
`&api_key=${encodeURIComponent(LASTFM_API_KEY)}` +
|
||||
"&format=json&limit=1";
|
||||
|
||||
async function update() {
|
||||
try {
|
||||
const res = await fetch(endpoint);
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
const track = data?.recenttracks?.track?.[0];
|
||||
if (!track) return;
|
||||
|
||||
const nowPlaying = track["@attr"]?.nowplaying === "true";
|
||||
const name = track.name || "";
|
||||
const artist = track.artist?.["#text"] || "";
|
||||
const url = track.url || `https://www.last.fm/user/${LASTFM_USER}`;
|
||||
const images = track.image || [];
|
||||
const art = images[images.length - 1]?.["#text"] || "";
|
||||
|
||||
labelEl.textContent = nowPlaying ? "Now playing" : "Last played";
|
||||
trackEl.textContent = name;
|
||||
artistEl.textContent = artist;
|
||||
el.href = url;
|
||||
el.classList.toggle("is-live", nowPlaying);
|
||||
|
||||
if (art) {
|
||||
artEl.src = art;
|
||||
artEl.style.display = "";
|
||||
} else {
|
||||
artEl.style.display = "none";
|
||||
}
|
||||
|
||||
el.hidden = false;
|
||||
} catch (e) {
|
||||
/* network hiccup — keep last state, try again next tick */
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
setInterval(update, POLL_MS);
|
||||
})();
|
||||
|
|
@ -4,21 +4,21 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Clove Twilight - Link Center</title>
|
||||
<title>Clove Twilight - Tech Stack</title>
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="icon" type="image/svg+xml" href="/images/favicon.svg">
|
||||
|
||||
<!-- SEO Meta Tags -->
|
||||
<meta name="description" content="Link Center for Clove Twilight" />
|
||||
<meta name="description" content="Tech Stack for Clove Twilight" />
|
||||
<meta name="keywords" content="Portfolio, Personal, Developer" />
|
||||
<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://clove.is-a.dev" />
|
||||
<link rel="canonical" href="https://clove.is-a.dev/tech-stack" />
|
||||
|
||||
<!-- Alternate for mobile -->
|
||||
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://clove.is-a.dev" />
|
||||
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://clove.is-a.dev/tech-stack" />
|
||||
|
||||
<!-- Theme Color -->
|
||||
<meta name="theme-color" content="#f5c2e7" />
|
||||
|
|
@ -26,15 +26,15 @@
|
|||
<!-- Open Graph / Discord / Facebook -->
|
||||
<meta property="og:site_name" content="clove.is-a.dev" />
|
||||
<meta property="og:title" content="Clove Twilight" />
|
||||
<meta property="og:description" content="Link Center for Clove Twilight" />
|
||||
<meta property="og:description" content="Tech Stack for Clove Twilight" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://clove.is-a.dev" />
|
||||
<meta property="og:url" content="https://clove.is-a.dev/tech-stack" />
|
||||
<meta property="og:locale" content="en_GB" />
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Clove Twilight" />
|
||||
<meta name="twitter:description" content="Link Center for Clove Twilight" />
|
||||
<meta name="twitter:description" content="Tech Stack for Clove Twilight" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
@ -45,7 +45,19 @@
|
|||
<a class="nav-link selected" data-href="/tech-stack">Tech Stack</a>
|
||||
</nav>
|
||||
</header>
|
||||
<a rel="me" href="https://mastodon.social/@doughmination" style="display: none;"></a>
|
||||
|
||||
<a class="now-playing" id="now-playing" target="_blank" rel="noopener" hidden>
|
||||
<img class="np-art" alt="" referrerpolicy="no-referrer">
|
||||
<span class="np-bars" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
|
||||
<span class="np-text">
|
||||
<span class="np-label">Now playing</span>
|
||||
<span class="np-track"></span>
|
||||
<span class="np-artist"></span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a class="version-tag" data-href="/changelog" title="Changelog">v1.4.0</a>
|
||||
|
||||
<main class="hub">
|
||||
<header class="hub-header">
|
||||
<img class="pfp" src="https://cdn.discordapp.com/avatars/1464890289922641993/83c6f674b7bdf901ab7b1e65204795ca.png" alt="Clove Twilight avatar">
|
||||
|
|
@ -145,6 +157,8 @@
|
|||
|
||||
<script src="/js/cat.js" data-cat="/images/oneko.gif"></script>
|
||||
<script src="/js/nav.js"></script>
|
||||
<script src="/js/now-playing.js"></script>
|
||||
<script src="/js/cat-modes.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Clove Twilight - Template</title>
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="icon" type="image/svg+xml" href="/images/favicon.svg">
|
||||
|
||||
<!-- SEO Meta Tags -->
|
||||
<meta name="description" content="Template Page for Clove Twilight" />
|
||||
<meta name="keywords" content="Clove Twilight, Portfolio, Personal, Developer" />
|
||||
<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://clove.is-a.dev/template" />
|
||||
|
||||
<!-- Alternate for mobile -->
|
||||
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://clove.is-a.dev/template" />
|
||||
|
||||
<!-- Theme Color -->
|
||||
<meta name="theme-color" content="#f5c2e7" />
|
||||
|
||||
<!-- Open Graph / Discord / Facebook -->
|
||||
<meta property="og:site_name" content="clove.is-a.dev" />
|
||||
<meta property="og:title" content="Clove Twilight" />
|
||||
<meta property="og:description" content="Template Page for Clove Twilight" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://clove.is-a.dev/template" />
|
||||
<meta property="og:locale" content="en_GB" />
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Clove Twilight" />
|
||||
<meta name="twitter:description" content="Template Page for Clove Twilight" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="nav">
|
||||
<nav class="nav-links">
|
||||
<a class="nav-link selected" data-href="/template">Template</a>
|
||||
</nav>
|
||||
</header>
|
||||
<main class="hub">
|
||||
<header class="hub-header">
|
||||
<img class="pfp"
|
||||
src="https://cdn.discordapp.com/avatars/1464890289922641993/83c6f674b7bdf901ab7b1e65204795ca.png"
|
||||
alt="Clove Twilight avatar">
|
||||
<h1>Clove Twilight</h1>
|
||||
<h2 class="pronouns">(fae/faer)</h2>
|
||||
<p class="tagline">Template</p>
|
||||
</header>
|
||||
<h1>Template</h1>
|
||||
<p>This is a simple template for the clove.is-a.dev website, it's to make it easier for myself to create new pages.</p>
|
||||
</main>
|
||||
|
||||
<aside class="badges" aria-label="System badges">
|
||||
<span class="badge">
|
||||
<img class="badge-icon" src="/images/amd.svg" alt="">
|
||||
AMD Purist
|
||||
</span>
|
||||
<span class="badge">
|
||||
<img class="badge-icon" src="/images/arch.svg" alt="">
|
||||
I use arch btw
|
||||
</span>
|
||||
<span class="badge">
|
||||
<img class="badge-icon" src="/images/debian.svg" alt="">
|
||||
Debian Professional
|
||||
</span>
|
||||
<span class="badge">
|
||||
<img class="badge-icon" src="/images/apple.svg" alt="">
|
||||
Apple Ecosystem Enthusiast
|
||||
</span>
|
||||
</aside>
|
||||
|
||||
<script src="/js/cat.js" data-cat="/images/oneko.gif"></script>
|
||||
<script src="/js/nav.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Reference in New Issue