Commit Graph
30 Commits
Author SHA1 Message Date
jgamboaandClaude 01739e4cf4 Fix Stage-1 layout regressions; ListView fills the pane
Three layouts collapsed in fe028a9, where the isMacChrome branches were
removed by a scripted edit that was wrong in two ways. The *bindings* were
dead by construction; the layout classes inside them were not, and nothing
replaced them.

- tab-bar: the edit appended a second `class` attribute to an element that
  already had one. A duplicate attribute is silently dropped, so the
  workspace strip lost h-9/pt-1/pl-1.5 entirely and collapsed under the
  title bar. Merged into one attribute, with a comment saying why there is
  exactly one. A template sweep found no other element carrying two.
- connection-manager + editor-window <header>: the edit deleted all five
  [class.h-*]/[class.pl-*] bindings and put nothing back, leaving both
  headers with no height and no left padding. Restored h-9 pl-3 (the
  non-mac arm) and dropped the now-false "on macOS this row IS the
  titlebar" comments — every window is frameless now.

Separately, the ListView never filled its panel: 7.css sets table-layout:
fixed but declares no width, so the table shrank to content and left a dead
grey gutter down the right of each pane. w-full is safe as a utility
precisely because 7.css declares no width for `skin` to outrank it with;
the unsized first <col> then absorbs the slack, which is what makes Name
elastic.

Verified on a live window capture, not from a build log: the tab strip has
its height back and both tables reach the pane edge. The connection-manager
window needs a click to reach and is unverified visually — its fix is a
verbatim copy of the editor-window one.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-16 03:46:36 +02:00
jgamboaandClaude fe028a9b01 Stage 1: make this branch Windows 7 only
The dual-skin arrangement existed to let one build toggle between the modern
shadcn look and 7.css. Keeping both correct is what forced the cascade tricks
that fight 7.css, so the branch drops the toggle: this build IS the Windows 7
build.

- `skin` is gone from AppSettings/DEFAULT_SETTINGS, the settings store, the
  SettingsService (signal, applySkin, persist payload), the options popover
  control, and the i18n keys.
- buildPreload adds `.win7` unconditionally; `chromeOptions()` no longer takes a
  skin and always returns frameless `titleBarStyle: "hidden"`.
- `IS_WIN7_CHROME` and `IS_MAC_CHROME` are deleted along with every
  `isMacChrome` branch in the tab bar, editor window and connection manager.
  Those reserved `pl-24` for macOS traffic lights, which frameless chrome
  removes on every platform, so the branches were dead by construction.
- The title bar is no longer conditional — it is the window's only chrome.
- index.html keeps just the win7 anti-flash arm (four theme states).

Not done here, deliberately: stripping Tailwind's element styling. The
neutralizers in styles.css (notably `.win7 button { min-width: 0 }`) are still
load-bearing until each component's markup is converted to 7.css's real
contract, so they come out per component rather than in one sweep.

Verified: backend `tsc --noEmit` clean, `bun run build:ui` clean; bundle
490.50 kB, down from 492.52 kB.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-16 01:45:40 +02:00
jgamboaandClaude 07825c1bd1 Add a toggleable Windows 7 (7.css) skin behind a new skin setting
Evaluation branch: a full Aero skin, including frameless windows with our own
title bar, switchable against the existing modern look.

The app already had a four-axis runtime skinning mechanism and zero component
stylesheets, so the skin is one new setting plus one stylesheet section rather
than a parallel UI. The key move is cascade order: 7.css is imported into a
`skin` layer ABOVE Tailwind's `utilities`, so its bare element rules outrank
the ~1900 inline utility classes already in the templates. Template changes are
limited to additive, skin-inert hooks (ARIA roles, `has-scrollbar`,
`w7-toolbar`, `w7-btn`).

- styles.css: explicit layer order, `7.css/dist/7.scoped.css` via `layer(skin)`,
  a token bridge re-pointing the existing semantic tokens at Win7 values (no new
  tokens, so `@theme inline` is untouched), a hand-authored dark Win7 palette,
  and neutralizers that `revert-layer` 7.css's dialog-button metrics back to the
  utility layer. Neutralizers must live inside `skin`, not `skinfix` —
  `revert-layer` only reaches `utilities` from one layer up.
- Frameless chrome: `chromeOptions(skin)` is now the single place either skin's
  frame is decided. `titleBarStyle: "hidden"` on every platform, which is also
  the only way to drop the macOS traffic lights. New `title-bar` component
  mounted by all three window roots.
