summaryrefslogtreecommitdiff
path: root/public
diff options
context:
space:
mode:
authorKyren223 <contact@kyren.codes>2026-10-08 19:44:46 +0300
committerKyren223 <contact@kyren.codes>2026-10-08 19:44:46 +0300
commit9b03d2790b8b8db1b5a6755b6130f37e5f7f2455 (patch)
treea84f6e9cfe2b8aaf087d55830c938443f6be683e /public
parent6e70fe447ec9504757fbdc152b5b3697c9af8def (diff)
WIP
Diffstat (limited to 'public')
-rw-r--r--public/copy.js14
-rw-r--r--public/main.css5
-rw-r--r--public/my_uptime.js18
-rw-r--r--public/scrollbar.js52
-rw-r--r--public/style.css376
-rw-r--r--public/styles/terminal.css23
6 files changed, 404 insertions, 84 deletions
diff --git a/public/copy.js b/public/copy.js
new file mode 100644
index 0000000..751f2ae
--- /dev/null
+++ b/public/copy.js
@@ -0,0 +1,14 @@
+document.addEventListener("click", async (e) => {
+ const el = e.target.closest("[data-copy]");
+ if (!el) return;
+ try {
+ await navigator.clipboard.writeText(el.dataset.copy);
+ } catch (err) {
+ console.error("copy failed:", err);
+ return;
+ }
+ const scope = el.closest("[data-copy-scope]") ?? el;
+ scope.setAttribute("data-copied", "");
+ clearTimeout(scope._copyTimer);
+ scope._copyTimer = setTimeout(() => scope.removeAttribute("data-copied"), 1500);
+});
diff --git a/public/main.css b/public/main.css
index f93965c..772f896 100644
--- a/public/main.css
+++ b/public/main.css
@@ -5,3 +5,8 @@
@source "../**/*.go";
@source "../**/*.templ";
+
+@keyframes pop { 50% { transform: scale(1.3); } }
+[data-copied] svg { animation: pop 0.25s; }
+
+@keyframes bump { 50% { transform: scale(1.03); } }
diff --git a/public/my_uptime.js b/public/my_uptime.js
new file mode 100644
index 0000000..25f549a
--- /dev/null
+++ b/public/my_uptime.js
@@ -0,0 +1,18 @@
+async function updateUptime() {
+ try {
+ const res = await fetch("/api/my-uptime");
+ if (!res.ok) return;
+ const data = await res.json();
+
+ const text = document.getElementById("Uptime");
+
+ if (text && text.textContent !== data.uptime) {
+ text.textContent = data.uptime;
+ }
+ } catch (e) {}
+}
+
+// Run on page load after all DOM elements loaded
+DOMContentLoaded(updateUptime());
+
+setInterval(updateUptime, 5 * 1000); // in ms
diff --git a/public/scrollbar.js b/public/scrollbar.js
new file mode 100644
index 0000000..da6aded
--- /dev/null
+++ b/public/scrollbar.js
@@ -0,0 +1,52 @@
+function initScrollbox(box) {
+ const area = box.querySelector("[data-scroll-area]");
+ const track = box.querySelector("[data-scroll-track]");
+ const thumb = box.querySelector("[data-scroll-thumb]");
+
+ const inset = () => parseFloat(getComputedStyle(thumb).left) || 0;
+
+ const update = () => {
+ const pad = inset();
+ const room = track.clientHeight - pad * 2;
+ const maxScroll = area.scrollHeight - area.clientHeight;
+ const ratio = Math.min(1, area.clientHeight / area.scrollHeight);
+ const height = Math.max(room * ratio, thumb.clientWidth);
+ const progress = maxScroll > 0 ? area.scrollTop / maxScroll : 0;
+ thumb.style.height = `${height}px`;
+ thumb.style.top = `${pad + progress * (room - height)}px`;
+ };
+
+ thumb.addEventListener("pointerdown", (e) => {
+ e.preventDefault();
+ thumb.setPointerCapture(e.pointerId);
+ const startY = e.clientY;
+ const startTop = parseFloat(thumb.style.top) || 0;
+
+ const move = (ev) => {
+ const pad = inset();
+ const room = track.clientHeight - pad * 2 - thumb.offsetHeight;
+ const top = Math.min(
+ Math.max(startTop - pad + ev.clientY - startY, 0),
+ room,
+ );
+ const progress = room > 0 ? top / room : 0;
+ area.scrollTop = progress * (area.scrollHeight - area.clientHeight);
+ };
+ const stop = () => {
+ thumb.removeEventListener("pointermove", move);
+ thumb.removeEventListener("pointerup", stop);
+ thumb.removeEventListener("pointercancel", stop);
+ };
+ thumb.addEventListener("pointermove", move);
+ thumb.addEventListener("pointerup", stop);
+ thumb.addEventListener("pointercancel", stop);
+ });
+
+ area.addEventListener("scroll", update, { passive: true });
+ const observer = new ResizeObserver(update);
+ observer.observe(area);
+ for (const child of area.children) observer.observe(child);
+ update();
+}
+
+document.querySelectorAll("[data-scrollbox]").forEach(initScrollbox);
diff --git a/public/style.css b/public/style.css
index d1e775f..c555b7d 100644
--- a/public/style.css
+++ b/public/style.css
@@ -13,6 +13,8 @@
--text-3xl--line-height: calc(2.25 / 1.875);
--font-weight-normal: 400;
--font-weight-bold: 700;
+ --default-transition-duration: 150ms;
+ --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: var(--font-sans);
--default-mono-font-family: var(--font-mono);
}
@@ -178,18 +180,54 @@
.fixed {
position: fixed;
}
+ .relative {
+ position: relative;
+ }
.static {
position: static;
}
+ .inset-x-\[0\.3rem\] {
+ inset-inline: 0.3rem;
+ }
+ .top-1 {
+ top: var(--spacing);
+ }
+ .top-1\/2 {
+ top: calc(1 / 2 * 100%);
+ }
.top-\[-0\.7em\] {
top: -0.7em;
}
+ .top-\[-0\.75rem\] {
+ top: -0.75rem;
+ }
+ .top-\[0\.6rem\] {
+ top: 0.6rem;
+ }
+ .right-\[0\.6rem\] {
+ right: 0.6rem;
+ }
+ .right-full {
+ right: 100%;
+ }
.bottom-\[-0\.7em\] {
bottom: -0.7em;
}
+ .bottom-\[-0\.75rem\] {
+ bottom: -0.75rem;
+ }
.left-\[0\.5em\] {
left: 0.5em;
}
+ .left-\[0\.625rem\] {
+ left: 0.625rem;
+ }
+ .col-span-2 {
+ grid-column: span 2 / span 2;
+ }
+ .-m-\[0\.4rem\] {
+ margin: calc(0.4rem * -1);
+ }
.m-0 {
margin: 0px;
}
@@ -217,6 +255,9 @@
.my-\[5vw\] {
margin-block: 5vw;
}
+ .mt-\[0\.5rem\] {
+ margin-top: 0.5rem;
+ }
.mt-\[0\.625vw\] {
margin-top: 0.625vw;
}
@@ -229,6 +270,9 @@
.mt-\[10vw\] {
margin-top: 10vw;
}
+ .mr-2 {
+ margin-right: calc(var(--spacing) * 2);
+ }
.mr-\[0\.1vw\] {
margin-right: 0.1vw;
}
@@ -241,21 +285,24 @@
.mb-6 {
margin-bottom: calc(var(--spacing) * 6);
}
- .mb-6\.25 {
- margin-bottom: calc(var(--spacing) * 6.25);
- }
- .mb-\[1\.5625rem\] {
- margin-bottom: 1.5625rem;
+ .mb-\[0\.30rem\] {
+ margin-bottom: 0.30rem;
}
.mb-\[1\.5625vw\] {
margin-bottom: 1.5625vw;
}
+ .mb-\[1rem\] {
+ margin-bottom: 1rem;
+ }
.mb-\[5vw\] {
margin-bottom: 5vw;
}
.mb-\[7vw\] {
margin-bottom: 7vw;
}
+ .-ml-\[0\.1rem\] {
+ margin-left: calc(0.1rem * -1);
+ }
.ml-\[-4vw\] {
margin-left: -4vw;
}
@@ -280,6 +327,9 @@
.h-0 {
height: 0px;
}
+ .h-38 {
+ height: calc(var(--spacing) * 38);
+ }
.h-\[9\.5vw\] {
height: 9.5vw;
}
@@ -307,42 +357,24 @@
.max-h-\[80svh\] {
max-height: 80svh;
}
+ .min-h-0 {
+ min-height: 0px;
+ }
.w-0 {
width: 0px;
}
- .w-300 {
- width: calc(var(--spacing) * 300);
+ .w-8 {
+ width: calc(var(--spacing) * 8);
}
.w-\[30\%\] {
width: 30%;
}
- .w-\[40rem\] {
- width: 40rem;
- }
.w-\[67\%\] {
width: 67%;
}
.w-\[70\%\] {
width: 70%;
}
- .w-\[75\.0rem\] {
- width: 75.0rem;
- }
- .w-\[75\.001rem\] {
- width: 75.001rem;
- }
- .w-\[75\.1rem\] {
- width: 75.1rem;
- }
- .w-\[75\.12rem\] {
- width: 75.12rem;
- }
- .w-\[75\.13rem\] {
- width: 75.13rem;
- }
- .w-\[75\.123rem\] {
- width: 75.123rem;
- }
.w-\[75rem\] {
width: 75rem;
}
@@ -364,18 +396,41 @@
.flex-1 {
flex: 1;
}
+ .flex-shrink {
+ flex-shrink: 1;
+ }
+ .shrink-0 {
+ flex-shrink: 0;
+ }
.border-collapse {
border-collapse: collapse;
}
+ .-translate-y-1 {
+ --tw-translate-y: calc(var(--spacing) * -1);
+ translate: var(--tw-translate-x) var(--tw-translate-y);
+ }
+ .-translate-y-1\/2 {
+ --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
+ translate: var(--tw-translate-x) var(--tw-translate-y);
+ }
.transform {
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
}
+ .cursor-grab {
+ cursor: grab;
+ }
.cursor-pointer {
cursor: pointer;
}
+ .touch-none {
+ touch-action: none;
+ }
.resize {
resize: both;
}
+ .\[scrollbar-width\:none\] {
+ scrollbar-width: none;
+ }
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@@ -385,6 +440,9 @@
.grid-cols-5 {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
+ .grid-cols-\[29\%_1fr\] {
+ grid-template-columns: 29% 1fr;
+ }
.flex-col {
flex-direction: column;
}
@@ -394,21 +452,24 @@
.justify-between {
justify-content: space-between;
}
+ .gap-4 {
+ gap: calc(var(--spacing) * 4);
+ }
.gap-10 {
gap: calc(var(--spacing) * 10);
}
.gap-16 {
gap: calc(var(--spacing) * 16);
}
- .gap-20 {
- gap: calc(var(--spacing) * 20);
- }
.gap-\[1\.25vw\] {
gap: 1.25vw;
}
.gap-\[1ch\] {
gap: 1ch;
}
+ .gap-x-8 {
+ column-gap: calc(var(--spacing) * 8);
+ }
.gap-x-\[5vw\] {
column-gap: 5vw;
}
@@ -417,6 +478,9 @@
margin-inline-start: calc(1.25vw * var(--tw-space-x-reverse));
margin-inline-end: calc(1.25vw * calc(1 - var(--tw-space-x-reverse)));
}
+ .gap-y-4 {
+ row-gap: calc(var(--spacing) * 4);
+ }
.truncate {
overflow: hidden;
text-overflow: ellipsis;
@@ -434,29 +498,16 @@
.overflow-y-auto {
overflow-y: auto;
}
- .border {
- border-style: var(--tw-border-style);
- border-width: 1px;
- }
- .border-0 {
- border-style: var(--tw-border-style);
- border-width: 0px;
+ .rounded-\[0\.4rem\] {
+ border-radius: 0.4rem;
}
- .border-1 {
+ .border {
border-style: var(--tw-border-style);
border-width: 1px;
}
- .border-2 {
- border-style: var(--tw-border-style);
- border-width: 2px;
- }
- .border-3 {
- border-style: var(--tw-border-style);
- border-width: 3px;
- }
- .border-10 {
+ .border-\[0\.1rem\] {
border-style: var(--tw-border-style);
- border-width: 10px;
+ border-width: 0.1rem;
}
.border-\[0\.1vw\] {
border-style: var(--tw-border-style);
@@ -466,10 +517,6 @@
border-style: var(--tw-border-style);
border-width: 0.2rem;
}
- .border-\[0\.25rem\] {
- border-style: var(--tw-border-style);
- border-width: 0.25rem;
- }
.border-\[0\.25vh\] {
border-style: var(--tw-border-style);
border-width: 0.25vh;
@@ -494,6 +541,15 @@
.border-\[var\(--alt\)\] {
border-color: var(--alt);
}
+ .bg-\(--background\) {
+ background-color: var(--background);
+ }
+ .bg-\(--secondary\) {
+ background-color: var(--secondary);
+ }
+ .bg-\[var\(--background\)\] {
+ background-color: var(--background);
+ }
.fill-\[\#7ed4fb\]\/50 {
fill: color-mix(in oklab, #7ed4fb 50%, transparent);
}
@@ -509,57 +565,57 @@
.p-0 {
padding: 0px;
}
- .p-2 {
- padding: calc(var(--spacing) * 2);
- }
- .p-3 {
- padding: calc(var(--spacing) * 3);
- }
.p-4 {
padding: calc(var(--spacing) * 4);
}
.p-8 {
padding: calc(var(--spacing) * 8);
}
- .p-10 {
- padding: calc(var(--spacing) * 10);
+ .p-\[0\.4rem\] {
+ padding: 0.4rem;
}
.p-\[0\.8em\] {
padding: 0.8em;
}
- .p-\[2\.0rem\] {
- padding: 2.0rem;
- }
- .p-\[2\.2rem\] {
- padding: 2.2rem;
+ .p-\[1rem\] {
+ padding: 1rem;
}
.p-\[2\.2svh\] {
padding: 2.2svh;
}
- .p-\[2\.5rem\] {
- padding: 2.5rem;
- }
- .p-\[2\.rem\] {
- padding: 2.rem;
- }
- .p-\[2rem\] {
- padding: 2rem;
- }
.p-\[3vw\] {
padding: 3vw;
}
+ .px-3 {
+ padding-inline: calc(var(--spacing) * 3);
+ }
+ .px-3\.5 {
+ padding-inline: calc(var(--spacing) * 3.5);
+ }
.px-\[0\.1vw\] {
padding-inline: 0.1vw;
}
+ .px-\[0\.4rem\] {
+ padding-inline: 0.4rem;
+ }
.px-\[0\.5em\] {
padding-inline: 0.5em;
}
+ .px-\[0\.625rem\] {
+ padding-inline: 0.625rem;
+ }
+ .py-\(--ypad\) {
+ padding-block: var(--ypad);
+ }
.py-16 {
padding-block: calc(var(--spacing) * 16);
}
.py-\[0\.625vw\] {
padding-block: 0.625vw;
}
+ .pt-3 {
+ padding-top: calc(var(--spacing) * 3);
+ }
.pt-\[1\.0625em\] {
padding-top: 1.0625em;
}
@@ -569,6 +625,9 @@
.pt-\[5vw\] {
padding-top: 5vw;
}
+ .pt-\[calc\(var\(--ypad\)\+0\.0625rem\)\] {
+ padding-top: calc(var(--ypad) + 0.0625rem);
+ }
.pr-\[1\.25vw\] {
padding-right: 1.25vw;
}
@@ -584,19 +643,24 @@
.font-mono {
font-family: var(--font-mono);
}
- .text-3xl {
- font-size: var(--text-3xl);
- line-height: var(--tw-leading, var(--text-3xl--line-height));
+ .text-\[0\.8rem\] {
+ font-size: 0.8rem;
}
.text-\[0\.96vw\] {
font-size: 0.96vw;
}
+ .text-\[0\.675rem\] {
+ font-size: 0.675rem;
+ }
.text-\[1\.125rem\] {
font-size: 1.125rem;
}
.text-\[1\.375rem\] {
font-size: 1.375rem;
}
+ .text-\[1rem\] {
+ font-size: 1rem;
+ }
.text-\[2\.5vw\] {
font-size: 2.5vw;
}
@@ -618,6 +682,14 @@
.text-\[130\%\] {
font-size: 130%;
}
+ .leading-\[normal\] {
+ --tw-leading: normal;
+ line-height: normal;
+ }
+ .font-\[150\%\] {
+ --tw-font-weight: 150%;
+ font-weight: 150%;
+ }
.font-bold {
--tw-font-weight: var(--font-weight-bold);
font-weight: var(--font-weight-bold);
@@ -626,18 +698,60 @@
--tw-font-weight: var(--font-weight-normal);
font-weight: var(--font-weight-normal);
}
+ .wrap-anywhere {
+ overflow-wrap: anywhere;
+ }
+ .whitespace-nowrap {
+ white-space: nowrap;
+ }
+ .text-\(--accent\) {
+ color: var(--accent);
+ }
+ .text-\(--alt\) {
+ color: var(--alt);
+ }
+ .text-\(--extra\) {
+ color: var(--extra);
+ }
.text-\(--primary\) {
color: var(--primary);
}
+ .text-\(--secondary\) {
+ color: var(--secondary);
+ }
+ .text-\[\#54D7A9\] {
+ color: #54D7A9;
+ }
+ .text-\[\#D8C44B\] {
+ color: #D8C44B;
+ }
+ .text-\[\#F16265\] {
+ color: #F16265;
+ }
+ .text-\[--\] {
+ color: --;
+ }
+ .text-\[--accent\] {
+ color: --accent;
+ }
+ .text-\[--extra\] {
+ color: --extra;
+ }
+ .text-\[--secondary\] {
+ color: --secondary;
+ }
+ .text-\[color\:var\(--alt\)\] {
+ color: var(--alt);
+ }
.text-\[var\(--accent\)\] {
color: var(--accent);
}
- .text-\[var\(--primary\)\] {
- color: var(--primary);
- }
.text-\[var\(--secondary\)\] {
color: var(--secondary);
}
+ .no-underline {
+ text-decoration-line: none;
+ }
.underline {
text-decoration-line: underline;
}
@@ -648,6 +762,27 @@
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
+ .transition-colors {
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
+ }
+ .select-text {
+ -webkit-user-select: text;
+ user-select: text;
+ }
+ .\[--border-py\:0\.5rem\] {
+ --border-py: 0.5rem;
+ }
+ .\[--border-py\:0\.75rem\] {
+ --border-py: 0.75rem;
+ }
+ .\[--border-py\:0\.875rem\] {
+ --border-py: 0.875rem;
+ }
+ .\[--ypad\:var\(--border-py\,0\.875rem\)\] {
+ --ypad: var(--border-py,0.875rem);
+ }
@media (hover: hover) {
.group-hover\:text-\[var\(--alt\)\]:is(:where(.group):hover *) {
color: var(--alt);
@@ -658,10 +793,29 @@
.group-hover\:underline:is(:where(.group):hover *) {
text-decoration-line: underline;
}
- .hover\:text-\(--accent\):hover {
- color: var(--accent);
+ }
+ .group-data-copied\:block:is(:where(.group)[data-copied] *) {
+ display: block;
+ }
+ .group-data-copied\/copy\:block:is(:where(.group\/copy)[data-copied] *) {
+ display: block;
+ }
+ .group-data-copied\/copy\:bg-\(--primary\)\/25\!:is(:where(.group\/copy)[data-copied] *) {
+ background-color: var(--primary) !important;
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--primary) 25%, transparent) !important;
}
- .hover\:text-\[var\(--accent\)\]:hover {
+ }
+ @media (hover: hover) {
+ .hover\:bg-\(--alt\)\/25:hover {
+ background-color: var(--alt);
+ }
+ @supports (color: color-mix(in lab, red, red)) {
+ .hover\:bg-\(--alt\)\/25:hover {
+ background-color: color-mix(in oklab, var(--alt) 25%, transparent);
+ }
+ }
+ .hover\:text-\(--accent\):hover {
color: var(--accent);
}
.hover\:text-\[var\(--alt\)\]:hover {
@@ -673,6 +827,18 @@
.hover\:text-gray-700:hover {
color: var(--color-gray-700);
}
+ .hover\:no-underline:hover {
+ text-decoration-line: none;
+ }
+ }
+ .data-copied\:animate-\[bump_0\.25s\][data-copied] {
+ animation: bump 0.25s;
+ }
+ .data-copied\:bg-\(--primary\)\/25\![data-copied] {
+ background-color: var(--primary) !important;
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--primary) 25%, transparent) !important;
+ }
}
@media (width >= 40rem) {
.sm\:invisible {
@@ -835,6 +1001,40 @@
grid-template-columns: repeat(1, minmax(0, 1fr));
}
}
+ .\[\&\:\:-webkit-scrollbar\]\:hidden::-webkit-scrollbar {
+ display: none;
+ }
+ .\[\&\>\*\+\*\]\:mt-\[-0\.1rem\] > * + * {
+ margin-top: -0.1rem;
+ }
+}
+@keyframes pop {
+ 50% {
+ transform: scale(1.3);
+ }
+}
+[data-copied] svg {
+ animation: pop 0.25s;
+}
+@keyframes bump {
+ 50% {
+ transform: scale(1.03);
+ }
+}
+@property --tw-translate-x {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0;
+}
+@property --tw-translate-y {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0;
+}
+@property --tw-translate-z {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0;
}
@property --tw-rotate-x {
syntax: "*";
@@ -866,6 +1066,10 @@
inherits: false;
initial-value: solid;
}
+@property --tw-leading {
+ syntax: "*";
+ inherits: false;
+}
@property --tw-font-weight {
syntax: "*";
inherits: false;
@@ -878,6 +1082,9 @@
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-translate-z: 0;
--tw-rotate-x: initial;
--tw-rotate-y: initial;
--tw-rotate-z: initial;
@@ -885,6 +1092,7 @@
--tw-skew-y: initial;
--tw-space-x-reverse: 0;
--tw-border-style: solid;
+ --tw-leading: initial;
--tw-font-weight: initial;
--tw-outline-style: solid;
}
diff --git a/public/styles/terminal.css b/public/styles/terminal.css
index f44bcd0..e0e80aa 100644
--- a/public/styles/terminal.css
+++ b/public/styles/terminal.css
@@ -45,3 +45,26 @@ body {
color: var(--accent);
}
}
+
+.scrollbox::-webkit-scrollbar {
+ width: 1.5rem;
+}
+.scrollbox::-webkit-scrollbar-track {
+ background: transparent;
+ border-left: 0.1rem solid var(--alt);
+}
+.scrollbox::-webkit-scrollbar-thumb {
+ background: var(--primary);
+ border: 0.3rem solid transparent;
+ background-clip: padding-box;
+ border-radius: 0;
+}
+.scrollbox::-webkit-scrollbar-thumb:hover {
+ background: var(--accent);
+}
+
+@supports not selector(::-webkit-scrollbar) {
+ .scrollbox {
+ scrollbar-color: var(--primary) transparent;
+ }
+}