Commit graph

199 commits

Author SHA1 Message Date
CRT
0e344ee119 Tests: neutral sample account names in the profile fixtures 2026-10-19 01:02:33 +07:00
CRT
af631fd1f8 Make panel: the create commands wrap instead of being cut off by a hidden scrollbar 2026-10-15 05:57:18 +08:00
CRT
a6629942f7 README: real screenshots of wayBetter for X instead of composed cards and clips
hero (the deck: three of our accounts), the Make settings page, the Windows 98 theme and four other
themes, all captured from the app; the make clip is gone.
2026-10-15 05:55:35 +08:00
CRT
ee0dc35363 host (macOS): an iframe's navigation no longer becomes the tab's address
wry asks the navigation handler for every WKNavigationAction, iframes included, so an embedded
player (Chat+ link previews' YouTube frame) put its URL in the address bar and left the tab loading
forever. macOS now does the page-level work from on_page_load (Started), the main frame only, as
Linux already did. Verified live: the player plays, the address stays on x.com, no spinner.
2026-10-15 05:45:42 +08:00
CRT
7cf4c81e30 README: real terminal shots (tools/readme-term-shots.mjs) instead of hand-drawn SVGs, a badge row
The architecture and create-terminal SVGs were drawn by hand and their text overflowed. The quick
start now shows the real output of npm create waybetter, rendered the way storebound renders its
terminal shots; the layers stay a table.
2026-10-15 04:27:29 +08:00
CRT
6d05240afc Remove the privacy-scan command; releases run an optional owner-supplied check instead
waybetter release and the remote builds no longer scan artifacts themselves: WAYBETTER_RELEASE_CHECK
can name a command that gets every artifact path before anything is copied or signed (a non-zero
exit stops the release). The command, its tests and every mention in the docs, the template and
the architecture diagram are gone.
2026-10-11 07:32:38 +08:00
CRT
e29a472f84 Theme engine v3 step 10: the frame marker
installFrameMarker: framed parts inside the watched scopes get data-wb-void when nothing
in them renders and collapse (frameMarkerCss); a ResizeObserver per part and a
child-list/attribute observer on the scopes trigger the check, batched per frame. The
per-part 1.5 s polling of the X app's void cards is replaced.
2026-10-02 06:18:38 +07:00
CRT
5c04f4de60 Theme engine v3: component inks solved on the grounds they sit on
A part's text role is still swapped for a readable one on its own fill, and its ink is
then solved with inkOn: on its fill, or with no fill of its own on every surface it can
sit on, the page canvas included (Solarized Light's outline Post button in the rail:
accent on the page read 4.45:1). Roles made for a parent's fill (onAccent, onInverse,
bg) stand. Invariant suite: Solarized Light I1 107 -> 0.
2026-10-02 06:14:15 +07:00
CRT
58e7fff6c6 host: no opener link handler in webviews (target=_blank clicks in site tabs were cancelled and never opened) 2026-10-02 06:11:38 +07:00
CRT
4945a84d8b themeInvariants: controls are not empty frames (I6); a layer over the bar is not a bar hit-test failure (I4) 2026-10-02 06:02:30 +07:00
CRT
d6b9520df9 Theme engine v3 step 9: the bar's label mode is measured
themeBar.ts: the sum of the whole labels (each in its own computed font, via canvas
measureText, so a hidden label still counts), icons, paddings and gaps against the
nav's room, with 16px hysteresis; writes html[data-wb-bar=labels|icons] on nav
resize, font loads and window resize. No width breakpoint decides it any more.
2026-10-02 05:58:34 +07:00
CRT
923ad74465 Theme engine v3 step 8: the layer guard
themeGuards.ts: watches the site's layer container; every new popover (and one that the
site moves or that grows) is measured in an idle callback and shifted into the viewport
minus the bar insets with a translate (data-wb-clamped, --wb-clamp-x/y); taller than the
viewport it scrolls. Bounded: only nodes that hold a popover are measured, at most 4 per
pass; a moved popover is seen through its own style attribute and a ResizeObserver.
clampShift/viewportBox are pure and unit tested.
2026-10-02 05:46:52 +07:00
CRT
2507f63327 Theme engine v3 step 5: SurfaceSet, the shell chrome reads it
themeDerive.ts: canvas, content, card, chrome, raised, panel, strong, accentFill and
tooltip, each with ink, inkSoft, link, line, hover, selected and focus solved on its
fill (both gradient ends). Hover and selected step back toward the fill until every
ink still reads on them; hover is neutral unless the theme sets one (no accent wash);
a strong gradient's end moves until one ink reads on both; targets no ink can reach
on a mid-tone fill are capped and noted. 5,000-palette property test.
chromeTheme.ts: legible() is the solver; the bevel title bar, selection and face inks
come from the strong and chrome surfaces. Chrome vars of the 13 built-ins: only the
faint/warn/danger inks move (closer to the theme colour, still 4.5:1).
2026-10-02 05:00:43 +07:00
CRT
e94636ee09 Theme engine v3 step 1: themeInvariants, the numeric invariant probe (I1-I8, I10)
A pure measurement over a rendered document (fixtures and live): text and icon contrast over the
painted backdrop, X colour leakage, truncated bar/nav/button labels, bar geometry and hit tests, X line
icons under a pack, empty and nested frames, popover bounds, target sizes. Grew out of theme-qa/probe.js.
2026-10-02 05:00:02 +07:00
CRT
c66d66e3a8 Theme engine v3 step 4: inkOn, the contrast solver
themeInk.ts: OKLCH lightness search toward the pole with headroom, hue kept, chroma
cut only for the gamut; several fills (gradient ends, glass grounds); compositing.
reach() now runs on it (8% headroom when a colour has to move, for the site's tints
mixed from these surfaces). Property test: 5,000 random pairs reach 4.5:1 and 3:1;
the live 1.0.2 cases ("New" pill 1.19:1, HoverLabel 2.7:1, like pink 3.84:1) pass.
2026-10-02 04:56:04 +07:00
CRT
0f0f51988b Store: status words follow the theme (ok/warn/danger ink tokens), with a token test
A literal #3ecf8e green read 1.03:1 on the Windows 98 silver card (theme QA r1). Status text now mixes
the status hue toward --wb-text; store.css may hold no literal text colours outside its token defaults.
2026-10-02 04:29:27 +07:00
CRT
8308eab727 Icon names for X's newer rail items: history, studio, articles 2026-10-02 04:09:11 +07:00
CRT
0d78a6b5ef Shell: do not save the layout before the saved one is restored
A save timer queued before the async startup (settings, profiles, workspaces) finished fired on the still-empty dock and overwrote the stored layout, so a shell reload came back with one fresh Home tab. Saves now wait for layoutReady.
2026-10-02 04:03:23 +07:00
CRT
f3baf479b3 waybetter 0.7.0, create-waybetter 0.2.0 2026-10-02 02:57:36 +07:00
CRT
67373aeeef create-waybetter: the template's host command list gains menu_set 2026-10-02 02:35:49 +07:00
CRT
084465e424 Native menu bar words in every catalog (42 wb.menu.* keys, macOS menu names per language); Media panel key is Cmd+Shift+M on macOS (Cmd+Shift+G is Find Previous), Ctrl+Shift+G elsewhere, shown in the palette and Settings from the platform 2026-10-02 02:12:17 +07:00
CRT
66c4151011 shell test: unused parameter 2026-10-02 02:01:27 +07:00
CRT
4c957df89c Native menu bar (macOS): the shell describes it (menu_set, shell-only), host validates and builds it, a chosen id goes back to the shell (native-menu); App/File/Edit/View/Account/Plugins/Window/Help from the in-app menu's state, words wb.menu.* 2026-10-02 02:00:15 +07:00
CRT
d7903e80ce shell: menus readable under every theme; account rows no longer collapse in Windows 98
Owner, live 2026-10-02: the account switcher's rows overlapped (names and handles collided) and
"Not signed in yet" was unreadable. Causes: edges.css forced every menu button to 26px, which squashed the
two-line account rows; the status inks (#f0b14a signed out, #ff8a80 errors) and the hint ink (a 38% fade of
the secondary text) were Night Ink literals, 2.1 to 3.6:1 on other themes' menus. Now the forced height is
gone, status, hint and secondary inks are measured on the menu surface (the face in bevelled themes) at
4.5:1 (--wb-c-warn, --wb-c-danger-ink, --wb-c-faint, --wb-c-muted), every line of a selected bevelled row
takes the selection's ink, and wayBetter's own default hint ink is legible. Checked: every shell menu
(accounts, app menu, tab menu, workspaces, palette) under 14 themes with an overlap and contrast scan
(verification/design-pass/1.0.2/menus-shots.mjs); new frame test for the inks.
2026-10-02 01:43:36 +07:00
CRT
16e6555013 macOS: a visible pane whose real frame drifted from the cached placement (AppKit moved it behind our back) is placed again, with a diag line 2026-10-02 01:28:03 +07:00
CRT
d69dcc8d67 diag: keep the previous run's log as diag.prev.log 2026-10-02 01:12:33 +07:00
CRT
769491ca66 macOS: the red close button sends the window to the Dock and the app keeps running (Dock click restores, Cmd+Q quits); a pane shown after being parked is shown before it is sized and told to re-lay out (X drew an empty timeline) 2026-10-02 00:52:24 +07:00
CRT
e31f2d3f39 README: make clip re-cut from the final launch film 2026-10-02 00:51:37 +07:00
CRT
e6114d4ec0 README: what wayBetter is, an architecture diagram, the npm create waybetter quick start with its real output, the packages, and wayBetter for X as the showcase (assets/readme: hero, SVGs, one muted looping clip) 2026-10-02 00:46:10 +07:00
CRT
dffeb3f159 Theme icons: pixel-art glyphs render with crisp edges
A glyph made only of axis-aligned rectangles (M, h, v, z) is pixel art: its SVG gets
shape-rendering="crispEdges", so a 16-cell glyph stays sharp at sizes that are not a whole multiple
of its grid (X's rail draws 26px icons, the action bar 18.75px).
2026-10-01 16:59:03 +07:00
CRT
60cb4f17ac host: a pane's own theme wins over a theme preview
A preview (the Theme Builder's, developer mode's, or one an automation left on through theme_preview)
replaced every site tab's theme, pane themes included, also on reload; "Theme for this pane" then
showed its choice checked while the page kept the preview. Reproduced live: a preview of Windows 98
turned a Paper pane into Windows 98 until the preview ended. Now a pane with its own theme keeps it;
every other tab shows the preview, as before.
2026-10-01 16:51:42 +07:00
CRT
a63eca9d67 host: tab_find doc names the Custom Highlight fallback 2026-10-01 16:19:12 +07:00
CRT
6a2fc7976c host: the drafts vault commands (draft_list/save/revisions/status, observation_list, data_export) are the host's (AppConfig::with_vault, commands::VAULT); the app takes the vault through vault_commands::lock 2026-10-01 16:17:30 +07:00
CRT
98d32abb98 host: the drafts vault (CAS revisions, append-only history, archive, export, capture budget) with the app's VaultRules; feature vault 2026-10-01 16:08:40 +07:00
CRT
10b236ae8a create-waybetter: the template's host command list gains tab_run_command (matches commands.rs again) 2026-10-01 16:07:58 +07:00
CRT
360933a47c host: AlertsConfig and ThemeConfig live in ungated modules, so the host compiles and tests without the tauri feature 2026-10-01 16:05:27 +07:00
CRT
30ba30797d Theme icons: glyphs drawn whole in the icon's content box
Live 2026-10-01: X's search-field icon is a 28x16 box with 12px of padding; sized at 100% of that width a
pixel glyph lost its top and bottom and sat left of X's own icon. Glyphs are now sized with contain (a
scaled pack by the box's height) and placed in the content box, for masks and images alike.
2026-10-01 15:52:56 +07:00
CRT
c3f07d46d2 Locales: icon packs, install, Store tabs, area switch and the theme doctor in the remaining catalogs (47 languages, machine) 2026-10-01 14:57:53 +07:00
CRT
8588c5e63c Store: two catalog files from one source, so apps from before a kind keep a working Store
An app that does not know a catalog item's kind refuses the whole signed file, so
the icons and builtin kinds can never go into catalog.json. `waybetter store build`
now writes catalog.json (format 2: theme, plugin, strings only; what every app
reads today) and catalog.v3.json (format 3: every kind) from the same items;
`sign` and `verify` handle the pair; the rules refuse a format 2 file that lists a
newer kind (CLI, JSON Schema, host). The host reads catalog.v3.json first and falls
back to catalog.json only when the newer file is not there (a newer file that does
not verify is an error). An item of a kind a version does not know is skipped
instead of refusing the file, so the next new kind costs current apps nothing.
2026-10-01 14:41:29 +07:00
CRT
a8e5e20ef4 shell: a pane's edges follow its own theme
themeStore marks every dock group whose theme (the pane's own, else the global one) is bevelled with
.wb-bevel; edges.css draws tabs, toolbar, address field, wB button and the settings panel per group.
The window-level parts (title bar, caption buttons, menus, palette, scrollbars) keep following the
global theme. A Windows 98 pane is bevelled inside a flat window, and a flat pane stays flat inside a
Windows 98 window.
2026-10-01 14:39:11 +07:00
CRT
3571b38029 host: the popover host (webview, session, z-order, close rules) is the host's
popover_host owns the one popover webview of an app: creation (recreated above tabs created after
it), placement through popover::place, the session (seq, source tab, app meta flattened into the
JSON the page reads), the toggle-closed window, close on layout change, navigation (the app says
whether the context moved on), shell raise, and the popover_only / current caller checks. The app
passes a PopoverConfig (page url, open event, macOS ground). Tests: layout staleness and the
session JSON shape.
2026-10-01 14:33:10 +07:00
CRT
1c4e872fb0 Theme decor: selection colors with a bare ::selection
With an ancestor in front (:root:root ::selection) every node the site inserts cost extra style
recalculation: Terminal measured 4 elements per insertion on the theme matrix (6 after a bar theme,
over the budget of 5); a bare ::selection measures 2 (3 after a bar theme). The rule did not predate
the design pass's changes; it was in Terminal's decor from the start.
2026-10-01 14:26:29 +07:00
CRT
0bbb09d636 host: popover geometry (card placement, label, constants) is the host's
Pure placement of a trusted local card under a button of a site tab, kept inside the tab, flipped
above when short, with the caret on the button; moved from the X app with its seven tests.
2026-10-01 14:26:25 +07:00
CRT
5aa66e7191 Store: Open With (files the OS hands over) and the icons and builtin catalog kinds
Open With: store_commands keeps each existing file the OS hands over (launch
argument, a second launch forwarded by single-instance with its working
directory, a macOS file:// open-URL) under a random id (Store::receive_file:
name says what it is, regular file, size cap, 8 kept, 15 minutes) and queues
LinkEvent.opened {id, name, kind}. The shell-only install_stage_opened {id}
reads that one file once and stages it exactly like a dropped file; it takes
an id only (testkit asserts that), so the shell cannot name a path. The shell
shows the same install screen; nothing installs without it. The NSIS template
lists the app under "Open with" for the declared extensions (OpenWithProgids)
and never makes it the default program, unlike Tauri's own macro.

Catalog kinds: icons (an icon pack, *.icons.json, at most 120 KB; validate_icons,
staged and committed as text for the shell, the install screen draws every icon,
.icons.json is no longer read as a theme) and builtin (a feature the app
already has, such as an area plugin: no url, sha256, size or file; never staged;
the Store view lists it as Built in with the app's own switch via the areas
prop). Rust: Kind, CatalogItem.check, verify_item, install links refuse builtin.
JS: storeModel, installController (requestOpened, icons adapter), InstallDialog,
StoreView, StoreSection (remove an icon pack, area switches), words. CLI and
JSON Schema: kinds, optional url/sha256/size on builtin, icons size cap; the
test schema validator learns not and if/then/else. docs/STORE.md.
2026-10-01 14:23:23 +07:00
CRT
e85a00eca3 host: the palette commands of site tabs are the host's (tab_commands, tab_run_command)
tab_commands keeps the list each site tab reported (validated by plugins::commands, accepted only
from a tab on the site's origin), clears it when a new document starts, tells the shell, and checks
the shell-only tab_run_command: only a command that tab reported, only while it is on the site.
tab_run_command joins commands::SHELL (guard checked by assert_host_guards); the app's tab_report
hands its `commands` to tab_commands::reported.
2026-10-01 14:22:00 +07:00
CRT
2dd5d88718 String packs: rich-text entries, language conditions and word rewriting; theme doctor report; translate-mode words
- Rich sentences (a link or button inside text) can be replaced by data: the inventory gives a rich entry `slots`, a pack value places the site's own elements with {e0}, {e1}, ... (each once, the last may be left out; no markup, plural or other parameters). The engine returns a pieces + element order template; the page inventory carries `rich` slot counts.
- Packs may carry `when: { languages }` (applies only while the site shows one of them; `en` matches `en-GB`) and `rewrite: { words }` (whole-word rewording of the site's own text, messages keep their parameters' values; no sentences of the site in the pack). The hook tells the engine the site's language; a rewording pack makes the delivery carry the whole inventory.
- Apps can ship built-in packs (BuiltInPacks) delivered before installed ones; syncStringPacks hands the tabs a delivery at start only when it changed.
- Translate mode words are a function the app supplies (asked at each draw) and gain a `plural` word; host validates `when` and `rewrite` envelopes.
- Theme doctor: every finding says where (token path or CSS rule), what and how to fix, as catalog keys wb.doctor.*; the Theme Builder shows the full report; the import hint is translated. Doctor words are in the 17 supported catalogs.
- waybetter strings check describes conditions and rewrites.
2026-10-01 14:19:36 +07:00
CRT
2ea6f784b8 host: keyword alert settings are the host's (AppConfig::with_alerts, commands::ALERTS)
alerts_commands keeps the owner's AlertSettings (saved in app data, validated by alerts), serves
the shell-only alerts_get / alerts_set (testkit::assert_alerts_guards) and builds the script that
hands the page runtime the keywords to watch. The app names the file and the runtime member
(AlertsConfig); store()/script() are the app's own writers (backup import).
2026-10-01 14:14:34 +07:00
CRT
62e28c87be shell: the active tab's mark and the palette's edge take the theme's accent instead of wayBetter's brush 2026-10-01 14:14:27 +07:00
CRT
49c0569982 macOS find: page matches drawn with the CSS Custom Highlight API (window.find showed nothing while the page was not the key view); --diag logs exit requests, window close/destroy and each native pane placement on macOS 2026-10-01 14:13:53 +07:00
CRT
a6f44a212b host: site themes are the host's (AppConfig::with_themes, commands::THEME)
theme_commands serves theme_get / theme_set / theme_preview / theme_scopes_get / theme_scopes_set
(shell-only, each checks its caller first; testkit::assert_theme_guards) over the theme state the
host now keeps: the owner's theme, account and pane themes, the Theme Builder preview. The app
only names its built-in themes and the two files (ThemeConfig). apply() themes every site tab
(script, cached Google font bytes, native background); page_scripts()/tab_background() serve a new
document; set_theme/set_scopes/set_preview are the app's own writers (backup import, dev mode).
A font install or removal re-themes the tabs in the host itself.
2026-10-01 14:10:43 +07:00