feat: leads QR scanner — Auto/Multi modes, 4-mode fancy selector, UX polish
Scanner modes (now 4, persisted per exhibit): - Rapid: confirm tap → auto-reset (existing, fixed) - Qualify: confirm tap → navigate to lead detail (existing, fixed) - Auto: badge found → auto-add immediately, no confirmation tap needed - Multi: BarcodeDetector batch scan → responsive grid of confirm cards Multi scanner (new ae_comp__lead_qr_scanner_multi.svelte): - Native BarcodeDetector API (Chrome/Edge/Safari 17+); Firefox fallback message - 16:9 viewfinder with corner guides + "Align up to 4 badges flat" overlay - Capture Batch tap → up to 8 QR codes detected in one frame - Per-card states: loading skeleton, ready (Add/Skip), blocked (opt-out), already-captured (View/OK), adding spinner, success (auto-fade), error - Add All (N) bulk action; cards fade+scale out smoothly on dismiss Mode selector (ae_tab__add.svelte): - Replaces Rapid/Qualify toggle with collapsible 4-mode fancy select - Trigger shows active mode icon (color-coded) + name + description - 2×2 options grid expands on tap, closes on selection QR scanner element (element_qr_scanner_v3.svelte): - object-fit: cover eliminates 4:3 camera letterbox dead zone - 7-second start timeout with actionable error message - Starting/error overlays with high-contrast styling - Try Again button with RefreshCw icon Style guide updated: icon+text button rule (§8), btn/preset-filled workaround (§12) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# Aether UI — Design System Style Guidelines
|
||||
> **Version:** 1.1 (2026-03-17)
|
||||
> **Version:** 1.2 (2026-03-20)
|
||||
> **Author:** One Sky IT / Scott Idem
|
||||
> **Scope:** All Aether SvelteKit frontend components
|
||||
> **Related:** `AE__UI_Component_Patterns.md`, `ae-firefly.css`, `documentation/AE__Components.md`
|
||||
@@ -34,6 +34,7 @@ To maintain codebase health and performance, all new development must adhere to
|
||||
- **Mandatory**: Use `preset-*` classes for interactive elements (e.g., `preset-tonal-primary`).
|
||||
- **Forbidden**: Legacy Skeleton v3 `variant-*` classes.
|
||||
- **Customization**: Use Tailwind 4 `@theme` blocks for project-wide overrides.
|
||||
- **URLs**: Skeleton for Svelte for LLMs docs: https://www.skeleton.dev/llms-svelte.txt
|
||||
|
||||
### 🔣 Lucide Icons
|
||||
- **Mandatory**: Use `@lucide/svelte` components (e.g., `<Calendar size="1em" />`).
|
||||
@@ -192,6 +193,7 @@ Always wrap in `{#if $lq__obj}{...}{:else}...skeleton...{/if}` — **never** sho
|
||||
| Form inputs | Visible `<label>` linked via `for` / `id`, or explicit `aria-label` |
|
||||
| Color-only information | Always pair color coding with icon or text — never color alone |
|
||||
| Minimum touch target | 44×44px effective hit area for all tap targets |
|
||||
| Button label + icon | All buttons should include **both a Lucide icon and text label**. Icon-only is acceptable for space-constrained toolbar/header actions (with `title` attribute); text-only is acceptable when layout is extremely tight. The icon+text combination aids non-English-native users who may not read the label fluently. |
|
||||
|
||||
---
|
||||
|
||||
@@ -241,3 +243,34 @@ $events_sess.pres_mgmt.session_qr_url[$lq__obj.id] = result; // ← URL string
|
||||
- **`text-sm leading-relaxed`**: Standard for body-level descriptive text in cards.
|
||||
- **`tracking-wide uppercase`**: Use for section label/eyebrow text with `opacity-40`.
|
||||
- **`whitespace-pre-wrap`**: Required for any `<pre>` or `<p>` displaying user-entered multi-line text (preserves breaks without horizontal overflow).
|
||||
|
||||
---
|
||||
|
||||
## 12. Known Issues & Workarounds
|
||||
|
||||
### `btn` + `preset-filled-*` resolves to transparent inside `card` components
|
||||
|
||||
**Symptom:** A button using `btn preset-filled-primary` (or any `preset-filled-*`) inside a `card` div renders with `background-color: transparent`, making it invisible against the card surface.
|
||||
|
||||
**Root cause:** The Skeleton v4 `btn` class sets a transparent background via a CSS variable chain. When nested inside a `card` element, the `preset-filled-*` class fails to win the specificity battle and the button appears invisible. This affects both light and dark mode.
|
||||
|
||||
**Workaround:** Skip `btn` and `preset-filled-*` entirely for buttons inside `card` elements. Use direct Tailwind token classes instead:
|
||||
|
||||
```svelte
|
||||
<!-- ✅ Correct — works reliably inside cards -->
|
||||
<button class="w-full rounded-xl py-5 font-bold flex items-center justify-center gap-2
|
||||
bg-primary-500 text-white hover:brightness-110 transition-all cursor-pointer">
|
||||
...
|
||||
</button>
|
||||
|
||||
<!-- Secondary / cancel button inside a card -->
|
||||
<button class="w-full rounded-lg py-3 text-sm font-medium flex items-center justify-center gap-2
|
||||
border border-surface-500/40 hover:bg-surface-200-800 transition-colors cursor-pointer opacity-70">
|
||||
...
|
||||
</button>
|
||||
|
||||
<!-- ❌ Broken inside card — do not use -->
|
||||
<button class="btn btn-xl preset-filled-primary">...</button>
|
||||
```
|
||||
|
||||
**Scope:** `btn` + `preset-*` classes work correctly on standalone buttons (e.g. page headers, nav bars). The issue is specific to the `card` component context. If we migrate away from Skeleton `card`/`btn`, this issue goes away.
|
||||
|
||||
Reference in New Issue
Block a user