41 Commits

Author SHA1 Message Date
Florian Schroedl
6fec58ef80 refactor: move scrollbar styles to global utilities
Apply thin subtle scrollbars globally via utilities.css instead of
only on .sidebar-content. Uses scrollbar-width/scrollbar-color for
Firefox and ::-webkit-scrollbar for Chrome/Safari. Removes the
now-redundant sidebar-specific scrollbar rules.
2026-03-30 09:05:07 +02:00
Florian Schroedl
293df10590 feat: add tasks list recipe and small badge size variant
Add a shadcn-inspired tasks list recipe (src/recipes/tasks.cljc) that
composes card, table, badge, button, form, and icon components into a
full task management page with toolbar, data table, and pagination.

Add :size :sm prop to the badge component for compact inline labels
used in the tasks table. Small badges have tighter padding, smaller
font, and full pill border-radius.

Wire the tasks page into all three dev targets (hiccup, replicant,
squint) with navigation and routing. Add small badge demos to the
components overview in all targets.
2026-03-30 09:05:07 +02:00
Florian Schroedl
63e853b6ac style: spacing 2026-03-29 20:09:55 +02:00
Florian Schroedl
b9406cc024 style: spacing 2026-03-29 20:02:07 +02:00
Florian Schroedl
5449d3c0f3 feat(dialog): add overlay-based dialog pattern (dialog-overlay + dialog-panel)
For reactive frameworks (Eucalypt, etc.) where native <dialog> with
.showModal() isn't practical. dialog-overlay provides the fixed backdrop,
dialog-panel provides the content box with padding/gap/animation.

Shared inner styles (dialog-header, dialog-body, dialog-footer) work
with both native <dialog> and overlay-based patterns.
2026-03-29 13:21:19 +02:00
Florian Schroedl
5994f1d1da fix(calendar-events): remove border-radius from event pills 2026-03-29 12:23:08 +02:00
Florian Schroedl
7f1a679b74 Revert "feat(calendar-events): add view toggle, source filters, detail dialog, error banner, loading indicator"
This reverts commit d8e280df2a.
2026-03-29 11:20:55 +02:00
Florian Schroedl
d8e280df2a feat(calendar-events): add view toggle, source filters, detail dialog, error banner, loading indicator
New stateless components ported from org-mode-agenda-cli reference app:
- view-toggle: Grid/Agenda segmented control
- source-toggles: colored pill buttons for event source filtering
- event-detail-dialog: overlay with title, date, time, tags, source
- error-banner: dismissible error bar
- loading-indicator: pulsing dot for async state

Enhanced existing components:
- calendar-event-grid: added :loading?, :header-actions slots
- agenda-day-group/agenda-list: added :day-actions slot per day header
- Event data format extended with :tags and :source fields

CSS: view toggle, loading pulse animation, error banner, source toggles,
detail dialog overlay — all using theme tokens with dark mode support.

Tests: 126 tests, 794 assertions, 0 failures.
Dev demos updated in all 3 targets with full interactive calendar app.
2026-03-29 11:17:24 +02:00
Florian Schroedl
d6d205cb3b feat: add calendar docs with inline markdown rendering
Add src/ui/calendar.md with full documentation for both calendar
namespaces (picker props, event grid, ticker, agenda, event data
format, date utilities, CSS classes).

Add a minimal markdown-to-hiccup renderer (ui.markdown) that handles
headings, fenced code blocks, tables, lists, inline code, and bold.
Styled with ui/markdown.css using theme tokens.

Each dev target renders the docs inline on the Calendar page:
- Hiccup: slurps the .md file at render time
- Replicant: embeds via compile-time macro (ui.macros/inline-file)
- Squint: fetches from /calendar.md served by Vite

Also fixes calendar event grid day cells to be square (aspect-ratio: 1
with overflow: hidden instead of min-height).
2026-03-29 09:59:31 +02:00
Florian Schroedl
25f868fb69 feat: add calendar widget components
Add date picker and event calendar components inspired by shadcn/radix
Calendar and org-mode-agenda-cli.

Components:
- ui.calendar: Month grid date picker with navigation, today/selected
  highlighting, outside-month dimming. Pure date math utilities
  (days-in-month, day-of-week, calendar-days, etc.)
- ui.calendar-events: Event-aware grid with colored pills, horizontal
  day ticker strip with dot indicators, and agenda list view with
  grouped events by day

CSS: Token-based styling with dark mode support for event color
variants (accent/danger/success/warning). Responsive breakpoints.

All three targets supported (squint/cljs/clj). Dev pages show calendar
on its own page with interactive demos (date selection, month nav,
event grid, ticker, agenda list).

