diff --git a/README.md b/README.md index b7f2e03..317f12d 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Dense reference material lives in [docs/](docs/): [architecture](docs/architectu | Desktop | Electrobun 1.18 (native webview, typed RPC bridge) | | Frontend | Angular 22 (standalone, signals, zoneless) in `ui/` | | Styling | Tailwind CSS v4, shadcn-style tokens (no component library) | -| Icons | @ng-icons/mynaui | +| Icons | @ng-icons/tdesign-icons | | SSH/SFTP | `ssh2` (pure-JS under Bun) | The repo is a Bun workspace: the Electrobun app at the root, the Angular app in diff --git a/bun.lock b/bun.lock index 98aa74f..15dd5b0 100644 --- a/bun.lock +++ b/bun.lock @@ -26,7 +26,7 @@ "@angular/core": "^22.0.0", "@angular/platform-browser": "^22.0.0", "@ng-icons/core": "^34.0.0", - "@ng-icons/mynaui": "^34.0.0", + "@ng-icons/tdesign-icons": "^34.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", }, @@ -307,7 +307,7 @@ "@ng-icons/core": ["@ng-icons/core@34.0.0", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular-devkit/schematics": ">=21.0.0", "@angular/common": ">=21.0.0", "@angular/core": ">=21.0.0", "@schematics/angular": ">=21.0.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "sha512-SrL8dBApSKzXhihEGmiJ/tAj+wSvt6XmZJOAzUTVcgkuV0YuL1WCHVfAwXgQHVG5Te27JkjyXd2n76pNFMuekw=="], - "@ng-icons/mynaui": ["@ng-icons/mynaui@34.0.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-Wstqby65RIOmlbBzrHfSEb9+HX87GbOHmIfSh3oEV8Wr6vulnOnQ11S8M3aYT5kuuIe9Bq00OzYwbHuqYBCNrw=="], + "@ng-icons/tdesign-icons": ["@ng-icons/tdesign-icons@34.0.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-FIRho+rAX3ludOeIMP+/Tr0Xp3zi3j/JXT5YooGeoMo8AF3qk0gvG4Cu1kI+8V5r3SxoOia9ktPxt0ADKt3LXg=="], "@npmcli/agent": ["@npmcli/agent@4.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-EUEuWAxnL07Sp5/iC/1X6Xj+XThUvnbei9zfRWZdEXa7lss9RTHMhAHBeg+MZ5To9s/gGaSI+UwZTPdYMvKSeg=="], diff --git a/docs/architecture.md b/docs/architecture.md index 96dfa43..a989392 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -265,6 +265,10 @@ component; tokens → `ui/src/styles.css`. walker check the flag themselves. - `file-icons.ts` — extension → category map driving glyphs, colors (fixed `--icon-*` tokens, never accent-tinted) and the Kind column. +- `icons.ts` — the one icon registry (TDesign, `@ng-icons/tdesign-icons`), passed to + `provideIcons` in `app.config.ts`. Icon names are plain strings in templates and + the build never checks them: an unregistered name renders nothing (console error + only), so every name used anywhere must be listed here. - `platform.ts` — preload-global readers (`PLATFORM`, `APP_MODE`, `EDITOR_CONTEXT`, `IS_MAC`/`IS_MAC_CHROME`, `IS_WINDOWS`, `IS_LINUX`, `MOD_LABEL`/`ALT_LABEL`) + `blockNativeContextMenu` (kills WebKit's diff --git a/ui/package.json b/ui/package.json index a031235..59b60ee 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,7 +14,7 @@ "@angular/core": "^22.0.0", "@angular/platform-browser": "^22.0.0", "@ng-icons/core": "^34.0.0", - "@ng-icons/mynaui": "^34.0.0", + "@ng-icons/tdesign-icons": "^34.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0" }, diff --git a/ui/src/app/core/file-icons.ts b/ui/src/app/core/file-icons.ts index 996cfb1..3895124 100644 --- a/ui/src/app/core/file-icons.ts +++ b/ui/src/app/core/file-icons.ts @@ -13,27 +13,27 @@ const LINK = 'shrink-0 text-icon-link'; const CATEGORIES: Record = { image: { - glyph: 'mynaImage', + glyph: 'tdesignImage', class: 'shrink-0 text-icon-image', extensions: 'png jpg jpeg gif webp avif svg ico icns bmp tiff tif heic heif raw'.split(' '), }, audio: { - glyph: 'mynaMusic', + glyph: 'tdesignMusic', class: 'shrink-0 text-icon-media', extensions: 'mp3 wav flac aac ogg oga m4a opus wma aiff aif mid midi'.split(' '), }, video: { - glyph: 'mynaVideo', + glyph: 'tdesignVideo', class: 'shrink-0 text-icon-media', extensions: 'mp4 mkv mov avi webm m4v mpg mpeg wmv flv 3gp'.split(' '), }, archive: { - glyph: 'mynaArchive', + glyph: 'tdesignFileZip', class: 'shrink-0 text-icon-archive', extensions: 'zip tar gz tgz bz2 xz zst 7z rar dmg iso jar deb rpm pkg apk'.split(' '), }, code: { - glyph: 'mynaCode', + glyph: 'tdesignCode', class: 'shrink-0 text-icon-code', // ".ts" is TypeScript here, not an MPEG transport stream (deliberate) extensions: ( @@ -45,7 +45,7 @@ const CATEGORIES: Record
- +

{{ i18n.t('app.notConnectedTitle') }}

{{ i18n.t('app.notConnectedBody') }} @@ -28,7 +28,7 @@ (mousedown)="focusManager()" >

- +

{{ i18n.t('app.managerOpen') }}

@@ -36,14 +36,14 @@ [title]="i18n.t('connMgr.newConnectionHint')" class="flex items-center gap-1 rounded-md px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground" > - {{ i18n.t('connMgr.newConnection') }} + {{ i18n.t('connMgr.newConnection') }}
@@ -67,7 +67,7 @@ [title]="group.stack.collapsed ? i18n.t('connMgr.expand') : i18n.t('connMgr.collapse')" > @@ -88,14 +88,14 @@ [title]="i18n.t('connMgr.renameStack')" class="grid size-4 place-items-center rounded text-muted-foreground hover:text-foreground" > - + @if (group.connections.length) { }
@@ -119,7 +119,7 @@ [class.bg-accent]="draft()?.id === connection.id" [class.opacity-50]="draggedId() === connection.id" > - + {{ connection.name }} } @empty { @@ -155,7 +155,7 @@ [class.bg-accent]="draft()?.id === connection.id" [class.opacity-50]="draggedId() === connection.id" > - + {{ connection.name }} } @@ -332,7 +332,7 @@ (click)="deleteCurrent()" class="flex items-center gap-1.5 rounded-md px-2 py-1.5 text-xs text-muted-foreground hover:bg-accent hover:text-destructive" > - {{ i18n.t('common.delete') }} + {{ i18n.t('common.delete') }} @@ -362,7 +362,7 @@ } @else {
- +

{{ i18n.t('connMgr.selectPrompt') }}

diff --git a/ui/src/app/skins/shadlike/context-menu.ts b/ui/src/app/skins/shadlike/context-menu.ts index 4ff40d9..d53b0e6 100644 --- a/ui/src/app/skins/shadlike/context-menu.ts +++ b/ui/src/app/skins/shadlike/context-menu.ts @@ -62,7 +62,7 @@ const EDGE_GAP = 6; // px on purpose: a viewport-edge margin, not a UI size > @if (item.checked) { - + } {{ item.label }} diff --git a/ui/src/app/skins/shadlike/dialogs/overwrite-dialog.ts b/ui/src/app/skins/shadlike/dialogs/overwrite-dialog.ts index 6d43270..df797bc 100644 --- a/ui/src/app/skins/shadlike/dialogs/overwrite-dialog.ts +++ b/ui/src/app/skins/shadlike/dialogs/overwrite-dialog.ts @@ -60,7 +60,7 @@ import { FocusService } from '@core/focus.service';
diff --git a/ui/src/app/skins/shadlike/editor-window/editor-window.html b/ui/src/app/skins/shadlike/editor-window/editor-window.html index 191e436..63e3919 100644 --- a/ui/src/app/skins/shadlike/editor-window/editor-window.html +++ b/ui/src/app/skins/shadlike/editor-window/editor-window.html @@ -2,7 +2,7 @@ @if (!ctx) {
- +

{{ i18n.t('editor.noFileTitle') }}

{{ i18n.t('editor.noFileBody') }} @@ -20,7 +20,7 @@ [class.h-9]="!isMacChrome" [class.pl-3]="!isMacChrome" > - +

{{ ctx.name }}{{ dirty() ? ' •' : '' }}

@@ -41,13 +41,13 @@ [title]="i18n.t('editor.findHint', { mod: modLabel })" class="grid size-6 place-items-center rounded-md text-muted-foreground electrobun-webkit-app-region-no-drag hover:bg-accent hover:text-foreground" > - + @if (findOpen()) {
- + - +
} @@ -93,19 +93,19 @@
- + {{ i18n.t('editor.disconnected', { name: ctx.sessionTitle }) }}
} @if (loading()) {
- +
} @else if (loadError(); as error) {
- +

{{ i18n.t('editor.cantOpen', { name: ctx.name }) }}

{{ error }}

diff --git a/ui/src/app/skins/shadlike/file-panel/file-panel.html b/ui/src/app/skins/shadlike/file-panel/file-panel.html index 2a2a28a..ae2da88 100644 --- a/ui/src/app/skins/shadlike/file-panel/file-panel.html +++ b/ui/src/app/skins/shadlike/file-panel/file-panel.html @@ -6,17 +6,17 @@ [title]="i18n.t('panel.choosePanel')" > @if (panel().connecting()) { - + } @else { } {{ isRemote() ? panel().title() : i18n.t('common.local') }} @@ -38,7 +38,7 @@ [title]="i18n.t('panel.editFile')" class="flex h-(--action-h) shrink-0 items-center rounded-md px-1 text-muted-foreground hover:bg-accent hover:text-foreground" > - + @if (chmodAvailable()) { } @@ -90,10 +90,10 @@ (click)="pickLocal()" class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-(length:--path-font) hover:bg-accent" > - + {{ i18n.t('common.local') }} @if (!isRemote()) { - + } @@ -103,7 +103,7 @@ (click)="pickDrive(drive)" class="flex w-full items-center gap-2 py-1.5 pr-3 pl-6 text-left text-(length:--path-font) hover:bg-accent" > - + {{ drive }} } @@ -116,7 +116,7 @@ (click)="pickConnection(connection)" class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-(length:--path-font) hover:bg-accent" > - + {{ connection.name }} } @@ -129,7 +129,7 @@ (click)="pickConnection(connection)" class="flex w-full items-center gap-2 py-1.5 pr-3 pl-5 text-left text-(length:--path-font) hover:bg-accent" > - + {{ connection.name }} } @@ -147,7 +147,7 @@ [title]="sshHostTitle(host)" class="flex w-full items-center gap-2 py-1.5 pr-3 pl-5 text-left text-(length:--path-font) hover:bg-accent disabled:opacity-60 disabled:hover:bg-transparent" > - + {{ host.name }} } @@ -165,7 +165,7 @@ [title]="i18n.t('panel.parentDir')" class="grid size-(--path-ctl-h) shrink-0 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:hover:bg-transparent" > - + @if (panel().loading()) { - + } @else { - + }
@@ -215,7 +215,7 @@ @if (panel().filter(); as query) {
- + {{ query }} {{ i18n.t('panel.matches', { count: filterMatches() }) }} @@ -225,7 +225,7 @@ [title]="i18n.t('panel.clearFilter')" class="grid size-5 shrink-0 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground" > - +
} @@ -243,7 +243,7 @@ @if (panel().connecting()) {
- + {{ i18n.t('panel.connectingTo', { name: panel().connectingTo() ?? '' }) }} @@ -321,7 +321,7 @@
@if (panel().slowLoad() && !panel().connecting()) {
- +
}
diff --git a/ui/src/app/skins/shadlike/file-panel/file-panel.ts b/ui/src/app/skins/shadlike/file-panel/file-panel.ts index 0fbecb0..bc3b555 100644 --- a/ui/src/app/skins/shadlike/file-panel/file-panel.ts +++ b/ui/src/app/skins/shadlike/file-panel/file-panel.ts @@ -59,7 +59,7 @@ export class FilePanel { /** Input is ignored while the panel is connecting or a listing is in flight. */ readonly blocked = computed(() => this.panel().busy()); /** The copy button points toward the other panel. */ - readonly copyIcon = computed(() => (this.side() === 'left' ? 'mynaArrowRight' : 'mynaArrowLeft')); + readonly copyIcon = computed(() => (this.side() === 'left' ? 'tdesignArrowRight' : 'tdesignArrowLeft')); readonly pathDraft = signal(''); readonly menuOpen = signal(false); diff --git a/ui/src/app/skins/shadlike/status-bar/status-bar.ts b/ui/src/app/skins/shadlike/status-bar/status-bar.ts index cd6d298..bb105c3 100644 --- a/ui/src/app/skins/shadlike/status-bar/status-bar.ts +++ b/ui/src/app/skins/shadlike/status-bar/status-bar.ts @@ -21,7 +21,7 @@ import { TransfersService } from '@core/transfers.service'; [title]="i18n.t('transfer.showDetails')" > @if (transfers.currentJob(); as job) { - + {{ i18n.t('transfer.copying', { name: job.name, percent: percent(job), speed: speedSuffix(job) }) }} @if (transfers.queuedCount(); as queued) { @@ -29,12 +29,12 @@ import { TransfersService } from '@core/transfers.service'; } } @else if (transfers.failedJobs().length; as failed) { - + {{ i18n.t('transfer.failed', { count: failed }) }} } @else if (transfers.hasJobs()) { - + {{ i18n.t('transfer.finished') }} } @else { {{ i18n.t('transfer.ready') }} @@ -44,7 +44,7 @@ import { TransfersService } from '@core/transfers.service';
diff --git a/ui/src/app/skins/shadlike/tab-bar/tab-bar.ts b/ui/src/app/skins/shadlike/tab-bar/tab-bar.ts index 106d8d3..ee65277 100644 --- a/ui/src/app/skins/shadlike/tab-bar/tab-bar.ts +++ b/ui/src/app/skins/shadlike/tab-bar/tab-bar.ts @@ -77,7 +77,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const; [title]="panels.workspaceName(ws)" > - + } @else { @@ -108,7 +108,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const; [title]="i18n.t('tabBar.newTab', { mod: modLabel })" class="ml-0.5 grid size-6 place-items-center rounded-md text-muted-foreground electrobun-webkit-app-region-no-drag hover:bg-accent hover:text-foreground" > - +
@@ -131,13 +131,13 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const; @switch (updater.state()) { @case ('available') { - {{ i18n.t('tabBar.update') }} + {{ i18n.t('tabBar.update') }} } @case ('downloading') { - {{ i18n.t('tabBar.updating') }} {{ updater.progress() }}% + {{ i18n.t('tabBar.updating') }} {{ updater.progress() }}% } @case ('ready') { - {{ i18n.t('tabBar.restartToUpdate') }} + {{ i18n.t('tabBar.restartToUpdate') }} } } @@ -150,7 +150,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const; [title]="i18n.t('tabBar.manageConnections')" class="grid h-6 px-2 py-1 place-items-center rounded-md text-[0.6875rem] text-muted-foreground electrobun-webkit-app-region-no-drag hover:bg-accent hover:text-foreground" > - + {{ i18n.t('tabBar.connections') }} @@ -160,7 +160,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const; [title]="i18n.t('tabBar.options')" class="grid size-6 place-items-center rounded-md text-muted-foreground electrobun-webkit-app-region-no-drag hover:bg-accent hover:text-foreground" > - + @if (settingsOpen()) { @@ -368,7 +368,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const; [title]="i18n.t('options.resetDefault')" class="grid size-5 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground" > - + }
diff --git a/ui/src/app/skins/shadlike/toasts/toasts.ts b/ui/src/app/skins/shadlike/toasts/toasts.ts index a09a13d..6bfbab6 100644 --- a/ui/src/app/skins/shadlike/toasts/toasts.ts +++ b/ui/src/app/skins/shadlike/toasts/toasts.ts @@ -24,7 +24,7 @@ import { ToastService } from '@core/toast.service'; (click)="toast.dismiss(t.id)" class="shrink-0 text-muted-foreground hover:text-foreground" > - +
- {{ i18n.t('transfer.clearFinished') }} + {{ i18n.t('transfer.clearFinished') }}
@@ -40,7 +40,7 @@ [title]="i18n.t('transfer.cancel')" class="shrink-0 rounded p-1 text-muted-foreground hover:bg-accent hover:text-destructive" > - + } @else { }
diff --git a/ui/src/app/skins/shadlike/transfer-bar/transfer-bar.ts b/ui/src/app/skins/shadlike/transfer-bar/transfer-bar.ts index a23ed12..dc752fc 100644 --- a/ui/src/app/skins/shadlike/transfer-bar/transfer-bar.ts +++ b/ui/src/app/skins/shadlike/transfer-bar/transfer-bar.ts @@ -33,12 +33,12 @@ export class TransferBar { stateIcon(job: TransferSnapshot): string { switch (job.state) { case 'completed': - return 'mynaCheckCircle'; + return 'tdesignCheckCircle'; case 'failed': case 'cancelled': - return 'mynaXCircle'; + return 'tdesignCloseCircle'; default: - return 'mynaSpinner'; + return 'tdesignLoading'; } }