feat(ui): add bounded workspace windows

This commit is contained in:
Codex
2026-07-16 20:56:23 +03:00
parent a1c4ecaa93
commit 5f583caa05
8 changed files with 661 additions and 3 deletions
+171 -2
View File
@@ -15,13 +15,13 @@
box-sizing: border-box;
}
:where(.nodedc-button, .nodedc-icon-button, .nodedc-checker, .nodedc-select-trigger, .nodedc-select__toggle, .nodedc-dropdown-option, .nodedc-segmented__item, .nodedc-header__nav-item, .nodedc-inspector__section-trigger, .nodedc-window__close) {
:where(.nodedc-button, .nodedc-icon-button, .nodedc-checker, .nodedc-select-trigger, .nodedc-select__toggle, .nodedc-dropdown-option, .nodedc-segmented__item, .nodedc-header__nav-item, .nodedc-inspector__section-trigger, .nodedc-window__close, .nodedc-workspace-window__action, .nodedc-workspace-window__resize) {
border: 0;
outline: 0;
font: inherit;
}
:where(.nodedc-button, .nodedc-icon-button, .nodedc-checker, .nodedc-select-trigger, .nodedc-select__toggle, .nodedc-dropdown-option, .nodedc-segmented__item, .nodedc-header__nav-item, .nodedc-inspector__section-trigger, .nodedc-window__close):focus-visible {
:where(.nodedc-button, .nodedc-icon-button, .nodedc-checker, .nodedc-select-trigger, .nodedc-select__toggle, .nodedc-dropdown-option, .nodedc-segmented__item, .nodedc-header__nav-item, .nodedc-inspector__section-trigger, .nodedc-window__close, .nodedc-workspace-window__action, .nodedc-workspace-window__resize):focus-visible {
background-color: var(--nodedc-focus-surface);
box-shadow: var(--nodedc-glass-control-shadow), inset 0 0 0 1px rgb(var(--nodedc-accent-rgb) / 0.22);
}
@@ -2163,6 +2163,174 @@ textarea.nodedc-field__control {
gap: var(--nodedc-space-2);
}
.nodedc-workspace-window {
position: absolute;
isolation: isolate;
display: grid;
min-width: 0;
min-height: 0;
grid-template-rows: auto minmax(0, 1fr) auto;
overflow: hidden;
border: 0;
border-radius: var(--nodedc-radius-modal);
animation: nodedc-window-in var(--nodedc-duration-normal) var(--nodedc-ease-standard);
touch-action: none;
}
.nodedc-workspace-window[data-active="true"] {
box-shadow: var(--nodedc-modal-shadow), 0 0 0 1px color-mix(in srgb, var(--nodedc-text-primary) 16%, transparent);
}
.nodedc-workspace-window[data-maximized="true"] {
border-radius: inherit;
}
.nodedc-workspace-window__head {
display: grid;
min-height: 3.45rem;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: var(--nodedc-space-3);
padding: 0.62rem 0.65rem 0.5rem 1rem;
cursor: grab;
outline: 0;
touch-action: none;
user-select: none;
}
.nodedc-workspace-window__head:focus-visible {
background: var(--nodedc-focus-surface);
box-shadow: inset 0 0 0 1px rgb(var(--nodedc-accent-rgb) / 0.22);
}
.nodedc-workspace-window[data-maximized="true"] .nodedc-workspace-window__head {
cursor: default;
}
.nodedc-workspace-window[data-interaction="move"] .nodedc-workspace-window__head {
cursor: grabbing;
}
.nodedc-workspace-window__titles {
display: grid;
min-width: 0;
gap: 0.2rem;
}
.nodedc-workspace-window__title-row {
display: flex;
min-width: 0;
align-items: center;
gap: var(--nodedc-space-2);
}
.nodedc-workspace-window__title,
.nodedc-workspace-window__subtitle {
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.nodedc-workspace-window__title {
color: var(--nodedc-text-primary);
font-size: var(--nodedc-font-size-md);
font-weight: var(--nodedc-font-weight-strong);
line-height: 1.2;
}
.nodedc-workspace-window__subtitle,
.nodedc-workspace-window__status {
color: var(--nodedc-text-muted);
font-size: var(--nodedc-font-size-xs);
font-weight: var(--nodedc-font-weight-medium);
line-height: 1.25;
}
.nodedc-workspace-window__status {
flex: 0 0 auto;
}
.nodedc-workspace-window__actions {
display: flex;
align-items: center;
gap: 0.35rem;
}
.nodedc-workspace-window__action {
display: inline-grid;
width: 2rem;
height: 2rem;
place-items: center;
border-radius: var(--nodedc-radius-circle);
background: var(--nodedc-glass-control-bg);
color: var(--nodedc-text-secondary);
box-shadow: var(--nodedc-glass-control-shadow);
cursor: pointer;
}
.nodedc-workspace-window__action:hover {
background: var(--nodedc-glass-control-hover);
color: var(--nodedc-text-primary);
}
.nodedc-workspace-window__body {
min-width: 0;
min-height: 0;
overflow: auto;
overscroll-behavior: contain;
padding: 0.25rem 1rem 0.8rem;
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.14) transparent;
touch-action: auto;
}
.nodedc-workspace-window__footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--nodedc-space-2);
padding: 0.55rem 1rem 0.8rem;
}
.nodedc-workspace-window__resize {
position: absolute;
z-index: 3;
right: 0.2rem;
bottom: 0.2rem;
width: 1.55rem;
height: 1.55rem;
border-radius: 0.4rem;
background: transparent;
color: var(--nodedc-text-muted);
cursor: nwse-resize;
touch-action: none;
}
.nodedc-workspace-window__resize::before,
.nodedc-workspace-window__resize::after {
position: absolute;
right: 0.32rem;
bottom: 0.32rem;
border-right: 1px solid currentColor;
border-bottom: 1px solid currentColor;
content: "";
}
.nodedc-workspace-window__resize::before {
width: 0.72rem;
height: 0.72rem;
}
.nodedc-workspace-window__resize::after {
width: 0.36rem;
height: 0.36rem;
}
.nodedc-workspace-window[data-interaction="resize"] .nodedc-workspace-window__resize {
color: var(--nodedc-text-primary);
}
.nodedc-toolbar-wrap {
position: fixed;
z-index: calc(var(--nodedc-layer-header) + 20);
@@ -2823,6 +2991,7 @@ textarea.nodedc-field__control {
.nodedc-dropdown-surface,
.nodedc-overlay,
.nodedc-window,
.nodedc-workspace-window,
.nodedc-application-panel,
.nodedc-inspector__section-content {
animation: none;