Tests: 27 new assertions covering date math, class generation,
component structure, event filtering/sorting.
2026-03-29 09:42:29 +02:00
Florian Schroedl
93edebf144 feat: add icon support to button, alert, badge, and form input
Button:
- :icon-left, :icon-right props for buttons with leading/trailing icons
- :icon prop for icon-only buttons (square padding via .btn-icon class)
- Icon size scales with button size (sm→sm, md/lg→sm/md)

Alert:
- Auto-assigns variant-specific icons (circle-check, alert-triangle,
  alert-circle, info) per variant
- :icon-name prop to override default, false to suppress
- Layout restructured with .alert-icon + .alert-content wrapper

Badge:
- :icon-name prop adds a leading icon before text
- .badge-icon CSS scales icon to match badge font size

Form input:
- :icon-left and :icon-right props on form-input
- Wraps input in .form-input-wrap with absolutely-positioned icon spans
- Padding adjusts automatically via .form-input--icon-left/right

All three dev targets (hiccup, replicant, squint) updated with demos.
2026-03-23 10:19:14 +01:00
Florian Schroedl
e305109324 fix(form): increase form-field gap from size-1 to size-2
The tighter size-1 gap left too little space between the label and input.
2026-03-11 18:51:10 +01:00
Florian Schroedl
e9e0b15e16 feat: add separator component
Horizontal and vertical separator (divider) with CSS classes, ARIA
role="none", and data-orientation attribute. Includes dark mode support,
unit tests, and demos in all three dev targets.
2026-03-11 18:38:20 +01:00
Florian Schroedl
64bf5e029c feat(card): add card-list component with full and inset dividers
Adds `card-list` and `card-list-item` to the card module for rendering
a list of items inside a single card background with border separators.

The `:divider` prop controls separator style:
- `:full` (default) — borders go edge-to-edge
- `:inset` — borders are inset from edges by `--size-4`h
2026-03-11 18:29:39 +01:00
Florian Schroedl
e356bc2e6a fix(form): remove left border-radius from buttons inside form-group
The `.form-group` CSS reset `border-radius: 0` only for `.form-input`
and `.form-select`, leaving `.btn` elements with their default radius
on all sides. This caused buttons inside input groups to have rounded
left corners instead of flush edges against adjacent inputs.
2026-03-11 17:09:18 +01:00
Florian Schroedl
e01cb075c6 style: change button and badge font-weight to semi-bold (600) 2026-03-11 16:55:18 +01:00
Florian Schroedl
9f3ebe453f refactor(dev): dogfood framework CSS in theme adapter panel
Replace all inline styles in theme-adapter.js with framework classes.
The panel now uses its own tokens (var(--bg-1), var(--fg-0), etc.) so
it visually adapts when you change theme colors — true dogfooding.

New framework components added to fill gaps:
- popover.css — fixed-position floating panel (.popover, .popover-br)
- chip.css + chip.cljc — selectable preset buttons (.chip, .chip-active)
- swatch.css — color preview strips (.swatch-row, .swatch)
- button.css — icon-only buttons (.btn-icon, .btn-icon-round)
- card.css — sectioned card variant (.card-flush, .card-section)
- utilities.css — text/flex helpers (.text-xs, .font-semibold, .flex-1, etc.)

Theme adapter JS shrunk from 340 to 250 lines by removing the 60-line
inline style object and applyStyle() helper.
2026-03-11 16:53:08 +01:00
Florian Schroedl
59d46700bc refactor(theme): switch color generation from HSL to OKLCH
OKLCH is a perceptually uniform color space — equal lightness values
produce equal perceived brightness across all hues, unlike HSL where
blue at 50% looks much darker than yellow at 50%.

Color scales now output oklch() CSS values directly:
  --gray-500: oklch(0.530 0.035 285);
  --accent-500: oklch(0.595 0.230 286);

The browser handles gamut mapping natively. Scale definitions in
tokens.edn use [label lightness chroma] tuples where L is 0-1
perceptual lightness, C is chroma (colorfulness), H is hue degrees.

Theme adapter updated: sliders now control OKLCH hue/chroma,
swatches render with oklch() CSS, Copy EDN outputs OKLCH config.

gen.clj includes oklch->srgb and oklch->hex for validation/tools.
2026-03-11 12:04:33 +01:00
Florian Schroedl
fa38d9f9c3 feat(theme): add HSL-based color scale generation with jon/color-tools
Replace hardcoded hex color tokens with algorithmic color scales generated
from HSL parameters. Each scale is defined by hue, saturation, and
lightness steps in tokens.edn, then converted to hex via jon/color-tools.

Color scales (gray, accent, danger, success, warning) generate 11 stops
each (50–950) into :root. Semantic tokens (bg-0, fg-0, accent, etc.)
reference scale variables with var(--gray-50), var(--accent-500), etc.
Dark theme switches which stop each semantic token points to.

