Replaces the caret-dropdown preset menu with two stacked cards:
Groups (top) — saved bundles of projects; click to open the archive
with that group's project set; per-row edit/delete
buttons.
Projects — filterable table; in default mode no checkboxes,
click any row to open just that project.
"+ New group" or a row's edit button enters select-mode: checkboxes
appear on each project row, an action bar shows above the projects card
with Save group / Open visible-checked / Cancel.
"Open visible-checked" intentionally excludes filter-hidden checked
projects so users can scope to a subset they're currently looking at.
Storage migrates from old zddc_landing_presets to zddc_landing_groups
(simpler shape: {name, projects: [...]}). One-shot migration runs on
first load.
Adds the new favicon SVG to the landing header alongside the title.
Drops the ?projects= URL state since selection is no longer the page's
primary state in click-to-open mode.
Updates Playwright suite: 9 new test cases covering click-to-open, group
crud, edit pre-population, "open selected visible" scoping, and legacy
preset migration. Adds a LandingApp._setNavigate test hook since
window.location.href cannot be reliably patched in modern engines.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
344 lines
7.6 KiB
CSS
344 lines
7.6 KiB
CSS
/* Landing page layout */
|
|
body {
|
|
margin: 0;
|
|
font-family: var(--font);
|
|
font-size: 14px;
|
|
background: var(--bg-secondary);
|
|
color: var(--text);
|
|
}
|
|
|
|
.landing-main {
|
|
max-width: 880px;
|
|
margin: 32px auto;
|
|
padding: 0 16px 64px;
|
|
}
|
|
|
|
/* Welcome / hero */
|
|
.landing-hero {
|
|
margin: 0 0 24px;
|
|
padding: 0 4px;
|
|
}
|
|
.landing-hero h1 {
|
|
margin: 0 0 8px;
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
}
|
|
.landing-hero-sub {
|
|
margin: 0;
|
|
color: var(--text-muted);
|
|
font-size: 0.95rem;
|
|
line-height: 1.5;
|
|
max-width: 60ch;
|
|
}
|
|
|
|
/* Access warning banner */
|
|
.access-warning-banner {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 10px 16px;
|
|
background: #fff3cd;
|
|
border: 1px solid #ffc107;
|
|
border-radius: var(--radius);
|
|
color: #664d03;
|
|
font-size: 0.875rem;
|
|
margin-bottom: 16px;
|
|
gap: 12px;
|
|
}
|
|
.access-warning-banner.hidden { display: none; }
|
|
.warning-dismiss-btn {
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
color: #664d03;
|
|
font-size: 1rem;
|
|
padding: 0 4px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Cards (groups + projects) */
|
|
.landing-card {
|
|
background: var(--bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
overflow: visible;
|
|
box-shadow: 0 1px 2px rgba(0,0,0,0.04);
|
|
margin-bottom: 16px;
|
|
}
|
|
.landing-card:last-child { margin-bottom: 0; }
|
|
|
|
.landing-card-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 12px 16px;
|
|
border-bottom: 1px solid var(--border);
|
|
gap: 12px;
|
|
flex-wrap: wrap;
|
|
}
|
|
.landing-card-title {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 8px;
|
|
}
|
|
.landing-card-header h2 {
|
|
margin: 0;
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
}
|
|
.landing-count {
|
|
color: var(--text-muted);
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.landing-header-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* ── Groups card ─────────────────────────────────────────────────────────── */
|
|
.groups-container { min-height: 0; }
|
|
.groups-empty {
|
|
padding: 16px 24px;
|
|
color: var(--text-muted);
|
|
font-size: 0.9rem;
|
|
line-height: 1.5;
|
|
}
|
|
.groups-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.9rem;
|
|
}
|
|
.groups-row {
|
|
cursor: pointer;
|
|
transition: background 0.08s;
|
|
}
|
|
.groups-row:hover { background: var(--bg-hover); }
|
|
.groups-row td {
|
|
padding: 8px 12px;
|
|
border-bottom: 1px solid var(--border);
|
|
vertical-align: middle;
|
|
}
|
|
.groups-row:last-child td { border-bottom: none; }
|
|
.groups-row-name {
|
|
font-weight: 500;
|
|
color: var(--text);
|
|
}
|
|
.groups-row-count {
|
|
color: var(--text-muted);
|
|
font-size: 0.85rem;
|
|
width: 8em;
|
|
white-space: nowrap;
|
|
}
|
|
.groups-row-actions {
|
|
width: 4.5em;
|
|
text-align: right;
|
|
white-space: nowrap;
|
|
}
|
|
.groups-btn-edit, .groups-btn-delete {
|
|
background: none;
|
|
border: 1px solid transparent;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
color: var(--text-muted);
|
|
font-size: 0.95rem;
|
|
padding: 2px 6px;
|
|
line-height: 1;
|
|
}
|
|
.groups-btn-edit:hover {
|
|
background: var(--bg-hover);
|
|
color: var(--text);
|
|
}
|
|
.groups-btn-delete:hover {
|
|
background: var(--bg-hover);
|
|
color: var(--danger, #c0392b);
|
|
}
|
|
|
|
/* ── Select-mode action bar ──────────────────────────────────────────────── */
|
|
.select-action-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
padding: 10px 16px;
|
|
background: var(--bg-secondary);
|
|
border-bottom: 1px solid var(--border);
|
|
flex-wrap: wrap;
|
|
}
|
|
.select-action-bar.hidden { display: none; }
|
|
.select-action-bar__label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex: 1 1 240px;
|
|
min-width: 0;
|
|
}
|
|
.select-action-bar__label > span {
|
|
font-weight: 500;
|
|
color: var(--text);
|
|
flex-shrink: 0;
|
|
}
|
|
.group-name-input {
|
|
flex: 1 1 0;
|
|
min-width: 120px;
|
|
padding: 5px 10px;
|
|
border: 1px solid var(--border);
|
|
border-radius: 3px;
|
|
font-size: 0.875rem;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
}
|
|
.group-name-input:focus {
|
|
outline: none;
|
|
border-color: var(--primary);
|
|
}
|
|
.select-action-bar__buttons {
|
|
display: flex;
|
|
gap: 6px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* ── Projects card ───────────────────────────────────────────────────────── */
|
|
.project-list-container {
|
|
min-height: 80px;
|
|
}
|
|
|
|
/* Empty / error states */
|
|
.project-list-empty {
|
|
padding: 32px 24px;
|
|
text-align: center;
|
|
color: var(--text-muted);
|
|
}
|
|
.project-list-empty h3 {
|
|
margin: 0 0 8px;
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
}
|
|
.project-list-empty p {
|
|
margin: 4px 0;
|
|
font-size: 0.9rem;
|
|
line-height: 1.5;
|
|
}
|
|
.landing-empty-help {
|
|
color: var(--text-muted);
|
|
font-size: 0.85rem !important;
|
|
margin-top: 12px !important;
|
|
max-width: 50ch;
|
|
margin-left: auto !important;
|
|
margin-right: auto !important;
|
|
}
|
|
|
|
/* Loading state */
|
|
.project-list-loading {
|
|
padding: 32px 16px;
|
|
text-align: center;
|
|
color: var(--text-muted);
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
/* Project table */
|
|
.project-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.9rem;
|
|
}
|
|
.project-table thead {
|
|
background: var(--bg-secondary);
|
|
}
|
|
.project-table-headers th {
|
|
padding: 10px 12px;
|
|
text-align: left;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
border-bottom: 1px solid var(--border);
|
|
user-select: none;
|
|
}
|
|
.project-table-headers th[data-sort] {
|
|
cursor: pointer;
|
|
}
|
|
.project-table-headers th[data-sort]:hover {
|
|
background: var(--bg-hover);
|
|
}
|
|
.project-table-checkbox-col {
|
|
width: 32px;
|
|
padding: 8px 12px;
|
|
text-align: center;
|
|
}
|
|
.project-table-checkbox-col input[type="checkbox"] {
|
|
width: 16px;
|
|
height: 16px;
|
|
cursor: pointer;
|
|
accent-color: var(--primary);
|
|
margin: 0;
|
|
vertical-align: middle;
|
|
}
|
|
.project-table-name-col {
|
|
min-width: 140px;
|
|
}
|
|
.project-table-title-col {
|
|
width: 100%;
|
|
}
|
|
.sort-indicator {
|
|
color: var(--text-muted);
|
|
margin-left: 4px;
|
|
font-size: 0.75rem;
|
|
}
|
|
.sort-indicator.active {
|
|
color: var(--text);
|
|
}
|
|
|
|
.project-table-filters th {
|
|
padding: 6px 12px;
|
|
border-bottom: 1px solid var(--border);
|
|
background: var(--bg);
|
|
}
|
|
.project-table-filters .column-filter {
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
padding: 4px 8px;
|
|
border: 1px solid var(--border);
|
|
border-radius: 3px;
|
|
font-size: 0.85rem;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
}
|
|
.project-table-filters .column-filter:focus {
|
|
outline: none;
|
|
border-color: var(--primary);
|
|
}
|
|
.project-table-filters .column-filter.filter-active {
|
|
background: var(--bg-secondary);
|
|
border-color: var(--primary);
|
|
}
|
|
|
|
.project-table-row {
|
|
cursor: pointer;
|
|
transition: background 0.08s;
|
|
}
|
|
.project-table-row:hover {
|
|
background: var(--bg-hover);
|
|
}
|
|
.project-table-row.is-selected {
|
|
background: var(--bg-selected, rgba(0, 105, 217, 0.08));
|
|
}
|
|
.project-table-row.is-selected:hover {
|
|
background: var(--bg-selected-hover, rgba(0, 105, 217, 0.15));
|
|
}
|
|
.project-table-row td {
|
|
padding: 8px 12px;
|
|
border-bottom: 1px solid var(--border);
|
|
vertical-align: middle;
|
|
}
|
|
.project-table-no-title {
|
|
color: var(--text-muted);
|
|
}
|
|
.project-table-no-match {
|
|
padding: 24px 16px !important;
|
|
text-align: center;
|
|
color: var(--text-muted);
|
|
}
|