@floless/app 0.23.0 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/floless-server.cjs +2 -2
- package/dist/web/app.css +63 -0
- package/dist/web/app.js +91 -0
- package/dist/web/index.html +27 -0
- package/package.json +1 -1
package/dist/floless-server.cjs
CHANGED
|
@@ -52729,7 +52729,7 @@ function appVersion() {
|
|
|
52729
52729
|
return resolveVersion({
|
|
52730
52730
|
isSea: isSea2(),
|
|
52731
52731
|
sqVersionXml: readSqVersionXml(),
|
|
52732
|
-
define: true ? "0.23.
|
|
52732
|
+
define: true ? "0.23.1" : void 0,
|
|
52733
52733
|
pkgVersion: readPkgVersion()
|
|
52734
52734
|
});
|
|
52735
52735
|
}
|
|
@@ -52739,7 +52739,7 @@ function resolveChannel(s) {
|
|
|
52739
52739
|
return "dev";
|
|
52740
52740
|
}
|
|
52741
52741
|
function appChannel() {
|
|
52742
|
-
return resolveChannel({ isSea: isSea2(), define: true ? "0.23.
|
|
52742
|
+
return resolveChannel({ isSea: isSea2(), define: true ? "0.23.1" : void 0 });
|
|
52743
52743
|
}
|
|
52744
52744
|
|
|
52745
52745
|
// oauth-presets.ts
|
package/dist/web/app.css
CHANGED
|
@@ -1799,6 +1799,9 @@
|
|
|
1799
1799
|
`hidden` attribute, so it showed even when unsupported (dev/non-Windows). Restore
|
|
1800
1800
|
the hide with a class+attribute selector (higher specificity than .menu-theme). */
|
|
1801
1801
|
.menu-startup[hidden] { display: none; }
|
|
1802
|
+
/* Same footgun: .menu-item is display:flex, so JS-hiding the fullscreen row on
|
|
1803
|
+
browsers without the Fullscreen API needs an explicit hide to win over flex. */
|
|
1804
|
+
#menu-fullscreen[hidden] { display: none; }
|
|
1802
1805
|
.theme-toggle {
|
|
1803
1806
|
display: flex;
|
|
1804
1807
|
gap: 2px;
|
|
@@ -1865,6 +1868,66 @@
|
|
|
1865
1868
|
to { opacity: 1; transform: translateY(0); }
|
|
1866
1869
|
}
|
|
1867
1870
|
|
|
1871
|
+
/* ========== FULLSCREEN NUDGE ==========
|
|
1872
|
+
One-time "need more space?" prompt, bottom-right. Deliberately shares the
|
|
1873
|
+
toast/whats-new notification language (surface card + 3px accent left rail)
|
|
1874
|
+
so it reads as a calm FloLess notice, not a marketing card — no glow, no
|
|
1875
|
+
gradient, no oversized shadow. */
|
|
1876
|
+
.fullscreen-nudge {
|
|
1877
|
+
position: fixed;
|
|
1878
|
+
right: 20px;
|
|
1879
|
+
bottom: 60px; /* clears the footer — matches the toast anchor */
|
|
1880
|
+
z-index: 210; /* above toasts (200): they share this corner */
|
|
1881
|
+
display: flex;
|
|
1882
|
+
align-items: flex-start;
|
|
1883
|
+
gap: 10px;
|
|
1884
|
+
width: 290px;
|
|
1885
|
+
background: var(--surface);
|
|
1886
|
+
border: 1px solid var(--border-strong);
|
|
1887
|
+
border-left: 3px solid var(--accent);
|
|
1888
|
+
border-radius: 6px;
|
|
1889
|
+
padding: 13px 12px 14px 15px;
|
|
1890
|
+
box-shadow: 0 12px 32px rgba(0,0,0,0.45);
|
|
1891
|
+
animation: fsn-in 0.16s ease-out;
|
|
1892
|
+
}
|
|
1893
|
+
/* .fullscreen-nudge is display:flex, which overrides the UA [hidden]{display:none}
|
|
1894
|
+
— restore the hide (same footgun the .menu-startup row hit). */
|
|
1895
|
+
.fullscreen-nudge[hidden] { display: none; }
|
|
1896
|
+
.fsn-text { flex: 1; min-width: 0; }
|
|
1897
|
+
.fsn-title { font-size: 13px; font-weight: 600; color: var(--text); line-height: 1.35; }
|
|
1898
|
+
.fsn-sub { font-size: 11.5px; color: var(--text-muted); line-height: 1.5; margin-top: 4px; }
|
|
1899
|
+
.fsn-go {
|
|
1900
|
+
margin-top: 11px;
|
|
1901
|
+
background: var(--accent);
|
|
1902
|
+
color: #fff;
|
|
1903
|
+
border: 1px solid var(--accent);
|
|
1904
|
+
border-radius: 4px;
|
|
1905
|
+
padding: 6px 12px;
|
|
1906
|
+
font-size: 11.5px;
|
|
1907
|
+
font-weight: 600;
|
|
1908
|
+
cursor: pointer;
|
|
1909
|
+
}
|
|
1910
|
+
.fsn-go:hover { background: var(--accent-bright); border-color: var(--accent-bright); box-shadow: 0 0 14px var(--accent-glow); }
|
|
1911
|
+
.fsn-dismiss {
|
|
1912
|
+
flex: none;
|
|
1913
|
+
background: transparent;
|
|
1914
|
+
border: none;
|
|
1915
|
+
color: var(--text-dim);
|
|
1916
|
+
font-size: 13px;
|
|
1917
|
+
line-height: 1;
|
|
1918
|
+
padding: 2px 4px;
|
|
1919
|
+
margin: -2px -2px 0 0;
|
|
1920
|
+
cursor: pointer;
|
|
1921
|
+
border-radius: 3px;
|
|
1922
|
+
}
|
|
1923
|
+
.fsn-dismiss:hover { color: var(--text); background: var(--surface-2); }
|
|
1924
|
+
@keyframes fsn-in {
|
|
1925
|
+
from { opacity: 0; transform: translateY(6px); }
|
|
1926
|
+
to { opacity: 1; transform: none; }
|
|
1927
|
+
}
|
|
1928
|
+
/* Calm, not flashy — honour reduced-motion by appearing without the fade/slide. */
|
|
1929
|
+
@media (prefers-reduced-motion: reduce) { .fullscreen-nudge { animation: none; } }
|
|
1930
|
+
|
|
1868
1931
|
/* ========== FIND OVERLAY ========== */
|
|
1869
1932
|
.find-overlay {
|
|
1870
1933
|
position: absolute;
|
package/dist/web/app.js
CHANGED
|
@@ -1042,6 +1042,7 @@ function handleMenuAction(action) {
|
|
|
1042
1042
|
case 'integrations': openIntegrations(); break;
|
|
1043
1043
|
case 'routines': openRoutines(); break;
|
|
1044
1044
|
case 'report-issue': openReportIssue(); break;
|
|
1045
|
+
case 'fullscreen': toggleFullscreen(); break;
|
|
1045
1046
|
}
|
|
1046
1047
|
}
|
|
1047
1048
|
|
|
@@ -1186,6 +1187,96 @@ if ($startupToggle) {
|
|
|
1186
1187
|
// e.g. the user disabling the task in Windows Settings).
|
|
1187
1188
|
refreshStartup();
|
|
1188
1189
|
|
|
1190
|
+
/* ============= FULLSCREEN ============= */
|
|
1191
|
+
// Browser Fullscreen API on the root element — gives the 3-col workspace the whole
|
|
1192
|
+
// screen. The ≡ menu row and a one-time "more space?" nudge both call toggleFullscreen.
|
|
1193
|
+
// The row's icon/label are kept honest by `fullscreenchange` (covers Esc and other
|
|
1194
|
+
// out-of-band exits). If the API is unsupported we hide the row and never nudge —
|
|
1195
|
+
// the app's "hide, never show a dead control" rule (mirrors the startup row).
|
|
1196
|
+
|
|
1197
|
+
const FS_NUDGE_KEY = 'floless-fullscreen-nudge-v1';
|
|
1198
|
+
const $fsRow = document.getElementById('menu-fullscreen');
|
|
1199
|
+
const $fsIcon = document.getElementById('menu-fullscreen-icon');
|
|
1200
|
+
const $fsLabel = document.getElementById('menu-fullscreen-label');
|
|
1201
|
+
const $fsNudge = document.getElementById('fullscreen-nudge');
|
|
1202
|
+
|
|
1203
|
+
// Lucide maximize / minimize (same icon family as the other menu rows).
|
|
1204
|
+
const FS_ICON_ENTER = '<svg viewBox="0 0 24 24"><path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/></svg>';
|
|
1205
|
+
const FS_ICON_EXIT = '<svg viewBox="0 0 24 24"><path d="M8 3v3a2 2 0 0 1-2 2H3"/><path d="M21 8h-3a2 2 0 0 1-2-2V3"/><path d="M3 16h3a2 2 0 0 1 2 2v3"/><path d="M16 21v-3a2 2 0 0 1 2-2h3"/></svg>';
|
|
1206
|
+
|
|
1207
|
+
function fullscreenSupported() {
|
|
1208
|
+
return !!(document.fullscreenEnabled && document.documentElement.requestFullscreen);
|
|
1209
|
+
}
|
|
1210
|
+
function isFullscreen() { return !!document.fullscreenElement; }
|
|
1211
|
+
|
|
1212
|
+
function syncFullscreenUi() {
|
|
1213
|
+
const on = isFullscreen();
|
|
1214
|
+
if ($fsLabel) $fsLabel.textContent = on ? 'Exit full screen' : 'Enter full screen';
|
|
1215
|
+
if ($fsIcon) $fsIcon.innerHTML = on ? FS_ICON_EXIT : FS_ICON_ENTER;
|
|
1216
|
+
// Once the user IS fullscreen (by any means), the nudge has served its purpose —
|
|
1217
|
+
// retire it for good so it never reappears in a later session.
|
|
1218
|
+
if (on) dismissFsNudge(true);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
async function toggleFullscreen() {
|
|
1222
|
+
const wasOn = isFullscreen();
|
|
1223
|
+
try {
|
|
1224
|
+
if (wasOn) await document.exitFullscreen();
|
|
1225
|
+
else await document.documentElement.requestFullscreen();
|
|
1226
|
+
} catch {
|
|
1227
|
+
// The user can't act on a blocked request — a warn toast names what failed.
|
|
1228
|
+
showToast(wasOn ? "Couldn't exit fullscreen" : "Couldn't enter fullscreen", 'warn');
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// Retire the nudge. `remember` persists the one-time flag so it never shows again.
|
|
1233
|
+
function dismissFsNudge(remember) {
|
|
1234
|
+
if ($fsNudge && $fsNudge.isConnected) {
|
|
1235
|
+
$fsNudge.hidden = true;
|
|
1236
|
+
$fsNudge.remove(); // keep the a11y tree clean once it's gone
|
|
1237
|
+
}
|
|
1238
|
+
if (remember) { try { localStorage.setItem(FS_NUDGE_KEY, '1'); } catch {} }
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
function nudgeAlreadySeen() {
|
|
1242
|
+
try { return localStorage.getItem(FS_NUDGE_KEY) === '1'; } catch { return false; }
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// One-time nudge: only when the window is clearly under-using the screen, the app
|
|
1246
|
+
// isn't already fullscreen, no what's-new strip is competing for the corner, and it
|
|
1247
|
+
// was never dismissed/used. Delayed ~2s so the layout settles first.
|
|
1248
|
+
function maybeShowFsNudge() {
|
|
1249
|
+
if (nudgeAlreadySeen()) return;
|
|
1250
|
+
setTimeout(() => {
|
|
1251
|
+
if (!$fsNudge || !$fsNudge.isConnected || !$fsNudge.hidden) return;
|
|
1252
|
+
if (nudgeAlreadySeen() || isFullscreen()) return;
|
|
1253
|
+
const wn = document.getElementById('whats-new-panel');
|
|
1254
|
+
if (wn && !wn.hidden) return; // don't stack on the post-update what's-new strip
|
|
1255
|
+
const h = window.innerHeight;
|
|
1256
|
+
const avail = (window.screen && window.screen.availHeight) || h;
|
|
1257
|
+
if (h < 400) return; // genuinely cramped window — a card is just noise
|
|
1258
|
+
if (h > avail * 0.85) return; // window already uses most of the screen
|
|
1259
|
+
$fsNudge.hidden = false;
|
|
1260
|
+
}, 2000);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
if (!fullscreenSupported()) {
|
|
1264
|
+
if ($fsRow) $fsRow.hidden = true; // hide the control; never nudge on an unsupported browser
|
|
1265
|
+
} else {
|
|
1266
|
+
document.addEventListener('fullscreenchange', syncFullscreenUi);
|
|
1267
|
+
syncFullscreenUi();
|
|
1268
|
+
// Query the two buttons independently — a present #fullscreen-nudge doesn't by
|
|
1269
|
+
// itself guarantee its children survive a future HTML refactor.
|
|
1270
|
+
const $fsGo = document.getElementById('fsn-go');
|
|
1271
|
+
const $fsDismiss = document.getElementById('fsn-dismiss');
|
|
1272
|
+
if ($fsGo) $fsGo.addEventListener('click', () => {
|
|
1273
|
+
dismissFsNudge(true);
|
|
1274
|
+
toggleFullscreen(); // synchronous within the click → counts as a user gesture
|
|
1275
|
+
});
|
|
1276
|
+
if ($fsDismiss) $fsDismiss.addEventListener('click', () => dismissFsNudge(true));
|
|
1277
|
+
if ($fsNudge) maybeShowFsNudge();
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1189
1280
|
/* ============= TOAST ============= */
|
|
1190
1281
|
|
|
1191
1282
|
function showToast(msg, type) {
|
package/dist/web/index.html
CHANGED
|
@@ -168,6 +168,22 @@
|
|
|
168
168
|
<div class="whats-new-detail"><div class="whats-new-detail-inner"></div></div>
|
|
169
169
|
</div>
|
|
170
170
|
|
|
171
|
+
<!-- One-time "need more space?" nudge (mirrors Excel's prompt). Shown ~2s after
|
|
172
|
+
load ONLY when the window is clearly under-using the screen, the app isn't
|
|
173
|
+
already fullscreen, the post-update what's-new strip isn't already showing,
|
|
174
|
+
and it was never dismissed/used (localStorage). position:fixed, so it doesn't disturb the
|
|
175
|
+
.app grid; placed here so Tab order is main → nudge → footer. Calm
|
|
176
|
+
notification styling (shares the toast/whats-new accent rail) — never an ad;
|
|
177
|
+
one dismiss/use retires it for good. aria-live=polite (not alert): passive. -->
|
|
178
|
+
<aside id="fullscreen-nudge" class="fullscreen-nudge" aria-label="Fullscreen suggestion" aria-live="polite" hidden>
|
|
179
|
+
<div class="fsn-text">
|
|
180
|
+
<div class="fsn-title">Need more working space?</div>
|
|
181
|
+
<div class="fsn-sub">Go fullscreen to give FloLess the whole screen.</div>
|
|
182
|
+
<button type="button" class="fsn-go" id="fsn-go">Go fullscreen</button>
|
|
183
|
+
</div>
|
|
184
|
+
<button type="button" class="fsn-dismiss" id="fsn-dismiss" aria-label="Dismiss fullscreen suggestion">✕</button>
|
|
185
|
+
</aside>
|
|
186
|
+
|
|
171
187
|
<footer>
|
|
172
188
|
<div class="status">
|
|
173
189
|
<span class="stat"><span class="dot"></span><span class="stat-val">runtime online</span></span>
|
|
@@ -269,6 +285,17 @@
|
|
|
269
285
|
<span class="menu-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" x2="4" y1="22" y2="15"/></svg></span>
|
|
270
286
|
<span class="menu-label">Report an issue</span>
|
|
271
287
|
</button>
|
|
288
|
+
<!-- Browser fullscreen toggle — gives the 3-col workspace the whole screen.
|
|
289
|
+
An action (not a stored pref: browsers won't restore fullscreen on load),
|
|
290
|
+
so it's a .menu-item button, not a switch. Icon + label flip with the live
|
|
291
|
+
fullscreen state via `fullscreenchange`. Hidden by JS when the Fullscreen
|
|
292
|
+
API is unavailable — hide, never show a dead control. No F11 kbd hint: F11
|
|
293
|
+
is the browser's own fullscreen, which is separate from the Fullscreen API
|
|
294
|
+
and wouldn't keep this control's state in sync. -->
|
|
295
|
+
<button class="menu-item" data-action="fullscreen" id="menu-fullscreen" role="menuitem">
|
|
296
|
+
<span class="menu-icon" aria-hidden="true" id="menu-fullscreen-icon"><svg viewBox="0 0 24 24"><path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/></svg></span>
|
|
297
|
+
<span class="menu-label" id="menu-fullscreen-label">Enter full screen</span>
|
|
298
|
+
</button>
|
|
272
299
|
<!-- Start-on-login + Theme are sibling machine preferences (no divider between
|
|
273
300
|
them — UX review 2026-05-31). Start-on-login toggles the per-user logon
|
|
274
301
|
Scheduled Task that keeps the local server alive across logins; hidden unless
|