Files
scadalink-design/src/ScadaLink.CentralUI/Components/Shared/TreeView.razor.css
Joseph Doherty b6e2ec8a50 refactor(ui/design): card grid, SMTP split, TemplateEdit vertical-stack
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.
2026-05-12 03:32:39 -04:00

153 lines
4.2 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* TreeView component styling — see docs/requirements/Component-TreeView.md "Visual Design Guide" (V1V7). */
/* 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;
}