Templates: <h4> in flex header, Expand/Collapse moved into a Bulk actions dropdown, hover-visible kebab on tree nodes with aria-labels. TreeView CSS gets a .tv-kebab opacity-on-hover utility. TemplateCreate: form-control (not -sm) for primary inputs; accessible Back button. TemplateEdit: Properties card vertical-stacked with Save at the bottom-right and Parent rendered as readonly plaintext. Add-member forms (Attributes, Alarms, Scripts, Compositions) reflowed from horizontal row g-2 align-items-end into cards with stacked col-12 inputs (Scripts gets rows=10). Lock/Unlock badges show full words. Per-row Delete moved into a kebab dropdown. Tab nav gains role="tablist" / role="tab" / aria-selected / aria-controls and panels get role="tabpanel". Validation entries get consistent strong-and- muted styling. SharedScripts: migrated from table to card grid (col-lg-6) matching Sites; cards show code preview + param/return badges + Edit + kebab. Search filter, empty state CTA, @key. SharedScriptForm: small ?-icon tooltips next to Parameters and Return Definition labels. ExternalSystems: SMTP split out to its own page; remaining tabs ( External Systems, DB Connections, Notification Lists, API Methods, API Keys) unified as card grids with per-tab search + empty-state CTA. Tab nav gets full ARIA instrumentation. Header gains a link to the new SMTP page. New page SmtpConfiguration.razor at /design/smtp: vertical-stacked form using the existing Credentials field on the entity. ExternalSystemForm: AuthConfig placeholder updates based on the selected AuthType (None / ApiKey / BasicAuth). DbConnectionForm: form-text below Connection String noting that the value is stored in plain text and is admin-only. ApiMethodForm: Script textarea rows=10; JSON example placeholders for Params and Returns. NotificationListForm: form-control sizing on Name/email inputs; thead.table-dark -> table-light on the recipients table.
153 lines
4.2 KiB
CSS
153 lines
4.2 KiB
CSS
/* TreeView component styling — see docs/requirements/Component-TreeView.md "Visual Design Guide" (V1–V7). */
|
||
|
||
/* Root list — no list styling. */
|
||
.tv-root,
|
||
.tv-root ul {
|
||
list-style: none;
|
||
padding-left: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
/* V1 — Row anatomy. Flex container; full-width hit surface; ~32px row. */
|
||
.tv-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.25rem;
|
||
padding: 0.25rem 0.5rem;
|
||
cursor: default;
|
||
border-radius: 0.25rem;
|
||
transition: background-color 0.08s linear;
|
||
}
|
||
|
||
/* V1 — slot widths. Toggle and glyph are always present so labels align across siblings. */
|
||
.tv-row .tv-toggle,
|
||
.tv-row .tv-spacer {
|
||
flex: 0 0 auto;
|
||
width: 1.25rem; /* 20px */
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
color: var(--bs-secondary-color);
|
||
user-select: none;
|
||
}
|
||
|
||
.tv-row .tv-spacer {
|
||
cursor: default;
|
||
}
|
||
|
||
.tv-row .tv-content {
|
||
flex: 1 1 auto;
|
||
min-width: 0; /* required so child label can ellipsis-truncate inside a flex item */
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.25rem;
|
||
}
|
||
|
||
/* V5 — primary label truncation. Consumers add their own bold class for branches. */
|
||
.tv-row .tv-label {
|
||
flex: 1 1 auto;
|
||
min-width: 0;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
/* V1 — meta slot right-aligns trailing badges/text against row edge. */
|
||
.tv-row .tv-meta {
|
||
margin-left: auto;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.25rem;
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
/* V4 — glyph slot. Bootstrap Icons render at 1em, inherit text color. */
|
||
.tv-row .tv-glyph {
|
||
flex: 0 0 auto;
|
||
width: 1.25rem; /* 20px, same slot size as toggle */
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* V3 — hover. Subtle gray wash; suppressed when row is selected. */
|
||
.tv-row:hover:not(.tv-selected) {
|
||
background-color: var(--bs-tertiary-bg);
|
||
}
|
||
|
||
/* V3 — selected. Bootstrap utility `bg-primary bg-opacity-10` is the SelectedCssClass default;
|
||
the .tv-selected hook is provided for consumers that prefer scoped styling. */
|
||
.tv-row.tv-selected {
|
||
background-color: rgba(var(--bs-primary-rgb), 0.1);
|
||
}
|
||
|
||
/* V3 — keyboard focus. Inset ring composes with hover/selected without layout shift. */
|
||
.tv-row:focus-visible {
|
||
outline: none;
|
||
box-shadow: inset 0 0 0 2px var(--bs-primary);
|
||
}
|
||
|
||
/* V3 — drop-target (valid). Overrides hover/selected. */
|
||
.tv-row.tv-drop-target {
|
||
background-color: rgba(var(--bs-info-rgb), 0.25);
|
||
}
|
||
|
||
/* V3 — dimmed (e.g. non-droppable while a drag is in progress; reserved for future use). */
|
||
.tv-row.tv-dimmed {
|
||
opacity: 0.5;
|
||
}
|
||
|
||
/* V2 — guide lines. A pseudo-element overlays the row's depth gutter and draws
|
||
one vertical line per ancestor depth at 24px intervals. The `--tv-depth` variable
|
||
is set inline per row; lines never extend into the content area. */
|
||
.tv-guides .tv-row {
|
||
position: relative;
|
||
}
|
||
|
||
.tv-guides .tv-row::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
bottom: 0;
|
||
width: calc(var(--tv-depth, 0) * 1.5rem);
|
||
pointer-events: none;
|
||
background-image: linear-gradient(
|
||
to right,
|
||
transparent calc(0.625rem - 0.5px),
|
||
var(--bs-border-color) calc(0.625rem - 0.5px),
|
||
var(--bs-border-color) calc(0.625rem + 0.5px),
|
||
transparent calc(0.625rem + 0.5px)
|
||
);
|
||
background-size: 1.5rem 100%;
|
||
background-repeat: repeat-x;
|
||
}
|
||
|
||
/* Branch chevron rotates on expand via the aria-expanded attribute on the parent treeitem.
|
||
Consumers using `bi-chevron-right` get the down-rotation for free. */
|
||
.tv-row .tv-toggle .bi-chevron-right {
|
||
transition: transform 0.1s linear;
|
||
}
|
||
|
||
[role="treeitem"][aria-expanded="true"] > .tv-row .tv-toggle .bi-chevron-right {
|
||
transform: rotate(90deg);
|
||
}
|
||
|
||
/* Per-row kebab (More actions): hidden by default, revealed on row hover or when
|
||
the dropdown is open. Consumers render `<span class="tv-kebab ...">` inside
|
||
NodeContent to opt in. */
|
||
.tv-row .tv-kebab {
|
||
flex: 0 0 auto;
|
||
opacity: 0;
|
||
transition: opacity 0.1s linear;
|
||
margin-left: 0.25rem;
|
||
}
|
||
|
||
.tv-row:hover .tv-kebab,
|
||
.tv-row:focus-within .tv-kebab,
|
||
.tv-row .tv-kebab.show,
|
||
.tv-row .tv-kebab .show {
|
||
opacity: 1;
|
||
}
|