feat(oxibadge): add settings screen for shifts, rounding and language
Check, format and test / build (push) Successful in 10m22s

Add a settings screen (gear button on the month-confirmation screen)
to configure the expected shift times, the rounding step, the
interface language, and the time clock address — replacing the old
onboarding-only connection flow. Settings persist to the same
preferences.toml as the reader address, under a single load_settings/
save_settings command pair.

The review screen's "fix shifts" action now redistributes stacked
punches by nearest configured shift time instead of blind position,
and a stacked cell manually cleared down to one entry no longer
leaves a dangling empty input.

Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 18:29:57 +02:00
parent acd3efeac6
commit b65e85f908
26 changed files with 1397 additions and 118 deletions
@@ -1,8 +1,10 @@
<script lang="ts">
import { _ } from 'svelte-i18n';
import { LUNCH, ROUND_STEP, dayWord } from './analysis';
import { autofocus } from '$lib/autofocus';
import type { Shifts } from '$lib/shifts';
import { dayWord } from './analysis';
import FixButton from './FixButton.svelte';
import IconButton from './IconButton.svelte';
import IconButton from '../IconButton.svelte';
let {
name,
@@ -17,6 +19,7 @@
stackedCount,
lunchCount,
roundCount,
shift,
onfixall,
onaddlunchall,
onroundall,
@@ -34,6 +37,7 @@
stackedCount: number;
lunchCount: number;
roundCount: number;
shift: Shifts;
onfixall: () => void;
onaddlunchall: () => void;
onroundall: () => void;
@@ -51,10 +55,6 @@
editing = false;
}
function autofocus(node: HTMLInputElement) {
node.focus();
node.select();
}
</script>
<div class="main-head">
@@ -121,7 +121,7 @@
{#if lunchCount}
<FixButton
size="lg"
title={$_('review.add_lunch_title', { values: { start: LUNCH.start, end: LUNCH.end } })}
title={$_('review.add_lunch_title', { values: { start: shift.out1, end: shift.in2 } })}
onclick={onaddlunchall}
>
{#snippet icon()}
@@ -139,7 +139,7 @@
><circle cx="12" cy="13" r="8" /><path d="M12 9v4l2.5 2.5M10 2h4" /></svg
>
{/snippet}
{$_('review.round_all', { values: { step: ROUND_STEP, days: dayWord(roundCount, $_) } })}
{$_('review.round_all', { values: { step: shift.round_step_min, days: dayWord(roundCount, $_) } })}
</FixButton>
{/if}
<div class="seg" role="group" aria-label={$_('review.day_filter_aria')}>