The reunion is complete: one build contains both UIs and picks between them at
bootstrap.
- src/shared/types.ts regains `skin: "modern" | "win7"` on AppSettings.
- SettingsService regains the skin signal, setSkin() and applySkin(), which
toggles the `.win7` class on <html>.
- buildPreload emits __APP_SKIN and adds `.win7` conditionally again, instead
of unconditionally as it had since fe028a9.
- chromeOptions() regains its parameter: win7 gets frameless + transparent,
modern gets the macOS hiddenInset fusion or the plain native frame.
- core/platform.ts regains APP_SKIN / IS_WIN7_CHROME (added in stage 4).
- main.ts now selects on both axes — skin picks the tree, APP_MODE picks the
root within it.
- Both tab-bars get a skin row, with the reopen caveat as its tooltip.
DEFAULT_SETTINGS.skin is "modern", matching the original design and `main`.
Worth flagging: this branch has booted win7 unconditionally since fe028a9, so
after this commit it starts in the modern UI unless the setting says otherwise.
One word in types.ts flips that if the win7 look should be the default.
i18n: en.ts is the source of truth and everything else falls back to it, so
only en was strictly required — but es/eu/fr/de/zh/ja got real translations
too, each matching the terminology that locale already uses for the Theme row.
Verified both skins on live single-instance captures. Modern boots and renders
fully styled, which also proves Tailwind scans skins/shadlike/** — a purge
would have produced an unstyled page rather than this one. Win7, selected by
setting skin in the persisted settings, is still pixel-identical to the
pre-refactor baseline across all five stages. The persisted settings file was
backed up and restored, so it still carries no skin key and resolves to the
default through the backend's merge.
Not verified: clicking the new skin row itself, which needs an interaction pass
— no window automation is available here. Its bindings compile and the built
bundle contains options.skin, setSkin and the translated labels.
Co-Authored-By: Claude <noreply@anthropic.com>
The 919-line stylesheet had a clean seam: `main`'s version is 278 lines and
this branch only ever APPENDED to it. Verified that directly — a diff of
main's styles.css against our first 298 lines differs only by the @layer
statement and the 7.css import.
- ui/src/styles.css (296) keeps the shared half: the @layer statement, the
Tailwind import, the OKLCH tokens, @theme inline, the data-text interface
sizes, the animations and the accent axis. The @layer statement must stay
first here — it is one of only two rule types allowed above @import, and it
is what sorts `skin` above `utilities`.
- app/skins/7like/7like.css (636) takes the whole win7 section plus the
scoped-7.css import that feeds layer(skin).
- app/skins/shadlike/shadlike.css is near-empty by nature, not by omission:
that skin IS the shared token system plus inline Tailwind, so there is no
framework to bridge and no cascade to invert. The file documents why, and
what does/does not belong in it.
Both are @imported from styles.css, so one bundle still ships both, scoped by
`.win7` exactly as before.
One real trap caught here: the @font-face url() is resolved relative to the
stylesheet, so moving the win7 section three directories deeper would have
silently 404'd Noto Sans — the build stays green and the app just falls back
to a different font. Fixed by moving the fonts INTO the skin (they exist only
for the Win7 look, where Noto Sans substitutes for Segoe UI), which keeps
`./fonts/...` correct wherever the folder goes. Confirmed in the built output:
both woff2 emitted as hashed assets with the url rewritten to ./media/.
Verified: build clean, built CSS keeps `@layer theme,base,components,
utilities,skin,skinfix` and all 7.css selectors, the live window's opaque
interior is pixel-identical to the pre-refactor baseline, and both harness
renders (light and dark) diff to exactly zero. A layer-assignment mistake here
would not be subtle — 7.css would lose to ~1900 Tailwind utilities and the app
would look nothing like this.
Co-Authored-By: Claude <noreply@anthropic.com>
All 14 components (including title-bar/, which has no modern counterpart)
move under app/skins/7like/. git records every one as a rename — no content
changed except main.ts.
The @core alias from stage 1 paid off exactly as intended: not one of the 67
service imports needed touching despite every file changing depth. The only
relative imports left inside the tree are skin-internal (app -> its dialogs,
connection-manager -> title-bar), and those survived because the move
preserved their relative structure.
Added skins/7like/index.ts exporting SEVEN_ROOTS { main, manager, editor }.
Every skin will export that same shape, so main.ts can pick a tree by skin
and then a root by APP_MODE without knowing either skin's internals. main.ts
selects from that barrel now, with the second axis still hardcoded until the
shadlike tree lands.
Verified: tsc clean, build:ui clean, opaque interior pixel-identical to the
pre-refactor baseline. That last check also proves Tailwind still scans the
templates from their new skins/** paths — a silent utility purge would have
collapsed the layout rather than reproducing it exactly.
The three structural 7.css contracts that a careless move breaks silently are
intact by construction, since no markup changed: app-title-bar is still a
direct child of .window.w7-frame, nothing new nests inside menu[role=tablist],
and the context menu still emits ul[role=menu] > li[role=menuitem] > button.
Co-Authored-By: Claude <noreply@anthropic.com>