feat(ux): B3.6 — editable energy labels (global + per-profile) + first-tap prompt

Settings → Energy: edit global energy labels (label + description per
level) with reset-to-defaults. Per-profile override toggle in the
Profiles section ("Customise for this profile" / "Use global").
EnergyChip and Tasks-page energy controls now resolve labels via
resolveEnergyLabels(profile, settings) — global by default, profile
override when present.

First-time prompt: on first energy-chip tap of the day (per profile)
or first-ever tap to Zero, an inline non-modal prompt asks "What does
Zero mean for you today?" with example chips. Per-day gate via
energyPromptLastShownDate; one-shot first-Zero gate via
energyPromptZeroSeen; Settings escape resets both.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-26 19:30:06 +01:00
parent 7daf5677c9
commit fc3a56c0dc
6 changed files with 375 additions and 19 deletions

View File

@@ -41,6 +41,20 @@ const PROFILES_KEY = "kon_profiles";
const TASK_LISTS_KEY = "kon_task_lists";
const TEMPLATES_KEY = "kon_templates";
/**
* B3.6 — exported energy-label defaults so the Settings "Reset to
* defaults" button can pull them without reaching into the private
* `defaults` block. Returns a fresh object on each call so callers
* cannot mutate the source-of-truth.
*/
export function defaultEnergyLabels(): SettingsState["energyLabels"] {
return {
high: { label: "High", description: "Sharp focus, big lifts" },
medium: { label: "Medium", description: "Steady work, moderate lifts" },
brain_dead: { label: "Zero", description: "Rest only, low-touch admin" },
};
}
const defaults: SettingsState = {
engine: "whisper",
modelSize: "Base",
@@ -97,11 +111,13 @@ const defaults: SettingsState = {
sparklineRangeDays: 7,
// Defaults mirror current EnergyChip copy so existing behaviour is
// unchanged until the user edits via the (B3.6) UI.
energyLabels: {
high: { label: "High", description: "Sharp focus, big lifts" },
medium: { label: "Medium", description: "Steady work, moderate lifts" },
brain_dead: { label: "Zero", description: "Rest only, low-touch admin" },
},
energyLabels: defaultEnergyLabels(),
// B3.6 — first-tap energy-prompt gates. Default ON for prompts;
// never-shown date stamp; first-Zero one-shot unfired. The merge in
// loadSettings will fill these on existing installs as well.
energyPromptsEnabled: true,
energyPromptLastShownDate: null,
energyPromptZeroSeen: false,
};
function canUseStorage(): boolean {