Gray scale uses hue 240 with tapered saturation for a purplish tint
matching the activity-tracker aesthetic. Accent is vivid purple (hue 252).
Border radii bumped to 6/10/16px for a rounder feel.

To shift the entire palette (e.g. warm gray), change hue/saturation in
tokens.edn and run `bb build-theme`.
2026-03-11 11:31:47 +01:00
Florian Schroedl
13508f4654 fix: improve CSS layout with box-sizing reset, responsive alerts, and form spacing
- Add universal box-sizing: border-box reset to base styles
- Make alert component responsive with container queries (flex-wrap,
  full-width title/body at narrow widths)
- Increase form legend margin-bottom from --size-1 to --size-3
2026-03-11 11:09:47 +01:00
Florian Schroedl
e003e1c4a8 docs: add agent rules for dev server management and browser verification
- Section 6: Never start dev servers from the agent (prevents orphan
  processes and broken tmux panes)
- Section 7: Check tmux panes for compile errors (renumbered)
- Section 8: Verify compiled output in browser before committing
  (catches squint's silent empty-file failures)
2026-03-05 14:30:01 +01:00
Florian Schroedl
b52361ebf1 refactor(form): replace inline error text with tooltip icon
Instead of rendering error messages as `<small class="form-error">`
below inputs, errors now display as a circle-x icon inside the input
area. Hovering the icon shows the error text in a danger-styled tooltip.

- Wrap children in `.form-field-control` when error is present
- Use existing tooltip + icon components for the error indicator
- Add CSS for positioning, padding-right offset, and danger color overrides
- Update tests to match new structure
- Add pre-commit tmux server check instructions to AGENTS.md
2026-03-05 14:01:26 +01:00
Florian Schroedl
5d4eceab95 fix(form): add spacing between inline fieldset legend and radio buttons
<legend> elements have special rendering behavior inside <fieldset>
that doesn't participate properly in flexbox gap. Change
margin-bottom from 0 to var(--size-1) on .form-fieldset--inline
.form-legend to add visible spacing.
2026-03-05 13:32:52 +01:00
Florian Schroedl
6a1e185877 fix(button): remove color override on anchor buttons
`a.btn` had `color: inherit` which overrode variant-specific colors
(e.g. `--fg-on-accent` on `.btn-primary`) due to higher specificity
(element+class > class). This caused black text on primary link buttons
in light mode. Let variant classes control text color instead.
2026-03-05 13:24:41 +01:00
Florian Schroedl
425d00529e fix: disable CSS transitions during dark/light theme toggle
Add a `[data-no-transitions]` CSS rule that suppresses all transitions.
The theme toggle in all three dev targets (hiccup, replicant, squint)
sets this attribute before switching, then removes it on the next
animation frame, preventing the jarring animated color shift.
2026-03-05 13:16:07 +01:00
Florian Schroedl
c857954845 feat: add icon component with 50+ Lucide-based SVG icons
Adds a general-purpose icon system (ui.icon) with inline SVG rendering:
- 50+ icons from the Lucide icon set (navigation, actions, objects, UI,
  status, dev/technical categories)
- Size variants: sm (--size-4), md (--size-5), lg (--size-6), xl (--size-8)
- Pure data approach: icon paths stored as hiccup vectors, rendered into
  SVG with stroke="currentColor" so icons inherit text color
- API: (icon/icon {:icon-name :home :size :lg :class "custom"})

Integrates icons into the sidebar component:
- sidebar-menu-item now accepts :icon-name prop
- Renders icon in a .sidebar-menu-item-icon wrapper at :sm size

All three dev targets updated with icon gallery demo and sidebar icons.
2026-03-05 12:49:22 +01:00
Florian Schroedl
e3787363d2 feat: add focus-visible rings and refactor accordion chevron
Add global :focus-visible outline style and migrate form components
from :focus box-shadow to :focus-visible outline. Refactor accordion
chevron from CSS ::after pseudo-element to explicit span element.
2026-03-05 11:34:07 +01:00
Florian Schroedl
1b4929224b fix(accordion): place children inside content div and add group wrapper
Children were appended to the outer <details> element instead of inside
the .accordion-content div, causing text to render outside the accordion
box. Also adds .accordion-group wrapper to eliminate parent gap between
stacked items, and styles content with smaller font and muted color.
2026-03-03 17:12:29 +01:00
Florian Schroedl
0dd8a9c8bf fix(card): reduce internal spacing and bump footer button size
Refactor card to use flex column with gap-based spacing instead of
per-section padding, tightening the space between header, body, and
footer from size-6 to size-3. Add .card-footer .btn override to
render buttons at font-base size.
2026-03-03 17:08:29 +01:00
Florian Schroedl
e4ee7b750e feat(button): add link variant and polymorphic <a> rendering
When :href is provided, the button renders as <a> instead of <button>,
enabling navigation links with full button styling.

New :link variant renders as a minimal text link (underlined, accent
color, no background/padding) — works as both <button> and <a>.

CSS includes reset styles for a.btn (removes default link decoration)
and preserves underline for a.btn-link.
2026-03-03 17:04:41 +01:00
Florian Schroedl
6a3fee34c4 fix(badge): increase font size and use token-based line-height
Bump font-size from --font-xs to --font-sm and line-height from
raw 1.5 to --size-5 for better visual sizing matching oat.ink style.
2026-03-03 12:05:14 +01:00
Florian Schroedl
5cb339e04b fix(tooltip): close gap between arrow and tooltip box
The triangle's `bottom` offset was too large, leaving a visible gap
(and 1px sub-pixel seam) between the arrow and the tooltip body.
Changed from `calc(100% - 5px)` to `calc(100% - 1px)` so the arrow
slightly overlaps the box, eliminating the gap.
2026-03-03 12:03:29 +01:00
Florian Schroedl
398811305c fix(alert): vertically center alert content
Add align-items: center to .alert flex container and remove bottom
margin from .alert-title that was offsetting the text.
2026-03-03 12:00:08 +01:00
Florian Schroedl
b3da46ac02 feat(dialog): close dialog on backdrop click
Add click handlers to the dialog component for all three targets that
close the dialog when clicking the backdrop area (outside the dialog box).
Uses event.target === event.currentTarget to distinguish backdrop clicks
from content clicks.

- :clj — inline onclick attribute
- :cljs — Replicant :on {:click handler}
- :squint — :on-click handler
- CSS: cursor: pointer on ::backdrop for affordance
2026-03-03 11:50:30 +01:00
Florian Schroedl
c36ee05c68 fix: set dialog text color to use theme foreground
The native `<dialog>` element has browser-default black text that
doesn't inherit from the body, making it unreadable in dark mode.
2026-03-03 11:43:20 +01:00
Florian Schroedl
18043cb150 feat: add 13 components adapted from Oat UI
Components (.cljc + .css + tests):
- Alert (success/warning/danger/info variants)
- Badge (primary/secondary/outline/success/warning/danger)
- Card (card/card-header/card-body/card-footer)
- Accordion (collapsible with open/closed state)
- Table (headers/rows, striped/bordered variants)
- Dialog (modal with header/body/footer sections)
- Breadcrumb (nav with active item)
- Pagination (current/total with prev/next)
- Progress (value bar with color variants)
- Spinner (sm/md/lg sizes)
- Skeleton (line/box/circle/heading placeholders)
- Switch (toggle with checked/disabled states)
- Tooltip (hover text via data-tooltip attr)

CSS-only additions:
- Form elements (inputs, selects, checkboxes, radios, range, groups)
- Grid (12-column system with offsets, responsive)
- Utilities (flex, spacing, alignment, sr-only)

Also adds warning/fg-on-warning tokens to light and dark themes.
All 3 dev targets updated with full component showcase.
40 tests, 213 assertions, all passing.
2026-03-03 11:37:05 +01:00
Florian Schroedl
d55e3d3a90 refactor: remove all CSS transition animations
Remove transition properties from body (background-color/color) and
button (background-color/box-shadow/opacity) styles.
2026-03-03 11:19:59 +01:00
Florian Schroedl
609613f4fb feat: add algorithmic size and font scales
Add :scales config to tokens.edn with two generated scales:
- Size (linear): --size-1 through --size-16, base 0.25rem × N
- Font (geometric): --font-xs through --font-3xl, ratio 1.25

gen.clj computes values and emits them into :root only (not dark
theme blocks). button.css now uses scale vars instead of raw rem.
Change base or ratio in tokens.edn to recompute the entire scale.
2026-03-03 11:16:23 +01:00
Florian Schroedl
988617617c refactor: replace BEM with utility classes, move component CSS to files
- Rename CSS classes from BEM double-dash (btn--primary) to flat
  utility-style single-dash (btn-primary)
- Move button CSS from inline Clojure string in gen.clj to
  src/ui/button.css next to button.cljc
- gen.clj now auto-collects all src/ui/*.css files via babashka.fs glob
- Replace clojure.java.io with babashka.fs throughout gen.clj
- Update AGENTS.md to reflect new conventions
2026-03-03 11:11:47 +01:00
Florian Schroedl
6b4899f8bf refactor: centralize body base styles in theme.css
Move font-family, background, color, margin, and transition from
duplicated inline <style> blocks in each dev target into the CSS
generator (base-css). Dev pages now only set page-specific padding.

Also fixes hiccup target rendering the wrong font due to hiccup2
HTML-escaping quotes inside <style> tags, and adds missing <!DOCTYPE>.
2026-03-03 11:04:27 +01:00
Florian Schroedl
42ddb56d65 Init 2026-03-03 11:02:08 +01:00