style: visual polish — accent tokens, starfield, fixed card/output heights, focus rings, spatial fixes

This commit is contained in:
emil
2026-05-11 01:36:58 +03:00
parent 8de77203aa
commit e089dd07de
19 changed files with 240 additions and 103 deletions
+6 -6
View File
@@ -38,10 +38,10 @@ const { class: sizeClass, horizontal } = specs[size];
href={ad.href}
target="_blank"
rel="noopener sponsored"
class={`${sizeClass} flex ${horizontal ? "flex-row items-center gap-4 px-6" : "flex-col items-center justify-center gap-3 px-4"} rounded-xl border border-zinc-800 bg-zinc-900/50 hover:border-[#534AB7]/50 hover:bg-zinc-900 transition-colors duration-200 group`}
class={`${sizeClass} flex ${horizontal ? "flex-row items-center gap-4 px-6" : "flex-col items-center justify-center gap-3 px-4"} rounded-xl border border-zinc-800 bg-zinc-900/50 hover:border-accent/50 hover:bg-zinc-900 transition-colors duration-200 group`}
>
<svg
class="shrink-0 text-[#FC3F1D]"
class="shrink-0 text-yandex"
width={horizontal ? "32" : "40"}
height={horizontal ? "32" : "40"}
viewBox="0 0 40 40"
@@ -62,12 +62,12 @@ const { class: sizeClass, horizontal } = specs[size];
<div class="text-xs font-medium text-zinc-500 uppercase tracking-widest mb-0.5">
Реклама
</div>
<div class="text-sm font-semibold text-zinc-100 group-hover:text-[#534AB7] transition-colors leading-tight">
<div class="text-sm font-semibold text-zinc-100 group-hover:text-accent transition-colors leading-tight">
{ad.label}
</div>
<div class="text-xs text-zinc-500 mt-0.5">{ad.sublabel}</div>
</div>
<span class="shrink-0 text-xs font-semibold text-white bg-[#FC3F1D] px-3 py-1.5 rounded-lg group-hover:bg-[#e03518] transition-colors whitespace-nowrap">
<span class="shrink-0 text-xs font-semibold text-white bg-yandex px-3 py-1.5 rounded-lg group-hover:bg-yandex-hover transition-colors whitespace-nowrap">
{ad.cta}
</span>
</>
@@ -77,12 +77,12 @@ const { class: sizeClass, horizontal } = specs[size];
<div class="text-xs font-medium text-zinc-500 uppercase tracking-widest mb-2">
Реклама
</div>
<div class="text-base font-semibold text-zinc-100 group-hover:text-[#534AB7] transition-colors leading-snug">
<div class="text-base font-semibold text-zinc-100 group-hover:text-accent transition-colors leading-snug">
{ad.label}
</div>
<div class="text-xs text-zinc-500 mt-1">{ad.sublabel}</div>
</div>
<span class="text-xs font-semibold text-white bg-[#FC3F1D] px-4 py-2 rounded-lg group-hover:bg-[#e03518] transition-colors">
<span class="text-xs font-semibold text-white bg-yandex px-4 py-2 rounded-lg group-hover:bg-yandex-hover transition-colors">
{ad.ctaMobile}
</span>
</>
+6 -6
View File
@@ -36,31 +36,31 @@ const icons: Record<string, string> = {
isLive ? (
<a
href={href}
class="group block border border-zinc-800 rounded-xl p-5 hover:border-[#534AB7] transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7]"
class="group block h-full border border-zinc-800 rounded-xl p-5 shadow-lg shadow-black/20 hover:border-accent hover:shadow-xl hover:shadow-black/30 hover:-translate-y-0.5 transition-colors transition-shadow transition-transform duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950"
>
<div class="flex items-start justify-between gap-3">
<div
class="text-[#534AB7]"
class="inline-flex w-8 h-8 rounded-lg bg-accent/10 items-center justify-center text-accent shrink-0"
aria-hidden="true"
set:html={icons[icon] ?? icons["hash"]}
/>
<span class="text-xs font-medium text-[#534AB7] bg-[#534AB7]/10 px-2 py-0.5 rounded-full">
<span class="text-xs font-medium text-accent bg-accent/10 px-2 py-0.5 rounded-full">
{T.live}
</span>
</div>
<h2 class="mt-3 text-base font-semibold text-zinc-100 group-hover:text-[#534AB7] transition-colors duration-150">
<h2 class="mt-3 text-base font-semibold text-zinc-100 group-hover:text-accent transition-colors duration-150">
{title}
</h2>
<p class="mt-1 text-sm text-zinc-400 leading-relaxed">{description}</p>
</a>
) : (
<div
class="block border border-zinc-800/50 rounded-xl p-5 opacity-40 cursor-default"
class="block h-full border border-zinc-800/50 rounded-xl p-5 shadow-lg shadow-black/10 opacity-40 cursor-default"
aria-label={`${title} — ${T.comingSoon}`}
>
<div class="flex items-start justify-between gap-3">
<div
class="text-zinc-500"
class="inline-flex w-8 h-8 rounded-lg bg-zinc-800 items-center justify-center text-zinc-500 shrink-0"
aria-hidden="true"
set:html={icons[icon] ?? icons["hash"]}
/>
+2 -2
View File
@@ -12,7 +12,7 @@ const alternatePath = isRu
<a
href={isRu ? alternatePath : "#"}
id="lang-en"
class={`px-2 py-1 rounded-md transition-colors ${isRu ? "text-zinc-400 hover:text-zinc-200" : "bg-[#534AB7] text-white"}`}
class={`px-2 py-1 rounded-md transition-colors ${isRu ? "text-zinc-400 hover:text-zinc-200" : "bg-accent text-white"}`}
aria-current={isRu ? undefined : "true"}
data-target-lang="en"
data-alternate={isRu ? alternatePath : ""}>EN</a
@@ -20,7 +20,7 @@ const alternatePath = isRu
<a
href={isRu ? "#" : alternatePath}
id="lang-ru"
class={`px-2 py-1 rounded-md transition-colors ${isRu ? "bg-[#534AB7] text-white" : "text-zinc-400 hover:text-zinc-200"}`}
class={`px-2 py-1 rounded-md transition-colors ${isRu ? "bg-accent text-white" : "text-zinc-400 hover:text-zinc-200"}`}
aria-current={isRu ? "true" : undefined}
data-target-lang="ru"
data-alternate={isRu ? "" : alternatePath}>RU</a
+7 -5
View File
@@ -13,22 +13,24 @@ const T = useT(lang);
---
<section
class="mt-12 border-t border-zinc-800/60 pt-8 text-sm text-zinc-500 space-y-4"
class="mt-12 border-t border-zinc-800/60 pt-8 text-sm text-zinc-500 flex flex-col gap-4"
>
<div>
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<h2
class="text-xs font-semibold uppercase tracking-widest text-zinc-600 mb-2"
class="flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-zinc-400 mb-2"
>
<span class="w-1.5 h-1.5 rounded-full bg-accent" aria-hidden="true"></span>
{T.howToUse}
</h2>
<ol class="space-y-1 list-decimal list-inside">
{howTo.map((step) => <li>{step}</li>)}
</ol>
</div>
<div>
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<h2
class="text-xs font-semibold uppercase tracking-widest text-zinc-600 mb-2"
class="flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-zinc-400 mb-2"
>
<span class="w-1.5 h-1.5 rounded-full bg-accent" aria-hidden="true"></span>
{T.whenToUse}
</h2>
<ul class="space-y-1 list-disc list-inside">
+97
View File
@@ -0,0 +1,97 @@
<canvas
id="starfield"
class="fixed inset-0 w-full h-full pointer-events-none"
style="z-index: 0;"
aria-hidden="true"
></canvas>
<script>
(function () {
const canvas = document.getElementById("starfield") as HTMLCanvasElement;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
let width = 0;
let height = 0;
let stars: { x: number; y: number; size: number; speed: number; opacity: number; phase: number }[] = [];
let animationId: number;
const STAR_COUNT = 180;
const TWINKLE_SPEED = 0.0008;
function resize() {
const dpr = Math.min(window.devicePixelRatio || 1, 2);
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width * dpr;
canvas.height = height * dpr;
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
function initStars() {
stars = [];
for (let i = 0; i < STAR_COUNT; i++) {
stars.push({
x: Math.random() * width,
y: Math.random() * height,
size: Math.random() < 0.95 ? 1 : Math.random() < 0.7 ? 1.5 : 2,
speed: 0.02 + Math.random() * 0.04,
opacity: 0.15 + Math.random() * 0.55,
phase: Math.random() * Math.PI * 2,
});
}
}
function draw(time: number) {
ctx.clearRect(0, 0, width, height);
for (const star of stars) {
const twinkle =
0.6 + 0.4 * Math.sin(time * TWINKLE_SPEED + star.phase);
const alpha = star.opacity * twinkle;
ctx.beginPath();
ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
ctx.fillStyle = `rgba(210, 210, 220, ${alpha})`;
ctx.fill();
star.y -= star.speed;
if (star.y < -2) {
star.y = height + 2;
star.x = Math.random() * width;
}
}
animationId = requestAnimationFrame(draw);
}
function start() {
resize();
initStars();
animationId = requestAnimationFrame(draw);
}
function stop() {
cancelAnimationFrame(animationId);
}
start();
window.addEventListener("resize", () => {
stop();
resize();
initStars();
start();
});
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
stop();
} else {
start();
}
});
})();
</script>
@@ -5,6 +5,7 @@ const T = useT(isRu ? "ru" : "en");
---
<div id="card-generator" class="mt-8">
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<div class="flex flex-col sm:flex-row gap-4 items-end">
<div class="flex-1">
<label
@@ -18,7 +19,7 @@ const T = useT(isRu ? "ru" : "en");
value="1"
min="1"
max="52"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
aria-label={T.cardsToDraw}
/>
</div>
@@ -28,7 +29,7 @@ const T = useT(isRu ? "ru" : "en");
<input
id="crd-replace"
type="checkbox"
class="w-4 h-4 rounded accent-[#534AB7] cursor-pointer"
class="w-4 h-4 rounded accent-accent cursor-pointer"
/>
<span
class="text-sm text-zinc-400 group-hover:text-zinc-200 transition-colors"
@@ -36,6 +37,7 @@ const T = useT(isRu ? "ru" : "en");
>
</label>
</div>
</div>
<p
id="crd-error"
@@ -45,7 +47,7 @@ const T = useT(isRu ? "ru" : "en");
>
</p>
<div class="my-10 min-h-32 flex flex-col items-center justify-center gap-4">
<div class="my-6 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8 h-52 overflow-hidden flex flex-col items-center justify-center gap-4">
<div
id="crd-cards"
class="flex flex-wrap justify-center gap-2"
@@ -58,7 +60,7 @@ const T = useT(isRu ? "ru" : "en");
id="crd-copy-btn"
type="button"
aria-label="Copy cards to clipboard"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] rounded"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded"
>
<span id="crd-copy-label">{T.copy}</span>
<span id="crd-copy-icon" aria-hidden="true">
@@ -80,7 +82,7 @@ const T = useT(isRu ? "ru" : "en");
</span>
<span
id="crd-check-icon"
class="hidden text-[#534AB7]"
class="hidden text-accent"
aria-hidden="true"
>
<svg
@@ -104,7 +106,7 @@ const T = useT(isRu ? "ru" : "en");
<button
id="crd-btn"
type="button"
class="w-full sm:w-auto px-8 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
class="w-full sm:w-auto px-8 py-3 bg-accent text-white font-semibold rounded-xl shadow-lg shadow-accent/25 hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
>
{T.draw}
</button>
@@ -5,7 +5,7 @@ const T = useT(isRu ? "ru" : "en");
---
<div id="coin-generator" class="mt-8">
<div>
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<div class="flex items-center justify-between mb-1">
<label for="coin-count" class="text-sm font-medium text-zinc-400"
>{T.numberOfCoins}</label
@@ -21,7 +21,7 @@ const T = useT(isRu ? "ru" : "en");
min="1"
max="20"
value="1"
class="w-full accent-[#534AB7] cursor-pointer"
class="w-full accent-accent cursor-pointer"
aria-label={T.numberOfCoins}
/>
<div class="flex justify-between text-xs text-zinc-600 mt-1 select-none">
@@ -29,7 +29,7 @@ const T = useT(isRu ? "ru" : "en");
</div>
</div>
<div class="my-10 min-h-28 flex flex-col items-center justify-center gap-4">
<div class="my-6 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8 h-52 overflow-hidden flex flex-col items-center justify-center gap-4">
<div
id="coin-coins"
class="flex flex-wrap justify-center gap-2"
@@ -45,7 +45,7 @@ const T = useT(isRu ? "ru" : "en");
id="coin-copy-btn"
type="button"
aria-label="Copy results to clipboard"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] rounded"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded"
>
<span id="coin-copy-label">{T.copy}</span>
<span id="coin-copy-icon" aria-hidden="true">
@@ -67,7 +67,7 @@ const T = useT(isRu ? "ru" : "en");
</span>
<span
id="coin-check-icon"
class="hidden text-[#534AB7]"
class="hidden text-accent"
aria-hidden="true"
>
<svg
@@ -91,7 +91,7 @@ const T = useT(isRu ? "ru" : "en");
<button
id="coin-btn"
type="button"
class="w-full sm:w-auto px-8 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
class="w-full sm:w-auto px-8 py-3 bg-accent text-white font-semibold rounded-xl shadow-lg shadow-accent/25 hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
>
{T.flip}
</button>
@@ -147,7 +147,7 @@ const T = useT(isRu ? "ru" : "en");
coin.className = [
"flex flex-col items-center justify-center w-14 h-14 rounded-full border-2 font-bold text-xs select-none",
isHeads
? "border-[#534AB7] bg-[#534AB7]/10 text-[#534AB7]"
? "border-accent bg-accent/10 text-accent"
: "border-zinc-600 bg-zinc-800 text-zinc-400",
].join(" ");
coin.textContent = isHeads ? HEADS_LABEL : TAILS_LABEL;
@@ -5,6 +5,7 @@ const T = useT(isRu ? "ru" : "en");
---
<div id="color-generator" class="mt-8">
<div class="my-6 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8">
<!-- Swatch -->
<div class="flex justify-center mb-8">
<div
@@ -41,7 +42,7 @@ const T = useT(isRu ? "ru" : "en");
id={`${id}-copy`}
type="button"
aria-label={`Copy ${label} value`}
class="group shrink-0 p-1 rounded text-zinc-600 hover:text-zinc-300 focus:outline-none focus-visible:ring-1 focus-visible:ring-[#534AB7] transition-colors cursor-pointer"
class="group shrink-0 p-1 rounded text-zinc-600 hover:text-zinc-300 focus:outline-none focus-visible:ring-1 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors cursor-pointer"
>
<svg
id={`${id}-copy-icon`}
@@ -60,7 +61,7 @@ const T = useT(isRu ? "ru" : "en");
</svg>
<svg
id={`${id}-check-icon`}
class="hidden text-[#534AB7]"
class="hidden text-accent"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
@@ -79,12 +80,14 @@ const T = useT(isRu ? "ru" : "en");
}
</div>
</div>
<!-- Generate button -->
<div class="flex justify-center">
<button
id="cg-btn"
type="button"
class="w-full sm:w-auto px-8 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
class="w-full sm:w-auto px-8 py-3 bg-accent text-white font-semibold rounded-xl shadow-lg shadow-accent/25 hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
>
{T.generate}
</button>
+16 -14
View File
@@ -27,12 +27,13 @@ const presets = [
---
<div id="dice-generator" class="mt-8">
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<!-- Presets toggle -->
<div class="mb-2">
<button
id="dg-presets-toggle"
type="button"
class="inline-flex items-center gap-1 text-sm font-medium text-zinc-500 hover:text-zinc-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] rounded transition-colors cursor-pointer"
class="inline-flex items-center gap-1 text-sm font-medium text-zinc-500 hover:text-zinc-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded transition-colors cursor-pointer"
>
<span>{presetsLabel}</span>
<svg
@@ -60,7 +61,7 @@ const presets = [
presets.map((p) => (
<button
type="button"
class="dg-preset px-3 py-1.5 rounded-lg border border-zinc-700 text-sm font-medium text-zinc-400 hover:border-[#534AB7] hover:text-[#534AB7] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] transition-colors cursor-pointer"
class="dg-preset px-3 py-1.5 rounded-lg border border-zinc-700 text-sm font-medium text-zinc-400 hover:border-accent hover:text-accent focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors cursor-pointer"
data-preset={p.notation}
>
{p.label}
@@ -79,7 +80,7 @@ const presets = [
placeholder={notationPlaceholder}
autocomplete="off"
spellcheck="false"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base font-mono focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base font-mono focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
/>
<p id="dg-notation-err" class="mt-1 text-xs text-red-500 hidden"></p>
</div>
@@ -96,7 +97,7 @@ const presets = [
value="2"
min="1"
max="20"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
aria-label={T.numberOfDice}
/>
</div>
@@ -115,7 +116,7 @@ const presets = [
class="sr-only peer"
checked={s === "6"}
/>
<span class="inline-flex items-center justify-center w-10 h-10 rounded-lg border border-zinc-700 text-sm font-semibold text-zinc-400 peer-checked:border-[#534AB7] peer-checked:text-[#534AB7] peer-checked:bg-[#534AB7]/10 hover:border-zinc-500 transition-colors select-none">
<span class="inline-flex items-center justify-center w-10 h-10 rounded-lg border border-zinc-700 text-sm font-semibold text-zinc-400 peer-checked:border-accent peer-checked:text-accent peer-checked:bg-accent/10 hover:border-zinc-500 transition-colors select-none">
d{s}
</span>
</label>
@@ -151,7 +152,7 @@ const presets = [
checked={value === "normal"}
/>
<span
class={`inline-flex items-center justify-center px-3 sm:px-4 h-9 text-sm font-medium text-zinc-400 peer-checked:text-[#534AB7] peer-checked:bg-[#534AB7]/10 hover:text-zinc-200 transition-colors select-none whitespace-nowrap${i < 2 ? " border-r border-zinc-700" : ""}`}
class={`inline-flex items-center justify-center px-3 sm:px-4 h-9 text-sm font-medium text-zinc-400 peer-checked:text-accent peer-checked:bg-accent/10 hover:text-zinc-200 transition-colors select-none whitespace-nowrap${i < 2 ? " border-r border-zinc-700" : ""}`}
>
{label}
</span>
@@ -170,9 +171,10 @@ const presets = [
class="mt-3 text-sm text-red-500 hidden"
>
</p>
</div>
<!-- Results -->
<div class="my-10 min-h-28 flex flex-col items-center justify-center gap-3">
<div class="my-6 h-52 overflow-hidden flex flex-col items-center justify-center gap-3 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8">
<div
id="dg-dice"
class="flex flex-wrap justify-center gap-2"
@@ -199,7 +201,7 @@ const presets = [
id="dg-copy-btn"
type="button"
aria-label="Copy results to clipboard"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] rounded"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded"
>
<span id="dg-copy-label">{T.copy}</span>
<span id="dg-copy-icon" aria-hidden="true">
@@ -219,7 +221,7 @@ const presets = [
></path>
</svg>
</span>
<span id="dg-check-icon" class="hidden text-[#534AB7]" aria-hidden="true">
<span id="dg-check-icon" class="hidden text-accent" aria-hidden="true">
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
@@ -242,7 +244,7 @@ const presets = [
<button
id="dg-btn"
type="button"
class="w-full sm:w-auto px-8 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
class="w-full sm:w-auto px-8 py-3 bg-accent text-white font-semibold rounded-xl shadow-lg shadow-accent/25 hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
>
{T.roll}
</button>
@@ -257,7 +259,7 @@ const presets = [
<button
id="dg-clear-btn"
type="button"
class="text-xs text-zinc-600 hover:text-zinc-300 transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-[#534AB7] rounded"
class="text-xs text-zinc-600 hover:text-zinc-300 transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded"
>
{clearHistory}
</button>
@@ -563,7 +565,7 @@ const presets = [
const text = String(v);
const color =
v === sides
? "border-[#534AB7] text-[#534AB7] bg-[#534AB7]/10"
? "border-accent text-accent bg-accent/10"
: v === 1
? "border-red-700/50 text-red-400 bg-red-900/10"
: "border-zinc-700 text-zinc-100 bg-zinc-900";
@@ -576,7 +578,7 @@ const presets = [
function dieHtml(v, sides) {
const cls =
v === sides
? "text-[#534AB7] font-bold"
? "text-accent font-bold"
: v === 1
? "text-red-400 font-bold"
: "text-zinc-300";
@@ -632,7 +634,7 @@ const presets = [
}
let color =
d.value === sides
? "text-[#534AB7]"
? "text-accent"
: d.value === 1
? "text-red-400"
: "text-zinc-100";
+10 -8
View File
@@ -5,6 +5,7 @@ const T = useT(isRu ? "ru" : "en");
---
<div id="list-generator" class="mt-8">
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<div class="flex flex-col gap-4">
<div>
<label
@@ -21,7 +22,7 @@ const T = useT(isRu ? "ru" : "en");
Bob
Carol
David"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-sm font-mono focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors resize-y"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-sm font-mono focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors resize-y"
aria-label={T.items}></textarea>
</div>
@@ -36,7 +37,7 @@ David"
type="number"
value="1"
min="1"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
aria-label={T.pick}
/>
</div>
@@ -46,7 +47,7 @@ David"
<input
id="lst-replace"
type="checkbox"
class="w-4 h-4 rounded accent-[#534AB7] cursor-pointer"
class="w-4 h-4 rounded accent-accent cursor-pointer"
/>
<span
class="text-sm text-zinc-400 group-hover:text-zinc-200 transition-colors"
@@ -63,8 +64,9 @@ David"
class="mt-3 text-sm text-red-500 hidden"
>
</p>
</div>
<div class="my-8 min-h-16 flex flex-col items-center justify-center gap-3">
<div class="my-6 h-52 overflow-hidden flex flex-col items-center justify-center gap-3 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8">
<div
id="lst-result"
class="flex flex-wrap justify-center gap-2"
@@ -77,7 +79,7 @@ David"
id="lst-copy-btn"
type="button"
aria-label="Copy picked items to clipboard"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] rounded"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded"
>
<span id="lst-copy-label">{T.copy}</span>
<span id="lst-copy-icon" aria-hidden="true">
@@ -99,7 +101,7 @@ David"
</span>
<span
id="lst-check-icon"
class="hidden text-[#534AB7]"
class="hidden text-accent"
aria-hidden="true"
>
<svg
@@ -123,7 +125,7 @@ David"
<button
id="lst-btn"
type="button"
class="w-full sm:w-auto px-8 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
class="w-full sm:w-auto px-8 py-3 bg-accent text-white font-semibold rounded-xl shadow-lg shadow-accent/25 hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
>
{T.pick}
</button>
@@ -212,7 +214,7 @@ David"
const chip = document.createElement("span");
chip.textContent = item;
chip.className =
"inline-flex items-center px-3 py-1.5 rounded-full border border-[#534AB7]/40 bg-[#534AB7]/10 text-zinc-100 text-sm font-medium";
"inline-flex items-center px-3 py-1.5 rounded-full border border-accent/40 bg-accent/10 text-zinc-100 text-sm font-medium";
resultEl.appendChild(chip);
});
@@ -5,6 +5,7 @@ const T = useT(isRu ? "ru" : "en");
---
<div id="lottery-generator" class="mt-8">
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div>
<label for="lg-from" class="block text-sm font-medium text-zinc-400 mb-1"
@@ -14,7 +15,7 @@ const T = useT(isRu ? "ru" : "en");
id="lg-from"
type="number"
value="1"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
/>
</div>
<div>
@@ -25,7 +26,7 @@ const T = useT(isRu ? "ru" : "en");
id="lg-to"
type="number"
value="49"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
/>
</div>
<div>
@@ -37,7 +38,7 @@ const T = useT(isRu ? "ru" : "en");
type="number"
value="6"
min="1"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
/>
</div>
</div>
@@ -49,8 +50,9 @@ const T = useT(isRu ? "ru" : "en");
class="mt-3 text-sm text-red-500 hidden"
>
</p>
</div>
<div class="my-10 min-h-24 flex flex-col items-center justify-center gap-4">
<div class="my-6 h-52 overflow-hidden flex flex-col items-center justify-center gap-4 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8">
<div
id="lg-result"
class="flex flex-wrap justify-center gap-2"
@@ -60,7 +62,7 @@ const T = useT(isRu ? "ru" : "en");
<button
id="lg-copy-btn"
type="button"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] rounded"
class="invisible inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded"
>
<span id="lg-copy-label">{T.copy}</span>
<span id="lg-copy-icon" aria-hidden="true"
@@ -79,7 +81,7 @@ const T = useT(isRu ? "ru" : "en");
></path></svg
></span
>
<span id="lg-check-icon" class="hidden text-[#534AB7]" aria-hidden="true"
<span id="lg-check-icon" class="hidden text-accent" aria-hidden="true"
><svg
xmlns="http://www.w3.org/2000/svg"
width="14"
@@ -99,7 +101,7 @@ const T = useT(isRu ? "ru" : "en");
<button
id="lg-btn"
type="button"
class="w-full sm:w-auto px-8 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
class="w-full sm:w-auto px-8 py-3 bg-accent text-white font-semibold rounded-xl shadow-lg shadow-accent/25 hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
>
{T.draw}
</button>
@@ -178,7 +180,7 @@ const T = useT(isRu ? "ru" : "en");
const ball = document.createElement("span");
ball.textContent = String(n);
ball.className =
"inline-flex items-center justify-center min-w-[2.5rem] h-10 px-2 rounded-full bg-[#534AB7]/15 border border-[#534AB7]/40 text-zinc-100 font-bold tabular-nums text-sm";
"inline-flex items-center justify-center min-w-[2.5rem] h-10 px-2 rounded-full bg-accent/15 border border-accent/40 text-zinc-100 font-bold tabular-nums text-sm";
resultEl.appendChild(ball);
});
copyBtn.classList.remove("invisible");
@@ -5,6 +5,7 @@ const T = useT(isRu ? "ru" : "en");
---
<div id="number-generator" class="mt-8" data-ru={isRu ? "1" : "0"}>
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<div class="flex flex-col sm:flex-row gap-4">
<div class="flex-1">
<label for="ng-from" class="block text-sm font-medium text-zinc-400 mb-1"
@@ -14,7 +15,7 @@ const T = useT(isRu ? "ru" : "en");
id="ng-from"
type="number"
value="1"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
/>
</div>
<div class="flex-1">
@@ -25,10 +26,11 @@ const T = useT(isRu ? "ru" : "en");
id="ng-to"
type="number"
value="100"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
/>
</div>
</div>
</div>
<p
id="ng-error"
@@ -38,11 +40,12 @@ const T = useT(isRu ? "ru" : "en");
>
</p>
<div class="my-10 min-h-36 flex flex-col items-center justify-center gap-3">
<div class="my-6 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8 h-52 overflow-hidden">
<div class="h-full flex flex-col items-center justify-center gap-3">
<button
id="ng-copy-btn"
type="button"
class="group relative invisible cursor-copy rounded-xl px-3 py-1 -mx-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7]"
class="group relative invisible cursor-copy rounded-xl px-3 py-1 -mx-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950"
aria-live="polite"
>
<span
@@ -72,7 +75,7 @@ const T = useT(isRu ? "ru" : "en");
</span>
<span
id="ng-check-icon"
class="absolute -right-7 top-1/2 -translate-y-1/2 hidden text-[#534AB7]"
class="absolute -right-7 top-1/2 -translate-y-1/2 hidden text-accent"
aria-hidden="true"
>
<svg
@@ -90,17 +93,18 @@ const T = useT(isRu ? "ru" : "en");
</button>
<span
id="ng-copied-label"
class="text-xs font-medium text-[#534AB7] opacity-0 transition-opacity duration-200"
class="text-xs font-medium text-accent opacity-0 transition-opacity duration-200"
aria-live="polite"
aria-atomic="true">{T.copied}</span
>
</div>
</div>
<div class="flex justify-center">
<button
id="ng-btn"
type="button"
class="w-full sm:w-auto px-8 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
class="w-full sm:w-auto px-8 py-3 bg-accent text-white font-semibold rounded-xl hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer shadow-lg shadow-accent/25"
>
{T.generate}
</button>
@@ -5,6 +5,7 @@ const T = useT(isRu ? "ru" : "en");
---
<div id="password-generator" class="mt-8">
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<div class="flex flex-col gap-5">
<div>
<div class="flex items-center justify-between mb-1">
@@ -22,7 +23,7 @@ const T = useT(isRu ? "ru" : "en");
min="4"
max="64"
value="16"
class="w-full accent-[#534AB7] cursor-pointer"
class="w-full accent-accent cursor-pointer"
/>
<div class="flex justify-between text-xs text-zinc-600 mt-1 select-none">
<span>4</span><span>64</span>
@@ -41,7 +42,7 @@ const T = useT(isRu ? "ru" : "en");
id={id}
type="checkbox"
checked
class="w-4 h-4 rounded accent-[#534AB7] cursor-pointer"
class="w-4 h-4 rounded accent-accent cursor-pointer"
/>
<span class="text-sm text-zinc-400 group-hover:text-zinc-200 transition-colors">
{label}
@@ -51,6 +52,7 @@ const T = useT(isRu ? "ru" : "en");
}
</div>
</div>
</div>
<p
id="pg-error"
@@ -60,11 +62,11 @@ const T = useT(isRu ? "ru" : "en");
>
</p>
<div class="my-10 min-h-24 flex flex-col items-center justify-center gap-3">
<div class="my-6 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8 h-52 overflow-hidden flex flex-col items-center justify-center gap-3">
<button
id="pg-copy-btn"
type="button"
class="group relative invisible cursor-copy rounded-xl px-3 py-2 -mx-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7]"
class="group relative invisible cursor-copy rounded-xl px-3 py-2 -mx-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950"
>
<span
id="pg-result"
@@ -92,7 +94,7 @@ const T = useT(isRu ? "ru" : "en");
</span>
<span
id="pg-check-icon"
class="absolute -right-7 top-1/2 -translate-y-1/2 hidden text-[#534AB7]"
class="absolute -right-7 top-1/2 -translate-y-1/2 hidden text-accent"
aria-hidden="true"
>
<svg
@@ -110,7 +112,7 @@ const T = useT(isRu ? "ru" : "en");
</button>
<span
id="pg-copied-label"
class="text-xs font-medium text-[#534AB7] opacity-0 transition-opacity duration-200"
class="text-xs font-medium text-accent opacity-0 transition-opacity duration-200"
aria-live="polite"
aria-atomic="true">{T.copied}</span
>
@@ -120,7 +122,7 @@ const T = useT(isRu ? "ru" : "en");
<button
id="pg-btn"
type="button"
class="w-full sm:w-auto px-8 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
class="w-full sm:w-auto px-8 py-3 bg-accent text-white font-semibold rounded-xl shadow-lg shadow-accent/25 hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
>
{T.generate}
</button>
@@ -5,6 +5,7 @@ const T = useT(isRu ? "ru" : "en");
---
<div id="uuid-generator" class="mt-8">
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<div class="flex flex-col gap-4">
<div>
<label class="block text-sm font-medium text-zinc-400 mb-2"
@@ -25,7 +26,7 @@ const T = useT(isRu ? "ru" : "en");
class="sr-only peer"
checked={value === "uuid"}
/>
<span class="inline-flex items-center justify-center px-4 h-9 rounded-lg border border-zinc-700 text-sm font-medium text-zinc-400 peer-checked:border-[#534AB7] peer-checked:text-[#534AB7] peer-checked:bg-[#534AB7]/10 hover:border-zinc-500 transition-colors select-none cursor-pointer">
<span class="inline-flex items-center justify-center px-4 h-9 rounded-lg border border-zinc-700 text-sm font-medium text-zinc-400 peer-checked:border-accent peer-checked:text-accent peer-checked:bg-accent/10 hover:border-zinc-500 transition-colors select-none cursor-pointer">
{label}
</span>
</label>
@@ -47,7 +48,7 @@ const T = useT(isRu ? "ru" : "en");
value="16"
min="4"
max="64"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
aria-label={T.lengthBytes}
/>
</div>
@@ -62,15 +63,16 @@ const T = useT(isRu ? "ru" : "en");
value="1"
min="1"
max="20"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-base focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors"
aria-label={T.count}
/>
</div>
</div>
</div>
</div>
<div
class="my-8 min-h-16 flex flex-col gap-2"
class="my-6 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8 h-52 overflow-hidden flex flex-col gap-2"
aria-live="polite"
aria-label="Generated tokens"
>
@@ -80,7 +82,7 @@ const T = useT(isRu ? "ru" : "en");
id="ug-copy-btn"
type="button"
aria-label="Copy all tokens to clipboard"
class="invisible self-start inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] rounded mt-1"
class="invisible self-start inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded mt-1"
>
<span id="ug-copy-label">{T.copyAll}</span>
<span id="ug-copy-icon" aria-hidden="true">
@@ -100,7 +102,7 @@ const T = useT(isRu ? "ru" : "en");
></path>
</svg>
</span>
<span id="ug-check-icon" class="hidden text-[#534AB7]" aria-hidden="true">
<span id="ug-check-icon" class="hidden text-accent" aria-hidden="true">
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
@@ -122,7 +124,7 @@ const T = useT(isRu ? "ru" : "en");
<button
id="ug-btn"
type="button"
class="w-full sm:w-auto px-8 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
class="w-full sm:w-auto px-8 py-3 bg-accent text-white font-semibold rounded-xl shadow-lg shadow-accent/25 hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer"
>
{T.generate}
</button>
+7 -5
View File
@@ -6,6 +6,7 @@ const T = useT(isRu ? "ru" : "en");
<div id="wheel-spinner" class="mt-8">
<!-- Items input -->
<div class="rounded-xl bg-zinc-900/50 border border-zinc-800/60 p-5">
<div class="flex flex-col gap-3">
<div>
<label
@@ -18,7 +19,7 @@ const T = useT(isRu ? "ru" : "en");
<textarea
id="ws-items"
rows="6"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-sm font-mono focus:outline-none focus:border-[#534AB7] focus:ring-1 focus:ring-[#534AB7] transition-colors resize-y"
class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 text-sm font-mono focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition-colors resize-y"
>Alice Bob Carol Dave Eve Frank</textarea
>
</div>
@@ -30,6 +31,7 @@ const T = useT(isRu ? "ru" : "en");
>
</p>
</div>
</div>
<!-- Wheel area -->
<div class="flex flex-col items-center mt-8 gap-6">
@@ -49,7 +51,7 @@ const T = useT(isRu ? "ru" : "en");
<button
id="ws-spin-btn"
type="button"
class="w-full sm:w-auto px-10 py-3 bg-[#534AB7] text-white font-semibold rounded-lg hover:bg-[#4740a0] active:bg-[#3d3990] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
class="w-full sm:w-auto px-10 py-3 bg-accent text-white font-semibold rounded-xl shadow-lg shadow-accent/25 hover:bg-accent-hover active:bg-accent-active focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 transition-colors duration-100 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
>
{T.spin}
</button>
@@ -58,7 +60,7 @@ const T = useT(isRu ? "ru" : "en");
<!-- Result card (hidden until first spin) -->
<div
id="ws-result-card"
class="hidden mt-10 flex flex-col items-center gap-3"
class="hidden my-6 rounded-2xl bg-zinc-900/80 border border-zinc-800/80 p-8 h-52 overflow-hidden flex flex-col items-center gap-3"
aria-live="polite"
>
<p
@@ -74,7 +76,7 @@ const T = useT(isRu ? "ru" : "en");
<button
id="ws-copy-btn"
type="button"
class="inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] rounded"
class="inline-flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded"
>
<span id="ws-copy-label">{T.copy}</span>
<span id="ws-copy-icon" aria-hidden="true">
@@ -94,7 +96,7 @@ const T = useT(isRu ? "ru" : "en");
></path>
</svg>
</span>
<span id="ws-check-icon" class="hidden text-[#534AB7]" aria-hidden="true">
<span id="ws-check-icon" class="hidden text-accent" aria-hidden="true">
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
+14 -4
View File
@@ -1,6 +1,7 @@
---
import { getRelativeLocaleUrl } from "astro:i18n";
import LanguageSwitcher from "../components/LanguageSwitcher.astro";
import Starfield from "../components/Starfield.astro";
import Analytics from "../components/Analytics.astro";
import { useT } from "../i18n/translations";
import type { Lang } from "../i18n/translations";
@@ -31,7 +32,7 @@ const webPageSchema = {
---
<!doctype html>
<html lang={lang}>
<html lang={lang} style="scroll-behavior:smooth;scrollbar-gutter:stable">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -51,7 +52,7 @@ const webPageSchema = {
type="application/ld+json"
set:html={JSON.stringify(webPageSchema)}
/>
<meta name="theme-color" content="#534AB7" />
<meta name="theme-color" content="#534ab7" />
<link rel="manifest" href="/manifest.json" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<slot name="head" />
@@ -64,8 +65,11 @@ const webPageSchema = {
</script>
</head>
<body class="bg-zinc-950 text-zinc-100 min-h-screen font-sans antialiased">
<LanguageSwitcher />
<slot />
<Starfield />
<div class="relative z-10">
<LanguageSwitcher />
<slot />
</div>
</body>
</html>
@@ -84,6 +88,11 @@ const webPageSchema = {
@theme {
--font-sans: "Space Grotesk", sans-serif;
--color-accent: #534ab7;
--color-accent-hover: #4740a0;
--color-accent-active: #3d3990;
--color-yandex: #fc3f1d;
--color-yandex-hover: #e03518;
}
:root {
@@ -106,6 +115,7 @@ const webPageSchema = {
rgba(83, 74, 183, 0.13) 0%,
transparent 65%
);
background-size: auto, auto;
}
input[type="number"] {
+5 -2
View File
@@ -68,7 +68,7 @@ const breadcrumbSchema = {
<nav aria-label="Breadcrumb" class="mb-10">
<a
href={isRu ? "/ru/" : "/"}
class="inline-flex items-center gap-1.5 text-sm text-zinc-500 hover:text-zinc-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#534AB7] rounded"
class="inline-flex items-center gap-1.5 text-sm text-zinc-600 hover:text-zinc-300 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 rounded"
aria-label={T.backToAll}
>
<svg
@@ -92,7 +92,7 @@ const breadcrumbSchema = {
<header class="mb-2">
<div class="flex items-center gap-2 mb-4">
<span
class="inline-block w-2.5 h-2.5 rounded-full bg-[#534AB7]"
class="inline-block w-2.5 h-2.5 rounded-full bg-accent"
aria-hidden="true"></span>
<span
class="text-sm font-medium text-zinc-400 uppercase tracking-widest"
@@ -102,14 +102,17 @@ const breadcrumbSchema = {
<h1 class="text-3xl sm:text-4xl font-bold text-zinc-100">
{isRu ? generator.ruPageTitle : generator.pageTitle}
</h1>
<div class="w-16 h-0.5 bg-accent/60 rounded-full mt-4" aria-hidden="true"></div>
<p class="mt-2 text-base text-zinc-400">
{isRu ? generator.ruDescription : generator.description}
</p>
</header>
<div class="border-t border-zinc-800/60 pt-8 mt-8">
<main>
<slot />
</main>
</div>
<div class="mt-12 flex justify-center">
<AdBanner size="tile" />
+8 -4
View File
@@ -27,9 +27,13 @@ const webSiteSchema = {
/>
<div class="max-w-4xl mx-auto px-4 py-12 sm:py-20">
<header class="mb-12">
<div class="flex items-center gap-2 mb-6">
<div class="relative flex items-center gap-2 mb-6">
<div
class="absolute -left-16 -top-12 w-64 h-64 rounded-full bg-accent/20 blur-3xl pointer-events-none"
aria-hidden="true"
></div>
<span
class="inline-block w-3 h-3 rounded-full bg-[#534AB7]"
class="inline-block w-3 h-3 rounded-full bg-accent"
aria-hidden="true"></span>
<span class="text-xl font-bold tracking-tight text-zinc-100"
>{T.brandLabel}</span
@@ -38,7 +42,7 @@ const webSiteSchema = {
<h1 class="text-3xl sm:text-4xl font-bold text-zinc-100 leading-tight">
{T.homeTitle}
</h1>
<p class="mt-3 text-base text-zinc-400 max-w-md">
<p class="mt-3 text-base text-zinc-300 max-w-md">
{T.homeSubtitle}
</p>
</header>
@@ -48,7 +52,7 @@ const webSiteSchema = {
<main class="mt-8">
<div
class="grid gap-3"
style="grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));"
style="grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); grid-auto-rows: 1fr;"
role="list"
aria-label="Generator catalog"
>
+2 -2
View File
@@ -29,7 +29,7 @@ const webSiteSchema = {
<header class="mb-12">
<div class="flex items-center gap-2 mb-6">
<span
class="inline-block w-3 h-3 rounded-full bg-[#534AB7]"
class="inline-block w-3 h-3 rounded-full bg-accent"
aria-hidden="true"></span>
<span class="text-xl font-bold tracking-tight text-zinc-100"
>{T.brandLabel}</span
@@ -48,7 +48,7 @@ const webSiteSchema = {
<main class="mt-8">
<div
class="grid gap-3"
style="grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));"
style="grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); grid-auto-rows: 1fr;"
role="list"
aria-label="Generator catalog"
>