global: add formatter

This commit is contained in:
Agahnim 2026-05-13 14:00:54 +02:00
parent eb6819bb76
commit 6c87abd4fc
Signed by: Agahnim
SSH key fingerprint: SHA256:Zj65PJnE0dRYye8Ltk/qDglynyXUxJngQ9qqx/VI+b4
19 changed files with 3925 additions and 288 deletions

View file

@ -1,5 +1,6 @@
{pkgs ? import <nixpkgs> {}}:
pkgs.mkShell {
{pkgs ? import <nixpkgs> {}}: let
in
pkgs.mkShell {
packages = with pkgs; [
rustc
rust-analyzer
@ -7,6 +8,8 @@ pkgs.mkShell {
clippy
cargo
cargo-watch
treefmt
prettier
];
shellHook = ''
@ -14,4 +17,4 @@ pkgs.mkShell {
echo "Pour lancer le projet et avoir les changements en temps réel : "
echo "- cargo watch -w content -w src -w templates -w static -x run"
'';
}
}

View file

@ -1,5 +1,5 @@
(function() {
const menu = document.createElement('helo');
(function () {
const menu = document.createElement("helo");
menu.innerHTML = `
<helo-content>
@ -7,7 +7,7 @@
</helo-content>
`;
menu.style.display = 'none';
menu.style.display = "none";
function ensureMenu() {
if (!document.body.contains(menu)) {
@ -18,7 +18,7 @@
const showMenu = (x, y) => {
ensureMenu();
menu.style.display = 'block';
menu.style.display = "block";
menu.style.left = `${x}px`;
menu.style.top = `${y}px`;
@ -34,20 +34,20 @@
};
const hideMenu = () => {
menu.style.display = 'none';
menu.style.display = "none";
};
document.addEventListener('contextmenu', (e) => {
document.addEventListener("contextmenu", (e) => {
e.preventDefault();
showMenu(e.clientX, e.clientY);
});
document.addEventListener('click', hideMenu);
document.addEventListener('scroll', hideMenu);
document.addEventListener("click", hideMenu);
document.addEventListener("scroll", hideMenu);
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') hideMenu();
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") hideMenu();
});
document.body.addEventListener('htmx:historyRestore', ensureMenu);
document.body.addEventListener("htmx:historyRestore", ensureMenu);
})();

View file

@ -15,7 +15,6 @@ function initMiniPlayer() {
const trackTitleEl = player.querySelector("track-title");
const trackArtistEl = player.querySelector("track-artist");
let isTransitioning = false;
let currentTrackIndex = 0;
let isPlaying = false;
@ -65,9 +64,13 @@ function initMiniPlayer() {
if (trackArtistEl) trackArtistEl.textContent = tracks[index].artist;
if (wasPlaying) {
audio.addEventListener("loadeddata", () => {
audio.addEventListener(
"loadeddata",
() => {
audio.play();
}, { once: true });
},
{ once: true },
);
}
};
@ -82,13 +85,15 @@ function initMiniPlayer() {
};
const handlePrev = () => {
const newIndex = currentTrackIndex === 0 ? tracks.length - 1 : currentTrackIndex - 1;
const newIndex =
currentTrackIndex === 0 ? tracks.length - 1 : currentTrackIndex - 1;
loadTrack(newIndex);
};
const handleNext = () => {
isTransitioning = true;
const newIndex = currentTrackIndex === tracks.length - 1 ? 0 : currentTrackIndex + 1;
const newIndex =
currentTrackIndex === tracks.length - 1 ? 0 : currentTrackIndex + 1;
loadTrack(newIndex);
};
@ -124,7 +129,6 @@ function initMiniPlayer() {
}
});
audio.addEventListener("pause", () => {
if (isTransitioning) return;

View file

@ -122,7 +122,7 @@ blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: "";
content: none;
}
@ -133,7 +133,6 @@ table {
/* Animations */
@keyframes fadeInNOut {
0% {
opacity: 0;
@ -149,7 +148,6 @@ table {
}
@keyframes woopwoop {
0%,
100% {
transform: translateY(0) rotate(-2deg);
@ -160,7 +158,6 @@ table {
}
}
@keyframes marquee {
from {
transform: translateX(0);
@ -184,7 +181,6 @@ table {
}
@keyframes boing {
0%,
100% {
transform: translateY(-25%);
@ -202,7 +198,6 @@ table {
src: url("assets/fonts/ah.ttf") format("truetype");
}
:root {
--lavender: #cdb4db;
--light-pink: #ffc8dd;
@ -219,20 +214,15 @@ table {
text-shadow: 0px 0px 3px var(--darkerer-pink);
}
body {
background-size: cover;
background-position: center;
min-height: 100lvh;
width: 100lvw;
overflow: auto;
font-family: "DotGothic16",
sans-serif;
font-family: "DotGothic16", sans-serif;
font-size: 1rem;
&:has(#content home-content) {
background-image: url(assets/images/tiledbgpink.webp);
}
@ -302,9 +292,11 @@ crt {
}
&::before {
background: linear-gradient(to bottom,
background: linear-gradient(
to bottom,
transparent 50%,
rgba(0, 0, 0, 0.2) 51%);
rgba(0, 0, 0, 0.2) 51%
);
background-size: 100% 4px;
animation: scanlines 1s steps(60) infinite;
}
@ -454,8 +446,6 @@ navbar {
margin-left: auto;
padding-right: 0.5rem;
}
}
}
@ -480,7 +470,9 @@ home-content {
box {
border-radius: 0.4rem;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
box-shadow:
0 4px 6px -1px rgb(0 0 0 / 0.1),
0 2px 4px -2px rgb(0 0 0 / 0.1);
background-color: white;
padding: 1rem;
@ -495,7 +487,7 @@ home-content {
display: flex;
gap: 1rem;
>socials-header {
> socials-header {
color: var(--darkerer-pink);
}
@ -507,7 +499,7 @@ home-content {
bibou-message {
font-style: italic;
color: var(--grey-500)
color: var(--grey-500);
}
bibou-container {
@ -542,9 +534,6 @@ home-content {
font-style: italic;
text-align: center;
}
}
&#newsbox {
@ -554,7 +543,7 @@ home-content {
justify-content: center;
gap: 0.6rem;
&>img {
& > img {
margin: auto;
}
}
@ -594,16 +583,14 @@ home-content {
flex-wrap: wrap;
gap: 1rem;
>img {
> img {
flex: 1 1 auto;
}
>img:nth-last-child(-n+3) {
> img:nth-last-child(-n + 3) {
flex: 1 1 30%;
}
}
}
}
@ -636,12 +623,23 @@ home-content {
woopwoop span {
display: inline-block;
background: linear-gradient(90deg, var(--blue), var(--darker-pink), var(--darkerer-pink), var(--lavender), var(--light-blue), var(--light-pink), var(--pink));
background: linear-gradient(
90deg,
var(--blue),
var(--darker-pink),
var(--darkerer-pink),
var(--lavender),
var(--light-blue),
var(--light-pink),
var(--pink)
);
background-size: 200% auto;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: woopwoop 1.2s ease-in-out infinite, woopwoopmove 2s linear infinite;
animation:
woopwoop 1.2s ease-in-out infinite,
woopwoopmove 2s linear infinite;
}
chibis {
@ -667,7 +665,6 @@ home-content {
/* Music */
music {
display: flex;
flex-direction: row;
flex-wrap: wrap;
@ -703,15 +700,16 @@ music {
}
}
box {
border-radius: 0.4rem;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
box-shadow:
0 4px 6px -1px rgb(0 0 0 / 0.1),
0 2px 4px -2px rgb(0 0 0 / 0.1);
background-color: white;
padding: 1rem;
}
>cute-container {
> cute-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
@ -734,7 +732,9 @@ katcenkat {
max-width: 100svw;
height: auto;
object-fit: contain;
transition: opacity 5s ease, transform 5s ease-out;
transition:
opacity 5s ease,
transform 5s ease-out;
opacity: 1;
transform: translateY(0px);
@ -755,7 +755,9 @@ mini-player {
border: 2px solid;
border-color: #ffffff #808080 #808080 #ffffff;
box-shadow: 2px 2px 0 #000;
transition: opacity 0.3s, translate 0.3s;
transition:
opacity 0.3s,
translate 0.3s;
font-size: clamp(0.625rem, 2svw, 0.75rem);
ominous-message {
@ -986,7 +988,6 @@ mini-player {
pink-statusbar {
display: none;
}
}
/* Music page */
@ -1039,7 +1040,7 @@ helo {
padding: 0.5rem 0;
min-width: 150px;
z-index: 9999;
font-family: 'VT323', monospace;
font-family: "VT323", monospace;
font-size: 1.2rem;
helo-content {
@ -1052,5 +1053,4 @@ helo {
width: 5svw;
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,22 +1,27 @@
<!-- Welcome!! -->
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, interactive-widget=resizes-content" />
<link rel="icon" type="image/gif" href="/static/assets/gifs/pcgif.gif">
<meta
name="viewport"
content="width=device-width, interactive-widget=resizes-content"
/>
<link rel="icon" type="image/gif" href="/static/assets/gifs/pcgif.gif" />
<!-- <title></title> -->
<title>Agahnim proto</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=DotGothic16&family=VT323&display=swap">
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=DotGothic16&family=VT323&display=swap"
/>
<link rel="stylesheet" href="/static/style.css" />
<script src="/static/vendor/htmx.min.js"></script>
<script>
htmx.config.scrollIntoViewOnBoost = false;
</script>
</head>
</head>
<body hx-boost="true" hx-target="#content">
<body hx-boost="true" hx-target="#content">
<crt>
<!-- They won't ever disappear -->
<persistent-ui>
@ -27,9 +32,7 @@
</persistent-ui>
<!-- Will get swapped by HTMX-->
<main id="content">
{% block content %}{% endblock %}
</main>
<main id="content">{% block content %}{% endblock %}</main>
</crt>
<!-- Noooooooooooooooooooooooooo -->
@ -37,55 +40,56 @@
<script src="/static/contextmenu.js"></script>
<script>
function updateMiniplayerVisibility() {
const isMusicPage = window.location.pathname === '/music';
const miniplayer = document.getElementById('miniplayer-container');
const isMusicPage = window.location.pathname === "/music";
const miniplayer = document.getElementById("miniplayer-container");
if (miniplayer) {
miniplayer.style.display = isMusicPage ? 'none' : '';
miniplayer.style.display = isMusicPage ? "none" : "";
}
if (isMusicPage) {
const audio = document.querySelector('mini-player audio');
const audio = document.querySelector("mini-player audio");
if (audio) audio.pause();
}
}
function updateNavState() {
const path = window.location.pathname;
document.querySelectorAll('navbar input[type="radio"]').forEach(radio => {
document
.querySelectorAll('navbar input[type="radio"]')
.forEach((radio) => {
radio.checked = false;
});
if (path === '/home') {
const homeRadio = document.getElementById('nav-home');
if (path === "/home") {
const homeRadio = document.getElementById("nav-home");
if (homeRadio) homeRadio.checked = true;
} else if (path === '/music') {
const musicRadio = document.getElementById('nav-music');
} else if (path === "/music") {
const musicRadio = document.getElementById("nav-music");
if (musicRadio) musicRadio.checked = true;
} else if (path === "/blog") {
const blogRadio = document.getElementById('nav-blog');
const blogRadio = document.getElementById("nav-blog");
if (blogRadio) blogRadio.checked = true;
} else if (path === "/about") {
const aboutRadio = document.getElementById('nav-about');
const aboutRadio = document.getElementById("nav-about");
if (aboutRadio) aboutRadio.checked = true;
} else if (path === "/projects") {
const projectsRadio = document.getElementById('nav-projects');
const projectsRadio = document.getElementById("nav-projects");
if (projectsRadio) projectsRadio.checked = true;
}
}
function closeMobileMenu() {
const checkbox = document.getElementById('nav-toggle-checkbox');
const checkbox = document.getElementById("nav-toggle-checkbox");
if (checkbox) checkbox.checked = false;
}
updateMiniplayerVisibility();
updateNavState();
document.body.addEventListener('htmx:afterSwap', () => {
document.body.addEventListener("htmx:afterSwap", () => {
updateMiniplayerVisibility();
updateNavState();
closeMobileMenu();
window.scrollTo(0, 0);
});
</script>
</body>
</body>
</html>

View file

@ -1,9 +1,3 @@
{% extends "base.html" %}
{% block content %}
{% include "partials/home.html" %}
{% endblock %}
{% block miniplayer %}
{% include "partials/miniplayer.html" %}
{% extends "base.html" %} {% block content %} {% include "partials/home.html" %}
{% endblock %} {% block miniplayer %} {% include "partials/miniplayer.html" %}
{% endblock %}

View file

@ -1,9 +1,3 @@
{% extends "base.html" %}
{% block content %}
{% include "partials/music.html" %}
{% endblock %}
{% block miniplayer %}
{% include "partials/miniplayer.html" %}
{% endblock %}
{% extends "base.html" %} {% block content %} {% include "partials/music.html"
%} {% endblock %} {% block miniplayer %} {% include "partials/miniplayer.html"
%} {% endblock %}

View file

@ -1,6 +1,2 @@
{% extends "base.html" %}
{% block content %}
{% include "partials/notfound.html" %}
{% endblock %}
{% extends "base.html" %} {% block content %} {% include
"partials/notfound.html" %} {% endblock %}

View file

@ -1,5 +1,5 @@
<navbar>
<input type="checkbox" id="nav-toggle-checkbox">
<input type="checkbox" id="nav-toggle-checkbox" />
<navbar-toggle>
<label for="nav-toggle-checkbox" class="hamburger">
<span></span>
@ -9,15 +9,15 @@
</navbar-toggle>
<navbar-content>
<a href="/home">Home</a>
<input type="radio" name="nav" id="nav-home" checked>
<input type="radio" name="nav" id="nav-home" checked />
<a href="/about">About me</a>
<input type="radio" name="nav" id="nav-about">
<input type="radio" name="nav" id="nav-about" />
<a href="/blog">Blog</a>
<input type="radio" name="nav" id="nav-blog">
<input type="radio" name="nav" id="nav-blog" />
<a href="/projects">Projects</a>
<input type="radio" name="nav" id="nav-projects">
<input type="radio" name="nav" id="nav-projects" />
<a href="/music">Music</a>
<input type="radio" name="nav" id="nav-music">
<input type="radio" name="nav" id="nav-music" />
</navbar-content>
<pink-statusbar>
<status-dot></status-dot>
@ -27,18 +27,18 @@
</navbar>
<script>
(function() {
const dateEl = document.querySelector('current-date');
(function () {
const dateEl = document.querySelector("current-date");
if (dateEl) {
const update = () => {
const now = new Date();
const h = String(now.getHours()).padStart(2, '0');
const m = String(now.getMinutes()).padStart(2, '0');
const s = String(now.getSeconds()).padStart(2, '0');
const h = String(now.getHours()).padStart(2, "0");
const m = String(now.getMinutes()).padStart(2, "0");
const s = String(now.getSeconds()).padStart(2, "0");
dateEl.textContent = `${h}:${m}:${s}`;
};
update();
setInterval(update, 1000);
}
})();
})();
</script>

View file

@ -1,85 +1,142 @@
<home-content>
<welcome>
<img src="/static/assets/images/welcome.webp" width="400px" alt="A welcome text in pink" />
<img
src="/static/assets/images/welcome.webp"
width="400px"
alt="A welcome text in pink"
/>
<marquee>
{% for _ in 0..12 %}
&nbsp;彡★Welcome to my little corner of the Web★彡&nbsp;
{% endfor %}
{% for _ in 0..12 %} &nbsp;彡★Welcome to my little corner of the
Web★彡&nbsp; {% endfor %}
</marquee>
</welcome>
<boxes>
<box id="bigbox">
Thank you for visiting my <woopwoop>brand new</woopwoop> website !
For now it's still a <darkerer-pink>work in progress</darkerer-pink> but I'm sure you will see
changes if you come back from time to time :)
<br /><br />
Thank you for visiting my <woopwoop>brand new</woopwoop> website ! For now
it's still a <darkerer-pink>work in progress</darkerer-pink> but I'm sure
you will see changes if you come back from time to time :) <br /><br />
My name is <darkerer-pink>Agahnim</darkerer-pink>
<pronouns>she/her</pronouns>,
I'm a <darkerer-pink>developer</darkerer-pink> and <darkerer-pink>music producer</darkerer-pink> from
<darkerer-pink>France</darkerer-pink> !
<br /><br />
I created this website not just to <darkerer-pink>improve</darkerer-pink> my
web development
skills, but also because it's <boing>fun</boing>
to
build a project like this. It's a small, personal space on the internet, away from the social climate, which is
getting <shitty>worse and worse.</shitty>
<br /><br />
This website is inspired by the <darkerer-pink>vaporwave
aesthetic</darkerer-pink> and
the old
PCs I used to tinker with when I was a kid.
I always liked this type of aesthetic and the mix of melancholy of comfort it brings me.
It feels good to bring that vibe into one of my projects.
<pronouns>she/her</pronouns>, I'm a
<darkerer-pink>developer</darkerer-pink> and
<darkerer-pink>music producer</darkerer-pink> from
<darkerer-pink>France</darkerer-pink> ! <br /><br />
I created this website not just to
<darkerer-pink>improve</darkerer-pink> my web development skills, but also
because it's <boing>fun</boing> to build a project like this. It's a
small, personal space on the internet, away from the social climate, which
is getting <shitty>worse and worse.</shitty> <br /><br />
This website is inspired by the
<darkerer-pink>vaporwave aesthetic</darkerer-pink> and the old PCs I used
to tinker with when I was a kid. I always liked this type of aesthetic and
the mix of melancholy of comfort it brings me. It feels good to bring that
vibe into one of my projects.
<badges>
<img src="/static/assets/badges/88x31computer.gif" alt="88x31 pixel art badge with a retro computer" />
<img src="/static/assets/badges/cssisawesome.webp" alt="Badge with text 'CSS is Awesome'" />
<img src="/static/assets/badges/queer.webp" alt="Queer pride flag badge" />
<img width="100px" src="/static/assets/badges/skywardsword.webp"
alt="Cover art for The Legend of Zelda Skyward Sword" />
<img src="/static/assets/badges/transrightsnow.webp" alt="Trans rights badge with text 'Trans Rights Now'" />
<img width="30%" src="/static/assets/badges/kirby.gif" alt="Kirby character animated GIF" />
<img width="30%" src="/static/assets/badges/pink.gif" alt="Pink animated pixel art badge" />
<img width="30%" src="/static/assets/badges/trans.gif" alt="Trans pride flag animated badge" />
<img
src="/static/assets/badges/88x31computer.gif"
alt="88x31 pixel art badge with a retro computer"
/>
<img
src="/static/assets/badges/cssisawesome.webp"
alt="Badge with text 'CSS is Awesome'"
/>
<img
src="/static/assets/badges/queer.webp"
alt="Queer pride flag badge"
/>
<img
width="100px"
src="/static/assets/badges/skywardsword.webp"
alt="Cover art for The Legend of Zelda Skyward Sword"
/>
<img
src="/static/assets/badges/transrightsnow.webp"
alt="Trans rights badge with text 'Trans Rights Now'"
/>
<img
width="30%"
src="/static/assets/badges/kirby.gif"
alt="Kirby character animated GIF"
/>
<img
width="30%"
src="/static/assets/badges/pink.gif"
alt="Pink animated pixel art badge"
/>
<img
width="30%"
src="/static/assets/badges/trans.gif"
alt="Trans pride flag animated badge"
/>
</badges>
</box>
<box id="smallbox">
<socials-header> Socials ! </socials-header>
<socials>
<a href="https://github.com/naguiagahnim" target="_blank"><img src="/static/assets/icons/github.webp"
width="30px" alt="GitHub logo" /></a>
<a href="https://open.spotify.com/intl-fr/artist/4BPUhsH6krKkCNFrdMZnZF?si=E3luyIf0S_yfJRmm82S5OA"
target="_blank"><img src="/static/assets/icons/spotify.webp" width="30px" alt="Spotify logo" /></a>
<a href="https://www.instagram.com/agahnim_music/" target="_blank"><img src="/static/assets/icons/insta.webp"
width="30px" alt="Instagram logo" /></a>
<a href="https://github.com/naguiagahnim" target="_blank"
><img
src="/static/assets/icons/github.webp"
width="30px"
alt="GitHub logo"
/></a>
<a
href="https://open.spotify.com/intl-fr/artist/4BPUhsH6krKkCNFrdMZnZF?si=E3luyIf0S_yfJRmm82S5OA"
target="_blank"
><img
src="/static/assets/icons/spotify.webp"
width="30px"
alt="Spotify logo"
/></a>
<a href="https://www.instagram.com/agahnim_music/" target="_blank"
><img
src="/static/assets/icons/insta.webp"
width="30px"
alt="Instagram logo"
/></a>
</socials>
<img width="200px" src="/static/assets/gifs/divider2.gif" alt="Decorative divider" />
<bibou-message>Consult the wisdom of the Bibou, if thou darest...</bibou-message>
<img
width="200px"
src="/static/assets/gifs/divider2.gif"
alt="Decorative divider"
/>
<bibou-message
>Consult the wisdom of the Bibou, if thou darest...</bibou-message
>
<bibou-container>
<img class="boubou" src="/static/assets/images/boubou.webp" alt="Bibou endormi" />
<img class="bibou" src="/static/assets/images/bibou.webp" alt="Bibou éveillé" />
<img
class="boubou"
src="/static/assets/images/boubou.webp"
alt="Bibou endormi"
/>
<img
class="bibou"
src="/static/assets/images/bibou.webp"
alt="Bibou éveillé"
/>
</bibou-container>
<bibou-text>
</bibou-text>
<bibou-text> </bibou-text>
</box>
<box id="newsbox">
<website-news>
<img width="70%" src="/static/assets/gifs/updates.gif" alt="Animated text 'Updates'" />
<img
width="70%"
src="/static/assets/gifs/updates.gif"
alt="Animated text 'Updates'"
/>
{% for article in news %}
<article-entry>
<time datetime="{{ article.date }}">
{{ article.date.format("%d/%m/%Y") }}
</time>
<article-body>
{{ article.body }}
</article-body>
<img width="300px" src="/static/assets/gifs/divider2.gif" alt="Decorative divider" />
<article-body> {{ article.body }} </article-body>
<img
width="300px"
src="/static/assets/gifs/divider2.gif"
alt="Decorative divider"
/>
</article-entry>
{% else %}
<ominous-message>
Nothing to see here, for now...
</ominous-message>
<ominous-message> Nothing to see here, for now... </ominous-message>
{% endfor %}
</website-news>
</box>

View file

@ -13,31 +13,78 @@
</title-bar>
<progress-bar-container>
<input class="progress-input" type="range" min="0" max="0" value="0" step="0.01" />
<input
class="progress-input"
type="range"
min="0"
max="0"
value="0"
step="0.01"
/>
</progress-bar-container>
<controls-bar>
<transport-controls>
<button data-action="prev" aria-label="Previous">
<img src="/static/assets/svgs/skip-back.svg" width="12" height="12" alt="Skip back" />
<img
src="/static/assets/svgs/skip-back.svg"
width="12"
height="12"
alt="Skip back"
/>
</button>
<button data-action="play" aria-label="Play/Pause">
<img class="play-icon" src="/static/assets/svgs/play.svg" width="12" height="12" alt="Play" />
<img class="pause-icon" src="/static/assets/svgs/pause.svg" width="12" height="12" alt="Pause" style="display: none;" />
<img
class="play-icon"
src="/static/assets/svgs/play.svg"
width="12"
height="12"
alt="Play"
/>
<img
class="pause-icon"
src="/static/assets/svgs/pause.svg"
width="12"
height="12"
alt="Pause"
style="display: none"
/>
</button>
<button data-action="next" aria-label="Next">
<img src="/static/assets/svgs/skip-forward.svg" width="12" height="12" alt="Skip forward" />
<img
src="/static/assets/svgs/skip-forward.svg"
width="12"
height="12"
alt="Skip forward"
/>
</button>
</transport-controls>
<volume-controls>
<img src="/static/assets/svgs/volume-2.svg" width="12" height="12" alt="Volume" />
<input class="volume-input" type="range" min="0" max="1" step="0.01" value="0.7" />
<img
src="/static/assets/svgs/volume-2.svg"
width="12"
height="12"
alt="Volume"
/>
<input
class="volume-input"
type="range"
min="0"
max="1"
step="0.01"
value="0.7"
/>
</volume-controls>
</controls-bar>
<audio hidden>
{% for track in tracks %}
<source src="{{ track.src }}" data-index="{{ loop.index0 }}" data-title="{{ track.title }}" data-artist="{{ track.artist }}" />
<source
src="{{ track.src }}"
data-index="{{ loop.index0 }}"
data-title="{{ track.title }}"
data-artist="{{ track.artist }}"
/>
{% endfor %}
</audio>
{% endif %}

View file

@ -6,17 +6,17 @@
</music>
<script>
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const container = document.getElementById('bg-text');
const container = document.getElementById("bg-text");
const colWidth = 20;
const rowHeight = 24;
const cols = Math.ceil(window.innerWidth / colWidth);
const rows = Math.ceil(window.innerHeight / rowHeight);
for (let c = 0; c < cols; c++) {
const col = document.createElement('vertical-marquee-inner');
col.style.left = (c * colWidth) + 'px';
const col = document.createElement("vertical-marquee-inner");
col.style.left = c * colWidth + "px";
for (let r = 0; r < rows; r++) {
const span = document.createElement('text');
const span = document.createElement("text");
span.textContent = chars[Math.floor(Math.random() * chars.length)];
col.appendChild(span);
}

View file

@ -1,4 +1,10 @@
<katcenkat>
<img src="/static/assets/images/notfound.webp" alt="Pink text, 404 Not Found" />
<img src="/static/assets/images/leuf.webp" alt="A drawing depicting a cute but fat cat" />
<img
src="/static/assets/images/notfound.webp"
alt="Pink text, 404 Not Found"
/>
<img
src="/static/assets/images/leuf.webp"
alt="A drawing depicting a cute but fat cat"
/>
</katcenkat>

9
treefmt.toml Normal file
View file

@ -0,0 +1,9 @@
[formatter.rustfmt]
command = "rustfmt"
options = ["--edition", "2024"]
includes = ["*.rs"]
[formatter.prettier]
command = "prettier"
options = ["--write"]
includes = ["*.html", "*.css", "*.js", "*.ts", "*.json", "*.md"]