flet-box 1.0.6 → 1.0.7
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 +28 -1
- package/bin/cli.js +77 -11
- package/bin/commands/auditFix.js +682 -0
- package/bin/commands/checkApi.js +7 -5
- package/bin/commands/create.js +40 -10
- package/bin/commands/createBundle.js +54 -1
- package/bin/commands/images.js +349 -0
- package/bin/commands/pruneAssets.js +170 -0
- package/bin/commands/release.js +34 -1
- package/bin/commands/runCloudflare.js +47 -9
- package/bin/commands/runServer.js +81 -24
- package/bin/commands/toPng.js +346 -0
- package/bin/commands/unpack.js +1173 -0
- package/bin/ota/loader.js +90 -0
- package/bin/utils/appSources.js +101 -0
- package/bin/utils/bundleConfig.js +166 -0
- package/bin/utils/dtsProps.js +147 -0
- package/bin/utils/imageTools.js +271 -0
- package/bin/utils/images/bmp.js +99 -0
- package/bin/utils/images/gif.js +244 -0
- package/bin/utils/images/index.js +163 -0
- package/bin/utils/images/jpeg.js +643 -0
- package/bin/utils/images/png.js +486 -0
- package/bin/utils/images/unsupported.js +29 -0
- package/bin/utils/neutralise.js +109 -6
- package/bin/utils/templates.js +307 -64
- package/docs/cli/README.md +82 -0
- package/docs/guides/online-updates.md +57 -9
- package/docs/widget/Accordion.md +1 -0
- package/docs/widget/AdMob.md +1 -0
- package/docs/widget/AdSense.md +1 -0
- package/docs/widget/AnimatedBox.md +1 -0
- package/docs/widget/AnimatedText.md +1 -0
- package/docs/widget/Audio.md +2 -1
- package/docs/widget/Avatar.md +12 -3
- package/docs/widget/Badge.md +1 -0
- package/docs/widget/Button.md +1 -0
- package/docs/widget/Card.md +1 -0
- package/docs/widget/Carousel.md +1 -0
- package/docs/widget/Chart.md +1 -0
- package/docs/widget/Checkbox.md +1 -0
- package/docs/widget/Chip.md +1 -0
- package/docs/widget/CircularBar.md +1 -0
- package/docs/widget/CircularChart.md +1 -0
- package/docs/widget/CodeViewer.md +1 -0
- package/docs/widget/Column.md +1 -0
- package/docs/widget/Container.md +1 -0
- package/docs/widget/DataTable.md +1 -0
- package/docs/widget/Divider.md +1 -0
- package/docs/widget/DraggBox.md +3 -2
- package/docs/widget/Dropdown.md +3 -0
- package/docs/widget/DroppBox.md +2 -1
- package/docs/widget/FloatingActionButton.md +1 -0
- package/docs/widget/GridView.md +1 -0
- package/docs/widget/Icon.md +1 -0
- package/docs/widget/Image.md +11 -3
- package/docs/widget/Input.md +1 -0
- package/docs/widget/InstallButton.md +1 -0
- package/docs/widget/ListTile.md +1 -0
- package/docs/widget/ListView.md +1 -0
- package/docs/widget/Maps.md +188 -0
- package/docs/widget/Markdown.md +1 -0
- package/docs/widget/MatrixRain.md +1 -0
- package/docs/widget/Pagination.md +1 -0
- package/docs/widget/ParallaxBox.md +1 -0
- package/docs/widget/ProgressBar.md +1 -0
- package/docs/widget/QRCode.md +1 -0
- package/docs/widget/README.md +12 -10
- package/docs/widget/Radio.md +1 -0
- package/docs/widget/Rating.md +1 -0
- package/docs/widget/Row.md +1 -0
- package/docs/widget/Skeleton.md +1 -0
- package/docs/widget/Slider.md +1 -0
- package/docs/widget/Stack.md +1 -0
- package/docs/widget/Stepper.md +1 -0
- package/docs/widget/Switch.md +1 -0
- package/docs/widget/Text.md +1 -0
- package/docs/widget/Tooltip.md +11 -13
- package/docs/widget/TreeView.md +1 -0
- package/docs/widget/Video.md +3 -2
- package/package.json +2 -2
- package/src/core/hmr-client.js +129 -34
- package/src/index.d.ts +132 -0
- package/src/index.js +1 -0
- package/src/navigations/AppBar.js +15 -4
- package/src/navigations/Drawer.js +9 -1
- package/src/widget-factory/translateProps.js +32 -1
- package/src/widgets/Avatar.js +228 -131
- package/src/widgets/Container.js +13 -0
- package/src/widgets/Dropdown.js +33 -1
- package/src/widgets/Image.js +102 -3
- package/src/widgets/Maps.js +1495 -0
- package/src/widgets/Tooltip.js +12 -2
- package/src/widgets/index.js +1 -0
package/bin/utils/templates.js
CHANGED
|
@@ -55,7 +55,7 @@ export const indexHtml = (appName = "FletBox App") => `<!DOCTYPE html>
|
|
|
55
55
|
<div id="root"></div>
|
|
56
56
|
<script>
|
|
57
57
|
if ('serviceWorker' in navigator) {
|
|
58
|
-
navigator.serviceWorker.register('
|
|
58
|
+
navigator.serviceWorker.register('./service-worker.js')
|
|
59
59
|
.then(reg => console.log('Service Worker registered', reg))
|
|
60
60
|
.catch(err => console.log('Service Worker registration error', err));
|
|
61
61
|
}
|
|
@@ -711,6 +711,8 @@ export const packageJson = (name) => `{
|
|
|
711
711
|
"scripts": {
|
|
712
712
|
"dev": "bash run.sh",
|
|
713
713
|
"check": "node scripts/check-app.mjs",
|
|
714
|
+
"fix": "flet-box audit-fix",
|
|
715
|
+
"api": "flet-box unpack --all --md",
|
|
714
716
|
"build": "flet-box createBundle www",
|
|
715
717
|
"start": "npm run dev",
|
|
716
718
|
"android:init": "npm run build && cap add android",
|
|
@@ -1121,58 +1123,85 @@ export const manifest = (appName = "FletBox App") => `{
|
|
|
1121
1123
|
}
|
|
1122
1124
|
`;
|
|
1123
1125
|
|
|
1124
|
-
// GitHub Actions workflow that builds
|
|
1125
|
-
//
|
|
1126
|
+
// GitHub Actions workflow that builds and publishes the WEB. Two jobs, the way
|
|
1127
|
+
// the docs site does it: `build` checks and bundles `www/` and only *uploads* it,
|
|
1128
|
+
// `deploy` is the sole job that can touch Pages — so a build that fails leaves
|
|
1129
|
+
// the live site alone. The native builds are a second file (build-native.yml)
|
|
1130
|
+
// that only runs when started by hand.
|
|
1126
1131
|
// NOTE: every GitHub `${{ }}` expression is escaped as `\${{ }}` because this is
|
|
1127
1132
|
// a JS template literal — an unescaped `${` would be parsed as interpolation.
|
|
1128
|
-
export const githubWorkflow = (appName = "FletBox App"
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
# One
|
|
1137
|
-
#
|
|
1138
|
-
#
|
|
1139
|
-
#
|
|
1140
|
-
#
|
|
1141
|
-
#
|
|
1133
|
+
export const githubWorkflow = (appName = "FletBox App") => `name: Deploy ${appName}
|
|
1134
|
+
|
|
1135
|
+
# Publishes the PWA to GitHub Pages. Every push to main (and every manual run)
|
|
1136
|
+
# builds a fresh site, and only the deploy job can touch Pages, so a broken
|
|
1137
|
+
# bundle never replaces the live one. Android and iOS are NOT here: they live in
|
|
1138
|
+
# build-native.yml and run only when you start them, because a macOS runner is
|
|
1139
|
+
# not free.
|
|
1140
|
+
#
|
|
1141
|
+
# One consequence to know about: this Pages site is also what an installed app
|
|
1142
|
+
# polls for an OTA update (www/config.json), and the app compares the bundle
|
|
1143
|
+
# hash, not the version. So the manifest is left out of every build whose commit
|
|
1144
|
+
# carries no \`v*\` tag (see "Ship the update feed only when this commit is a
|
|
1145
|
+
# release" below): the site is live on every push, while installed apps keep
|
|
1146
|
+
# running the last \`flet-box release\`.
|
|
1147
|
+
#
|
|
1148
|
+
# Publishing a release: push main, then \`git tag -a v1.2.3 && git push origin
|
|
1149
|
+
# v1.2.3\`, then Actions -> this workflow -> Run workflow. The manual run deploys
|
|
1150
|
+
# the tagged commit, and it is the run that puts config.json on the site. The tag
|
|
1151
|
+
# itself cannot deploy: GitHub refuses Pages deployments that start from a tag.
|
|
1152
|
+
|
|
1142
1153
|
on:
|
|
1143
1154
|
push:
|
|
1144
1155
|
branches: [ main ]
|
|
1145
|
-
tags:
|
|
1146
|
-
|
|
1147
|
-
|
|
1156
|
+
# Deliberately NO tags: trigger. The github-pages environment only accepts
|
|
1157
|
+
# deployments from the default branch, so a run that starts from a tag fails
|
|
1158
|
+
# at the deploy job with "Tag v1.0.0 is not allowed to deploy to github-pages
|
|
1159
|
+
# due to environment protection rules". A release is therefore made by
|
|
1160
|
+
# pushing main and then running this workflow again, by hand, once the tag
|
|
1161
|
+
# exists: that run is on main, and it sees the tag on HEAD.
|
|
1148
1162
|
workflow_dispatch:
|
|
1149
1163
|
|
|
1150
|
-
#
|
|
1164
|
+
# The deploy job needs Pages write access; it is declared once, for the file.
|
|
1165
|
+
permissions:
|
|
1166
|
+
contents: read
|
|
1167
|
+
pages: write
|
|
1168
|
+
id-token: write
|
|
1169
|
+
|
|
1170
|
+
# Allow only one concurrent deployment, skipping runs queued between the run
|
|
1171
|
+
# in-progress and the latest queued. Do NOT cancel in-progress: a production
|
|
1172
|
+
# deployment is allowed to finish, because the site that is live while it runs is
|
|
1173
|
+
# the previous one, and a cancelled deploy leaves Pages holding a half-written
|
|
1174
|
+
# artifact.
|
|
1151
1175
|
concurrency:
|
|
1152
|
-
group:
|
|
1153
|
-
cancel-in-progress:
|
|
1176
|
+
group: pages
|
|
1177
|
+
cancel-in-progress: false
|
|
1154
1178
|
|
|
1155
|
-
# The generated app depends on the public \`flet-box\` npm package. If you
|
|
1156
|
-
#
|
|
1157
|
-
#
|
|
1179
|
+
# The generated app depends on the public \`flet-box\` npm package. If you
|
|
1180
|
+
# develop against a local copy, publish it (or vendor it) before these jobs can
|
|
1181
|
+
# \`npm install\` it. package-lock.json is gitignored, so we use npm install.
|
|
1158
1182
|
|
|
1159
1183
|
jobs:
|
|
1160
|
-
# ----------
|
|
1161
|
-
|
|
1162
|
-
name:
|
|
1184
|
+
# ---------- BUILD: check, bundle, upload. Nothing here reaches Pages. ----------
|
|
1185
|
+
build:
|
|
1186
|
+
name: Build site
|
|
1163
1187
|
runs-on: ubuntu-latest
|
|
1164
|
-
permissions:
|
|
1165
|
-
contents: read
|
|
1166
|
-
pages: write
|
|
1167
|
-
id-token: write
|
|
1168
|
-
environment:
|
|
1169
|
-
name: github-pages
|
|
1170
|
-
url: \${{ steps.deployment.outputs.page_url }}
|
|
1171
1188
|
steps:
|
|
1172
1189
|
- uses: actions/checkout@v5
|
|
1190
|
+
with:
|
|
1191
|
+
# The release decision below reads the tags pointing at this commit, and
|
|
1192
|
+
# a shallow checkout of one commit does not fetch them by itself.
|
|
1193
|
+
fetch-tags: true
|
|
1194
|
+
|
|
1195
|
+
# Registers the Pages integration for this run and reports the site's base
|
|
1196
|
+
# path, which is /<repo>/ for a project site and empty on a custom domain.
|
|
1197
|
+
# It belongs in the build job, before the artifact is uploaded.
|
|
1198
|
+
- name: Setup Pages
|
|
1199
|
+
uses: actions/configure-pages@v5
|
|
1173
1200
|
|
|
1174
1201
|
- uses: actions/setup-node@v5
|
|
1175
1202
|
with:
|
|
1203
|
+
# 22 is the current LTS. 20 is EOL, and the runner says so on every
|
|
1204
|
+
# build of a generated app.
|
|
1176
1205
|
node-version: 22
|
|
1177
1206
|
|
|
1178
1207
|
- name: Install dependencies
|
|
@@ -1183,28 +1212,103 @@ jobs:
|
|
|
1183
1212
|
- name: Check app API usage (npm run check)
|
|
1184
1213
|
run: npm run check
|
|
1185
1214
|
|
|
1186
|
-
- name:
|
|
1215
|
+
- name: Build site (flet-box createBundle www)
|
|
1187
1216
|
run: npm run build
|
|
1188
1217
|
|
|
1189
|
-
#
|
|
1190
|
-
#
|
|
1191
|
-
#
|
|
1192
|
-
|
|
1218
|
+
# Printed before the deploy, because this is the address the whole workflow
|
|
1219
|
+
# is about, and because a missing Pages setting otherwise shows up as a
|
|
1220
|
+
# green run with no site: Pages lower-cases the owner, hence the tr.
|
|
1221
|
+
- name: Where this lives
|
|
1222
|
+
run: |
|
|
1223
|
+
owner=$(printf '%s' "$GITHUB_REPOSITORY_OWNER" | tr '[:upper:]' '[:lower:]')
|
|
1224
|
+
repo=\${GITHUB_REPOSITORY#*/}
|
|
1225
|
+
echo " site: https://$owner.github.io/$repo/"
|
|
1226
|
+
echo " version: $(node -p "require('./package.json').version")"
|
|
1227
|
+
echo " If a green run leaves that 404, the source is wrong:"
|
|
1228
|
+
echo " Settings -> Pages -> Build and deployment -> Source: GitHub Actions"
|
|
1229
|
+
|
|
1230
|
+
# www/config.json is the OTA manifest: an installed app fetches it and
|
|
1231
|
+
# compares its \`hash\` with the bundle it is running, so publishing it from
|
|
1232
|
+
# an ordinary push would offer that unfinished build to every device that
|
|
1233
|
+
# checks for updates. Dropping the file makes the poll fail as "not
|
|
1234
|
+
# deployed yet" (see bin/ota/loader.js), which is the behaviour wanted:
|
|
1235
|
+
# the site is live for reading, the release feed stays on tagged builds.
|
|
1236
|
+
#
|
|
1237
|
+
# The decision reads the commit, not the ref: a tag push cannot deploy (the
|
|
1238
|
+
# environment refuses it), so \`github.ref\` is always a branch here. To
|
|
1239
|
+
# publish a release, push main, tag that commit, then run this workflow by
|
|
1240
|
+
# hand from Actions - the manual run is on main and sees the tag.
|
|
1241
|
+
- name: Ship the update feed only when this commit is a release
|
|
1242
|
+
run: |
|
|
1243
|
+
tag=$(git tag --points-at HEAD --list 'v*' | sort -V | tail -1)
|
|
1244
|
+
if [ -n "$tag" ]; then
|
|
1245
|
+
echo " ota: $tag is on this commit: config.json ships, installed apps may update"
|
|
1246
|
+
else
|
|
1247
|
+
rm -f www/config.json
|
|
1248
|
+
echo " ota: web-only: no v* tag on $(git rev-parse --short HEAD), manifest left out"
|
|
1249
|
+
fi
|
|
1250
|
+
|
|
1193
1251
|
- name: Upload Pages artifact
|
|
1194
|
-
if: startsWith(github.ref, 'refs/tags/v')
|
|
1195
1252
|
uses: actions/upload-pages-artifact@v5
|
|
1196
1253
|
with:
|
|
1197
1254
|
path: www
|
|
1198
1255
|
|
|
1199
|
-
|
|
1256
|
+
# ---------- DEPLOY: the only job with a path to Pages ----------
|
|
1257
|
+
deploy:
|
|
1258
|
+
name: Deploy to Pages
|
|
1259
|
+
needs: build
|
|
1260
|
+
runs-on: ubuntu-latest
|
|
1261
|
+
environment:
|
|
1262
|
+
name: github-pages
|
|
1263
|
+
url: \${{ steps.deployment.outputs.page_url }}
|
|
1264
|
+
steps:
|
|
1200
1265
|
- name: Deploy to GitHub Pages
|
|
1201
1266
|
id: deployment
|
|
1202
|
-
if: startsWith(github.ref, 'refs/tags/v')
|
|
1203
1267
|
uses: actions/deploy-pages@v5
|
|
1204
1268
|
|
|
1269
|
+
# The address in the job log and as a run annotation, so it is readable
|
|
1270
|
+
# from the workflow list without opening anything.
|
|
1271
|
+
- name: Published
|
|
1272
|
+
run: |
|
|
1273
|
+
echo " live at: \${{ steps.deployment.outputs.page_url }}"
|
|
1274
|
+
echo "::notice title=Site published to GitHub Pages::\${{ steps.deployment.outputs.page_url }}"
|
|
1275
|
+
`;
|
|
1276
|
+
|
|
1277
|
+
// Native builds: the same two jobs, but they run ONLY when started by hand from
|
|
1278
|
+
// Actions -> Run workflow, with a choice of platform. A push never pays for a
|
|
1279
|
+
// macOS runner, and `flet-box build android|ios` already covers a local build.
|
|
1280
|
+
export const nativeWorkflow = (appName = "FletBox App") => {
|
|
1281
|
+
const slug = appName
|
|
1282
|
+
.toLowerCase()
|
|
1283
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
1284
|
+
.replace(/^-+|-+$/g, "")
|
|
1285
|
+
.slice(0, 40) || "fletbox-app";
|
|
1286
|
+
return `name: Build ${appName} — native (manual)
|
|
1287
|
+
|
|
1288
|
+
# Nothing in here runs on a push. Start it by hand: Actions -> "${appName} —
|
|
1289
|
+
# native (manual)" -> Run workflow, then pick the platform. Each job bundles the
|
|
1290
|
+
# web first, because that bundle is what Capacitor copies into the app.
|
|
1291
|
+
|
|
1292
|
+
on:
|
|
1293
|
+
workflow_dispatch:
|
|
1294
|
+
inputs:
|
|
1295
|
+
platform:
|
|
1296
|
+
description: "What to build"
|
|
1297
|
+
type: choice
|
|
1298
|
+
options:
|
|
1299
|
+
- android
|
|
1300
|
+
- ios
|
|
1301
|
+
- both
|
|
1302
|
+
default: android
|
|
1303
|
+
|
|
1304
|
+
permissions:
|
|
1305
|
+
contents: read
|
|
1306
|
+
|
|
1307
|
+
jobs:
|
|
1205
1308
|
# ---------- ANDROID: debug APK ----------
|
|
1206
1309
|
android:
|
|
1207
1310
|
name: Android (APK)
|
|
1311
|
+
if: inputs.platform == 'android' || inputs.platform == 'both'
|
|
1208
1312
|
runs-on: ubuntu-latest
|
|
1209
1313
|
steps:
|
|
1210
1314
|
- uses: actions/checkout@v5
|
|
@@ -1246,9 +1350,19 @@ jobs:
|
|
|
1246
1350
|
path: android/app/build/outputs/apk/debug/app-debug.apk
|
|
1247
1351
|
if-no-files-found: error
|
|
1248
1352
|
|
|
1353
|
+
# An artifact has no public URL: it is on the run page, and this prints
|
|
1354
|
+
# which run. The debug APK installs as it is; a release one would have to be
|
|
1355
|
+
# signed with your own keystore first.
|
|
1356
|
+
- name: Where the APK is
|
|
1357
|
+
run: |
|
|
1358
|
+
echo " artifact: ${slug}-android-debug"
|
|
1359
|
+
echo " download: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
|
|
1360
|
+
echo "::notice title=APK ready::${slug}-android-debug, on this run page"
|
|
1361
|
+
|
|
1249
1362
|
# ---------- iOS: simulator build ----------
|
|
1250
1363
|
ios:
|
|
1251
1364
|
name: iOS (simulator)
|
|
1365
|
+
if: inputs.platform == 'ios' || inputs.platform == 'both'
|
|
1252
1366
|
runs-on: macos-latest
|
|
1253
1367
|
steps:
|
|
1254
1368
|
- uses: actions/checkout@v5
|
|
@@ -1295,6 +1409,12 @@ jobs:
|
|
|
1295
1409
|
name: ${slug}-ios-simulator
|
|
1296
1410
|
path: ios/App/build/Build/Products/Debug-iphonesimulator/App.app
|
|
1297
1411
|
if-no-files-found: error
|
|
1412
|
+
|
|
1413
|
+
- name: Where the build is
|
|
1414
|
+
run: |
|
|
1415
|
+
echo " artifact: ${slug}-ios-simulator"
|
|
1416
|
+
echo " download: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
|
|
1417
|
+
echo "::notice title=Simulator build ready::${slug}-ios-simulator, on this run page"
|
|
1298
1418
|
`;
|
|
1299
1419
|
};
|
|
1300
1420
|
|
|
@@ -1340,6 +1460,8 @@ framework from scratch:
|
|
|
1340
1460
|
Claude Code and Cursor.
|
|
1341
1461
|
- \`.fletbox/api/cheatsheet.md\` — every widget and its real props, generated from the
|
|
1342
1462
|
installed package. This is the lookup an agent reads instead of the framework.
|
|
1463
|
+
- \`.fletbox/api/api.json\` — the same surface as data: per prop its engine target,
|
|
1464
|
+
default, aliases and a \`sample\` value the types prove works. Write calls from this.
|
|
1343
1465
|
- \`.fletbox/memory/\` — notes the agent keeps between sessions, so it does not
|
|
1344
1466
|
rediscover the same thing twice.
|
|
1345
1467
|
- \`scripts/check-app.mjs\` — the gate that catches hallucinated APIs.
|
|
@@ -1348,10 +1470,16 @@ framework from scratch:
|
|
|
1348
1470
|
npm run check # scan src/ for invented widgets, props, imports
|
|
1349
1471
|
npm run check -- --props Button # print the real props of one widget
|
|
1350
1472
|
npm run check -- --list # print every public export
|
|
1473
|
+
npm run fix # rewrite typos it can prove (imports, prop keys)
|
|
1474
|
+
npm run api # regenerate .fletbox/api/api.json and api.md
|
|
1475
|
+
flet-box unpack Button # each prop, where it really goes, and what is dead
|
|
1476
|
+
flet-box unpack Button --example # a paste-ready call using only verified props
|
|
1477
|
+
flet-box unpack Modal --diff # where types, engine, docs and code disagree
|
|
1351
1478
|
\`\`\`
|
|
1352
1479
|
|
|
1353
1480
|
\`npm run check\` exits non-zero on a real error and also runs in CI. If you upgrade
|
|
1354
|
-
\`flet-box\`, regenerate the cheatsheet with \`flet-box check-api --emit-api
|
|
1481
|
+
\`flet-box\`, regenerate the cheatsheet with \`flet-box check-api --emit-api\` and the
|
|
1482
|
+
machine-readable surface with \`npm run api\`.
|
|
1355
1483
|
|
|
1356
1484
|
## Android
|
|
1357
1485
|
|
|
@@ -1414,29 +1542,45 @@ CORS configuration and use HTTPS for the remote service.
|
|
|
1414
1542
|
|
|
1415
1543
|
## Continuous Integration (GitHub Actions)
|
|
1416
1544
|
|
|
1417
|
-
|
|
1418
|
-
GitHub, each push to \`main\` (or a manual **Run workflow**) fans out into three
|
|
1419
|
-
parallel jobs:
|
|
1545
|
+
Two workflow files ship with the project, and they answer to different triggers:
|
|
1420
1546
|
|
|
1421
|
-
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1547
|
+
- \`.github/workflows/build.yml\` — **the web, automatic**. Every push to \`main\`
|
|
1548
|
+
(and every \`v*\` tag, and a manual run) builds \`www/\` and publishes it to
|
|
1549
|
+
**GitHub Pages**, in two jobs: **Build site** checks the app, bundles it and
|
|
1550
|
+
uploads the result; **Deploy to Pages** is the only job that can replace the
|
|
1551
|
+
live site, so a bundle that fails to build leaves the current one running.
|
|
1552
|
+
- \`.github/workflows/build-native.yml\` — **Android and iOS, manual only**. Nothing
|
|
1553
|
+
runs on a push. Open **Actions → "… — native (manual)" → Run workflow** and pick
|
|
1554
|
+
\`android\`, \`ios\` or \`both\`. Each job uploads its build as a run artifact and
|
|
1555
|
+
prints the artifact name and the run URL in its own log.
|
|
1425
1556
|
|
|
1426
|
-
###
|
|
1557
|
+
### Publish the web (one-time setup)
|
|
1427
1558
|
|
|
1428
1559
|
1. Push this project to a GitHub repository.
|
|
1429
1560
|
2. Open **Settings → Pages** in that repo.
|
|
1430
|
-
3. Set **Source** to **GitHub Actions** (not "Deploy from a branch").
|
|
1431
|
-
|
|
1561
|
+
3. Set **Source** to **GitHub Actions** (not "Deploy from a branch"). Skip this
|
|
1562
|
+
and the deploy step fails on every push.
|
|
1563
|
+
4. Push. The **Where this lives** step prints the address before the deploy runs,
|
|
1564
|
+
and the **Published** step prints it again as a run annotation, so you do not
|
|
1565
|
+
have to hunt for the environment box under the job.
|
|
1432
1566
|
|
|
1433
1567
|
The site goes live at \`https://<your-user>.github.io/<repo-name>/\`. That is a
|
|
1434
1568
|
sub-path, so \`index.html\` uses relative asset paths and works without changes.
|
|
1435
1569
|
|
|
1570
|
+
**Why a push does not update anyone's app:** this same address is the OTA feed
|
|
1571
|
+
installed apps poll, and the update check compares bundle **hashes**, not version
|
|
1572
|
+
numbers. So the workflow leaves \`www/config.json\` out of every artifact that is
|
|
1573
|
+
not a \`v*\` tag: the site is live for reading, while a device keeps running the
|
|
1574
|
+
last \`flet-box release\` until a tag publishes a manifest. The **Where this
|
|
1575
|
+
lives** step prints which of the two a given run was. Cut a release with
|
|
1576
|
+
\`flet-box release --patch --push\` when the app is worth updating.
|
|
1577
|
+
|
|
1436
1578
|
### Download the mobile artifacts
|
|
1437
1579
|
|
|
1438
|
-
|
|
1439
|
-
|
|
1580
|
+
Start it by hand — **Actions → "… — native (manual)" → Run workflow**, pick a
|
|
1581
|
+
platform — and open that run: the Android APK and the iOS \`.app\` are listed
|
|
1582
|
+
under **Artifacts** at the bottom of the run summary, and the job's own log prints
|
|
1583
|
+
the artifact name plus the URL of the run it belongs to.
|
|
1440
1584
|
|
|
1441
1585
|
> The workflow installs dependencies with \`npm install\`, which resolves the
|
|
1442
1586
|
> \`flet-box\` package from npm. If you develop against a local copy of the
|
|
@@ -1514,10 +1658,19 @@ updates:
|
|
|
1514
1658
|
- Replace \`TU-USUARIO\` with your GitHub username and \`TU-REPO\` with the
|
|
1515
1659
|
repository name, or set \`update.url\` to any HTTPS host that serves your
|
|
1516
1660
|
\`config.json\` + bundle.
|
|
1517
|
-
- Enable GitHub Pages: **Settings → Pages → Source: GitHub Actions**.
|
|
1661
|
+
- Enable GitHub Pages: **Settings → Pages → Source: GitHub Actions**. Without
|
|
1662
|
+
that the deploy step is green and no site exists.
|
|
1518
1663
|
- Cut a release with \`flet-box release --push\` (bumps the version, rebuilds
|
|
1519
1664
|
\`www/\`, commits and tags \`vX.Y.Z\`). CI then deploys \`www/\` and installed
|
|
1520
1665
|
apps self-update the next time they open.
|
|
1666
|
+
- A plain \`git push\` also deploys \`www/\` — that is the preview, and the job
|
|
1667
|
+
prints the address. It never publishes \`www/config.json\`, because that file
|
|
1668
|
+
is the update feed and the app compares bundle **hashes**: without it an
|
|
1669
|
+
installed app finds no manifest and stays on the last release. Do not "fix"
|
|
1670
|
+
that gate; the release tag is the only thing that should reach users.
|
|
1671
|
+
- Android and iOS are not built on a push. Start
|
|
1672
|
+
\`.github/workflows/build-native.yml\` from **Actions → Run workflow** and pick
|
|
1673
|
+
\`android\`, \`ios\` or \`both\`.
|
|
1521
1674
|
- The update URL is also reflected in \`www/config.json\` after \`flet-box
|
|
1522
1675
|
createBundle www\`; it is baked into Android/iOS builds at \`cap sync\` time.
|
|
1523
1676
|
- Only web files are updated OTA. Native changes (plugins, permissions,
|
|
@@ -1896,7 +2049,8 @@ export const agentsMd = (appName, template, version) =>
|
|
|
1896
2049
|
'',
|
|
1897
2050
|
'This file is the contract. Read it before writing any code in this project.',
|
|
1898
2051
|
'You do **not** need to read the whole framework to work here — sections 1 to 3',
|
|
1899
|
-
'tell you where the authoritative answers live,
|
|
2052
|
+
'tell you where the authoritative answers live, the design system in section 4',
|
|
2053
|
+
'fixes every size and color you may use, and the checker in section 5',
|
|
1900
2054
|
'proves you right or wrong in seconds.',
|
|
1901
2055
|
'',
|
|
1902
2056
|
'## 1. The API is a fact, not a guess',
|
|
@@ -1907,8 +2061,11 @@ export const agentsMd = (appName, template, version) =>
|
|
|
1907
2061
|
'| --- | --- |',
|
|
1908
2062
|
'| Which widgets exist and which props each accepts | `.fletbox/api/cheatsheet.md` (generated, covers every widget) |',
|
|
1909
2063
|
'| Everything for one widget | `npm run check -- --props <Widget>` |',
|
|
2064
|
+
'| Whether a prop actually reaches the DOM, or is typed but dead | `flet-box unpack <Widget>` |',
|
|
2065
|
+
'| A call that is safe to paste | `flet-box unpack <Widget> --example` |',
|
|
1910
2066
|
'| Prose, types and a worked example | `node_modules/flet-box/docs/widget/<Widget>.md` |',
|
|
1911
2067
|
'| Every public export of the package | `npm run check -- --list` |',
|
|
2068
|
+
'| The whole surface as data, to build calls from | `.fletbox/api/api.json` |',
|
|
1912
2069
|
'',
|
|
1913
2070
|
'**If a name is not in those files, it does not exist.** A prop that silently',
|
|
1914
2071
|
'does nothing is worse than a compile error: it renders as a broken layout and',
|
|
@@ -1917,6 +2074,10 @@ export const agentsMd = (appName, template, version) =>
|
|
|
1917
2074
|
'- Do not edit `node_modules/flet-box`. It is a dependency, not source.',
|
|
1918
2075
|
'- The cheatsheet is generated output. Regenerate it with',
|
|
1919
2076
|
' `flet-box check-api --emit-api` after upgrading the package; never hand-edit it.',
|
|
2077
|
+
'- `.fletbox/api/api.json` and `api.md` are generated the same way:',
|
|
2078
|
+
' `npm run api`. They carry one entry per prop with its engine target, default,',
|
|
2079
|
+
' aliases and a `sample` value, so a call can be written from data instead of',
|
|
2080
|
+
' memory.',
|
|
1920
2081
|
'',
|
|
1921
2082
|
'## 2. FletBox syntax only — no other framework',
|
|
1922
2083
|
'',
|
|
@@ -2006,7 +2167,62 @@ export const agentsMd = (appName, template, version) =>
|
|
|
2006
2167
|
'broken, prove it with a minimal repro and record the finding in memory** — do',
|
|
2007
2168
|
'not work around it silently.',
|
|
2008
2169
|
'',
|
|
2009
|
-
'## 4.
|
|
2170
|
+
'## 4. Design system — one scale, three colors',
|
|
2171
|
+
'',
|
|
2172
|
+
'A screen is designed, not decorated. Every size and every color on this app',
|
|
2173
|
+
'comes from the two lists below. A value outside them is a bug you have to',
|
|
2174
|
+
'justify, and `padding: 13` or `#4f46e5` written by hand is the usual sign a',
|
|
2175
|
+
'screen drifted away from the rest.',
|
|
2176
|
+
'',
|
|
2177
|
+
'**Color: three roles, no more.**',
|
|
2178
|
+
'',
|
|
2179
|
+
'| Role | Token | Where it may appear |',
|
|
2180
|
+
'| --- | --- | --- |',
|
|
2181
|
+
'| Brand | `colors.primary` | the one action the screen asks for: primary button, active tab, focus ring, links |',
|
|
2182
|
+
'| Emphasis | `colors.secondary` | a deliberate second voice: gradients, badges, a highlighted stat |',
|
|
2183
|
+
'| Feedback | `colors.success` / `colors.warning` / `colors.danger` | status only — never as decoration |',
|
|
2184
|
+
'',
|
|
2185
|
+
'Everything else is neutral: `colors.background`, `colors.surface`,',
|
|
2186
|
+
'`colors.card`, `colors.text`, `colors.textSecondary`, `colors.textDisabled`,',
|
|
2187
|
+
'`colors.border`, `colors.divider`, plus the `gray50`…`gray900` ramp. Rules:',
|
|
2188
|
+
'',
|
|
2189
|
+
'- A screen uses **one** brand color. Two accent colors competing on one view',
|
|
2190
|
+
' means one of them is wrong.',
|
|
2191
|
+
'- Never type a hex or `rgb()` literal. If a token is missing, add it to a',
|
|
2192
|
+
' `theme.js` in this app that re-exports `colors` — do not scatter the value.',
|
|
2193
|
+
'- Text on a dark fill is white; hierarchy comes from opacity',
|
|
2194
|
+
' (`rgba(255,255,255,.72)`), not from a second color.',
|
|
2195
|
+
'- `error` ≡ `danger` and `*Bg` variants exist for alert fills; use the pair',
|
|
2196
|
+
' (`colors.danger` + `colors.errorBg`), not a hand-mixed tint.',
|
|
2197
|
+
'',
|
|
2198
|
+
'**Space and type: an 8-based scale.** Use these numbers and nothing between',
|
|
2199
|
+
'them. They are plain props (`padding`, `gap`, `margin`, `width`, `height`,',
|
|
2200
|
+
'`size`, `radius`) — the factory takes the number, no unit and no `px` string.',
|
|
2201
|
+
'',
|
|
2202
|
+
'```',
|
|
2203
|
+
'spacing 4 · hairline, icon inset',
|
|
2204
|
+
' 8 · tight gaps, chip padding',
|
|
2205
|
+
' 12 · control padding (input/button height − text)',
|
|
2206
|
+
' 16 · default card padding, section gap, screen gutter',
|
|
2207
|
+
' 18 · card-to-card rhythm on a dense grid',
|
|
2208
|
+
' 24 · between sections',
|
|
2209
|
+
' 32 · between page blocks',
|
|
2210
|
+
' 48 · hero spacing',
|
|
2211
|
+
'radius 4 / 8 / 12 / 16 / 999 (pill)',
|
|
2212
|
+
'type 12 caption · 14 body-small · 16 body · 18 subtitle · 24 title · 32 headline',
|
|
2213
|
+
'weight 400 body · 500 label · 600 title · 700 headline',
|
|
2214
|
+
'line-height 1.5 body · 1.2 heading',
|
|
2215
|
+
'```',
|
|
2216
|
+
'',
|
|
2217
|
+
'- Padding inside a card is `16`; the gap between cards is `16` or `24`. Never',
|
|
2218
|
+
' mix the two on the same list.',
|
|
2219
|
+
'- One text size per element, one weight per role. If a label and its value are',
|
|
2220
|
+
' the same size, the hierarchy is carried by color, not by a fourth size.',
|
|
2221
|
+
'- Tap targets are at least `40` on a side; get there with `height`, not padding.',
|
|
2222
|
+
'- `useState` bindings, `flex` and `gap` do the layout. Reach for an absolute',
|
|
2223
|
+
' offset only for overlays, and use `stackPosition` rather than raw coordinates.',
|
|
2224
|
+
'',
|
|
2225
|
+
'## 5. Verification loop (required)',
|
|
2010
2226
|
'',
|
|
2011
2227
|
'After every edit, before you say a task is done:',
|
|
2012
2228
|
'',
|
|
@@ -2021,7 +2237,14 @@ export const agentsMd = (appName, template, version) =>
|
|
|
2021
2237
|
'It reads the installed package, so it is always in sync with what runs. A',
|
|
2022
2238
|
'warning is allowed to stay only when you can justify it in one sentence.',
|
|
2023
2239
|
'',
|
|
2024
|
-
'
|
|
2240
|
+
'When the error is a mistyped name, `npm run fix` rewrites it for you — a',
|
|
2241
|
+
'relative path that does not resolve, a name the target module never exports,',
|
|
2242
|
+
'an identifier used without its `import`, and a prop key the API does not know',
|
|
2243
|
+
'(`chilldren` → `children`, `bgColr` → `bgColor`). It only rewrites when exactly',
|
|
2244
|
+
'one real name is close enough; anything ambiguous is printed untouched for you',
|
|
2245
|
+
'to decide. Run `npm run check` again after it, and read the diff.',
|
|
2246
|
+
'',
|
|
2247
|
+
'## 6. Memory — do not relearn the same thing',
|
|
2025
2248
|
'',
|
|
2026
2249
|
'At the start of every session read `.fletbox/memory/MEMORY.md` and any entry it',
|
|
2027
2250
|
'points at. That is how this agent remembers the framework between chats instead',
|
|
@@ -2036,13 +2259,18 @@ export const agentsMd = (appName, template, version) =>
|
|
|
2036
2259
|
' to be wrong rather than appending a correction beside it.',
|
|
2037
2260
|
'- Commit memory files with the code change they describe.',
|
|
2038
2261
|
'',
|
|
2039
|
-
'##
|
|
2262
|
+
'## 7. Commands',
|
|
2040
2263
|
'',
|
|
2041
2264
|
'| Command | What it does |',
|
|
2042
2265
|
'| --- | --- |',
|
|
2043
2266
|
'| `npm run dev` | static dev server on port 8000 |',
|
|
2044
2267
|
'| `npm run check` | anti-hallucination gate over `src/` |',
|
|
2268
|
+
'| `npm run fix` | rewrite mistyped imports and prop names it can prove |',
|
|
2045
2269
|
'| `npm run check -- --props Button` | print the real props of a widget |',
|
|
2270
|
+
'| `flet-box unpack Button` | everything Button accepts **and that actually works** |',
|
|
2271
|
+
'| `flet-box unpack Button --example` | a paste-ready call using only live props |',
|
|
2272
|
+
'| `flet-box unpack Button --diff` | doc vs code gaps: dead, invented, undocumented |',
|
|
2273
|
+
'| `npm run api` | rebuild `.fletbox/api/api.json` + `api.md` for the whole surface |',
|
|
2046
2274
|
'| `npm run build` | esbuild bundle into `dist/` |',
|
|
2047
2275
|
'| `flet-box build android` / `ios` | Capacitor native build |',
|
|
2048
2276
|
'| `flet-box run-native android` | compile and launch on device/emulator |',
|
|
@@ -2060,6 +2288,16 @@ export const claudeMd = () =>
|
|
|
2060
2288
|
'follow it exactly — FletBox syntax only, real props only, `npm run check` after',
|
|
2061
2289
|
'every edit.',
|
|
2062
2290
|
'',
|
|
2291
|
+
'Two shortcuts replace guessing:',
|
|
2292
|
+
'',
|
|
2293
|
+
'- `flet-box unpack <Widget>` prints every prop the widget really honors, with',
|
|
2294
|
+
' its type, default and engine target. `--example` gives a call you can paste,',
|
|
2295
|
+
' `--diff` lists the props that are documented but dead or used but undeclared.',
|
|
2296
|
+
' `.fletbox/api/api.json` is the same surface for all widgets, as data.',
|
|
2297
|
+
'- Design is fixed, not improvised: one brand color per screen from the `colors`',
|
|
2298
|
+
' tokens (never a hex literal), and sizes only from the 8-based scale —',
|
|
2299
|
+
' 4 · 8 · 12 · 16 · 18 · 24 · 32 · 48. AGENTS.md §4 has the full table.',
|
|
2300
|
+
'',
|
|
2063
2301
|
'Memory: read `.fletbox/memory/MEMORY.md` before working, and write new entries',
|
|
2064
2302
|
'there when you learn something the next session should not rediscover.',
|
|
2065
2303
|
'',
|
|
@@ -2079,8 +2317,13 @@ export const cursorRules = () =>
|
|
|
2079
2317
|
'- Widgets are function calls returning an element: `Text({ text: "Hi", size: 18 })`.',
|
|
2080
2318
|
' No JSX, no positional args, no Flutter/Vue/Svelte/React syntax or imports.',
|
|
2081
2319
|
'- Before using a widget or prop you have not just seen in',
|
|
2082
|
-
' `.fletbox/api/cheatsheet.md`, look it up: `
|
|
2083
|
-
' If it is not listed, it does not exist —
|
|
2320
|
+
' `.fletbox/api/cheatsheet.md`, look it up: `flet-box unpack <Widget>` (or',
|
|
2321
|
+
' `npm run check -- --props <Widget>`). If it is not listed, it does not exist —',
|
|
2322
|
+
' do not invent it. `unpack --example` prints a call that is safe to paste.',
|
|
2323
|
+
'- Design rules: one brand color per screen, taken from the `colors` tokens —',
|
|
2324
|
+
' never a hex literal. Sizes come from the 8-based scale only:',
|
|
2325
|
+
' 4 · 8 · 12 · 16 · 18 · 24 · 32 · 48 spacing, radii 4/8/12/16/999, type',
|
|
2326
|
+
' 12/14/16/18/24/32. See AGENTS.md §4.',
|
|
2084
2327
|
'- Run `npm run check` after every change and fix what it reports.',
|
|
2085
2328
|
'- Check `.fletbox/memory/MEMORY.md` at session start; record new non-obvious',
|
|
2086
2329
|
' findings there instead of re-deriving them.',
|
package/docs/cli/README.md
CHANGED
|
@@ -423,8 +423,86 @@ Capacitor template with different slots keeps working. It:
|
|
|
423
423
|
The script is idempotent: running it twice leaves identical files. The brand
|
|
424
424
|
color `#1a1a2e` is defined at the top of the script.
|
|
425
425
|
|
|
426
|
+
## Convert asset images to PNG
|
|
427
|
+
|
|
428
|
+
Screens need PNG, and a `logo.jpg` dropped into `assets/` still works — until an
|
|
429
|
+
Android or iOS build asks for a format the source photo cannot give it.
|
|
430
|
+
`flet-box to-png` converts a folder of images to PNG using nothing but Node
|
|
431
|
+
itself, so it works on a machine where no image library is installed.
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
flet-box to-png # converts ./assets, ./public/assets or ./src/assets
|
|
435
|
+
flet-box to-png assets # converts one folder
|
|
436
|
+
flet-box to-png assets --dry-run
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
It recognises a file by its leading bytes, never by its extension, so a
|
|
440
|
+
`logo.jpg` that is really a PNG is treated as the PNG it is. What it converts:
|
|
441
|
+
|
|
442
|
+
| Format | Notes |
|
|
443
|
+
| --- | --- |
|
|
444
|
+
| JPEG | Baseline and extended sequential, greyscale or colour, any sampling factor (4:4:4, 4:2:2, 4:2:0, 4:1:1), restart intervals. Progressive, arithmetic-coded, lossless, 12-bit and CMYK files are refused with the reason. |
|
|
445
|
+
| PNG | Colour types grey/RGB/palette/grey+alpha/RGBA at 1–16 bits, all five row filters, `tRNS` transparency. Already a PNG, so it is left alone unless you ask with `--optimize` or `--force`. Interlaced (Adam7) files are refused. |
|
|
446
|
+
| GIF | First frame, with or without interlacing and transparency. An animated file converts with a note saying how many frames were dropped. |
|
|
447
|
+
| BMP | Uncompressed 1/4/8/24/32-bit, top-down or bottom-up. Run-length (RLE) files are refused. |
|
|
448
|
+
|
|
449
|
+
These need a codec or a rasteriser that a zero-dependency package cannot carry,
|
|
450
|
+
so they are reported as declined rather than quietly skipped: WebP, AVIF/HEIF,
|
|
451
|
+
TIFF, ICO and SVG.
|
|
452
|
+
|
|
453
|
+
Nothing is overwritten. `assets/logo.jpg` becomes `assets/logo.png` beside it and
|
|
454
|
+
the source stays; if `logo.png` already exists the file is kept and reported as a
|
|
455
|
+
name clash, because that collision usually means someone already converted it by
|
|
456
|
+
hand. `--replace` deletes each source, and only after the PNG it replaces has been
|
|
457
|
+
read back and checked:
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
flet-box to-png assets --out build/img # write the PNGs somewhere else
|
|
461
|
+
flet-box to-png assets --force # replace an existing logo.png
|
|
462
|
+
flet-box to-png assets --replace # delete the source once its PNG is verified
|
|
463
|
+
flet-box to-png assets --optimize # re-pack the PNGs already in the folder
|
|
464
|
+
flet-box to-png assets --flat # top level only, no sub-folders
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
The summary counts the outcomes apart — converted, declined, already a PNG, name
|
|
468
|
+
clashes, and with `--optimize` also optimized, already optimal and the bytes saved
|
|
469
|
+
— and only a file whose bytes could not be decoded counts as a failure, which is
|
|
470
|
+
the one case that exits non-zero.
|
|
471
|
+
|
|
472
|
+
### The PNG it writes is the smallest one that holds the picture
|
|
473
|
+
|
|
474
|
+
A converted file is not written in one fixed layout. The writer looks at the
|
|
475
|
+
pixels first and keeps whichever arrangement is smallest: a palette when the
|
|
476
|
+
frame really does hold 256 colours or fewer (an exact address per pixel, not a
|
|
477
|
+
quantisation), greyscale when every channel already agrees, three bytes per pixel
|
|
478
|
+
when no pixel uses alpha. It then deflates the five row filters and keeps the
|
|
479
|
+
shortest result. Nothing is approximated, so the file reads back as the same
|
|
480
|
+
picture — and the command checks that before it calls the conversion a success.
|
|
481
|
+
|
|
482
|
+
`--optimize` asks the same question about files that already are PNG, which is
|
|
483
|
+
how a hand-made asset gets its turn:
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
flet-box to-png assets --optimize
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
It replaces a PNG only when the new bytes are smaller *and* every pixel matches,
|
|
490
|
+
so running it twice is free: the second pass reports each file as already optimal
|
|
491
|
+
and touches nothing. The repo's own icons lose 13 KB on the 1024 maskable and 3 KB
|
|
492
|
+
on the logo, and the other four come back as already optimal. A 16-bit PNG is left
|
|
493
|
+
alone either way — rewriting it would trade someone else's bit depth for a smaller
|
|
494
|
+
file, and "smaller without losing quality" does not cover that.
|
|
495
|
+
|
|
496
|
+
What this cannot do is make a photograph small. PNG stores every pixel, and a
|
|
497
|
+
camera JPEG has already thrown most of them away, so the PNG of a photo comes out
|
|
498
|
+
three to four times the file it came from (a 3.5 MB picture writes as 12 MB). The
|
|
499
|
+
command converts it anyway and says so in the report: keep the JPEG — or a WebP
|
|
500
|
+
from a tool that carries a codec — for that picture, and let `to-png` do the flat
|
|
501
|
+
art, the logos and the icons.
|
|
502
|
+
|
|
426
503
|
## Command reference
|
|
427
504
|
|
|
505
|
+
|
|
428
506
|
| Command | What it does |
|
|
429
507
|
| --- | --- |
|
|
430
508
|
| `flet-box create <name>` | Creates a default project. |
|
|
@@ -447,6 +525,10 @@ color `#1a1a2e` is defined at the top of the script.
|
|
|
447
525
|
| `flet-box run-native <android\|ios>` | Compiles and launches the app on an emulator/simulator or connected device. |
|
|
448
526
|
| `flet-box run-native <android\|ios> --device` | Forces a physical device instead of the emulator. |
|
|
449
527
|
| `flet-box run-native <android\|ios> --livereload` | Launches the app with hot reload on the device. |
|
|
528
|
+
| `flet-box to-png [dir]` | Converts JPEG, GIF, BMP and non-PNG-precision images in a folder to PNG. |
|
|
529
|
+
| `flet-box to-png --dry-run` | Reports what would happen, writes nothing. |
|
|
530
|
+
| `flet-box to-png --replace` | Deletes each source after its PNG was written and read back. |
|
|
531
|
+
| `flet-box to-png --optimize` | Re-packs the PNGs already in the folder, and only when that makes them smaller. |
|
|
450
532
|
| `flet-box pkg` | Opens the package manager. |
|
|
451
533
|
| `flet-box --version` | Shows the CLI version. |
|
|
452
534
|
| `flet-box --help` | Shows the command list. |
|