Add pomodoro, microbreaks, breathing guide, screen dimming, presentation mode, goals, multi-monitor, and activity manager
Major feature release (v0.1.3) adding 15 new features to the break timer: Backend (Rust): - Pomodoro cycle tracking with configurable short/long break pattern - Microbreak scheduling (20-20-20 rule) with independent timer - Screen dimming events with gradual opacity progression - Presentation mode detection (fullscreen app deferral) - Smart break detection (natural idle breaks counting toward goals) - Daily goal tracking and streak milestone events - Multi-monitor break overlay support - Working hours enforcement with per-day schedules - Weekly summary and natural break stats queries - Config expanded to 71 validated fields Frontend (Svelte): - 6 new components: BreathingGuide, ActivityManager, BreakOverlay, MicrobreakOverlay, DimOverlay, Celebration - Breathing guide with 5 patterns and animated pulsing halo - Activity manager with favorites, custom activities, momentum scroll - Confetti celebrations on milestones and goal completion - Dashboard indicators (pomodoro/microbreak/goal) moved inside ring - Settings reorganized into 18 logical cards - Breathing pattern selector redesigned with timing descriptions - Break activities expanded from 40 to 71 curated exercises - Sound presets expanded from 4 to 8 - Stats view with weekly summary and natural break tracking Also: version bump to 0.1.3, CHANGELOG, README and CLAUDE.md updates
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
<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">
|
||||
<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 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-[#8a8a8a] 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>
|
||||
Reference in New Issue
Block a user