- Window controls over RPC (minimize/toggle-maximize/close/is-maximized), served
  per window kind so the X reuses each one's existing close path — editors still
  get their dirty prompt. electrobun has no maximize event, so the state is
  derived from `resize`; double-click-to-maximize is implemented here too.
- Font: Noto Sans vendored (OFL-1.1) under ui/src/fonts, since Segoe UI is
  absent off Windows and not redistributable.

Verified: backend `tsc --noEmit` clean, `bun run build:ui` clean (486 kB initial,
under the 500 kB budget), app launches with the skin active and no console
errors. The rendered result has not been eyeballed — screen capture and
accessibility are both denied to the shell on this machine.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-14 15:02:27 +02:00
jgamboaandClaude e4ba846719 Retone dark theme to warm gray #1a1a19 with layered surfaces
The dark palette was shadcn's cool zinc (#202023, hue ~286). Anchor it on
#1a1a19 instead — cds gray-830, a warm near-neutral (hue 107) — and retone
the whole dark neutral family to match, since a warm background under cool
panels clashes. Lightness ramp is preserved; chromatic tokens (destructive,
success, icon hues, accent formulas) and the light palette are untouched.

Also introduce --chrome so the app isn't one flat tone: frame strips (tab
bar, status bar, transfer bar, editor/manager header+footer, connection
sidebar) now sit one step below the content panes, with popovers and hover
above them — the standard dark-UI elevation order.

Dark ramp: #151514 chrome, #1a1a19 content, #20201f card, #2e2e2d hover;
the "darker" tone drops chrome to true black. Light gains only a zinc-50
chrome step.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-14 13:20:47 +02:00
jgamboaandClaude a40433b99e Add built-in auto-updater with tab-bar update pill
Wires electrobun's Updater to the /dl download host. The packaged app checks
https://miniscp.com/dl on launch + every 6h; when a newer build exists, an
accent-colored "update tool" appears next to Connections in the tab bar. It
announces the update, becomes its own inline progress bar while downloading,
then flips to "Restart to apply" (two-step: download, then user-triggered
relaunch).

- electrobun.config.ts: release.baseUrl = https://miniscp.com/dl (baked into
  version.json at build; miniscp.com fronted by an external proxy for TLS).
- rpc.ts: checkForUpdate/downloadUpdate/applyUpdate requests + updateStatus push.
- rpc-handlers.ts + index.ts: call Updater; poll on launch+6h; stream
  onStatusChange progress. checkForUpdate self-guards the dev channel.
- rpc.service.ts + new updater.service.ts: signal-based state
  (available -> downloading -> ready, ready derived from downloadUpdate ok).
- tab-bar.ts: single bg-primary pill; progress fills the pill itself.
- icons.ts: register mynaDownload. i18n: tabBar + menu keys across all locales.
- menu.ts + app.ts: "Check for Updates…" app-menu item -> UpdaterService.check().
- docs: build-and-release + architecture updated.

