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
2 changes: 2 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<button type="button" class="tool-button btn btn-sm btn-text" data-mode="text" title="Text tool (T)">✎ Text</button>
</div>
<div class="toolbar-spacer"></div>
<div class="toolbar-actions" aria-label="Workspace actions">
<div class="dropdown relative inline-flex">
<button id="arrange-menu" type="button" class="dropdown-toggle btn btn-sm btn-text" aria-haspopup="menu" aria-expanded="false">Arrange <span class="menu-caret">⌄</span></button>
<ul class="dropdown-menu compact-menu dropdown-open:opacity-100 hidden min-w-56" role="menu" aria-orientation="vertical" aria-labelledby="arrange-menu">
Expand Down Expand Up @@ -155,6 +156,7 @@
<button type="button" class="btn btn-sm btn-text command-trigger" title="Command menu (Ctrl+K)" aria-label="Open command menu" aria-haspopup="dialog" aria-expanded="false" aria-controls="command-modal" data-overlay="#command-modal">⌘K</button>
<button type="button" class="btn btn-sm btn-text btn-square" title="Settings" aria-label="Settings" aria-haspopup="dialog" aria-expanded="false" aria-controls="settings-modal" data-overlay="#settings-modal">⚙</button>
<button type="button" class="btn btn-sm btn-text btn-square" title="Keyboard shortcuts" aria-label="Keyboard shortcuts" aria-haspopup="dialog" aria-expanded="false" aria-controls="shortcuts-modal" data-overlay="#shortcuts-modal">?</button>
</div>
<input id="file-input" type="file" accept="application/json,application/xml,text/xml,.json,.xml" hidden>
</header>

Expand Down
35 changes: 29 additions & 6 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ button.active { color: var(--accent-strong); background: var(--accent-soft); bor
.document-title:hover, .document-title:focus { border-color: var(--border); }
.toolbar-separator { width: 1px; height: 24px; margin: 0 2px; background: var(--border); }
.toolbar-spacer { flex: 1; min-width: 4px; }
.toolbar-actions { display: flex; align-items: center; gap: 4px; min-width: 0; }
.tool-group { display: flex; align-items: center; gap: 1px; }
.toolbar button { font-size: 12px; }
.toolbar .dropdown { position: relative; }
Expand Down Expand Up @@ -588,7 +589,7 @@ kbd { padding: 3px 7px; color: var(--text); background: var(--panel-active); bor
@media (max-width: 840px) {
:root { --toolbar-height: 84px; }
#app { grid-template-columns: 1fr; grid-template-rows: var(--toolbar-height) 82px minmax(0, 1fr) 25px; }
.toolbar { align-content: center; flex-wrap: wrap; overflow: hidden; }
.toolbar { align-content: center; flex-wrap: wrap; overflow: visible; }
.document-title { width: 155px; }
.toolbar-spacer { display: none; }
.shape-panel { grid-column: 1; grid-row: 2; border-right: 0; border-bottom: 1px solid var(--border); overflow-x: auto; overflow-y: hidden; }
Expand All @@ -603,13 +604,35 @@ kbd { padding: 3px 7px; color: var(--text); background: var(--panel-active); bor
}

@media (max-width: 540px) {
:root { --toolbar-height: 116px; }
.toolbar { align-items: flex-start; padding: 5px; }
:root { --toolbar-height: 118px; }
.toolbar {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
grid-template-rows: 32px 36px 32px;
align-items: center;
gap: 3px 5px;
padding: 5px;
}
.toolbar button { font-size: 11px; }
.document-title { flex: 1; min-width: 140px; }
.brand-mark span:last-child, .theme-toggle span { display: none; }
.brand-mark { grid-column: 1; grid-row: 1; }
.document-title { grid-column: 2; grid-row: 1; width: 100%; min-width: 0; }
.toolbar > .tool-group:not(.tool-pills) { grid-column: 3; grid-row: 1; }
.tool-pills { grid-column: 1 / -1; grid-row: 2; width: 100%; }
.tool-pills button { flex: 1 1 0; min-width: 0; min-height: 32px; padding-inline: 4px; }
.toolbar-actions {
display: grid;
grid-column: 1 / -1;
grid-row: 3;
grid-template-columns: 1fr 1fr .72fr 32px 32px 32px;
gap: 2px;
width: 100%;
}
.toolbar-actions > * { min-width: 0; }
.toolbar-actions .dropdown-toggle { width: 100%; min-height: 30px; padding-inline: 3px; white-space: nowrap; }
.toolbar-actions > .dropdown:nth-child(-n + 2) .dropdown-menu { right: auto; left: 0; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the File menu within narrow phone viewports

On 320 px-wide phones, only Arrange and View are left-aligned; File retains right: 0 while its min-w-64 menu is 256 px wide. The File button's third grid column ends at roughly 213 px, so the menu starts off-screen to the left and is clipped by html, body { overflow: hidden }, making import/export and save actions inaccessible. Align File to the viewport edge (or otherwise clamp/reposition its menu) at these widths as well.

Useful? React with 👍 / 👎.

.brand-mark span:last-child, #theme-label, .toolbar-actions .menu-caret { display: none; }
.dropdown-menu { max-width: calc(100vw - 12px); }
.properties-panel { top: 123px; }
.properties-panel { top: 125px; }
#canvas-size-status { display: none; }
.settings-layout { grid-template-columns: 1fr; min-height: 0; }
.settings-tabs { flex-direction: row; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--border-soft); }
Expand Down
10 changes: 10 additions & 0 deletions tests/browser-smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,16 @@ try {
check();
}))()`);
assert(xmlImport.status.includes("Imported XML") && xmlImport.nodes === 10 && xmlImport.edges === 7, `XML round-trip failed: ${JSON.stringify(xmlImport)}`);

await client.send("Emulation.setDeviceMetricsOverride", { width: 390, height: 844, deviceScaleFactor: 1, mobile: true });
const mobileToolbar = await client.evaluate(`new Promise((resolve) => requestAnimationFrame(() => {
const controls = [...document.querySelectorAll('.toolbar [data-mode], #arrange-menu, #view-menu, #project-menu, #theme-toggle, .toolbar button[title="Settings"], .toolbar button[title="Keyboard shortcuts"]')];
resolve(controls.map((control) => {
const rect = control.getBoundingClientRect();
return { label: control.getAttribute('aria-label') || control.textContent.trim(), left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom, visible: getComputedStyle(control).display !== 'none' };
}));
}))`);
assert(mobileToolbar.every((control) => control.visible && control.left >= 0 && control.right <= 390 && control.top >= 0 && control.bottom <= 118), `Mobile toolbar controls are clipped: ${JSON.stringify(mobileToolbar)}`);
assert(client.errors.length === 0, `Browser errors: ${client.errors.join("; ")}`);

console.log("Browser smoke test passed: FlyonUI settings, commands, themes, locking, menus, modals, rendering, connectors, persistence, XML/JSON projects, and SVG/PNG export.");
Expand Down
Loading