Initial commit -- Core Cooldown v0.1.0

Portable Windows break timer to prevent RSI and eye strain.
Tauri v2 + Svelte 5 + Tailwind CSS v4. No installer, no telemetry,
no data leaves the machine. CC0 public domain.
This commit is contained in:
Your Name
2026-02-07 01:12:32 +02:00
commit 2fc44f0d65
48 changed files with 15133 additions and 0 deletions

149
src/lib/stores/config.ts Normal file
View File

@@ -0,0 +1,149 @@
import { writable, get } from "svelte/store";
import { invoke } from "@tauri-apps/api/core";
export interface TimeRange {
start: string; // Format: "HH:MM"
end: string; // Format: "HH:MM"
}
export interface DaySchedule {
enabled: boolean;
ranges: TimeRange[];
}
export type { TimeRange, DaySchedule };
export interface Config {
break_duration: number;
break_frequency: number;
auto_start: boolean;
break_title: string;
break_message: string;
fullscreen_mode: boolean;
strict_mode: boolean;
allow_end_early: boolean;
immediately_start_breaks: boolean;
working_hours_enabled: boolean;
working_hours_schedule: DaySchedule[]; // 7 days: Mon, Tue, Wed, Thu, Fri, Sat, Sun
dark_mode: boolean;
color_scheme: string;
backdrop_opacity: number;
notification_enabled: boolean;
notification_before_break: number;
snooze_duration: number;
snooze_limit: number;
skip_cooldown: number;
sound_enabled: boolean;
sound_volume: number;
sound_preset: string;
idle_detection_enabled: boolean;
idle_timeout: number;
smart_breaks_enabled: boolean;
smart_break_threshold: number;
smart_break_count_stats: boolean;
show_break_activities: boolean;
ui_zoom: number;
accent_color: string;
break_color: string;
countdown_font: string;
background_blobs_enabled: boolean;
mini_click_through: boolean;
mini_hover_threshold: number;
}
const defaultConfig: Config = {
break_duration: 5,
break_frequency: 25,
auto_start: true,
break_title: "Rest your eyes",
break_message: "Look away from the screen. Stretch and relax.",
fullscreen_mode: true,
strict_mode: false,
allow_end_early: true,
immediately_start_breaks: false,
working_hours_enabled: false,
working_hours_schedule: [
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] }, // Monday
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] }, // Tuesday
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] }, // Wednesday
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] }, // Thursday
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] }, // Friday
{ enabled: false, ranges: [{ start: "09:00", end: "18:00" }] }, // Saturday
{ enabled: false, ranges: [{ start: "09:00", end: "18:00" }] }, // Sunday
],
dark_mode: true,
color_scheme: "Ocean",
backdrop_opacity: 0.92,
notification_enabled: true,
notification_before_break: 30,
snooze_duration: 5,
snooze_limit: 3,
skip_cooldown: 60,
sound_enabled: true,
sound_volume: 70,
sound_preset: "bell",
idle_detection_enabled: true,
idle_timeout: 120,
smart_breaks_enabled: true,
smart_break_threshold: 300,
smart_break_count_stats: false,
show_break_activities: true,
ui_zoom: 100,
accent_color: "#ff4d00",
break_color: "#7c6aef",
countdown_font: "",
background_blobs_enabled: true,
mini_click_through: true,
mini_hover_threshold: 3.0,
};
export const config = writable<Config>(defaultConfig);
export async function loadConfig() {
try {
const cfg = await invoke<Config>("get_config");
config.set(cfg);
} catch (e) {
console.error("Failed to load config:", e);
}
}
export async function saveConfig(): Promise<boolean> {
try {
const cfg = get(config);
await invoke("save_config", { config: cfg });
return true;
} catch (e) {
console.error("Failed to save config:", e);
return false;
}
}
export async function notifyConfigChanged() {
try {
const cfg = get(config);
await invoke("update_pending_config", { config: cfg });
} catch (e) {
console.error("Failed to update pending config:", e);
}
}
export async function resetConfig() {
try {
const cfg = await invoke<Config>("reset_config");
config.set(cfg);
} catch (e) {
console.error("Failed to reset config:", e);
}
}
// Debounced auto-save: updates backend immediately, persists to disk after 400ms idle
let saveTimer: ReturnType<typeof setTimeout> | null = null;
export function autoSave() {
notifyConfigChanged();
if (saveTimer) clearTimeout(saveTimer);
saveTimer = setTimeout(() => {
saveConfig();
}, 400);
}