Add cue-anchored "When [cue], [action]" framing to the task-decomposition prompt where natural cues are present (Gollwitzer-style implementation intentions, d=0.65 effect size). Soften Bionic Reading and accessibility- font copy to honest preference framing per the v3 audit (Strukelj 2024; Doyon n=2,074). Update timer nudge from "Still on that timer?" (which read as judgmental) to "Timer's still running." Replace stale Tasks page header copy promising automatic extraction. Audio envelopes (focusTimer 20ms ramp, sounds.ts 10ms attack) verified correct per memo §B; no code change needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
114 lines
4.8 KiB
Svelte
114 lines
4.8 KiB
Svelte
<script lang="ts">
|
|
import type { FontFamily, ReduceMotion } from "$lib/types/app";
|
|
import { getPreferences, updateAccessibility } from '$lib/stores/preferences.svelte.js';
|
|
import Toggle from '$lib/components/Toggle.svelte';
|
|
import SegmentedButton from '$lib/components/SegmentedButton.svelte';
|
|
|
|
const prefs = getPreferences();
|
|
|
|
const fontOptions = [
|
|
{ id: 'lexend', label: 'Lexend' },
|
|
{ id: 'atkinson', label: 'Atkinson' },
|
|
{ id: 'opendyslexic', label: 'OpenDyslexic' },
|
|
] satisfies { id: FontFamily; label: string }[];
|
|
|
|
let bionicChecked = $state(prefs.accessibility.bionicReading || false);
|
|
let motionValue = $state(
|
|
prefs.accessibility.reduceMotion === 'on' ? 'On'
|
|
: prefs.accessibility.reduceMotion === 'off' ? 'Off'
|
|
: 'System'
|
|
);
|
|
|
|
$effect(() => {
|
|
if (bionicChecked !== prefs.accessibility.bionicReading) {
|
|
updateAccessibility({ bionicReading: bionicChecked });
|
|
}
|
|
});
|
|
|
|
$effect(() => {
|
|
const mapped: ReduceMotion = motionValue === 'On' ? 'on' : motionValue === 'Off' ? 'off' : 'system';
|
|
if (mapped !== prefs.accessibility.reduceMotion) {
|
|
updateAccessibility({ reduceMotion: mapped });
|
|
}
|
|
});
|
|
|
|
function rangeValue(event: Event): number {
|
|
return Number((event.currentTarget as HTMLInputElement).value);
|
|
}
|
|
</script>
|
|
|
|
<div class="flex flex-col gap-5">
|
|
<!-- Font family -->
|
|
<div class="flex flex-col gap-2">
|
|
<p class="text-[12px] text-text-secondary font-medium">Body font</p>
|
|
<div class="flex gap-2">
|
|
{#each fontOptions as opt}
|
|
<button
|
|
class="flex-1 px-3 py-2 rounded-lg text-[12px] border
|
|
{prefs.accessibility.fontFamily === opt.id
|
|
? 'border-accent bg-accent-subtle text-text'
|
|
: 'border-border-subtle text-text-secondary hover:border-border'}"
|
|
style="font-family: {opt.id === 'lexend' ? "'Lexend'" : opt.id === 'atkinson' ? "'Atkinson Hyperlegible Next'" : "'OpenDyslexic'"}; transition-duration: var(--duration-ui)"
|
|
onclick={() => updateAccessibility({ fontFamily: opt.id })}
|
|
>
|
|
{opt.label}
|
|
</button>
|
|
{/each}
|
|
</div>
|
|
<p class="text-[11px] text-text-tertiary leading-relaxed">Pick whichever feels easier to read. Evidence on dyslexia-specific fonts is contested — this is preference, not prescription.</p>
|
|
</div>
|
|
|
|
<!-- Font size -->
|
|
<div class="flex flex-col gap-1.5">
|
|
<div class="flex justify-between">
|
|
<p class="text-[12px] text-text-secondary font-medium">Font size</p>
|
|
<span class="text-[11px] text-text-tertiary">{prefs.accessibility.fontSize}px</span>
|
|
</div>
|
|
<input type="range" min="16" max="24" step="1" value={prefs.accessibility.fontSize}
|
|
oninput={(e) => updateAccessibility({ fontSize: rangeValue(e) })}
|
|
class="w-full accent-accent" />
|
|
</div>
|
|
|
|
<!-- Letter spacing -->
|
|
<div class="flex flex-col gap-1.5">
|
|
<div class="flex justify-between">
|
|
<p class="text-[12px] text-text-secondary font-medium">Letter spacing</p>
|
|
<span class="text-[11px] text-text-tertiary">{prefs.accessibility.letterSpacing.toFixed(2)}em</span>
|
|
</div>
|
|
<input type="range" min="0" max="0.15" step="0.01" value={prefs.accessibility.letterSpacing}
|
|
oninput={(e) => updateAccessibility({ letterSpacing: rangeValue(e) })}
|
|
class="w-full accent-accent" />
|
|
</div>
|
|
|
|
<!-- Line height -->
|
|
<div class="flex flex-col gap-1.5">
|
|
<div class="flex justify-between">
|
|
<p class="text-[12px] text-text-secondary font-medium">Line height</p>
|
|
<span class="text-[11px] text-text-tertiary">{prefs.accessibility.lineHeight.toFixed(1)}</span>
|
|
</div>
|
|
<input type="range" min="1.3" max="2.2" step="0.1" value={prefs.accessibility.lineHeight}
|
|
oninput={(e) => updateAccessibility({ lineHeight: rangeValue(e) })}
|
|
class="w-full accent-accent" />
|
|
</div>
|
|
|
|
<!-- Transcript font size -->
|
|
<div class="flex flex-col gap-1.5">
|
|
<div class="flex justify-between">
|
|
<p class="text-[12px] text-text-secondary font-medium">Transcript font size</p>
|
|
<span class="text-[11px] text-text-tertiary">{prefs.accessibility.transcriptSize}px</span>
|
|
</div>
|
|
<input type="range" min="16" max="24" step="1" value={prefs.accessibility.transcriptSize}
|
|
oninput={(e) => updateAccessibility({ transcriptSize: rangeValue(e) })}
|
|
class="w-full accent-accent" />
|
|
</div>
|
|
|
|
<!-- Bionic reading -->
|
|
<Toggle label="Bionic reading" description="Bolds the first few characters of each word. Some people find it helps; the evidence is mixed. Try it and keep it on if it feels better." bind:checked={bionicChecked} />
|
|
|
|
<!-- Reduce motion -->
|
|
<div class="flex flex-col gap-2">
|
|
<p class="text-[12px] text-text-secondary font-medium">Reduce motion</p>
|
|
<SegmentedButton options={['System', 'On', 'Off']} bind:value={motionValue} size="small" />
|
|
</div>
|
|
</div>
|