feat(owner): clickable identity cards replace node dropdown selector

This commit is contained in:
gadgethd
2026-08-06 21:08:49 +00:00
parent b33696442b
commit 14cdb96189
2 changed files with 25 additions and 33 deletions
+12 -15
View File
@@ -304,21 +304,7 @@ export const OwnerPortalPage: React.FC = () => {
</button>
</div>
{dashboard.nodes.length > 1 ? (
<div className="owner-select">
<label htmlFor="owner-node-select">Node</label>
<select
id="owner-node-select"
className="owner-select__input"
value={selectedNodeId}
onChange={(e) => setSelectedNodeId(e.target.value)}
>
{dashboard.nodes.map((node) => (
<option key={node.canonicalId} value={node.node_id}>
{node.name ?? node.canonicalId}
</option>
))}
</select>
</div>
<p className="prose-note">Select a repeater by clicking its identity card below.</p>
) : null}
<div className="owner-node-identities" aria-label="Owned repeater identities">
{dashboard.nodes.map((node) => (
@@ -326,6 +312,17 @@ export const OwnerPortalPage: React.FC = () => {
key={node.canonicalId}
className={`owner-node-identity${node.node_id === selectedNodeId ? ' owner-node-identity--selected' : ''}`}
data-canonical-id={node.canonicalId}
onClick={() => setSelectedNodeId(node.node_id)}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
setSelectedNodeId(node.node_id);
}
}}
role="button"
tabIndex={0}
aria-pressed={node.node_id === selectedNodeId}
title={dashboard.nodes.length > 1 ? `View ${node.name ?? 'this node'}` : undefined}
>
<div className="owner-node-identity__head">
<strong>{node.name ?? 'Unnamed node'}</strong>
+13 -18
View File
@@ -315,24 +315,6 @@
font-size: 11px;
font-family: var(--font-mono);
}
.owner-select {
margin: 12px 0 16px;
display: flex;
flex-direction: column;
gap: 6px;
}
.owner-select label {
color: var(--text-secondary);
font-size: 12px;
}
.owner-select__input {
max-width: 360px;
background: var(--bg-panel);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text-primary);
padding: 8px 10px;
}
.owner-node-identities {
display: grid;
gap: 10px;
@@ -343,9 +325,22 @@
border: 1px solid var(--border);
border-radius: var(--radius);
background: var(--bg-panel-alt);
cursor: pointer;
transition: border-color 120ms ease, background-color 120ms ease;
}
.owner-node-identity:hover {
border-color: var(--text-secondary);
}
.owner-node-identity:focus-visible {
outline: 2px solid rgba(0, 196, 255, 0.55);
outline-offset: 2px;
}
.owner-node-identity--selected {
border-color: rgba(0, 196, 255, 0.55);
background: color-mix(in srgb, var(--bg-panel-alt) 80%, rgba(0, 196, 255, 0.06));
}
.owner-node-identity--selected:hover {
border-color: rgba(0, 196, 255, 0.8);
}
.owner-node-identity__head {
display: flex;