flet-box 1.0.8 → 1.0.9
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/README.md +3 -0
- package/bin/utils/templates.js +25 -9
- package/docs/README.md +2 -0
- package/docs/cli/README.md +1 -1
- package/docs/guides/mobile-and-platforms.md +31 -0
- package/docs/tools/theme.md +1 -0
- package/docs/widget/README.md +2 -0
- package/package.json +1 -1
- package/src/utils/themes.js +48 -4
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ Real DOM · No Virtual DOM · No build config to learn.
|
|
|
23
23
|
<br><br>
|
|
24
24
|
|
|
25
25
|
<a href="https://kuko53348.github.io/flet-box-docs/">📖 Docs</a> •
|
|
26
|
+
<a href="https://kuko53348.github.io/flet-box-widgets-exemples/">🧪 Widget gallery</a> •
|
|
26
27
|
<a href="#quick-start">Quick start</a> •
|
|
27
28
|
<a href="https://www.youtube.com/@flet-box">▶ YouTube</a> •
|
|
28
29
|
<a href="#support--sponsorship">❤️ Sponsor</a>
|
|
@@ -157,6 +158,8 @@ Read the docs online: **[The FletBox Book — kuko53348.github.io/flet-box-docs]
|
|
|
157
158
|
|
|
158
159
|
They are **one continuous book** — the cover maps every page: [The FletBox Book source](docs/README.md).
|
|
159
160
|
|
|
161
|
+
Rather than read, click: **[the live widget gallery](https://kuko53348.github.io/flet-box-widgets-exemples/)** gives every widget its own page, renders each example in the browser it was written for, and prints the exact call underneath it. The theme toggle in the corner shows the same screen in light and dark, which is the honest way to judge a default color.
|
|
162
|
+
|
|
160
163
|
- [Your first app](docs/guides/first-app.md) — build a working todo app in 20 minutes
|
|
161
164
|
- [The widget book](docs/widget/README.md) — every widget with property tables and examples
|
|
162
165
|
- [State, Router & Services](docs/guides/state.md) — shared state, routing, storage, and HTTP
|
package/bin/utils/templates.js
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
// bin/utils/templates.js
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The plate behind everything a reader sees before the app paints: the PWA
|
|
5
|
+
* splash (`manifest.json`), the Android and iOS launch screens, the adaptive
|
|
6
|
+
* icon background, and the static `<meta name="theme-color">`.
|
|
7
|
+
*
|
|
8
|
+
* It is the dark palette's `surface` — the zinc scale the 2026-10 design rebuild
|
|
9
|
+
* moved to, replacing the indigo shell color that stayed in the scaffold and kept
|
|
10
|
+
* showing on installed PWAs long after the app itself had changed color. One
|
|
11
|
+
* value because a native splash cannot follow a theme; `applyPalette()` writes
|
|
12
|
+
* the live palette onto `<meta name="theme-color">` at runtime, so the bars do.
|
|
13
|
+
*/
|
|
14
|
+
export const SHELL_BRAND = "#18181b";
|
|
15
|
+
|
|
16
|
+
/** `SHELL_BRAND` as the channels the icon and splash scripts composite with. */
|
|
17
|
+
export const SHELL_BRAND_RGB = { r: 24, g: 24, b: 27 };
|
|
18
|
+
|
|
3
19
|
export const indexHtml = (appName = "FletBox App") => `<!DOCTYPE html>
|
|
4
20
|
<html lang="en">
|
|
5
21
|
<head>
|
|
@@ -19,7 +35,7 @@ export const indexHtml = (appName = "FletBox App") => `<!DOCTYPE html>
|
|
|
19
35
|
<meta property="og:description" content="${appName} built with Flet-Box.">
|
|
20
36
|
<meta property="og:type" content="website">
|
|
21
37
|
|
|
22
|
-
<meta name="theme-color" content="
|
|
38
|
+
<meta name="theme-color" content="${SHELL_BRAND}">
|
|
23
39
|
|
|
24
40
|
<!-- ============================================================
|
|
25
41
|
GOOGLE ADSENSE (optional — disabled by default)
|
|
@@ -904,7 +920,7 @@ export const capacitorConfig = (appName, appId) => `${JSON.stringify(
|
|
|
904
920
|
appId,
|
|
905
921
|
appName,
|
|
906
922
|
webDir: "www",
|
|
907
|
-
backgroundColor:
|
|
923
|
+
backgroundColor: SHELL_BRAND,
|
|
908
924
|
server: { androidScheme: "https", iosScheme: "https" },
|
|
909
925
|
},
|
|
910
926
|
null,
|
|
@@ -960,7 +976,7 @@ const densities = [
|
|
|
960
976
|
["xxhdpi", 144],
|
|
961
977
|
["xxxhdpi", 192],
|
|
962
978
|
];
|
|
963
|
-
const background = { r:
|
|
979
|
+
const background = { r: ${SHELL_BRAND_RGB.r}, g: ${SHELL_BRAND_RGB.g}, b: ${SHELL_BRAND_RGB.b} };
|
|
964
980
|
|
|
965
981
|
for (const [density, size] of densities) {
|
|
966
982
|
const directory = path.join(androidRes, \`mipmap-\${density}\`);
|
|
@@ -998,7 +1014,7 @@ const backgroundColor = /(<color name="ic_launcher_background">)#(?:[A-Fa-f0-9]{
|
|
|
998
1014
|
if (!backgroundColor.test(xml)) {
|
|
999
1015
|
throw new Error(\`Invalid adaptive icon background resource: \${backgroundPath}\`);
|
|
1000
1016
|
}
|
|
1001
|
-
await writeFile(backgroundPath, xml.replace(backgroundColor, "$1
|
|
1017
|
+
await writeFile(backgroundPath, xml.replace(backgroundColor, "$1${SHELL_BRAND}$2"));
|
|
1002
1018
|
|
|
1003
1019
|
// SPLASH SCREENS
|
|
1004
1020
|
// The launch theme (AppTheme.NoActionBarLaunch) shows @drawable/splash while the
|
|
@@ -1066,8 +1082,8 @@ const infoPlistPath = path.join(nativeAppDir, "Info.plist");
|
|
|
1066
1082
|
const launchScreenPath = path.join(nativeAppDir, "Base.lproj", "LaunchScreen.storyboard");
|
|
1067
1083
|
const logoPath = path.join(projectRoot, "assets", "logo.png");
|
|
1068
1084
|
|
|
1069
|
-
// Brand background, the same
|
|
1070
|
-
const background = { r:
|
|
1085
|
+
// Brand background, the same value as theme-color in index.html and manifest.json.
|
|
1086
|
+
const background = { r: ${SHELL_BRAND_RGB.r}, g: ${SHELL_BRAND_RGB.g}, b: ${SHELL_BRAND_RGB.b} };
|
|
1071
1087
|
const backgroundComponent = (value) => Number((value / 255).toFixed(6));
|
|
1072
1088
|
|
|
1073
1089
|
const requireExists = async (target) => {
|
|
@@ -1245,8 +1261,8 @@ export const manifest = (appName = "FletBox App") => `{
|
|
|
1245
1261
|
"scope": "./",
|
|
1246
1262
|
"display": "standalone",
|
|
1247
1263
|
"display_override": ["window-controls-overlay"],
|
|
1248
|
-
"theme_color": "
|
|
1249
|
-
"background_color": "
|
|
1264
|
+
"theme_color": "${SHELL_BRAND}",
|
|
1265
|
+
"background_color": "${SHELL_BRAND}",
|
|
1250
1266
|
"orientation": "any",
|
|
1251
1267
|
"icons": [
|
|
1252
1268
|
{
|
|
@@ -1739,7 +1755,7 @@ run \`npm run ios:open\`.
|
|
|
1739
1755
|
|
|
1740
1756
|
Replace \`assets/logo.png\` with a 1024×1024 logo before distributing; the icon,
|
|
1741
1757
|
the launch images and the launch background are all generated from it. The
|
|
1742
|
-
launch background is the app brand color
|
|
1758
|
+
launch background is the app brand color \`${SHELL_BRAND}\`, which lives in
|
|
1743
1759
|
\`scripts/sync-ios-assets.mjs\`.
|
|
1744
1760
|
|
|
1745
1761
|
Capacitor uses a local HTTPS origin (\`https://localhost\`) in the Android and
|
package/docs/README.md
CHANGED
|
@@ -4,6 +4,8 @@ FletBox is a tiny UI framework: you describe your screen with plain JavaScript *
|
|
|
4
4
|
|
|
5
5
|
This documentation is one continuous book. Start at **Chapter 0** and follow the "Continue reading" links at the bottom of every page; each page teaches you something real and links to the next.
|
|
6
6
|
|
|
7
|
+
> **Want to see before you read?** The [live widget gallery](https://kuko53348.github.io/flet-box-widgets-exemples/) runs in the browser: one page per widget, every example rendered, with the exact call printed under it and a light/dark toggle. It is the same code the chapters describe, so it doubles as the answer to "what does this look like when it is real?".
|
|
8
|
+
|
|
7
9
|
## The reading path
|
|
8
10
|
|
|
9
11
|
| # | Chapter | What you learn | Level |
|
package/docs/cli/README.md
CHANGED
|
@@ -448,7 +448,7 @@ Capacitor template with different slots keeps working. It:
|
|
|
448
448
|
status bar style ignored.
|
|
449
449
|
|
|
450
450
|
The script is idempotent: running it twice leaves identical files. The brand
|
|
451
|
-
color `#
|
|
451
|
+
color `#18181b` is defined at the top of the script.
|
|
452
452
|
|
|
453
453
|
## Convert asset images to PNG
|
|
454
454
|
|
|
@@ -331,6 +331,37 @@ A PWA needs:
|
|
|
331
331
|
|
|
332
332
|
PWA installation depends on browser and platform support.
|
|
333
333
|
|
|
334
|
+
### The browser chrome follows the theme
|
|
335
|
+
|
|
336
|
+
Once installed, Android and iOS paint two more surfaces you do not control from
|
|
337
|
+
CSS: the status bar at the top and the navigation bar at the bottom. Chrome takes
|
|
338
|
+
both from `<meta name="theme-color">` in the document — a value it reads once per
|
|
339
|
+
page, unless the page rewrites it.
|
|
340
|
+
|
|
341
|
+
FletBox rewrites it. Every `setTheme`, `registerPalette` and system-preference
|
|
342
|
+
change updates that single meta tag with the live `colors.surface`, the color the
|
|
343
|
+
`AppBar` and the `BottomNavigation` are painted with, so the bars meet the app
|
|
344
|
+
instead of sitting against it. It also sets `color-scheme` on the root element,
|
|
345
|
+
which is what tells the operating system to draw dark scrollbars, dark form
|
|
346
|
+
controls and light status-bar glyphs on a dark page.
|
|
347
|
+
|
|
348
|
+
That means the colors in `manifest.json` are only the **splash screen** — the
|
|
349
|
+
plate shown while the app boots:
|
|
350
|
+
|
|
351
|
+
```json
|
|
352
|
+
{
|
|
353
|
+
"theme_color": "#18181b",
|
|
354
|
+
"background_color": "#18181b"
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Leave them at the brand color generated by `flet-box create` (the dark palette's
|
|
359
|
+
surface) and let the runtime handle the rest. There is no manifest field for a
|
|
360
|
+
per-theme bar color, and an installed app keeps the manifest copy it was
|
|
361
|
+
installed with, so editing these two lines does not recolor a home-screen icon
|
|
362
|
+
that is already there — reinstall, or let the first paint of the new version
|
|
363
|
+
update the document.
|
|
364
|
+
|
|
334
365
|
## Desktop options
|
|
335
366
|
|
|
336
367
|
Capacitor targets Android and iOS. For desktop packaging, consider a desktop shell such as Electron or Tauri around the same `dist` output.
|
package/docs/tools/theme.md
CHANGED
|
@@ -122,6 +122,7 @@ runApp(ThemeProvider({ children: ThemedApp() }), "root");
|
|
|
122
122
|
## Notes
|
|
123
123
|
|
|
124
124
|
- The shared palette tokens are updated across all widgets when you switch themes; widgets referencing `colors.*` at build time pick up the active palette.
|
|
125
|
+
- Switching a theme also repaints the browser's own chrome: the `<meta name="theme-color">` the installed PWA takes for its status and navigation bars, and the root `color-scheme` that decides how the OS draws scrollbars and form controls. Both read the live palette, so an app that changes `colors.surface` changes its system bars with it — see [Mobile and platforms](../guides/mobile-and-platforms.md#the-browser-chrome-follows-the-theme).
|
|
125
126
|
- `colors.glass` is genuinely see-through: its contrast depends on whatever is behind it, so use it over photography or gradients with a scrim, and keep body copy off the most colourful part of the backdrop. The dark token is a dark pane, not white glass.
|
|
126
127
|
- `watchSystemTheme()` and `applySystemTheme()` read `prefers-color-scheme`; both return/need cleanup to release listeners.
|
|
127
128
|
- `subscribeTheme(callback)` fires with the new palette object — remember to unsubscribe when a feature is destroyed.
|
package/docs/widget/README.md
CHANGED
|
@@ -13,6 +13,8 @@ If you have never used FletBox, begin with [Start here](START_HERE.md), then fol
|
|
|
13
13
|
|
|
14
14
|
Related guides: [Build your first FletBox app](../guides/app-templates.md) · [Routing with FletBox](../guides/router.md) · [FletBox CLI](../cli/README.md).
|
|
15
15
|
|
|
16
|
+
Every page here has a live twin: **[the widget gallery](https://kuko53348.github.io/flet-box-widgets-exemples/)** renders each example in the browser and prints the call that made it under the result, so you can read a property table and see the same prop move something.
|
|
17
|
+
|
|
16
18
|
## The reading path
|
|
17
19
|
|
|
18
20
|
### Chapter 1 · First steps: the core mental model
|
package/package.json
CHANGED
package/src/utils/themes.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/components/flet-box/utils/themes.js
|
|
2
|
+
import { readableInk } from "./readableInk.js";
|
|
2
3
|
|
|
3
4
|
// ========== DEFAULT COLORS (static, safe) ==========
|
|
4
5
|
const DEFAULT_COLORS = {
|
|
@@ -247,6 +248,41 @@ const notifyThemeChange = () => {
|
|
|
247
248
|
};
|
|
248
249
|
|
|
249
250
|
// ========== THEME FUNCTIONS ==========
|
|
251
|
+
/**
|
|
252
|
+
* Moves the browser's own chrome — the PWA status bar and navigation bar, the
|
|
253
|
+
* scrollbar and form-control canvases — onto the palette that was just painted.
|
|
254
|
+
*
|
|
255
|
+
* An installed web app paints those bars from `<meta name="theme-color">`, which
|
|
256
|
+
* is a document-level value the page must rewrite itself: nothing in CSS reaches
|
|
257
|
+
* it. Left alone, the app keeps whatever literal the scaffold wrote — the indigo
|
|
258
|
+
* every FletBox PWA shipped before the zinc rebuild — and the reader sees a
|
|
259
|
+
* system bar from the old palette hanging over the new one. `color-scheme` is the
|
|
260
|
+
* same problem in the other direction: without it the OS draws light-mode
|
|
261
|
+
* scrollbars and form controls on a dark page.
|
|
262
|
+
*
|
|
263
|
+
* @private
|
|
264
|
+
*/
|
|
265
|
+
const syncBrowserChrome = () => {
|
|
266
|
+
try {
|
|
267
|
+
let meta = document.querySelector('meta[name="theme-color"]');
|
|
268
|
+
if (!meta) {
|
|
269
|
+
meta = document.createElement("meta");
|
|
270
|
+
meta.name = "theme-color";
|
|
271
|
+
document.head.appendChild(meta);
|
|
272
|
+
}
|
|
273
|
+
// The bars sit directly against the AppBar and the BottomNavigation, and
|
|
274
|
+
// both paint `surface` — matching `background` would put a band of the page
|
|
275
|
+
// color between two panels and look like a gap in the chrome.
|
|
276
|
+
meta.setAttribute("content", colors.surface);
|
|
277
|
+
// Whether the page is dark is read from its own background, not from the
|
|
278
|
+
// palette's name: `registerPalette` lets an app call a dark scale anything.
|
|
279
|
+
document.documentElement.style.colorScheme =
|
|
280
|
+
readableInk(colors.background, "#ffffff") === "#ffffff" ? "dark" : "light";
|
|
281
|
+
} catch (e) {
|
|
282
|
+
// Non-browser environments have no chrome to sync.
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
250
286
|
/**
|
|
251
287
|
* Copies a registered palette onto the live `colors` object and refreshes the
|
|
252
288
|
* CSS custom properties. Shared by `setTheme` and `registerPalette`; it does not
|
|
@@ -275,6 +311,8 @@ const applyPalette = (themeName) => {
|
|
|
275
311
|
// Silently fail in non-browser environments
|
|
276
312
|
}
|
|
277
313
|
|
|
314
|
+
syncBrowserChrome();
|
|
315
|
+
|
|
278
316
|
notifyThemeChange();
|
|
279
317
|
return colors;
|
|
280
318
|
};
|
|
@@ -291,10 +329,16 @@ export const setTheme = (themeName) => {
|
|
|
291
329
|
// and a subscriber that reads `getTheme()` while it rebuilds (a toggle button
|
|
292
330
|
// labelling itself, a theme-aware screen) has to see the theme it is being
|
|
293
331
|
// rebuilt for, not the one being replaced.
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
332
|
+
//
|
|
333
|
+
// `window` is the test, not a try/catch around the call: Node 22+ defines a
|
|
334
|
+
// global `localStorage` that only answers with a warning and then throws, so
|
|
335
|
+
// an import-time theme would print an ExperimentalWarning on every server run.
|
|
336
|
+
if (typeof window !== "undefined") {
|
|
337
|
+
try {
|
|
338
|
+
localStorage.setItem("fletbox-theme", themeName);
|
|
339
|
+
} catch (e) {
|
|
340
|
+
// Silently fail
|
|
341
|
+
}
|
|
298
342
|
}
|
|
299
343
|
|
|
300
344
|
applyPalette(themeName);
|