Unsigned builds still update (applyUpdate strips the macOS quarantine xattr).
Verified: tsc --noEmit (exit 0) + build:ui AOT (exit 0). Live pill + full
download/apply flow require a two-build test on the host.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-14 16:43:40 +02:00
jgamboaandClaude Fable 5 a0f56822cd Internationalization: 7 languages with live switching
Custom signal-based runtime (no i18n dependency): shared src/shared/i18n
dictionaries, ui I18nService.t() reactive by construction so language
switches live, and a backend i18n.ts for native menus + thrown errors.
Every user-facing string keyed across templates, toasts, dialogs, file
kinds, columns, macOS menu/context menus, and errors. Language picker in
Options (auto-detects OS locale, falls back to English); switching
relabels the webview and native chrome instantly. English/Spanish/French/
German fully drafted; Chinese/Japanese/Basque drafted, flagged for native
review. Docs updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:52:54 +02:00
jgamboaandClaude Fable 5 ee5a9e13e6 Auto-refresh the active tab's panels (silent, non-disturbing)
Local panels are fs.watched (LocalDirWatcher + setWatchedDirs -> pathRefresh);
remote panels poll every 3s. New refresh({silent}) skips the loading/busy
flags and touches no DOM, snapshotting sessionId+cwd to discard results if the
user navigated mid-flight. Only the active tab is live; switching tabs
refreshes the new pair. A future on/off setting is left as commented
breadcrumbs. Docs updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 14:03:35 +02:00
jgamboa 2d95857de1 Button ui tweaks 2026-07-14 09:43:06 +02:00
JokinandClaude Fable 5 c7271fb7cf Windows compatibility pass (beta target)
External editor via cmd/start + exe picker; Permissions hidden for
Windows-local (chmod only flips read-only there); Explorer/Recycle Bin
wording; Ctrl vs Cmd shortcut labels; separator-aware path joins +
drive-root detection; drives list in the panel source picker; icon.ico
+ colored tray icon; icacls ACL on connections.json; README Windows
(beta) section with upstream known issues and a smoke-test checklist.
Runtime paths pending first boot on a real Windows machine.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 00:02:42 +02:00
JokinandClaude Fable 5 d80d5c23dc Sublime-style Build-n versioning + About box
Build n = commit count, baked at build time into a gitignored
version.gen.ts (postinstall + all build scripts regenerate it). About
lives in the macOS app menu and as a footer row in the options popover
(the cross-platform path), showing build, commit, date and engines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 23:55:39 +02:00
JokinandClaude Fable 5 7dd59a9752 Connection manager in its own native window, modal to main
Single window centered over the main app. Electrobun has no native
modality, so it's approximated: bun bounces the main window's focus back
to the manager, the main webview shows a click-swallowing overlay, and
main-targeted menu/keyboard actions are dropped while open. Editor
windows stay fully usable. Connect/open-stack execute in the main
window via the existing connect: action channel; store edits push a
connectionsChanged refresh. Trigger moved from the panel dropdown to a
tab-bar button.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 23:11:58 +02:00
Jokin 27d0ac81d6 file icons setting text 2026-07-13 23:04:16 +02:00
JokinandClaude Fable 5 70f3f2a2e6 Smaller accent swatches
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 21:54:56 +02:00
jgamboaandClaude Fable 5 bdae49ba24 Dark tone setting: grey Dark (default) vs near-black Darker
Tone row appears under Theme when the effective theme is dark.
Grey palette uses macOS-like #26262a background.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 15:43:01 +02:00
jgamboa eb86ca514d New tab icon sizing change 2026-07-13 14:28:53 +02:00
jgamboaandClaude Fable 5 628ccebd9a Rename Text size to Interface; scale panel header with it
Action buttons, server picker, and its dropdown now follow the size
setting via new --action-h/--action-font/--action-icon variables.
Default tier matches the old fixed sizes; tab bar stays fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 14:26:25 +02:00
jgamboa fdf65766b5 Change to mynaDots icon, size change 2026-07-13 13:49:32 +02:00
JokinandClaude Fable 5 320080de6d Blue as default accent; slightly smaller swatches
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 01:40:49 +02:00
JokinandClaude Fable 5 44f077380f File-type icon colors with Plain/Multi setting (multi default)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 01:31:10 +02:00
JokinandClaude Fable 5 2f4bc63ac8 Accent tone setting with macOS-style swatches (indigo default)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 01:26:35 +02:00
JokinandClaude Fable 5 e4f7ca86f7 Edit file: built-in editor + external editor with watch & auto-upload
- Built-in editor (default): large modal with monospace textarea, Cmd+S save,
  dirty guard; reads/writes through the provider streams so it works on local
  and remote files identically (2MB cap with a friendly error)
- External editor: remote files download to appDataDir/edits/<id>, open via
  macOS `open -a`, the temp DIR is watched (survives atomic rename-saves) and
  every save enqueues a normal upload job (progress/errors in the transfer
  list); watchers + temp dirs are cleaned when the session disconnects
- Editor setting: Built-in | Custom with a NATIVE app picker (electrobun
  openFileDialog, /Applications, .app filter) and reset-to-default
- Leftover temp files from a crash prompt for cleanup at boot
- F4, toolbar button (mynaFileText), and File > Edit File (Cmd+E) menu entry
- README: feature notes + Portability notes (open/start/xdg-open seam
  documented in code and README per user request)

Verified headless against the box: sftp read/write roundtrip incl. UTF-8,
size cap, watch->save->auto-upload->remote-updated, session cleanup, orphan
listing and clearing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:28:54 +02:00
JokinandClaude Fable 5 eaa2d00115 Finished-transfers setting + transfer-list header with Clear finished
- Options popover: 'Finished transfers' Auto-clear | Keep (default auto-clear,
  the previous behavior); persisted like the rest
- Transfer list header: 'N active · M finished' + Clear finished button
  (dismisses completed/failed/cancelled only, never running/queued)
