Remove redundant habit copy and document goal layouts

This commit is contained in:
syntaxbullet
2026-09-05 08:07:55 +02:00
parent b832b5734e
commit 1f017caee5
5 changed files with 27 additions and 31 deletions

View File

@@ -88,6 +88,11 @@ routines on days off; creating a habit or editing one out of todays schedule
it reachable in All habits. Saved calendars expand through **View history**, with
historical corrections available inside the expanded view.
Each saved habit uses its own action layout: count goals have a prominent counter
and unit, simple check-ins place the checkbox beside the clickable heading, and
routines show their task list without an accordion. Daily schedule labels and
duplicate progress copy are omitted; days off stay explicit.
Count totals can be typed directly and saved with **Save** or Enter. Escape restores
the recorded total; plus and minus remain available. Counts may exceed the target.
New habits offer editable Reading, Get outside, and Evening routine starters, with

View File

@@ -93,11 +93,10 @@ export function HabitForm({
}
return (
<Modal id="new-habit" eyebrow="A NEW HABIT" title={<>Make it <em>yours.</em></>} description="Choose what counts as complete. Your schedule follows your accounts timezone." onClose={onCancel} closeLabel="Close new habit" busy={busy} size="compact" initialFocus="input" returnFocus={() => document.getElementById("add-habit")}>
<Modal id="new-habit" eyebrow="A NEW HABIT" title={<>Make it <em>yours.</em></>} description="Schedules follow your accounts timezone." onClose={onCancel} closeLabel="Close new habit" busy={busy} size="compact" initialFocus="input" returnFocus={() => document.getElementById("add-habit")}>
<form ref={form} className="ds-edit-content" onSubmit={submit}>
<fieldset className="ds-task-editor-fieldset" disabled={busy}>
<div className="ds-habit-starters" role="group" aria-label="Start with an idea">
<p className="ds-footnote">Start with an idea, then make it your own.</p>
<div className="ds-habit-starter-options">
{STARTERS.map((starter) => (
<Button key={starter.label} variant="secondary" onClick={() => applyStarter(starter)}>{starter.label}</Button>

View File

@@ -40,7 +40,6 @@ export function isHabitColor(value: string) {
export function HabitColorPicker({
value,
onChange,
mode = "demo",
compact = false,
}: {
value: string;
@@ -55,8 +54,8 @@ export function HabitColorPicker({
return (
<fieldset className="ds-color-picker" aria-describedby={`${id}-hint`}>
<legend>Habit color</legend>
<p id={`${id}-hint`} className="ds-footnote">
{showDetails ? "Choose a suggested shade or enter a custom color for this habits calendar." : "Choose a color for your habit."}
<p id={`${id}-hint`} className={showDetails ? "ds-footnote" : "ds-visually-hidden"}>
Custom colors use six-digit hex values, such as #426582.
</p>
{compact && (
<>
@@ -156,13 +155,6 @@ export function HabitColorPicker({
<span className="ds-muted">0 complete</span>
</div>
)}
<p className="ds-footnote">
{mode === "create"
? "Saved with your habit."
: mode === "edit"
? "Save to apply this color; Cancel restores the saved color."
: "Charts preview changes immediately. Save keeps the demo color; Cancel reverts it."}
</p>
{!valid && (
<p id={`${id}-error`} role="alert" className="ds-form-feedback">
Use a six-digit hex color, such as #426582.

View File

@@ -135,7 +135,7 @@ test("invalid custom colors associate both guidance and corrective feedback", as
await act(async () => root.render(<HabitColorPicker value="#bad" onChange={() => {}} />));
const input = container.querySelector('input[type="text"]')!;
expect(input.getAttribute("aria-invalid")).toBe("true");
expect(description(input)).toContain("Choose a suggested shade");
expect(description(input)).toContain("Custom colors use six-digit hex values");
expect(description(input)).toContain("Use a six-digit hex color");
});

View File

@@ -540,24 +540,24 @@ function SavedHabit({
habit.requirements?.method === "tasks" ? (
<>
<ul className="ds-routine-items">
{habit.requirements.tasks.map((config) => {
const occurrence = habit.tasks.find((task) => task.taskId === config.id);
return (
<SavedTask
key={config.id}
task={{ taskId: config.id, name: config.name, done: occurrence?.done ?? false }}
disabled={disabled}
blocked={blocked || !occurrence}
scheduled={!!occurrence}
schedule={config.schedule}
habitSchedule={habit.requirements!.schedule}
date={date}
onCheck={(done) => void onUpdate(habit, { done }, config.id)}
onSave={(patch) => onManage(habit, patch, config.id)}
onDelete={() => onManage(habit, null, config.id)}
/>
);
})}
{habit.requirements.tasks.map((config) => {
const occurrence = habit.tasks.find((task) => task.taskId === config.id);
return (
<SavedTask
key={config.id}
task={{ taskId: config.id, name: config.name, done: occurrence?.done ?? false }}
disabled={disabled}
blocked={blocked || !occurrence}
scheduled={!!occurrence}
schedule={config.schedule}
habitSchedule={habit.requirements!.schedule}
date={date}
onCheck={(done) => void onUpdate(habit, { done }, config.id)}
onSave={(patch) => onManage(habit, patch, config.id)}
onDelete={() => onManage(habit, null, config.id)}
/>
);
})}
</ul>
{addingTask && (
<InlineTaskEditor