Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions configurator/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -127,27 +127,19 @@
}
});

// On narrow viewports the preview is a slide-over overlay, so it must start
// closed — opening a full-width scrim on first paint would bury the panel.
// The media query is tracked live: shrinking the window dismisses the
// overlay instead of dropping a scrim onto the app, and widening it back
// restores the desktop pane (its default-open state).
// Track live viewport changes for the preview slide-over and output drawer.
// Initial values are already set correctly by the store (viewport-aware
// initialisation), so these effects only need to handle subsequent changes
// (e.g. rotating the device, resizing a desktop window across a breakpoint).
$effect(() => {
const mql = window.matchMedia('(max-width: 1100px)');
if (mql.matches) ui.previewOpen = false;
const onChange = (e) => {
ui.previewOpen = !e.matches;
};
const onChange = (e) => { ui.previewOpen = !e.matches; };
mql.addEventListener('change', onChange);
return () => mql.removeEventListener('change', onChange);
});

// On phone-sized viewports the output drawer starts collapsed so the main
// area has enough room to be usable. The user can always tap the bar to expand.
// Tracked live: rotating to portrait closes it; widening back re-opens it.
$effect(() => {
const mql = window.matchMedia('(max-width: 600px)');
if (mql.matches) ui.outputOpen = false;
const onChange = (e) => { ui.outputOpen = !e.matches; };
mql.addEventListener('change', onChange);
return () => mql.removeEventListener('change', onChange);
Expand Down
24 changes: 16 additions & 8 deletions configurator/src/components/Preview.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@

/** Viewport width presets — the breakpoints the framework's fluid scale targets. */
const VIEWPORTS = [
{ id: 'mobile', label: '📱 Mobile', width: 360, hint: '360 px' },
{ id: 'tablet', label: '📱 Tablet', width: 768, hint: '768 px' },
{ id: 'laptop', label: '💻 Laptop', width: 1024, hint: '1024 px' },
{ id: 'desktop', label: '🖥️ Desktop', width: 1440, hint: '1440 px' },
{ id: 'fluid', label: '🌊 Fluid', width: null, hint: 'fill pane' },
{ id: 'mobile', emoji: '📱', label: 'Mobile', width: 360, hint: '360 px' },
{ id: 'tablet', emoji: '📱', label: 'Tablet', width: 768, hint: '768 px' },
{ id: 'laptop', emoji: '💻', label: 'Laptop', width: 1024, hint: '1024 px' },
{ id: 'desktop', emoji: '🖥️', label: 'Desktop', width: 1440, hint: '1440 px' },
{ id: 'fluid', emoji: '🌊', label: 'Fluid', width: null, hint: 'fill pane' },
];

// Combine the framework cascade with optional reduced-motion override.
Expand Down Expand Up @@ -73,8 +73,8 @@
class:cfg-seg__btn--on={ui.previewWidth === v.id}
onclick={() => (ui.previewWidth = v.id)}
aria-pressed={ui.previewWidth === v.id}
title="{v.label} — {v.hint}"
>{v.label}</button>
title="{v.emoji} {v.label} — {v.hint}"
>{v.emoji}<span class="preview__vp-text"> {v.label}</span></button>
{/each}
</div>
<!-- Theme / motion toggles live in the header too, but on narrow
Expand Down Expand Up @@ -373,13 +373,21 @@
border: 1px solid var(--cfg-border-strong);
border-radius: var(--cfg-radius-s);
cursor: pointer;
flex-shrink: 0;
}
.preview__close:hover { color: var(--cfg-text); border-color: var(--cfg-accent-strong); }
@media (max-width: 1100px) {
.preview__close { display: inline-grid; place-items: center; }
/* Minimum 44 × 44 px touch target per WCAG 2.5.5. */
.preview__close { display: inline-grid; place-items: center; min-width: 44px; min-height: 44px; }
.preview__hint { display: none; }
.preview__bar { flex-wrap: wrap; gap: 8px; }
}
/* On very narrow phones the viewport-button labels push the row past the
pane width; show only the emoji so all five buttons stay accessible. */
@media (max-width: 430px) {
.preview__vp-text { display: none; }
.preview__vp-btn { padding-inline: 7px; }
}
/* Sample UI authored against framework tokens with sane fallbacks. */
.pv {
font-family: var(--sf-font-body, system-ui, sans-serif);
Expand Down
15 changes: 11 additions & 4 deletions configurator/src/lib/store.svelte.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,17 @@ export const ui = $state({
outputMode: savedUi.outputMode ?? 'layer',
/** Sidebar collapse — for narrow viewports / a focus-mode. */
sidebarOpen: true,
/** Right-hand preview pane visible. */
previewOpen: true,
/** Output drawer (override CSS export) expanded. */
outputOpen: true,
/**
* Right-hand preview pane visible. Initialised from the current viewport so
* the mobile slide-over never flashes open on first paint (the App.svelte
* effect only handles subsequent viewport changes).
*/
previewOpen: typeof window === 'undefined' || !window.matchMedia('(max-width: 1100px)').matches,
/**
* Output drawer (override CSS export) expanded. Same viewport-aware
* initialisation pattern: phones start collapsed so the main area is usable.
*/
outputOpen: typeof window === 'undefined' || !window.matchMedia('(max-width: 600px)').matches,
});

/**
Expand Down