- Failed rows now name the file that failed alongside the error message

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 19:56:24 +02:00
JokinandClaude Fable 5 45df0e450f Options button icon: mynaCog -> mynaConfigVertical
Manage connections keeps the cog; the global options gear gets the vertical
sliders icon.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 19:38:31 +02:00
JokinandClaude Fable 5 83202ff414 More breathing room between macOS traffic lights and the tabs (pl-20 -> pl-24)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 19:13:39 +02:00
JokinandClaude Fable 5 169d3ea4d8 Tab strip scrolls horizontally on overflow
Tabs live in their own min-w-0 overflow-x-auto container (scrollbar hidden,
trackpad scrolls); the new-tab button and the options gear sit outside it and
stay pinned. The active tab scrolls into view when it changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 19:13:18 +02:00
JokinandClaude Fable 5 3e33bac426 Drag & drop tab reordering
Tabs are draggable within the strip: HTML5 DnD with the WebKit setData quirk
handled, an inset primary insertion line at the drop position (no layout
shift), and the dragged tab dimmed. Reordering only touches the workspaces
array order; ids, sessions, and the active tab are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 17:33:52 +02:00
JokinandClaude Fable 5 c95087c079 Serial/parallel transfers setting
Transfers: Single | Multi in the options popover, with an 'At once' picker
(2/3/4/6/8) when Multi. Engine concurrency becomes an instance field applied
live: at boot from settings.json and on every saveSettings (raising the limit
starts queued jobs immediately). Verified headless: 3 slow jobs overlap at
concurrency 3, stay strictly serial at 1, clamp works.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 17:32:21 +02:00
JokinandClaude Fable 5 ff62c07f15 Text size setting for path bar + file list (Compact/Default/Large)
Segmented row in the options popover; applied via data-text on <html> driving
CSS variables (--list-font / --list-meta-font / --path-font), persisted in
settings.json like theme and speed unit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 17:30:12 +02:00
JokinandClaude Fable 5 6048d5c814 v1.2: overwrite confirm, transfer speed/ETA, settings + themes, fused macOS titlebar
- Overwrite confirmation: name-collision detection before enqueue; dialog shows
  source vs destination (size, mtime, 'newer' badge) with per-item Skip/Replace
  and batch Skip all / Replace all; type mismatches auto-skip with a toast;
  cancel aborts the whole operation
- Transfer speed + ETA: UI computes smoothed bytes/sec from progress deltas
  (callback bus makes deltas meaningful); shown in the expanded queue rows and
  the status-bar summary; unit follows the speed-unit setting
- Settings: bun-side SettingsStore (settings.json, 0600, atomic) + get/save RPC;
  SettingsService; gear popover on the tab row (theme segmented control, speed
  unit); persisted across restarts
- Light theme: data-theme on <html> drives token overrides; absent = follow OS
- macOS fused titlebar: hiddenInset + trafficLightOffset, tab row becomes the
  draggable titlebar (app-region drag/no-drag classes); other platforms keep a
  separate titlebar (gated by a platform value injected via window preload)
- README: known-issues note for the upstream Bun/Electrobun FFI crash

Verified: tsc + ui build clean; SettingsStore roundtrip + 0600 headless;
app boots and the UI fetches settings over RPC at startup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 17:14:50 +02:00
JokinandClaude Fable 5 9eae6c58dc v1.1: fix transfer freeze, session tabs, per-panel toolbars, status bar
Freeze root cause: TransfersService consumed transferUpdate through an effect
that both read and wrote the jobMap signal — the first progress message spun
the effect into an infinite re-run loop, pegging the webview thread while the
copy completed fine bun-side. Push messages now flow through plain callback
registries on RpcService (also stops signal coalescing from dropping progress
snapshots). Verified live: a 60MB boot-time self-test copy streamed progress
into the running UI and the post-completion panel refreshes arrived.

- Tabs: workspaces (left+right PanelState pair each) in PanelsService; tab bar
  replaces the header; sessions persist in background tabs; Cmd+T/Cmd+W/Ctrl+Tab;
  closing a tab disconnects its sessions; last tab can't close
- Per-panel toolbar (top, icon-only): direction-explicit copy (-> / <-),
  rename, new folder/file, chmod, delete; panel footers removed
- VSCode-style status bar: transfer summary (spinner/percent/queued/failures,
  click to expand the job list) + active panel info; function bar removed
- transfer details list is collapsible, auto-expands on failure

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 14:50:19 +02:00