docs: add nodedc ui guideline registry

This commit is contained in:
DCCONSTRUCTIONS
2026-05-01 22:28:34 +03:00
parent 85aa322990
commit c99c91c826
26 changed files with 1209 additions and 0 deletions
@@ -0,0 +1,41 @@
{
"id": "action-dropdown",
"name": "ActionDropdown",
"kind": "component",
"status": "stable-reference",
"summary": "Shared action menu for ellipsis buttons and command lists. Used instead of local card menus.",
"sourceRefs": [
{
"project": "nodedc_taskmanager",
"file": "plane-src/packages/ui/src/dropdowns/action-dropdown.tsx",
"exports": ["ActionDropdown"]
},
{
"project": "nodedc_taskmanager",
"file": "HDROPDOWN-CANON.md",
"section": "Action dropdown"
}
],
"propsContract": {
"items": "Array of action menu items with key, icon, title, description, disabled, action, nestedMenuItems.",
"button": "Optional custom trigger.",
"buttonAsChild": "Allows using the provided trigger element as anchor.",
"placement": "Popper placement.",
"portalElement": "Defaults to document.body.",
"menuClassName": "Optional width/padding adjustment."
},
"behaviorContract": [
"Uses real trigger element.",
"Uses fixed Popper strategy.",
"Uses offset [0, 8].",
"Uses flip and preventOverflow.",
"Uses portal to document.body by default.",
"Stops trigger event propagation so cards do not open when the menu opens."
],
"rules": [
"Do not build card ellipsis menus with local isOpen and absolute positioning.",
"Menu item visual rendering lives inside ActionDropdown.",
"Nested items are allowed, but still use the same dropdown shell."
]
}
@@ -0,0 +1,45 @@
{
"id": "admin-side-nav",
"name": "AdminSideNav",
"kind": "component",
"status": "draft-stable",
"summary": "Left admin panel navigation with full-width rounded rows, circular icons, client selector, close button, and role footer.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/widgets/admin-overlay/AdminOverlay.tsx",
"classes": ["admin-panel-nav", "admin-panel-client-select", "admin-panel-nav-item", "admin-panel-role"]
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["admin-panel-nav", "admin-panel-nav-item", "admin-panel-nav-item__icon", "admin-panel-close"]
}
],
"anatomy": [
"panel shell",
"head: eyebrow, title, close action",
"client selector row",
"nav list",
"role footer"
],
"geometry": {
"width": "clamp(20.75rem, 19.5vw, 22rem)",
"panelPadding": "1.1rem",
"rowHeight": "controlRing + 2 * controlInset",
"iconSize": "controlRing",
"edgeInset": "5px"
},
"states": {
"inactive": "muted text, darker icon circle, partial opacity",
"active": "white icon circle and brighter row surface",
"hover": "slightly brighter row surface"
},
"rules": [
"Rows stretch to panel edges by counteracting panel padding.",
"Active nav icon is white, not green.",
"Close button is anchored at panel radius with 5px inset.",
"Client selector uses the same row/circle geometry as nav rows."
]
}
@@ -0,0 +1,43 @@
{
"id": "admin-table",
"name": "AdminTable",
"kind": "component",
"status": "draft-stable",
"summary": "Admin data table shell used for services, clients, users, groups, invites, sync, and audit.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/widgets/admin-overlay/AdminOverlay.tsx",
"functions": ["ServicesSection", "ClientsSection", "UsersSection", "GroupsSection", "InvitesSection", "SyncSection", "AuditSection"]
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["table-shell", "admin-data-table", "services-admin-table", "admin-table-input"]
}
],
"anatomy": [
"table-shell glass surface",
"table-toolbar",
"thead labels",
"tbody rows",
"inline editable cells",
"StatusControl cells",
"DateField cells",
"CircleActionButton action cells"
],
"visualContract": {
"background": "same family as inactive admin nav row, not a foreign panel",
"fontSize": "0.82rem table; compact labels 0.66rem",
"cellVerticalAlign": "middle",
"rowAction": "circular edit button at right"
},
"rules": [
"Create action is a solid circular plus, not a wide text CTA.",
"Inline editable cells use transparent input surfaces that brighten on hover/focus.",
"Status cells use StatusControl.",
"Date cells use CalendarPopover/DateField.",
"Drag handles move full rows, not detached ghosts."
]
}
@@ -0,0 +1,40 @@
{
"id": "app-header",
"name": "NodeDcAppHeader",
"kind": "component",
"status": "draft-stable",
"summary": "Top application header with logo, centered navigation group, workspace mark, and profile cluster.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/widgets/top-bar/TopBar.tsx"
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["nodedc-expanded-toolbar", "nodedc-expanded-nav-group", "nodedc-expanded-nav-button", "nodedc-expanded-user-group"]
},
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/core/components/core/app-header.tsx"
}
],
"anatomy": [
"left brand logo",
"center workspace mark",
"center segmented nav",
"right profile pill with optional notification icon and avatar"
],
"geometry": {
"shellPadding": "1.25rem top/right/left in launcher",
"pillHeight": "3rem in launcher expanded toolbar",
"brandLogo": "visual size follows Task Manager reference, not text-only brand"
},
"rules": [
"Header is monocolor black/dark, not gradient decoration.",
"Active top nav segment is white filled pill.",
"Profile avatar diameter must match reference topbar avatar.",
"Launcher and Task Manager headers must remain visually identical where routes overlap."
]
}
@@ -0,0 +1,47 @@
{
"id": "calendar-popover",
"name": "CalendarPopover",
"kind": "component",
"status": "stable-reference",
"summary": "Date picker popover based on Task Manager DateDropdown and nodedc-calendar-shell styling.",
"sourceRefs": [
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/core/components/dropdowns/date.tsx",
"exports": ["DateDropdown"]
},
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/styles/globals.css",
"classes": ["nodedc-calendar-shell"]
},
{
"project": "nodedc_launcher",
"file": "src/widgets/admin-overlay/AdminOverlay.tsx",
"functions": ["DateField"]
}
],
"anatomy": [
"date trigger button",
"portal dropdown surface",
"calendar shell",
"month/year controls",
"day buttons",
"single or range mode"
],
"visualContract": {
"surface": "DropdownSurface",
"calendarRadius": "1.1rem",
"dayButtonRadius": "999px",
"selectedRangeFill": "accentRgb with high contrast dark text",
"outsideDays": "muted"
},
"behaviorContract": [
"Default placement bottom-start.",
"Render through portal.",
"Support minDate, maxDate, clearable value, start-of-week preference.",
"Close on select when closeOnSelect is true."
],
"nextImplementationStep": "Replace launcher native input date fallback with this shared calendar component."
}
@@ -0,0 +1,53 @@
{
"id": "circle-action-button",
"name": "CircleActionButton",
"kind": "primitive",
"status": "draft-stable",
"summary": "Icon-only circular action control for close, add, edit, refresh, search, copy, drag-adjacent actions, and toolbar icon actions.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/shared/ui/Button.tsx",
"exports": ["IconButton"]
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["admin-circle-action", "admin-panel-close", "services-admin-table__edit"]
},
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/styles/globals.css",
"classes": ["nodedc-external-icon-button", "nodedc-toolbar-icon-button"]
}
],
"anatomy": [
"button element",
"single centered icon",
"aria-label/title",
"optional solid active/primary variant"
],
"geometry": {
"size": "tokens.size.controlRing",
"shape": "circle",
"insetToHostEdge": "tokens.size.controlInset when anchored in a rounded container"
},
"variants": {
"ghost": {
"background": "transparent",
"border": "soft white alpha only if needed",
"hover": "white alpha surface"
},
"solid": {
"background": "rgba(247, 248, 244, 0.96)",
"color": "onAccentRgb"
}
},
"rules": [
"Do not replace with text pill when action is clear by icon.",
"Close button starts transparent with only soft circular boundary.",
"Hover may add subtle surface fill.",
"All icon-only admin actions share the same diameter."
]
}
@@ -0,0 +1,48 @@
{
"id": "dropdown-surface",
"name": "DropdownSurface",
"kind": "primitive",
"status": "stable-reference",
"summary": "Canonical dark floating surface for selection dropdowns, action dropdowns, filters, and profile menu popovers.",
"sourceRefs": [
{
"project": "nodedc_taskmanager",
"file": "HDROPDOWN-CANON.md"
},
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/styles/globals.css",
"classes": ["nodedc-dropdown-surface", "nodedc-dropdown-search", "nodedc-dropdown-option"]
},
{
"project": "nodedc_launcher",
"file": "src/shared/ui/PortalDropdown.tsx"
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["portal-dropdown", "nodedc-dropdown-surface"]
}
],
"visualContract": {
"background": "linear-gradient(180deg, rgba(255,255,255,0.025), rgba(255,255,255,0.01)) over rgba(8,8,11,0.9)",
"radius": "1.25rem",
"padding": "0.75rem",
"blur": "44px",
"shadow": "tokens.shadow.dropdown",
"border": "0"
},
"behaviorContract": [
"Render on fixed/portal layer when inside cards, sidebars, tables, sticky headers, or scroll containers.",
"Close on outside pointer and Escape.",
"Use Popper or equivalent fixed-position placement.",
"Default selection placement is bottom-start.",
"Default action placement for card quick actions is bottom-start or bottom-end depending on anchor edge."
],
"optionContract": {
"radius": "0.9rem",
"hover": "rgba(255,255,255,0.06)",
"outline": "none"
}
}
@@ -0,0 +1,47 @@
{
"id": "entity-modal",
"name": "EntityModal",
"kind": "component",
"status": "draft-stable",
"summary": "Dark glass edit/create modal used for services, clients, users, and groups.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/widgets/admin-overlay/AdminOverlay.tsx",
"functions": ["ServiceContentModal", "ClientEditorModal", "UserEditorModal", "GroupEditorModal", "EntityModalHead", "EntityModalFoot"]
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["service-content-modal-layer", "service-content-modal", "service-content-field"]
},
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/styles/globals.css",
"classes": ["nodedc-glass-modal", "nodedc-modal-input", "nodedc-modal-editor", "nodedc-modal-primary-button"]
}
],
"anatomy": [
"fixed overlay layer",
"modal shell",
"head with eyebrow/title/close circle",
"scrollable responsive grid",
"fields",
"footer with cancel, optional delete, save"
],
"visualContract": {
"shellWidth": "min(58rem, viewport - 2.8rem)",
"radius": "modal",
"background": "dark matte glass",
"blur": "modal",
"fieldRadius": "1rem to 1.25rem",
"footerButtonHeight": "2.75rem"
},
"rules": [
"Delete is left of Save inside the right footer action group.",
"Cancel stays on the left.",
"Close action is circular and transparent until hover.",
"Fields/selects/textareas share the same glass family."
]
}
@@ -0,0 +1,36 @@
{
"id": "glass-panel",
"name": "GlassPanel",
"kind": "surface",
"status": "draft-stable",
"summary": "Dark matte glass container used for panels, cards, modal shells, dropdown shells, and admin content blocks.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/shared/ui/Glass.tsx"
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["glass-surface", "admin-panel-nav", "admin-panel-content", "service-content-modal"]
},
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/styles/globals.css",
"classes": ["nodedc-dropdown-surface", "nodedc-modal-field", "nodedc-settings-card"]
}
],
"tokens": {
"radius": "card | modal | control depending on scale",
"blur": "panel | modal | dropdown",
"background": "dark matte glass gradient over rgba black",
"border": "none or transparent soft glass only"
},
"rules": [
"Never use hard outline as the main visual boundary.",
"Use background opacity and blur to separate layers.",
"For major shells use radius.card or radius.modal.",
"For controls inside shells use radius.control."
]
}
@@ -0,0 +1,33 @@
{
"id": "launcher-showcase-stage",
"name": "LauncherShowcaseStage",
"kind": "recipe-component",
"status": "draft-stable",
"summary": "Large showcase stage with looping ambient media, selected service media square, and glass description square.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/widgets/service-stage/ServiceStage.tsx"
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["service-stage", "stage-service-overlay", "stage-media-card", "stage-description-card", "stage-video-controls"]
}
],
"anatomy": [
"stage container",
"ambient background media",
"topline back/title",
"left side controls",
"two centered equal squares: media and description",
"bottom center previous/next controls"
],
"rules": [
"The media card and description card have equal width and height.",
"Cards are separated by a small gap and each has four rounded corners.",
"Ambient media fills the stage and clips to radius.card.",
"When admin panel content is open, stage content controls are hidden and media becomes decorative."
]
}
@@ -0,0 +1,40 @@
{
"id": "media-source-field",
"name": "MediaSourceField",
"kind": "component",
"status": "draft-stable",
"summary": "Media input field that switches between local storage upload and external URL for card and background content.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/widgets/admin-overlay/AdminOverlay.tsx",
"functions": ["MediaSourceField", "MediaPreview"]
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["service-media-control", "service-media-file-button", "service-media-source-button"]
}
],
"anatomy": [
"label with icon",
"rounded input/control shell",
"file chooser button",
"selected filename",
"URL input",
"two circular source buttons: file, url",
"preview surface"
],
"behaviorContract": [
"Local file upload persists to public storage and returns stable URL.",
"Source switch decides whether field uses stored file URL or external URL.",
"Accepts images, gifs, videos, and common video extensions.",
"Preview renders video when mediaKind or extension indicates video."
],
"rules": [
"The file chooser is a single rounded button, never browser default file input UI.",
"The source buttons are circular and attached to the field right side.",
"Background content and card content both accept the same media categories."
]
}
@@ -0,0 +1,41 @@
{
"id": "profile-menu",
"name": "ProfileMenu",
"kind": "component",
"status": "stable-reference",
"summary": "User profile popover opened from the top toolbar avatar. Uses ActionDropdown shell with custom menu content.",
"sourceRefs": [
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/core/components/workspace/sidebar/user-menu-root.tsx",
"exports": ["UserMenuRoot"]
},
{
"project": "nodedc_taskmanager",
"file": "plane-src/packages/ui/src/dropdowns/action-dropdown.tsx",
"exports": ["ActionDropdown"]
}
],
"anatomy": [
"toolbar avatar trigger",
"cover image header",
"centered circular avatar",
"user name and email",
"action rows: settings, sign out",
"optional admin-only action"
],
"visualContract": {
"menuWidth": "18rem",
"menuPadding": "0.75rem",
"coverHeight": "7.25rem",
"coverRadius": "0.5rem in task manager reference; can be upgraded to token radius.control",
"rowRadius": "0.9rem",
"rowHover": "rgba(255,255,255,0.06)"
},
"rules": [
"Profile popover is an ActionDropdown menuContent variant, not a separate dropdown engine.",
"Avatar trigger stays circular and borderless.",
"Menu uses DropdownSurface/ActionDropdown stacking rules."
]
}
@@ -0,0 +1,34 @@
{
"id": "segmented-nav",
"name": "SegmentedNav",
"kind": "component",
"status": "draft-stable",
"summary": "Rounded grouped navigation control used in topbars and mode switchers.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["nodedc-expanded-nav-group", "nodedc-expanded-nav-button"]
},
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/styles/globals.css",
"classes": ["nodedc-toolbar-group", "nodedc-toolbar-pill", "nodedc-toolbar-primary"]
}
],
"visualContract": {
"groupRadius": "999px",
"groupPadding": "0.25rem",
"buttonRadius": "999px",
"buttonHeight": "2.5rem to 3rem depending on header scale",
"activeFill": "white or accent depending on context",
"inactiveFill": "transparent or dark group surface"
},
"rules": [
"No outlines.",
"All items share height.",
"Active segment does not resize the group.",
"Use text labels only for route/mode tabs; icon-only actions use CircleActionButton."
]
}
@@ -0,0 +1,39 @@
{
"id": "service-rail-card",
"name": "ServiceRailCard",
"kind": "component",
"status": "draft-stable",
"summary": "Bottom launcher rail item made from a square media tile and separate glass description tile with an attached circular arrow action.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/widgets/service-rail/ServiceRail.tsx"
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["service-rail", "service-rail-card", "service-rail-card__media", "service-rail-card__body"]
}
],
"anatomy": [
"rail glass strip with ambient media under blur",
"service card group",
"square media tile",
"separate square body tile",
"status pill",
"circular arrow action"
],
"layoutContract": [
"One service centers in the rail.",
"Two services divide available rail into three equal gaps.",
"Three services divide into five equal gaps.",
"When gaps would become smaller than one tile size, horizontal scroll starts."
],
"rules": [
"Media and body tiles are separated by a small seam gap.",
"Both tiles have four rounded corners.",
"Tiles touch rail vertical bounds from top to bottom after rail padding rules.",
"The arrow action can select/open the service card."
]
}
@@ -0,0 +1,33 @@
{
"id": "status-control",
"name": "StatusControl",
"kind": "component",
"status": "draft-stable",
"summary": "Status pill and status dropdown for service/client/user/invite/sync/audit states.",
"sourceRefs": [
{
"project": "nodedc_launcher",
"file": "src/widgets/admin-overlay/AdminOverlay.tsx",
"functions": ["ServiceStatusDropdown", "AdminStatusDropdown", "AdminStatusPill"]
},
{
"project": "nodedc_launcher",
"file": "src/styles/globals.css",
"classes": ["service-status-trigger", "admin-status-trigger", "admin-status-menu"]
}
],
"geometry": {
"width": "8.65rem for admin status, 7.45rem for compact service status",
"height": "2.08rem",
"radius": "999px",
"labelAlignment": "center"
},
"tones": ["green", "yellow", "violet", "red", "muted"],
"rules": [
"No outline and no select browser arrow inside status pills.",
"Clickable status opens DropdownSurface menu.",
"Static status uses the same pill geometry but pointer-events none.",
"Color opacity must stay restrained; status cannot become a bright visual hotspot."
]
}
@@ -0,0 +1,42 @@
{
"id": "work-item-card",
"name": "WorkItemCard",
"kind": "component",
"status": "stable-reference",
"summary": "Task Manager kanban work item card with avatar header, centered title, progress, footer metadata, and ellipsis action dropdown.",
"sourceRefs": [
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/core/components/issues/issue-layouts/shared/nodedc-work-item-card.tsx",
"exports": ["NodedcWorkItemCard", "NodedcWorkItemProgress", "getNodedcWorkItemCardAppearance"]
},
{
"project": "nodedc_taskmanager",
"file": "plane-src/apps/web/styles/globals.css",
"classes": ["nodedc-work-item-card"]
}
],
"anatomy": [
"rounded card surface",
"header",
"optional subtitle",
"center title area",
"segmented progress",
"footer"
],
"geometry": {
"radius": "28px in reference",
"padding": "1rem",
"minContentHeight": "220px"
},
"states": {
"passive": "cardPassive surface with muted foreground",
"active": "cardActive accent surface with on-card-active foreground"
},
"rules": [
"Kanban card ellipsis uses ActionDropdown.",
"Card click must not intercept dropdown trigger clicks.",
"Progress segments use three equal tracks and accent fill when passive."
]
}