feat(site-builder): tablet/mobile style overrides that never touch desktop

On tablet/mobile the useNodeProp style setters now route responsive keys
(spacing, font size, line height, letter spacing, alignment, size, flex
layout) into styleTablet/styleMobile; colours and other keys still write
style. An empty value removes the override. Continuous-burst keys include
the device so a desktop drag and a mobile drag never merge.

- shared.tsx: device-aware setters, new setResponsiveStyleProp /
  clearResponsiveStyleProp exports, setPropStylesContinuous
- responsive-panel.tsx: useResolvedStyle, useOverrideState, DeviceBanner
- OverrideDot: filled dot resets the override (one undo step), hollow dot
  marks an inherited value; wired into Text/Button/Container/Image/Media/
  BackgroundSection panels and both box-model sections
- Columns: "Stack on this device" toggle (flexDirection override)
- GuidedStyles: device banner under the type header
- RenderNode: every component node renders through one stable
  ResolvedRender so gaining/losing an override or switching device no
  longer remounts the node (the remount dropped inline-edit focus/caret
  and blanked a selected Heading)

Refs #45
This commit is contained in:
shadowdao committed 2026-10-07 11:51:53 -07:00
1 parent d8ff295093
commit c2a90cd7a7
15 files changed
+806 -78

No files matched your search

+69
View File
@@ -2441,3 +2441,72 @@ body {
background: var(--color-accent-subtle);
cursor: default;
}
/* #45 overrides */
.wsb-override-dot {
display: inline-block;
width: 8px;
height: 8px;
margin-left: 6px;
padding: 0;
vertical-align: middle;
border-radius: 50%;
box-sizing: border-box;
}
.wsb-override-dot.is-set {
background: var(--color-accent);
border: 1px solid var(--color-accent);
cursor: pointer;
}
.wsb-override-dot.is-set:hover,
.wsb-override-dot.is-set:focus-visible {
background: var(--color-danger);
border-color: var(--color-danger);
outline: none;
}
.wsb-override-dot.is-inherited {
background: transparent;
border: 1px solid var(--color-text-dim);
}
.wsb-device-banner {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px 8px;
margin: 0 0 8px;
padding: 8px 10px;
font-size: 11px;
line-height: 1.4;
color: var(--color-text);
background: var(--color-accent-subtle);
border: 1px solid var(--color-accent);
border-radius: var(--radius-md);
}
.wsb-device-banner > span {
flex: 1 1 180px;
}
.wsb-device-banner-back {
padding: 0;
font: inherit;
font-weight: 600;
color: var(--color-accent);
background: none;
border: 0;
cursor: pointer;
text-decoration: underline;
}
.wsb-stack-toggle {
display: flex;
align-items: center;
gap: 6px;
font-size: 11px;
color: var(--color-text);
cursor: pointer;
}