- Compat CSS layer (assets/css/live_table_compat.css) maps the shadcn tokens live_table/sutra_ui use (bg-muted, text-foreground, border-border, bg-background, select-trigger, input-group, etc.) onto daisyUI base colors, and provides hand-written component CSS for select/dropdown/input-group/empty so the table has a proper surface + a select popover that actually hides when closed. - Default-sort the Contacts table by most recent inserted_at. - Beacon detail "Plot path" now encodes lat/lon to an 8-char Maidenhead grid when coordinates are known, so the destination handed to the path calculator is more precise than the beacon's stored 4-char grid. - Rename BackfillLive -> StatusLive, move route from /admin/backfill to /status, retitle "Backfill Dashboard" -> "Status", drop the enqueue form (LiveStash + BackfillEnqueueWorker no longer needed on this page). Contact edit admin back-link now points at /status.
335 lines
7.9 KiB
CSS
335 lines
7.9 KiB
CSS
/* live_table / sutra_ui compat layer.
|
|
|
|
live_table's rendered components (and the SutraUI primitives it wraps)
|
|
use shadcn-style Tailwind utility classes — `bg-muted`, `text-foreground`,
|
|
`border-border`, `bg-background`, `text-muted-foreground`, `text-primary` —
|
|
plus component classes like `.select-trigger`, `.select-popover`,
|
|
`.input-group`, `.empty-outline`, `.dropdown-menu`. This project uses
|
|
daisyUI, which doesn't define any of those tokens or components.
|
|
|
|
Importing deps/sutra_ui/priv/static/sutra_ui.css wholesale would clobber
|
|
daisyUI's `.btn`, `.badge`, `.input`, `.alert`, and the theme `--color-*`
|
|
tokens. Instead, this file provides:
|
|
|
|
1) @theme mappings for the neutral shadcn tokens live_table uses,
|
|
aliased to daisyUI base colors so they don't conflict with
|
|
daisyUI's primary/secondary/accent/error.
|
|
2) Hand-written component CSS for the sutra_ui primitives live_table
|
|
wraps, using daisyUI variables directly (no @apply of shadcn names). */
|
|
|
|
@theme {
|
|
--color-background: var(--color-base-100);
|
|
--color-foreground: var(--color-base-content);
|
|
--color-muted: var(--color-base-200);
|
|
--color-muted-foreground: color-mix(in oklch, var(--color-base-content) 60%, transparent);
|
|
--color-border: var(--color-base-300);
|
|
--color-input: var(--color-base-300);
|
|
--color-popover: var(--color-base-100);
|
|
--color-popover-foreground: var(--color-base-content);
|
|
--color-card: var(--color-base-100);
|
|
--color-card-foreground: var(--color-base-content);
|
|
--color-ring: var(--color-primary);
|
|
}
|
|
|
|
/* SutraUI Select — used by live_table for the per-page selector. */
|
|
*:not(select).select {
|
|
position: relative;
|
|
display: inline-flex;
|
|
width: 100%;
|
|
}
|
|
|
|
.select-trigger {
|
|
display: flex;
|
|
height: 2.25rem;
|
|
width: 100%;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 0.5rem;
|
|
border-radius: 0.375rem;
|
|
border: 1px solid var(--color-base-300);
|
|
background: var(--color-base-100);
|
|
padding: 0.25rem 0.75rem;
|
|
font-size: 0.875rem;
|
|
line-height: 1.25rem;
|
|
color: var(--color-base-content);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.select-trigger:focus-visible {
|
|
outline: none;
|
|
box-shadow: 0 0 0 2px var(--color-primary);
|
|
}
|
|
|
|
.select-value {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.select-icon {
|
|
flex-shrink: 0;
|
|
width: 1rem;
|
|
height: 1rem;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.select-popover,
|
|
[data-popover] {
|
|
position: absolute;
|
|
z-index: 50;
|
|
margin-top: 0.25rem;
|
|
min-width: 100%;
|
|
border-radius: 0.375rem;
|
|
border: 1px solid var(--color-base-300);
|
|
background: var(--color-base-100);
|
|
color: var(--color-base-content);
|
|
padding: 0.25rem;
|
|
box-shadow: 0 4px 6px -1px oklch(0% 0 0 / 0.1), 0 2px 4px -2px oklch(0% 0 0 / 0.1);
|
|
}
|
|
|
|
.select-popover[aria-hidden="true"],
|
|
[data-popover][aria-hidden="true"] {
|
|
display: none;
|
|
}
|
|
|
|
.select-listbox,
|
|
[role="listbox"] {
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.select-option,
|
|
[role="option"] {
|
|
position: relative;
|
|
display: flex;
|
|
cursor: pointer;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
border-radius: 0.25rem;
|
|
padding: 0.375rem 0.5rem;
|
|
font-size: 0.875rem;
|
|
line-height: 1.25rem;
|
|
outline: none;
|
|
user-select: none;
|
|
}
|
|
|
|
.select-option[aria-hidden="true"],
|
|
[role="option"][aria-hidden="true"] {
|
|
display: none;
|
|
}
|
|
|
|
.select-option:hover,
|
|
.select-option.active,
|
|
.select-option:focus-visible,
|
|
.select-option[aria-selected="true"],
|
|
[role="option"]:hover,
|
|
[role="option"].active,
|
|
[role="option"]:focus-visible {
|
|
background: var(--color-base-200);
|
|
}
|
|
|
|
.select-separator,
|
|
[role="separator"] {
|
|
height: 1px;
|
|
margin: 0.25rem -0.25rem;
|
|
background: var(--color-base-300);
|
|
}
|
|
|
|
.select-group-label,
|
|
[role="listbox"] [role="heading"] {
|
|
display: flex;
|
|
padding: 0.375rem 0.5rem;
|
|
font-size: 0.75rem;
|
|
font-weight: 500;
|
|
color: color-mix(in oklch, var(--color-base-content) 60%, transparent);
|
|
}
|
|
|
|
/* SutraUI Input Group — used by live_table for the search box. */
|
|
.input-group {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
width: 100%;
|
|
}
|
|
|
|
.input-group-prefix,
|
|
.input-group-suffix {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
display: flex;
|
|
align-items: center;
|
|
color: color-mix(in oklch, var(--color-base-content) 60%, transparent);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.input-group-prefix { left: 0.75rem; }
|
|
.input-group-suffix { right: 0.75rem; }
|
|
|
|
.input-group-prefix-icon,
|
|
.input-group-suffix-icon {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
display: flex;
|
|
align-items: center;
|
|
color: color-mix(in oklch, var(--color-base-content) 60%, transparent);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.input-group-prefix-icon svg,
|
|
.input-group-suffix-icon svg { width: 1rem; height: 1rem; }
|
|
|
|
.input-group-prefix-icon { left: 0.75rem; }
|
|
.input-group-suffix-icon { right: 0.75rem; }
|
|
|
|
/* SutraUI Dropdown Menu — used by live_table for the Export button. */
|
|
.dropdown-menu {
|
|
position: relative;
|
|
display: inline-flex;
|
|
}
|
|
|
|
.dropdown-menu-trigger {
|
|
display: flex;
|
|
height: 2.25rem;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 0.5rem;
|
|
border-radius: 0.375rem;
|
|
border: 1px solid var(--color-base-300);
|
|
background: var(--color-base-100);
|
|
padding: 0.5rem 0.75rem;
|
|
font-size: 0.875rem;
|
|
line-height: 1.25rem;
|
|
color: var(--color-base-content);
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.dropdown-menu-trigger:focus-visible {
|
|
outline: none;
|
|
box-shadow: 0 0 0 2px var(--color-primary);
|
|
}
|
|
|
|
.dropdown-menu-chevron {
|
|
flex-shrink: 0;
|
|
opacity: 0.5;
|
|
transition: transform 150ms;
|
|
}
|
|
|
|
.dropdown-menu:has([aria-expanded="true"]) .dropdown-menu-chevron {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.dropdown-menu [role="menuitem"],
|
|
.dropdown-menu [role="menuitemcheckbox"],
|
|
.dropdown-menu [role="menuitemradio"] {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.375rem 0.5rem;
|
|
font-size: 0.875rem;
|
|
line-height: 1.25rem;
|
|
border-radius: 0.25rem;
|
|
user-select: none;
|
|
cursor: pointer;
|
|
outline: none;
|
|
width: 100%;
|
|
}
|
|
|
|
.dropdown-menu [role="menuitem"][aria-hidden="true"],
|
|
.dropdown-menu [role="menuitemcheckbox"][aria-hidden="true"],
|
|
.dropdown-menu [role="menuitemradio"][aria-hidden="true"] {
|
|
display: none;
|
|
}
|
|
|
|
.dropdown-menu [role="menuitem"]:focus-visible,
|
|
.dropdown-menu [role="menuitem"]:hover,
|
|
.dropdown-menu [role="menuitem"].active {
|
|
background: var(--color-base-200);
|
|
}
|
|
|
|
/* SutraUI Empty state — used by live_table when no rows match. */
|
|
.empty,
|
|
.empty-outline {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 3rem 1rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.empty header,
|
|
.empty-outline header {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.empty h3,
|
|
.empty-outline h3 {
|
|
font-size: 1.125rem;
|
|
font-weight: 600;
|
|
color: var(--color-base-content);
|
|
}
|
|
|
|
.empty p,
|
|
.empty-outline p {
|
|
font-size: 0.875rem;
|
|
max-width: 24rem;
|
|
color: color-mix(in oklch, var(--color-base-content) 60%, transparent);
|
|
}
|
|
|
|
.empty-icon {
|
|
margin-bottom: 1rem;
|
|
color: color-mix(in oklch, var(--color-base-content) 60%, transparent);
|
|
}
|
|
|
|
.empty-icon > svg { width: 3rem; height: 3rem; }
|
|
|
|
.empty-outline {
|
|
border: 2px dashed var(--color-base-300);
|
|
border-radius: 0.5rem;
|
|
}
|
|
|
|
/* live_table outer container should have a visible surface + border. */
|
|
#live-table table { background: var(--color-base-100); }
|
|
|
|
/* Filter bar used when filters are configured. */
|
|
.filter-bar {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.filter-bar-grid {
|
|
display: grid;
|
|
gap: 0.75rem;
|
|
grid-template-columns: repeat(var(--filter-cols, 3), minmax(0, 1fr));
|
|
}
|
|
|
|
.filter-bar-cols-1 { --filter-cols: 1; }
|
|
.filter-bar-cols-2 { --filter-cols: 2; }
|
|
.filter-bar-cols-3 { --filter-cols: 3; }
|
|
|
|
.filter-bar-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.filter-bar-clear {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
font-size: 0.875rem;
|
|
color: color-mix(in oklch, var(--color-base-content) 60%, transparent);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.filter-bar-clear:hover { color: var(--color-base-content); }
|