Files
core-cooldown/src/lib/components/MicrobreakOverlay.svelte
T
Your Name 5c064b2dc9 a11y: Tasks 9,13-17 — Settings ARIA, MiniTimer, overlays, ColorPicker, ActivityManager
- Settings: breathing radiogroup/radio, sound aria-pressed, contrast tokens,
  placeholder contrast, reset aria-live, abbreviation tags, title tooltips,
  back button 44px target
- MiniTimer: paused text #555→#a8a8a8 for AAA contrast
- MicrobreakOverlay: alertdialog role, sr-only heading, aria-describedby
- BreakOverlay: alertdialog role, sr-only heading, aria-label
- ColorPicker: enlarge swatches 22→28px with 44px hit areas, aria-pressed
- ActivityManager: enlarge action buttons to 44px targets, contrast tokens
2026-02-18 19:18:15 +02:00

82 lines
2.8 KiB
Svelte

<script lang="ts">
import { onMount } from "svelte";
import { listen } from "@tauri-apps/api/event";
import { invoke } from "@tauri-apps/api/core";
import type { TimerSnapshot } from "../stores/timer";
import { loadConfig, config } from "../stores/config";
import { pickRandomActivity, getCategoryLabel, type BreakActivity } from "../utils/activities";
let timeRemaining = $state(20);
let totalDuration = $state(20);
let activity = $state<BreakActivity | null>(null);
const progress = $derived(totalDuration > 0 ? 1 - timeRemaining / totalDuration : 0);
onMount(async () => {
await loadConfig();
if ($config.microbreak_show_activity) {
// Pick an eye-focused activity for microbreaks
activity = pickRandomActivity(undefined, $config);
}
try {
const snap = await invoke<TimerSnapshot>("get_timer_state");
timeRemaining = snap.microbreakTimeRemaining;
totalDuration = snap.microbreakTotalDuration;
} catch {}
await listen<TimerSnapshot>("timer-tick", (event) => {
const snap = event.payload;
timeRemaining = snap.microbreakTimeRemaining;
totalDuration = snap.microbreakTotalDuration;
});
await listen("microbreak-ended", () => {
// Window will be closed by backend
});
});
</script>
<div class="microbreak-card" role="alertdialog" aria-label="Microbreak" aria-describedby="microbreak-msg">
<h2 class="sr-only">Microbreak</h2>
<div class="flex items-center gap-3 mb-2">
<svg aria-hidden="true" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#7c6aef" stroke-width="1.5">
<path d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"/>
<circle cx="12" cy="12" r="3"/>
</svg>
<span id="microbreak-msg" class="text-[15px] font-medium text-white">Look away — 20 feet for {timeRemaining}s</span>
</div>
{#if activity && $config.microbreak_show_activity}
<p class="text-[12px] text-text-sec mb-3 ml-[34px]">
{activity.text}
</p>
{/if}
<!-- Progress bar -->
<div class="h-[3px] w-full rounded-full overflow-hidden" style="background: rgba(255,255,255,0.05);">
<div
class="h-full transition-[width] duration-1000 ease-linear rounded-full"
style="width: {progress * 100}%; background: linear-gradient(to right, #7c6aef, #4361ee);"
></div>
</div>
</div>
<style>
.microbreak-card {
position: fixed;
top: 16px;
left: 50%;
transform: translateX(-50%);
width: 380px;
background: rgba(12, 12, 12, 0.95);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 16px;
padding: 16px 20px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}
</style>