mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
feat(plugins): give plugins the surface, insets and mobile palette they need (#1886)
* Tell a plugin where it is mounted A plugin sits in one of six host surfaces and cannot see which: a trip tab and the plugin page fill their container and scroll themselves, a dashboard widget and the settings frame report their height, a detail slot is a narrow column in someone else's panel. The contracts differ, and on a filling surface the height report is discarded, so a plugin cannot even discover the difference by trying. trek:context now carries viewport: the surface by name, phone or desktop, the fill flag, and the insets the host already keeps clear. The insets describe space that is held free, not padding to add — the mobile trip tab is the only surface with chrome floating over it, and the numbers come from the same variables the native tabs use so the two cannot drift. * Seat the plugin tab like a native one The mobile plugin tab kept clearance at the bottom and none at the top, so the plugin's first row sat under the status bar and behind the floating back button. The bottom value was a copied 84 that ignored the safe area on the devices that have one, and the padding sat on the container rather than in the scroller. Both clearances now come from the variables TabScroller uses, so the tab cannot drift away from the native ones. The frame also states its surface, and pins color-scheme for the reason both settings mounts already pin it: Chromium paints a white canvas behind a transparent frame otherwise. The tab also had no name anywhere on screen. It is not in the dock, so nothing lit up there either, and the header had a branch for every other tab. It gets the same treatment, built from the tab entry the planner already assembles. * Keep the widget card intact on the phone The card is built from the dashboard's glass vocabulary, which is scoped to .trek-dash. The phone dashboard is a different route and mounts these widgets outside that subtree, so background, border, shadow and blur all resolved empty and the widget stood on the gradient as a bare title over an iframe. Each value now falls back to the mobile token the surrounding cards are made of. * Give the design kit a mobile layer The kit was written for the desktop and stayed there: a filled card with a drop shadow where the mobile design is translucent and border-led, inputs at 13px which make iOS Safari zoom on focus and never zoom back, feedback on :hover which never fires on a touchscreen, and one media query in the whole stylesheet. It reads the new viewport field now and sets data-form-factor, data-surface and data-fill on the document, plus the insets as variables. Everything mobile hangs off data-form-factor="phone", so nothing changes on the desktop: the card loses its shadow and takes the mobile surface tokens, targets grow to 44px, inputs to 16px, and pressing something scales it instead of waiting for a hover that will not come. A filling surface anchors the body and scrolls an inner element, because its height report is discarded by the host. Plus the pieces a v4 screen is actually made of, so an author does not have to reverse-engineer them: eyebrow, count pill, section header, status dot, round icon button, field, segmented control. Each falls back to a global token where the mobile family is absent, so they work on both. * Document what a plugin needs on a phone The guide had nothing on the subject: no mention of the second token family, of who scrolls, of what sizes to expect, or that the kit brings almost nothing responsive. It also promised more than it delivered, claiming the palette was complete and that applying it matches the host "exactly" — fonts are named, not shipped, so that was never true. The new section covers the six surfaces and which of them fill versus report a height, what insets mean (space already held free, not padding to add), the mobile palette with the branch-on-absence pattern, and the four rules that decide whether it feels native. It also says plainly that the dev preview cannot show a phone width yet.
This commit is contained in:
@@ -551,13 +551,15 @@ declared), no popups.
|
||||
|
||||
### Matching the TREK look by hand (`m.tokens`)
|
||||
|
||||
`tokens` is the whole global palette resolved for the **current** theme — surfaces
|
||||
`tokens` is the global palette resolved for the **current** theme — surfaces
|
||||
(`--bg-card`, `--bg-hover`, …), text (`--text-primary`/`-secondary`/`-muted`/`-faint`),
|
||||
borders, the **accent family** (`--accent`, `--accent-text`, `--accent-hover`,
|
||||
`--accent-subtle`), semantic + soft fills (`--success`/`--danger`/`--warning`/`--info`
|
||||
`-soft`), shadows (`--shadow-*`), radii (`--radius-*`) and fonts (`--font-system`).
|
||||
Apply them as CSS variables and your UI matches the host exactly — in both themes and
|
||||
under a custom accent or high-contrast — instead of hard-coding a palette that drifts:
|
||||
Apply them as CSS variables and your UI follows the host through a theme toggle, a
|
||||
custom accent and high-contrast, instead of hard-coding a palette that drifts. (Fonts
|
||||
are named, not shipped: the files live in the host bundle, so declare your own or fall
|
||||
back to a system stack.)
|
||||
|
||||
```js
|
||||
function applyContext(m) {
|
||||
@@ -579,6 +581,82 @@ bakes those, since they only change with light/dark, not the accent.) Honour
|
||||
and auto-size to the height you report via `trek:resize`, so render flush and
|
||||
transparent — the design kit reports your height for you.
|
||||
|
||||
## On a phone
|
||||
|
||||
TREK 4 gives the phone its own design, and your plugin is mounted inside it. Two things
|
||||
follow from that, and both arrive in `trek:context` under `viewport`:
|
||||
|
||||
```js
|
||||
m.viewport = {
|
||||
surface: 'trip-tab', // where you are mounted, see the table below
|
||||
formFactor: 'phone', // 'phone' | 'desktop'
|
||||
fill: true, // true = fill the host container, false = report your height
|
||||
insets: { top: 82, bottom: 106 }, // px the host ALREADY keeps clear around you
|
||||
}
|
||||
```
|
||||
|
||||
### Know which surface you are on
|
||||
|
||||
| `surface` | Shape | Notes |
|
||||
|---|---|---|
|
||||
| `trip-tab` | fills | Your own tab in a trip. You scroll yourself. |
|
||||
| `plugin-page` | fills | `/plugins/:id`. You scroll yourself. |
|
||||
| `dashboard-widget` | reports height | A card on the dashboard. |
|
||||
| `user-settings` | reports height | Your `settings.html`. |
|
||||
| `detail-slot` | reports height | A narrow column inside a place/day/reservation panel. |
|
||||
| `action-frame` | fills | The modal a table action opens. |
|
||||
|
||||
This matters because the contract differs: on a **filling** surface your `trek:resize`
|
||||
height is deliberately ignored, so give your document `height: 100%` and put the
|
||||
scrolling on an inner element. On a **reporting** surface let the content decide the
|
||||
height and never set `100%`, or the host reserves a screenful for two lines of text.
|
||||
The design kit does both for you when it sees `viewport.fill`.
|
||||
|
||||
### `insets` is not padding you have to add
|
||||
|
||||
It is the space the host is *already* keeping clear. On the mobile trip tab, floating
|
||||
controls hover above your frame and a translucent dock hovers below it, and the host
|
||||
holds both areas free for you. Use the numbers to line your own sticky header up with
|
||||
the host's chrome, not to add margin — that would double the gap.
|
||||
|
||||
### The mobile palette
|
||||
|
||||
Inside the mobile shell, `tokens` carries a **second** family alongside the global one:
|
||||
`--m-ink`, `--m-muted`, `--m-faint`, `--m-bg`, `--m-card`, `--m-cbr`, `--m-glass`,
|
||||
`--m-gbr`, `--m-inner`, `--m-act`, `--m-actfg`, `--m-ic`, `--m-rowbr`, the status canon
|
||||
(`--m-st-confirmed`, `--m-st-pending`, `--m-st-info`, `--m-st-danger`, `--m-st-neutral`)
|
||||
and `--m-safe-top`. These are what the native mobile screens are built from; the global
|
||||
palette describes the desktop chrome and looks foreign next to them.
|
||||
|
||||
They are **absent on desktop**, so branch on their presence rather than assuming both
|
||||
families are there:
|
||||
|
||||
```css
|
||||
.card {
|
||||
background: var(--m-card, var(--bg-card));
|
||||
border: 1px solid var(--m-cbr, var(--border-primary));
|
||||
}
|
||||
```
|
||||
|
||||
### Four rules that decide whether it feels native
|
||||
|
||||
1. **Inputs at 16px or larger.** Below that, iOS Safari zooms the page on focus and does
|
||||
not zoom back. This is the most common mobile bug in embedded UI.
|
||||
2. **Touch feedback on `:active`, not `:hover`.** A hover rule never fires on a phone, so
|
||||
a tap gives no response at all.
|
||||
3. **Targets at least 44px.** Anything smaller is a coin toss with a thumb.
|
||||
4. **No drop shadows on the mobile surface.** The design is translucent and border-led
|
||||
over a gradient; a shadow reads as a sticker glued on top.
|
||||
|
||||
The design kit applies all four automatically once `data-form-factor="phone"` is set,
|
||||
which it does from `viewport`. If you style everything yourself, they are on you.
|
||||
|
||||
### Seeing it
|
||||
|
||||
`trek-plugin dev` previews at a desktop size. Until that grows a phone width, resize the
|
||||
browser window and use your browser's device emulation — the frame is a real browsing
|
||||
context, so media queries inside it measure the frame, and they work.
|
||||
|
||||
## Settings
|
||||
|
||||
Declare settings in the manifest; TREK renders the form (you write no settings
|
||||
|
||||
Reference in New Issue
Block a user