Refine glass material and environment controls
This commit is contained in:
@@ -2,23 +2,57 @@ import { createAccentVariables, type RgbTuple } from "./accent.js";
|
||||
|
||||
export type NodedcTheme = "dark" | "light";
|
||||
|
||||
export interface NodedcMaterial {
|
||||
/** Base fill used by glass panels, application windows and modals. */
|
||||
panel?: RgbTuple;
|
||||
/** 0–1 alpha for the base glass panel. */
|
||||
panelOpacity?: number;
|
||||
/** Base fill used by text, range and selection fields. */
|
||||
field?: RgbTuple;
|
||||
/** 0–1 alpha for field fill. */
|
||||
fieldOpacity?: number;
|
||||
}
|
||||
|
||||
export interface ApplyThemeOptions {
|
||||
theme?: NodedcTheme;
|
||||
accent?: RgbTuple;
|
||||
material?: NodedcMaterial;
|
||||
}
|
||||
|
||||
function formatRgb([red, green, blue]: RgbTuple): string {
|
||||
return `${red} ${green} ${blue}`;
|
||||
}
|
||||
|
||||
function clampOpacity(value: number): number {
|
||||
return Math.max(0, Math.min(1, value));
|
||||
}
|
||||
|
||||
export function applyNodedcTheme(
|
||||
target: HTMLElement,
|
||||
{ theme = "dark", accent }: ApplyThemeOptions = {},
|
||||
{ theme = "dark", accent, material }: ApplyThemeOptions = {},
|
||||
): void {
|
||||
target.dataset.nodedcTheme = theme;
|
||||
target.dataset.nodedcUi = "true";
|
||||
|
||||
if (!accent) return;
|
||||
const variables = createAccentVariables(accent);
|
||||
Object.entries(variables).forEach(([property, value]) => {
|
||||
target.style.setProperty(property, value);
|
||||
});
|
||||
if (accent) {
|
||||
const variables = createAccentVariables(accent);
|
||||
Object.entries(variables).forEach(([property, value]) => {
|
||||
target.style.setProperty(property, value);
|
||||
});
|
||||
}
|
||||
|
||||
if (!material) return;
|
||||
if (material.panel) target.style.setProperty("--nodedc-panel-material-rgb", formatRgb(material.panel));
|
||||
if (typeof material.panelOpacity === "number" && Number.isFinite(material.panelOpacity)) {
|
||||
const opacity = clampOpacity(material.panelOpacity);
|
||||
target.style.setProperty("--nodedc-panel-material-opacity", String(opacity));
|
||||
target.style.setProperty("--nodedc-panel-material-strong-opacity", String(clampOpacity(opacity + 0.12)));
|
||||
target.style.setProperty("--nodedc-panel-material-soft-opacity", String(clampOpacity(Math.max(0.12, opacity - 0.2))));
|
||||
}
|
||||
if (material.field) target.style.setProperty("--nodedc-field-material-rgb", formatRgb(material.field));
|
||||
if (typeof material.fieldOpacity === "number" && Number.isFinite(material.fieldOpacity)) {
|
||||
target.style.setProperty("--nodedc-field-material-opacity", String(clampOpacity(material.fieldOpacity)));
|
||||
}
|
||||
}
|
||||
|
||||
export function clearNodedcAccent(target: HTMLElement): void {
|
||||
@@ -26,3 +60,13 @@ export function clearNodedcAccent(target: HTMLElement): void {
|
||||
target.style.removeProperty("--nodedc-on-accent-rgb");
|
||||
}
|
||||
|
||||
export function clearNodedcMaterial(target: HTMLElement): void {
|
||||
[
|
||||
"--nodedc-panel-material-rgb",
|
||||
"--nodedc-panel-material-opacity",
|
||||
"--nodedc-panel-material-strong-opacity",
|
||||
"--nodedc-panel-material-soft-opacity",
|
||||
"--nodedc-field-material-rgb",
|
||||
"--nodedc-field-material-opacity",
|
||||
].forEach((property) => target.style.removeProperty(property));
|
||||
}
|
||||
|
||||
+74
-34
@@ -23,7 +23,7 @@
|
||||
|
||||
: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 {
|
||||
background-color: var(--nodedc-focus-surface);
|
||||
box-shadow: var(--nodedc-glass-control-shadow), inset 0 0 0 1px rgba(var(--nodedc-accent-rgb), 0.22);
|
||||
box-shadow: var(--nodedc-glass-control-shadow), inset 0 0 0 1px rgb(var(--nodedc-accent-rgb) / 0.22);
|
||||
}
|
||||
|
||||
.nodedc-material-rim {
|
||||
@@ -54,8 +54,8 @@
|
||||
background: var(--nodedc-glass-panel-surface);
|
||||
color: var(--nodedc-text-primary);
|
||||
box-shadow: var(--nodedc-glass-panel-shadow);
|
||||
backdrop-filter: blur(var(--nodedc-blur-panel)) saturate(1.24) brightness(1.04);
|
||||
-webkit-backdrop-filter: blur(var(--nodedc-blur-panel)) saturate(1.24) brightness(1.04);
|
||||
backdrop-filter: blur(var(--nodedc-blur-panel)) saturate(1.28) brightness(1.05);
|
||||
-webkit-backdrop-filter: blur(var(--nodedc-blur-panel)) saturate(1.28) brightness(1.05);
|
||||
}
|
||||
|
||||
.nodedc-glass[data-tone="strong"] {
|
||||
@@ -136,12 +136,24 @@
|
||||
|
||||
.nodedc-button[data-variant="primary"],
|
||||
.nodedc-button[data-variant="accent"] {
|
||||
--nodedc-button-bg: rgb(var(--nodedc-accent-rgb));
|
||||
--nodedc-button-color: rgb(var(--nodedc-on-accent-rgb));
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.nodedc-button[data-variant="primary"]:hover:not(:disabled),
|
||||
.nodedc-button[data-variant="primary"] {
|
||||
--nodedc-button-bg: var(--nodedc-primary-action-bg);
|
||||
--nodedc-button-color: var(--nodedc-primary-action-color);
|
||||
box-shadow: var(--nodedc-primary-action-shadow);
|
||||
}
|
||||
|
||||
.nodedc-button[data-variant="accent"] {
|
||||
--nodedc-button-bg: rgb(var(--nodedc-accent-rgb));
|
||||
--nodedc-button-color: rgb(var(--nodedc-on-accent-rgb));
|
||||
}
|
||||
|
||||
.nodedc-button[data-variant="primary"]:hover:not(:disabled) {
|
||||
background: var(--nodedc-primary-action-hover);
|
||||
}
|
||||
|
||||
.nodedc-button[data-variant="accent"]:hover:not(:disabled) {
|
||||
background: color-mix(in srgb, rgb(var(--nodedc-accent-rgb)) 84%, white);
|
||||
}
|
||||
@@ -159,7 +171,7 @@
|
||||
}
|
||||
|
||||
.nodedc-button[data-variant="danger"]:hover:not(:disabled) {
|
||||
background: rgba(var(--nodedc-danger-rgb), 0.12);
|
||||
background: rgb(var(--nodedc-danger-rgb) / 0.12);
|
||||
}
|
||||
|
||||
.nodedc-button:disabled,
|
||||
@@ -279,7 +291,7 @@
|
||||
|
||||
.nodedc-field__control:focus-visible {
|
||||
background: var(--nodedc-focus-surface);
|
||||
box-shadow: var(--nodedc-glass-control-shadow), inset 0 0 0 1px rgba(var(--nodedc-accent-rgb), 0.22);
|
||||
box-shadow: var(--nodedc-glass-control-shadow), inset 0 0 0 1px rgb(var(--nodedc-accent-rgb) / 0.22);
|
||||
}
|
||||
|
||||
textarea.nodedc-field__control {
|
||||
@@ -366,8 +378,8 @@ textarea.nodedc-field__control {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--nodedc-radius-circle);
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
color: rgba(8, 8, 10, 0.96);
|
||||
background: var(--nodedc-primary-action-bg);
|
||||
color: var(--nodedc-primary-action-color);
|
||||
padding: 0 1rem;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 850;
|
||||
@@ -376,7 +388,7 @@ textarea.nodedc-field__control {
|
||||
}
|
||||
|
||||
.nodedc-media-file__button:hover {
|
||||
background: #fff;
|
||||
background: var(--nodedc-primary-action-hover);
|
||||
}
|
||||
|
||||
.nodedc-media-file__name {
|
||||
@@ -433,9 +445,9 @@ textarea.nodedc-field__control {
|
||||
}
|
||||
|
||||
.nodedc-media-source-button[data-active="true"] {
|
||||
border-color: rgba(255, 255, 255, 0.92);
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
color: rgba(8, 8, 10, 0.96);
|
||||
border-color: var(--nodedc-primary-action-bg);
|
||||
background: var(--nodedc-primary-action-bg);
|
||||
color: var(--nodedc-primary-action-color);
|
||||
}
|
||||
|
||||
.nodedc-media-preview {
|
||||
@@ -744,7 +756,7 @@ textarea.nodedc-field__control {
|
||||
|
||||
.nodedc-color-field__picker[data-open="true"],
|
||||
.nodedc-color-field__picker:focus-visible {
|
||||
box-shadow: 0 0 0 2px rgba(var(--nodedc-accent-rgb), 0.3), 0 0 0 3px var(--nodedc-canvas);
|
||||
box-shadow: 0 0 0 2px rgb(var(--nodedc-accent-rgb) / 0.3), 0 0 0 3px var(--nodedc-canvas);
|
||||
}
|
||||
|
||||
.nodedc-color-field__picker:disabled {
|
||||
@@ -780,7 +792,7 @@ textarea.nodedc-field__control {
|
||||
}
|
||||
|
||||
.nodedc-color-palette__spectrum:focus-visible {
|
||||
box-shadow: 0 0 0 2px rgba(var(--nodedc-accent-rgb), 0.28);
|
||||
box-shadow: 0 0 0 2px rgb(var(--nodedc-accent-rgb) / 0.28);
|
||||
}
|
||||
|
||||
.nodedc-color-palette__marker {
|
||||
@@ -881,22 +893,22 @@ textarea.nodedc-field__control {
|
||||
}
|
||||
|
||||
.nodedc-status[data-tone="success"] {
|
||||
background: rgba(var(--nodedc-success-rgb), 0.1);
|
||||
background: rgb(var(--nodedc-success-rgb) / 0.1);
|
||||
color: color-mix(in srgb, rgb(var(--nodedc-success-rgb)) 74%, var(--nodedc-text-primary));
|
||||
}
|
||||
|
||||
.nodedc-status[data-tone="warning"] {
|
||||
background: rgba(var(--nodedc-warning-rgb), 0.1);
|
||||
background: rgb(var(--nodedc-warning-rgb) / 0.1);
|
||||
color: color-mix(in srgb, rgb(var(--nodedc-warning-rgb)) 74%, var(--nodedc-text-primary));
|
||||
}
|
||||
|
||||
.nodedc-status[data-tone="danger"] {
|
||||
background: rgba(var(--nodedc-danger-rgb), 0.1);
|
||||
background: rgb(var(--nodedc-danger-rgb) / 0.1);
|
||||
color: color-mix(in srgb, rgb(var(--nodedc-danger-rgb)) 74%, var(--nodedc-text-primary));
|
||||
}
|
||||
|
||||
.nodedc-status[data-tone="accent"] {
|
||||
background: rgba(var(--nodedc-accent-rgb), 0.1);
|
||||
background: rgb(var(--nodedc-accent-rgb) / 0.1);
|
||||
color: color-mix(in srgb, rgb(var(--nodedc-accent-rgb)) 76%, var(--nodedc-text-primary));
|
||||
}
|
||||
|
||||
@@ -1682,7 +1694,7 @@ textarea.nodedc-field__control {
|
||||
}
|
||||
|
||||
.nodedc-dropdown-option[data-selected="true"] {
|
||||
background: rgba(var(--nodedc-accent-rgb), 0.14);
|
||||
background: rgb(var(--nodedc-accent-rgb) / 0.14);
|
||||
}
|
||||
|
||||
.nodedc-dropdown-option__icon,
|
||||
@@ -1773,7 +1785,7 @@ textarea.nodedc-field__control {
|
||||
|
||||
.nodedc-select__toggle:focus-visible {
|
||||
background: var(--nodedc-focus-surface);
|
||||
box-shadow: var(--nodedc-glass-control-shadow), inset 0 0 0 1px rgba(var(--nodedc-accent-rgb), 0.22);
|
||||
box-shadow: var(--nodedc-glass-control-shadow), inset 0 0 0 1px rgb(var(--nodedc-accent-rgb) / 0.22);
|
||||
}
|
||||
|
||||
.nodedc-dropdown-surface.nodedc-select__menu {
|
||||
@@ -1876,8 +1888,8 @@ textarea.nodedc-field__control {
|
||||
background: var(--nodedc-glass-panel-surface-strong);
|
||||
color: var(--nodedc-text-primary);
|
||||
box-shadow: var(--nodedc-glass-panel-shadow);
|
||||
backdrop-filter: blur(var(--nodedc-blur-modal)) saturate(1.35) brightness(1.04);
|
||||
-webkit-backdrop-filter: blur(var(--nodedc-blur-modal)) saturate(1.35) brightness(1.04);
|
||||
backdrop-filter: blur(var(--nodedc-blur-modal)) saturate(1.38) brightness(1.06);
|
||||
-webkit-backdrop-filter: blur(var(--nodedc-blur-modal)) saturate(1.38) brightness(1.06);
|
||||
animation: nodedc-window-in var(--nodedc-duration-normal) var(--nodedc-ease-standard);
|
||||
}
|
||||
|
||||
@@ -1922,11 +1934,11 @@ textarea.nodedc-field__control {
|
||||
|
||||
.nodedc-window__head {
|
||||
display: grid;
|
||||
min-height: 4.75rem;
|
||||
min-height: 4.25rem;
|
||||
grid-template-columns: minmax(0, 1fr) var(--nodedc-icon-button-size);
|
||||
align-items: center;
|
||||
gap: var(--nodedc-space-3);
|
||||
padding: 1rem 1rem 0.75rem 1.5rem;
|
||||
padding: 0.8rem 0.9rem 0.55rem 1.15rem;
|
||||
}
|
||||
|
||||
.nodedc-window__titles {
|
||||
@@ -2005,7 +2017,7 @@ textarea.nodedc-field__control {
|
||||
.nodedc-window__body {
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding: 0.75rem 1.5rem 1.5rem;
|
||||
padding: 0.5rem 1.15rem 0.9rem;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(255, 255, 255, 0.14) transparent;
|
||||
}
|
||||
@@ -2015,7 +2027,7 @@ textarea.nodedc-field__control {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--nodedc-space-3);
|
||||
padding: 0.9rem 1.5rem 1.25rem;
|
||||
padding: 0.65rem 1.15rem 0.9rem;
|
||||
}
|
||||
|
||||
.nodedc-window__footer-actions {
|
||||
@@ -2026,7 +2038,7 @@ textarea.nodedc-field__control {
|
||||
}
|
||||
|
||||
.nodedc-window.nodedc-share-access-window {
|
||||
width: min(37.5rem, calc(100vw - 2rem));
|
||||
width: min(35rem, calc(100vw - 2rem));
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
@@ -2038,7 +2050,7 @@ textarea.nodedc-field__control {
|
||||
|
||||
.nodedc-share-access {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
gap: 0.65rem;
|
||||
}
|
||||
|
||||
.nodedc-share-access__members,
|
||||
@@ -2052,7 +2064,7 @@ textarea.nodedc-field__control {
|
||||
.nodedc-share-access__members {
|
||||
position: relative;
|
||||
z-index: 20;
|
||||
gap: 0.62rem;
|
||||
gap: 0.38rem;
|
||||
}
|
||||
|
||||
.nodedc-share-access__section-label {
|
||||
@@ -2203,9 +2215,9 @@ textarea.nodedc-field__control {
|
||||
|
||||
.nodedc-share-access__invite {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 11rem;
|
||||
grid-template-columns: minmax(0, 1fr) 9.5rem;
|
||||
align-items: end;
|
||||
gap: 0.75rem;
|
||||
gap: 0.55rem;
|
||||
}
|
||||
|
||||
.nodedc-share-access__readonly {
|
||||
@@ -2244,7 +2256,7 @@ textarea.nodedc-field__control {
|
||||
height: 2.75rem;
|
||||
place-items: center;
|
||||
border-radius: var(--nodedc-radius-control-compact);
|
||||
background: rgba(var(--nodedc-danger-rgb), 0.1);
|
||||
background: rgb(var(--nodedc-danger-rgb) / 0.1);
|
||||
color: rgb(var(--nodedc-danger-rgb));
|
||||
}
|
||||
|
||||
@@ -2335,6 +2347,11 @@ textarea.nodedc-field__control {
|
||||
gap: var(--nodedc-inspector-control-gap);
|
||||
}
|
||||
|
||||
.nodedc-control-row[data-action="true"] {
|
||||
grid-template-columns: minmax(6.4rem, 1fr) minmax(0, 1fr) var(--nodedc-control-height);
|
||||
gap: var(--nodedc-space-2);
|
||||
}
|
||||
|
||||
.nodedc-control-row[data-layout="stack"] {
|
||||
grid-template-columns: 1fr;
|
||||
align-items: stretch;
|
||||
@@ -2352,6 +2369,12 @@ textarea.nodedc-field__control {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nodedc-control-row__action {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.nodedc-empty-state {
|
||||
display: grid;
|
||||
min-height: 12rem;
|
||||
@@ -2494,6 +2517,23 @@ textarea.nodedc-field__control {
|
||||
gap: var(--nodedc-space-2);
|
||||
}
|
||||
|
||||
.nodedc-control-row[data-action="true"] {
|
||||
grid-template-columns: minmax(0, 1fr) var(--nodedc-control-height);
|
||||
}
|
||||
|
||||
.nodedc-control-row[data-action="true"] .nodedc-control-row__label {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.nodedc-control-row[data-action="true"] .nodedc-control-row__control {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.nodedc-control-row[data-action="true"] .nodedc-control-row__action {
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.nodedc-media-control {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
border-radius: var(--nodedc-radius-card);
|
||||
|
||||
Reference in New Issue
Block a user