fix(ui): granular sleep sources, viewport-safe tour, one aligned settings language

A night with coarse apple-health samples next to granular watch data
showed only awake and asleep — the per-session source pick now prefers
the source that knows its stages. Tour popovers clamp into the
viewport, wrap their footer and fall back to a bottom sheet on narrow
screens. Settings and admin sections share one alignment rule — icon
column left, everything else flush on the content column — with neutral
header icons, no duplicated section titles under the shell heading, and
every select on the account-style idiom with a visible chevron. The
dashboard's customize icon matches insights, the target-settings link
leaves the home charts, and the mood heatmap adopts the damped fills
the other mood charts already use.
This commit is contained in:
Marc-André Bombeck committed 2026-06-10 21:19:05 +02:00
1 parent 9f2c403f84
commit 024da9fe96
67 files changed
+545 -344

No files matched your search

+8 -10
View File
@@ -46,10 +46,13 @@ import { cn } from "@/lib/utils";
// Doing it as a background (rather than an overlay element) keeps `<select>` a
// single element, so every call site's width / margin className still composes
// straight onto it. `pe-9` reserves room so a long value never runs under the
// chevron. The chevron glyph is the same path Lucide's `ChevronDownIcon` draws,
// at `currentColor` with 50 % opacity to match the trigger.
const CHEVRON_SVG =
"url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='0.5'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E\")";
// chevron. The chevron glyph is the same path Lucide's `ChevronDownIcon` draws.
// Colour: `currentColor` inside a background-image data URI resolves to black
// (no CSS cascade reaches it), which read as a near-black arrow on the light
// theme. The stroke is therefore baked per theme into the
// `--native-select-chevron` custom property in `globals.css`, pinned to the
// theme's `--muted-foreground` — same colour the shadcn `<SelectTrigger>`
// chevron uses.
const NATIVE_SELECT_CLASS =
"border-input bg-background text-foreground ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-11 sm:h-10 w-full appearance-none rounded-md border ps-3 pe-9 py-1 text-sm shadow-xs transition-[color,box-shadow] focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none bg-[image:var(--native-select-chevron)] bg-[length:1rem] bg-[position:right_0.75rem_center] bg-no-repeat";
@@ -65,12 +68,7 @@ export const NativeSelect = React.forwardRef<
ref={ref}
data-slot="native-select"
className={cn(NATIVE_SELECT_CLASS, className)}
style={
{
"--native-select-chevron": CHEVRON_SVG,
...style,
} as React.CSSProperties
}
style={style}
{...props}
>
{children}
+5 -1
View File
@@ -63,7 +63,11 @@ function SelectTrigger({
from the right edge than the value text sits from the left — the
trigger read lopsided. Pulling the icon box 2 px toward the edge
makes the visible chevron and the value text inset symmetric. */}
<ChevronDownIcon className="-me-0.5 size-4 opacity-50" />
{/* Full-strength muted-foreground (no `opacity-50`): the halved
chevron read near-invisible on the light theme while the value
text next to it sat at full strength. The chevron now matches
the NativeSelect chevron and the input text weight. */}
<ChevronDownIcon className="text-muted-foreground -me-0.5 size-4" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
);