Compact circuit list column headers with filter icons
- Replace the "Filtern" text buttons with a funnel icon next to the column label; an active filter is highlighted and shows its value count. - Header labels no longer break inside words (e.g. "Bemerkung"); hyphens are non-breaking and a trailing unit moves to its own line, so all headers share one height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e394ff93f4
commit
d95f0bf5c0
3 changed files with 74 additions and 12 deletions
|
|
@ -173,6 +173,10 @@ tooltip; the toolbar shows icon plus text, group headers and rows show icons
|
||||||
only, separated into logical blocks with `IconButtonSeparator`. Destructive
|
only, separated into logical blocks with `IconButtonSeparator`. Destructive
|
||||||
actions use `variant="danger"` (trash icon for circuits and groups, `ListX` for
|
actions use `variant="danger"` (trash icon for circuits and groups, `ListX` for
|
||||||
removing a device row).
|
removing a device row).
|
||||||
|
Column headers show the label (click to sort) with a funnel icon for the
|
||||||
|
value filter; an active filter is highlighted and shows its value count.
|
||||||
|
Header labels break only between words and put a trailing unit such as
|
||||||
|
`[kW]` on a second line.
|
||||||
|
|
||||||
## Bootstrap / Styling Rule
|
## Bootstrap / Styling Rule
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -892,24 +892,37 @@ a.kpi:hover {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* One header row: label (sort) on the left, filter icon on the right. */
|
||||||
.tree-grid .header-cell {
|
.tree-grid .header-cell {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
align-items: stretch;
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
gap: 0.2rem;
|
gap: 0.2rem;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-grid .header-filter-btn {
|
.tree-grid .header-filter-btn {
|
||||||
display: block;
|
display: inline-flex;
|
||||||
width: 100%;
|
flex: none;
|
||||||
border: 1px solid var(--panel-border-strong);
|
align-items: center;
|
||||||
background: var(--panel-bg);
|
gap: 0.15rem;
|
||||||
color: var(--text-strong);
|
border: 1px solid transparent;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-faint);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-size: 0.75rem;
|
font-size: 0.7rem;
|
||||||
padding: 0.15rem 0.35rem;
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0.15rem 0.2rem;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-grid .header-filter-btn:hover,
|
||||||
|
.tree-grid .header-filter-btn:focus-visible {
|
||||||
|
border-color: var(--panel-border-strong);
|
||||||
|
color: var(--text-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-grid .header-sort-btn {
|
.tree-grid .header-sort-btn {
|
||||||
|
|
@ -927,7 +940,10 @@ a.kpi:hover {
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
overflow-wrap: anywhere;
|
/* Break only between words; never inside a word such as "Bemerkung". */
|
||||||
|
overflow-wrap: normal;
|
||||||
|
word-break: normal;
|
||||||
|
hyphens: manual;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
@ -967,6 +983,18 @@ a.kpi:hover {
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tree-grid .header-cell .header-sort-btn {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: auto;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-grid .header-unit {
|
||||||
|
display: block;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-faint);
|
||||||
|
}
|
||||||
|
|
||||||
.tree-grid .header-sort-btn:hover span:first-child,
|
.tree-grid .header-sort-btn:hover span:first-child,
|
||||||
.tree-grid .header-sort-btn:focus-visible span:first-child {
|
.tree-grid .header-sort-btn:focus-visible span:first-child {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
|
@ -983,6 +1011,11 @@ a.kpi:hover {
|
||||||
background: var(--accent-blue-soft-bg);
|
background: var(--accent-blue-soft-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tree-grid .header-filter-count {
|
||||||
|
min-width: 0.7rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.tree-grid .header-filter-menu {
|
.tree-grid .header-filter-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 7;
|
z-index: 7;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
Columns3,
|
Columns3,
|
||||||
FilterX,
|
FilterX,
|
||||||
FolderPlus,
|
FolderPlus,
|
||||||
|
Funnel,
|
||||||
ListOrdered,
|
ListOrdered,
|
||||||
ListPlus,
|
ListPlus,
|
||||||
ListX,
|
ListX,
|
||||||
|
|
@ -268,6 +269,24 @@ function createValuesFromEditPatch(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Header labels break only between words: hyphens become non-breaking and a
|
||||||
|
* trailing unit such as "[kW]" is always shown on its own second line, so
|
||||||
|
* header heights stay uniform.
|
||||||
|
*/
|
||||||
|
function renderColumnHeaderLabel(label: string) {
|
||||||
|
const match = /^(.*?)s*([[^]]+])$/.exec(label);
|
||||||
|
const name = (match ? match[1] : label).replace(/-/g, "‑");
|
||||||
|
return match ? (
|
||||||
|
<>
|
||||||
|
{name}
|
||||||
|
<span className="header-unit">{match[2]}</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function CircuitTreeEditor(props: { projectId: string; circuitListId: string }) {
|
export function CircuitTreeEditor(props: { projectId: string; circuitListId: string }) {
|
||||||
/*
|
/*
|
||||||
Circuit-tree editor invariant overview:
|
Circuit-tree editor invariant overview:
|
||||||
|
|
@ -3440,7 +3459,9 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>{column.label}</span>
|
<span className="header-label">
|
||||||
|
{renderColumnHeaderLabel(column.label)}
|
||||||
|
</span>
|
||||||
{sortState?.key === column.key ? (
|
{sortState?.key === column.key ? (
|
||||||
<span className="sort-indicator" aria-label={sortState.direction === "asc" ? "aufsteigend" : "absteigend"}>
|
<span className="sort-indicator" aria-label={sortState.direction === "asc" ? "aufsteigend" : "absteigend"}>
|
||||||
{sortState.direction === "asc" ? "↑" : "↓"}
|
{sortState.direction === "asc" ? "↑" : "↓"}
|
||||||
|
|
@ -3451,6 +3472,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
||||||
type="button"
|
type="button"
|
||||||
className={`header-filter-btn ${(columnFilters[column.key]?.length ?? 0) > 0 ? "active" : ""}`}
|
className={`header-filter-btn ${(columnFilters[column.key]?.length ?? 0) > 0 ? "active" : ""}`}
|
||||||
onClick={() => toggleColumnFilterMenu(column.key)}
|
onClick={() => toggleColumnFilterMenu(column.key)}
|
||||||
|
aria-label={`${getFullColumnLabel(column)} filtern`}
|
||||||
aria-pressed={(columnFilters[column.key]?.length ?? 0) > 0}
|
aria-pressed={(columnFilters[column.key]?.length ?? 0) > 0}
|
||||||
title={
|
title={
|
||||||
(columnFilters[column.key]?.length ?? 0) > 0
|
(columnFilters[column.key]?.length ?? 0) > 0
|
||||||
|
|
@ -3458,7 +3480,10 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
||||||
: `${getFullColumnLabel(column)} filtern`
|
: `${getFullColumnLabel(column)} filtern`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Filtern{(columnFilters[column.key]?.length ?? 0) > 0 ? ` (${columnFilters[column.key]?.length})` : ""}
|
<Funnel aria-hidden="true" size={13} strokeWidth={2.2} />
|
||||||
|
{(columnFilters[column.key]?.length ?? 0) > 0 ? (
|
||||||
|
<span className="header-filter-count">{columnFilters[column.key]?.length}</span>
|
||||||
|
) : null}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{openFilterColumn === column.key ? (
|
{openFilterColumn === column.key ? (
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue