Switch the UI icons from mynaui to TDesign

Swap @ng-icons/mynaui for @ng-icons/tdesign-icons (34.0.0, the release
matching @ng-icons/core), drawn at TDesign's native stroke. Each former
mynaui name maps to one TDesign name everywhere it was used; the unused
ArrowLeftRight is dropped. The options button's ellipsis goes from 1.5rem
to 0.8rem: TDesign's dots span 18 of 24 units against mynaui's 8, so this
keeps today's footprint.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-23 17:00:43 +02:00
co-authored by Claude
parent a83264c77d
commit 99bfd3abc2
18 changed files with 163 additions and 160 deletions
+1 -1
View File
@@ -56,7 +56,7 @@ Dense reference material lives in [docs/](docs/): [architecture](docs/architectu
| Desktop | Electrobun 1.18 (native webview, typed RPC bridge) | | Desktop | Electrobun 1.18 (native webview, typed RPC bridge) |
| Frontend | Angular 22 (standalone, signals, zoneless) in `ui/` | | Frontend | Angular 22 (standalone, signals, zoneless) in `ui/` |
| Styling | Tailwind CSS v4, shadcn-style tokens (no component library) | | 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) | | SSH/SFTP | `ssh2` (pure-JS under Bun) |
The repo is a Bun workspace: the Electrobun app at the root, the Angular app in The repo is a Bun workspace: the Electrobun app at the root, the Angular app in
+2 -2
View File
@@ -26,7 +26,7 @@
"@angular/core": "^22.0.0", "@angular/core": "^22.0.0",
"@angular/platform-browser": "^22.0.0", "@angular/platform-browser": "^22.0.0",
"@ng-icons/core": "^34.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", "rxjs": "~7.8.0",
"tslib": "^2.3.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/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=="], "@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=="],
+4
View File
@@ -265,6 +265,10 @@ component; tokens → `ui/src/styles.css`.
walker check the flag themselves. walker check the flag themselves.
- `file-icons.ts` — extension → category map driving glyphs, colors - `file-icons.ts` — extension → category map driving glyphs, colors
(fixed `--icon-*` tokens, never accent-tinted) and the Kind column. (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`, - `platform.ts` — preload-global readers (`PLATFORM`, `APP_MODE`,
`EDITOR_CONTEXT`, `IS_MAC`/`IS_MAC_CHROME`, `IS_WINDOWS`, `IS_LINUX`, `EDITOR_CONTEXT`, `IS_MAC`/`IS_MAC_CHROME`, `IS_WINDOWS`, `IS_LINUX`,
`MOD_LABEL`/`ALT_LABEL`) + `blockNativeContextMenu` (kills WebKit's `MOD_LABEL`/`ALT_LABEL`) + `blockNativeContextMenu` (kills WebKit's
+1 -1
View File
@@ -14,7 +14,7 @@
"@angular/core": "^22.0.0", "@angular/core": "^22.0.0",
"@angular/platform-browser": "^22.0.0", "@angular/platform-browser": "^22.0.0",
"@ng-icons/core": "^34.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", "rxjs": "~7.8.0",
"tslib": "^2.3.0" "tslib": "^2.3.0"
}, },
+10 -10
View File
@@ -13,27 +13,27 @@ const LINK = 'shrink-0 text-icon-link';
const CATEGORIES: Record<Category, { glyph: string; class: string; extensions: string[] }> = { const CATEGORIES: Record<Category, { glyph: string; class: string; extensions: string[] }> = {
image: { image: {
glyph: 'mynaImage', glyph: 'tdesignImage',
class: 'shrink-0 text-icon-image', class: 'shrink-0 text-icon-image',
extensions: 'png jpg jpeg gif webp avif svg ico icns bmp tiff tif heic heif raw'.split(' '), extensions: 'png jpg jpeg gif webp avif svg ico icns bmp tiff tif heic heif raw'.split(' '),
}, },
audio: { audio: {
glyph: 'mynaMusic', glyph: 'tdesignMusic',
class: 'shrink-0 text-icon-media', class: 'shrink-0 text-icon-media',
extensions: 'mp3 wav flac aac ogg oga m4a opus wma aiff aif mid midi'.split(' '), extensions: 'mp3 wav flac aac ogg oga m4a opus wma aiff aif mid midi'.split(' '),
}, },
video: { video: {
glyph: 'mynaVideo', glyph: 'tdesignVideo',
class: 'shrink-0 text-icon-media', class: 'shrink-0 text-icon-media',
extensions: 'mp4 mkv mov avi webm m4v mpg mpeg wmv flv 3gp'.split(' '), extensions: 'mp4 mkv mov avi webm m4v mpg mpeg wmv flv 3gp'.split(' '),
}, },
archive: { archive: {
glyph: 'mynaArchive', glyph: 'tdesignFileZip',
class: 'shrink-0 text-icon-archive', class: 'shrink-0 text-icon-archive',
extensions: 'zip tar gz tgz bz2 xz zst 7z rar dmg iso jar deb rpm pkg apk'.split(' '), extensions: 'zip tar gz tgz bz2 xz zst 7z rar dmg iso jar deb rpm pkg apk'.split(' '),
}, },
code: { code: {
glyph: 'mynaCode', glyph: 'tdesignCode',
class: 'shrink-0 text-icon-code', class: 'shrink-0 text-icon-code',
// ".ts" is TypeScript here, not an MPEG transport stream (deliberate) // ".ts" is TypeScript here, not an MPEG transport stream (deliberate)
extensions: ( extensions: (
@@ -45,7 +45,7 @@ const CATEGORIES: Record<Category, { glyph: string; class: string; extensions: s
).split(' '), ).split(' '),
}, },
doc: { doc: {
glyph: 'mynaFileText', glyph: 'tdesignFile1',
class: MUTED, // docs keep the neutral color; only the glyph changes class: MUTED, // docs keep the neutral color; only the glyph changes
extensions: 'md markdown txt rtf pdf doc docx xls xlsx ppt pptx csv tsv log odt ods odp epub'.split(' '), extensions: 'md markdown txt rtf pdf doc docx xls xlsx ppt pptx csv tsv log odt ods odp epub'.split(' '),
}, },
@@ -85,11 +85,11 @@ export function fileKindKey(entry: FileEntry): string {
} }
export function fileGlyph(entry: FileEntry): string { export function fileGlyph(entry: FileEntry): string {
if (entry.name === '..') return 'mynaArrowUp'; if (entry.name === '..') return 'tdesignArrowUp';
if (entry.type === 'dir') return 'mynaFolder'; if (entry.type === 'dir') return 'tdesignFolder';
if (entry.type === 'symlink') return 'mynaLink'; if (entry.type === 'symlink') return 'tdesignLink';
const category = categoryOf(entry.name); const category = categoryOf(entry.name);
return category ? CATEGORIES[category].glyph : 'mynaFile'; return category ? CATEGORIES[category].glyph : 'tdesignFile';
} }
export function fileIconClass(entry: FileEntry): string { export function fileIconClass(entry: FileEntry): string {
+70 -71
View File
@@ -1,76 +1,75 @@
// Single icon registry for the whole app, registered once in app.config.ts. // Single icon registry for the whole app, registered once in app.config.ts.
// NOTE: @ng-icons/mynaui's package root is empty — always import from /outline // TDesign's package root exports every icon; named imports tree-shake. Names are
// (or /solid, where names get a `Solid` suffix). // plain strings in templates — the build never checks them, so every name used
// anywhere must be listed here (an unregistered one renders nothing).
import { import {
mynaArchive, tdesignAdd,
mynaArrowLeft, tdesignArrowLeft,
mynaArrowLeftRight, tdesignArrowRight,
mynaArrowRight, tdesignArrowUp,
mynaArrowUp, tdesignCheck,
mynaCheck, tdesignCheckCircle,
mynaCheckCircle, tdesignChevronDown,
mynaChevronDown, tdesignChevronRight,
mynaChevronRight, tdesignChevronUp,
mynaChevronUp, tdesignClose,
mynaCode, tdesignCloseCircle,
mynaCog, tdesignCode,
mynaDots, tdesignDelete,
mynaDownload, tdesignDownload,
mynaEdit, tdesignEdit,
mynaFile, tdesignEllipsis,
mynaFilePlus, tdesignFile,
mynaFileText, tdesignFile1,
mynaFolder, tdesignFileAdd,
mynaFolderPlus, tdesignFileZip,
mynaHardDrive, tdesignFolder,
mynaImage, tdesignFolderAdd,
mynaLink, tdesignHardDrive,
mynaLock, tdesignImage,
mynaMusic, tdesignLink,
mynaPlus, tdesignLoading,
mynaRefresh, tdesignLockOn,
mynaSearch, tdesignMusic,
mynaServers, tdesignRefresh,
mynaSpinner, tdesignSearch,
mynaTrash, tdesignServer,
mynaVideo, tdesignSetting,
mynaX, tdesignVideo,
mynaXCircle, } from "@ng-icons/tdesign-icons";
} from "@ng-icons/mynaui/outline";
export const APP_ICONS = { export const APP_ICONS = {
mynaArchive, tdesignAdd,
mynaArrowLeft, tdesignArrowLeft,
mynaArrowLeftRight, tdesignArrowRight,
mynaArrowRight, tdesignArrowUp,
mynaArrowUp, tdesignCheck,
mynaCheck, tdesignCheckCircle,
mynaCheckCircle, tdesignChevronDown,
mynaChevronDown, tdesignChevronRight,
mynaChevronRight, tdesignChevronUp,
mynaChevronUp, tdesignClose,
mynaCode, tdesignCloseCircle,
mynaCog, tdesignCode,
mynaDots, tdesignDelete,
mynaDownload, tdesignDownload,
mynaEdit, tdesignEdit,
mynaFile, tdesignEllipsis,
mynaFilePlus, tdesignFile,
mynaFileText, tdesignFile1,
mynaFolder, tdesignFileAdd,
mynaFolderPlus, tdesignFileZip,
mynaHardDrive, tdesignFolder,
mynaImage, tdesignFolderAdd,
mynaLink, tdesignHardDrive,
mynaLock, tdesignImage,
mynaMusic, tdesignLink,
mynaPlus, tdesignLoading,
mynaRefresh, tdesignLockOn,
mynaSearch, tdesignMusic,
mynaServers, tdesignRefresh,
mynaSpinner, tdesignSearch,
mynaTrash, tdesignServer,
mynaVideo, tdesignSetting,
mynaX, tdesignVideo,
mynaXCircle,
}; };
+2 -2
View File
@@ -2,7 +2,7 @@
@if (!rpc.available) { @if (!rpc.available) {
<div class="flex flex-1 items-center justify-center"> <div class="flex flex-1 items-center justify-center">
<div class="max-w-sm rounded-lg border border-border bg-card p-6 text-center shadow-sm"> <div class="max-w-sm rounded-lg border border-border bg-card p-6 text-center shadow-sm">
<ng-icon name="mynaXCircle" size="1.5rem" class="text-destructive" /> <ng-icon name="tdesignCloseCircle" size="1.5rem" class="text-destructive" />
<p class="mt-2 text-sm font-medium">{{ i18n.t('app.notConnectedTitle') }}</p> <p class="mt-2 text-sm font-medium">{{ i18n.t('app.notConnectedTitle') }}</p>
<p class="mt-1 text-xs text-muted-foreground"> <p class="mt-1 text-xs text-muted-foreground">
{{ i18n.t('app.notConnectedBody') }} {{ i18n.t('app.notConnectedBody') }}
@@ -28,7 +28,7 @@
(mousedown)="focusManager()" (mousedown)="focusManager()"
> >
<div class="rounded-lg border border-border bg-card px-5 py-4 text-center shadow-xl"> <div class="rounded-lg border border-border bg-card px-5 py-4 text-center shadow-xl">
<ng-icon name="mynaServers" size="1.25rem" class="text-muted-foreground" /> <ng-icon name="tdesignServer" size="1.25rem" class="text-muted-foreground" />
<p class="mt-1.5 text-xs text-muted-foreground">{{ i18n.t('app.managerOpen') }}</p> <p class="mt-1.5 text-xs text-muted-foreground">{{ i18n.t('app.managerOpen') }}</p>
<button <button
class="mt-3 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90" class="mt-3 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90"
@@ -9,7 +9,7 @@
[class.h-9]="!isMacChrome" [class.h-9]="!isMacChrome"
[class.pl-3]="!isMacChrome" [class.pl-3]="!isMacChrome"
> >
<ng-icon name="mynaServers" size="0.95rem" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignServer" size="0.95rem" class="shrink-0 text-muted-foreground" />
<h1 class="text-sm font-semibold">{{ i18n.t('connMgr.title') }}</h1> <h1 class="text-sm font-semibold">{{ i18n.t('connMgr.title') }}</h1>
<div class="flex-1"></div> <div class="flex-1"></div>
<button <button
@@ -19,9 +19,9 @@
class="flex items-center gap-1.5 rounded-md px-2 py-1 text-[0.6875rem] text-muted-foreground electrobun-webkit-app-region-no-drag hover:bg-accent hover:text-foreground disabled:opacity-50" class="flex items-center gap-1.5 rounded-md px-2 py-1 text-[0.6875rem] text-muted-foreground electrobun-webkit-app-region-no-drag hover:bg-accent hover:text-foreground disabled:opacity-50"
> >
@if (importing()) { @if (importing()) {
<ng-icon name="mynaSpinner" size="0.85rem" class="animate-spin" /> <ng-icon name="tdesignLoading" size="0.85rem" class="animate-spin" />
} @else { } @else {
<!-- <ng-icon name="mynaArchive" size="0.85rem" /> --> <!-- <ng-icon name="tdesignFileZip" size="0.85rem" /> -->
} }
{{ i18n.t('connMgr.importWinscp') }} {{ i18n.t('connMgr.importWinscp') }}
</button> </button>
@@ -36,14 +36,14 @@
[title]="i18n.t('connMgr.newConnectionHint')" [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" class="flex items-center gap-1 rounded-md px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaPlus" size="0.85rem" /> {{ i18n.t('connMgr.newConnection') }} <ng-icon name="tdesignAdd" size="0.85rem" /> {{ i18n.t('connMgr.newConnection') }}
</button> </button>
<button <button
(click)="newStack()" (click)="newStack()"
[title]="i18n.t('connMgr.newStackHint')" [title]="i18n.t('connMgr.newStackHint')"
class="flex items-center gap-1 rounded-md px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground" class="flex items-center gap-1 rounded-md px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaFolderPlus" size="0.85rem" /> {{ i18n.t('connMgr.newStack') }} <ng-icon name="tdesignFolderAdd" size="0.85rem" /> {{ i18n.t('connMgr.newStack') }}
</button> </button>
</div> </div>
@@ -67,7 +67,7 @@
[title]="group.stack.collapsed ? i18n.t('connMgr.expand') : i18n.t('connMgr.collapse')" [title]="group.stack.collapsed ? i18n.t('connMgr.expand') : i18n.t('connMgr.collapse')"
> >
<ng-icon <ng-icon
[name]="group.stack.collapsed ? 'mynaChevronRight' : 'mynaChevronDown'" [name]="group.stack.collapsed ? 'tdesignChevronRight' : 'tdesignChevronDown'"
size="0.8rem" size="0.8rem"
/> />
</button> </button>
@@ -88,14 +88,14 @@
[title]="i18n.t('connMgr.renameStack')" [title]="i18n.t('connMgr.renameStack')"
class="grid size-4 place-items-center rounded text-muted-foreground hover:text-foreground" class="grid size-4 place-items-center rounded text-muted-foreground hover:text-foreground"
> >
<ng-icon name="mynaEdit" size="0.75rem" /> <ng-icon name="tdesignEdit" size="0.75rem" />
</button> </button>
<button <button
(click)="deleteStack(group.stack)" (click)="deleteStack(group.stack)"
[title]="i18n.t('connMgr.deleteStack')" [title]="i18n.t('connMgr.deleteStack')"
class="grid size-4 place-items-center rounded text-muted-foreground hover:text-destructive" class="grid size-4 place-items-center rounded text-muted-foreground hover:text-destructive"
> >
<ng-icon name="mynaTrash" size="0.75rem" /> <ng-icon name="tdesignDelete" size="0.75rem" />
</button> </button>
@if (group.connections.length) { @if (group.connections.length) {
<button <button
@@ -103,7 +103,7 @@
[title]="i18n.t('connMgr.openStack')" [title]="i18n.t('connMgr.openStack')"
class="grid size-4 place-items-center rounded text-muted-foreground hover:text-primary" class="grid size-4 place-items-center rounded text-muted-foreground hover:text-primary"
> >
<ng-icon name="mynaArrowRight" size="0.8rem" /> <ng-icon name="tdesignArrowRight" size="0.8rem" />
</button> </button>
} }
</div> </div>
@@ -119,7 +119,7 @@
[class.bg-accent]="draft()?.id === connection.id" [class.bg-accent]="draft()?.id === connection.id"
[class.opacity-50]="draggedId() === connection.id" [class.opacity-50]="draggedId() === connection.id"
> >
<ng-icon name="mynaServers" size="0.85rem" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignServer" size="0.85rem" class="shrink-0 text-muted-foreground" />
<span class="truncate">{{ connection.name }}</span> <span class="truncate">{{ connection.name }}</span>
</button> </button>
} @empty { } @empty {
@@ -155,7 +155,7 @@
[class.bg-accent]="draft()?.id === connection.id" [class.bg-accent]="draft()?.id === connection.id"
[class.opacity-50]="draggedId() === connection.id" [class.opacity-50]="draggedId() === connection.id"
> >
<ng-icon name="mynaServers" size="0.85rem" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignServer" size="0.85rem" class="shrink-0 text-muted-foreground" />
<span class="truncate">{{ connection.name }}</span> <span class="truncate">{{ connection.name }}</span>
</button> </button>
} }
@@ -332,7 +332,7 @@
(click)="deleteCurrent()" (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" 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"
> >
<ng-icon name="mynaTrash" size="0.85rem" /> {{ i18n.t('common.delete') }} <ng-icon name="tdesignDelete" size="0.85rem" /> {{ i18n.t('common.delete') }}
</button> </button>
<button <button
(click)="moreOpen.set(!moreOpen())" (click)="moreOpen.set(!moreOpen())"
@@ -354,7 +354,7 @@
class="flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50" class="flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
> >
@if (busy()) { @if (busy()) {
<ng-icon name="mynaSpinner" size="0.85rem" class="animate-spin" /> <ng-icon name="tdesignLoading" size="0.85rem" class="animate-spin" />
} }
{{ i18n.t('common.connect') }} {{ i18n.t('common.connect') }}
</button> </button>
@@ -362,7 +362,7 @@
} @else { } @else {
<div class="grid flex-1 place-items-center"> <div class="grid flex-1 place-items-center">
<div class="text-center"> <div class="text-center">
<ng-icon name="mynaServers" size="1.75rem" class="text-muted-foreground" /> <ng-icon name="tdesignServer" size="1.75rem" class="text-muted-foreground" />
<p class="mt-2 text-xs text-muted-foreground"> <p class="mt-2 text-xs text-muted-foreground">
{{ i18n.t('connMgr.selectPrompt') }} {{ i18n.t('connMgr.selectPrompt') }}
</p> </p>
+1 -1
View File
@@ -62,7 +62,7 @@ const EDGE_GAP = 6; // px on purpose: a viewport-edge margin, not a UI size
> >
<span class="w-3.5 shrink-0"> <span class="w-3.5 shrink-0">
@if (item.checked) { @if (item.checked) {
<ng-icon name="mynaCheck" size="0.85rem" class="text-primary" /> <ng-icon name="tdesignCheck" size="0.85rem" class="text-primary" />
} }
</span> </span>
<span class="flex-1 truncate">{{ item.label }}</span> <span class="flex-1 truncate">{{ item.label }}</span>
@@ -60,7 +60,7 @@ import { FocusService } from '@core/focus.service';
</div> </div>
<div class="mt-1.5 flex items-center gap-1.5 text-xs"> <div class="mt-1.5 flex items-center gap-1.5 text-xs">
<ng-icon <ng-icon
[name]="isDir() ? 'mynaFolder' : 'mynaFile'" [name]="isDir() ? 'tdesignFolder' : 'tdesignFile'"
size="0.9rem" size="0.9rem"
class="shrink-0 text-muted-foreground" class="shrink-0 text-muted-foreground"
/> />
@@ -2,7 +2,7 @@
@if (!ctx) { @if (!ctx) {
<div class="flex flex-1 items-center justify-center"> <div class="flex flex-1 items-center justify-center">
<div class="max-w-sm rounded-lg border border-border bg-card p-6 text-center shadow-sm"> <div class="max-w-sm rounded-lg border border-border bg-card p-6 text-center shadow-sm">
<ng-icon name="mynaXCircle" size="1.5rem" class="text-destructive" /> <ng-icon name="tdesignCloseCircle" size="1.5rem" class="text-destructive" />
<p class="mt-2 text-sm font-medium">{{ i18n.t('editor.noFileTitle') }}</p> <p class="mt-2 text-sm font-medium">{{ i18n.t('editor.noFileTitle') }}</p>
<p class="mt-1 text-xs text-muted-foreground"> <p class="mt-1 text-xs text-muted-foreground">
{{ i18n.t('editor.noFileBody') }} {{ i18n.t('editor.noFileBody') }}
@@ -20,7 +20,7 @@
[class.h-9]="!isMacChrome" [class.h-9]="!isMacChrome"
[class.pl-3]="!isMacChrome" [class.pl-3]="!isMacChrome"
> >
<ng-icon name="mynaFileText" size="0.95rem" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignFile1" size="0.95rem" class="shrink-0 text-muted-foreground" />
<h1 class="min-w-0 truncate font-mono text-sm font-semibold"> <h1 class="min-w-0 truncate font-mono text-sm font-semibold">
{{ ctx.name }}{{ dirty() ? ' •' : '' }} {{ ctx.name }}{{ dirty() ? ' •' : '' }}
</h1> </h1>
@@ -41,13 +41,13 @@
[title]="i18n.t('editor.findHint', { mod: modLabel })" [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" class="grid size-6 place-items-center rounded-md text-muted-foreground electrobun-webkit-app-region-no-drag hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaSearch" size="0.85rem" /> <ng-icon name="tdesignSearch" size="0.85rem" />
</button> </button>
</header> </header>
@if (findOpen()) { @if (findOpen()) {
<div class="flex shrink-0 items-center gap-2 border-b border-border bg-chrome px-3 py-1.5"> <div class="flex shrink-0 items-center gap-2 border-b border-border bg-chrome px-3 py-1.5">
<ng-icon name="mynaSearch" size="0.85rem" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignSearch" size="0.85rem" class="shrink-0 text-muted-foreground" />
<input <input
#findBox #findBox
[value]="findQuery()" [value]="findQuery()"
@@ -69,14 +69,14 @@
[title]="i18n.t('editor.prevMatch')" [title]="i18n.t('editor.prevMatch')"
class="grid size-5 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground" class="grid size-5 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaChevronUp" size="0.8rem" /> <ng-icon name="tdesignChevronUp" size="0.8rem" />
</button> </button>
<button <button
(click)="findStep(1)" (click)="findStep(1)"
[title]="i18n.t('editor.nextMatch')" [title]="i18n.t('editor.nextMatch')"
class="grid size-5 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground" class="grid size-5 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaChevronDown" size="0.8rem" /> <ng-icon name="tdesignChevronDown" size="0.8rem" />
</button> </button>
<div class="flex-1"></div> <div class="flex-1"></div>
<button <button
@@ -84,7 +84,7 @@
[title]="i18n.t('editor.closeHint')" [title]="i18n.t('editor.closeHint')"
class="grid size-5 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground" class="grid size-5 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaX" size="0.8rem" /> <ng-icon name="tdesignClose" size="0.8rem" />
</button> </button>
</div> </div>
} }
@@ -93,19 +93,19 @@
<div <div
class="flex shrink-0 items-center gap-2 border-b border-border bg-destructive/10 px-3 py-1.5 text-[0.6875rem] text-destructive" class="flex shrink-0 items-center gap-2 border-b border-border bg-destructive/10 px-3 py-1.5 text-[0.6875rem] text-destructive"
> >
<ng-icon name="mynaXCircle" size="0.85rem" class="shrink-0" /> <ng-icon name="tdesignCloseCircle" size="0.85rem" class="shrink-0" />
{{ i18n.t('editor.disconnected', { name: ctx.sessionTitle }) }} {{ i18n.t('editor.disconnected', { name: ctx.sessionTitle }) }}
</div> </div>
} }
@if (loading()) { @if (loading()) {
<div class="flex flex-1 items-center justify-center"> <div class="flex flex-1 items-center justify-center">
<ng-icon name="mynaSpinner" size="1.25rem" class="animate-spin text-primary" /> <ng-icon name="tdesignLoading" size="1.25rem" class="animate-spin text-primary" />
</div> </div>
} @else if (loadError(); as error) { } @else if (loadError(); as error) {
<div class="flex flex-1 items-center justify-center"> <div class="flex flex-1 items-center justify-center">
<div class="max-w-md rounded-lg border border-border bg-card p-6 text-center shadow-sm"> <div class="max-w-md rounded-lg border border-border bg-card p-6 text-center shadow-sm">
<ng-icon name="mynaXCircle" size="1.5rem" class="text-destructive" /> <ng-icon name="tdesignCloseCircle" size="1.5rem" class="text-destructive" />
<p class="mt-2 text-sm font-medium">{{ i18n.t('editor.cantOpen', { name: ctx.name }) }}</p> <p class="mt-2 text-sm font-medium">{{ i18n.t('editor.cantOpen', { name: ctx.name }) }}</p>
<p class="mt-1 text-xs text-muted-foreground">{{ error }}</p> <p class="mt-1 text-xs text-muted-foreground">{{ error }}</p>
<button <button
@@ -159,7 +159,7 @@
class="flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50" class="flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
> >
@if (saving()) { @if (saving()) {
<ng-icon name="mynaSpinner" size="0.85rem" class="animate-spin" /> <ng-icon name="tdesignLoading" size="0.85rem" class="animate-spin" />
} }
{{ i18n.t('common.save') }} {{ i18n.t('common.save') }}
</button> </button>
@@ -6,17 +6,17 @@
[title]="i18n.t('panel.choosePanel')" [title]="i18n.t('panel.choosePanel')"
> >
@if (panel().connecting()) { @if (panel().connecting()) {
<ng-icon name="mynaSpinner" class="shrink-0 animate-spin text-primary" size="var(--action-icon)" /> <ng-icon name="tdesignLoading" class="shrink-0 animate-spin text-primary" size="var(--action-icon)" />
} @else { } @else {
<ng-icon <ng-icon
[name]="isRemote() ? 'mynaServers' : 'mynaHardDrive'" [name]="isRemote() ? 'tdesignServer' : 'tdesignHardDrive'"
[class]="isRemote() ? 'shrink-0 text-primary' : 'shrink-0 text-muted-foreground'" [class]="isRemote() ? 'shrink-0 text-primary' : 'shrink-0 text-muted-foreground'"
size="var(--action-icon)" size="var(--action-icon)"
/> />
} }
<span class="truncate">{{ isRemote() ? panel().title() : i18n.t('common.local') }}</span> <span class="truncate">{{ isRemote() ? panel().title() : i18n.t('common.local') }}</span>
<ng-icon <ng-icon
name="mynaChevronDown" name="tdesignChevronDown"
class="shrink-0 text-muted-foreground" class="shrink-0 text-muted-foreground"
size="calc(var(--action-icon) - 0.1rem)" size="calc(var(--action-icon) - 0.1rem)"
/> />
@@ -38,7 +38,7 @@
[title]="i18n.t('panel.editFile')" [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" class="flex h-(--action-h) shrink-0 items-center rounded-md px-1 text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaFileText" size="var(--action-icon)" /> <ng-icon name="tdesignFile1" size="var(--action-icon)" />
<span class="ml-1 hidden text-(length:--action-font) @[30rem]:inline">{{ i18n.t('panel.edit') }}</span> <span class="ml-1 hidden text-(length:--action-font) @[30rem]:inline">{{ i18n.t('panel.edit') }}</span>
</button> </button>
<button <button
@@ -46,7 +46,7 @@
[title]="i18n.t('panel.rename')" [title]="i18n.t('panel.rename')"
class="flex h-(--action-h) shrink-0 items-center rounded-md px-1 text-muted-foreground hover:bg-accent hover:text-foreground" class="flex h-(--action-h) shrink-0 items-center rounded-md px-1 text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaEdit" size="var(--action-icon)" /> <ng-icon name="tdesignEdit" size="var(--action-icon)" />
<span class="ml-1 hidden text-(length:--action-font) @[30rem]:inline">{{ i18n.t('common.rename') }}</span> <span class="ml-1 hidden text-(length:--action-font) @[30rem]:inline">{{ i18n.t('common.rename') }}</span>
</button> </button>
<button <button
@@ -54,14 +54,14 @@
[title]="i18n.t('panel.newFolder')" [title]="i18n.t('panel.newFolder')"
class="grid size-(--action-h) shrink-0 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground" class="grid size-(--action-h) shrink-0 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaFolderPlus" size="var(--action-icon)" /> <ng-icon name="tdesignFolderAdd" size="var(--action-icon)" />
</button> </button>
<button <button
(click)="run('createFile')" (click)="run('createFile')"
[title]="i18n.t('panel.newFile')" [title]="i18n.t('panel.newFile')"
class="grid size-(--action-h) shrink-0 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground" class="grid size-(--action-h) shrink-0 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaFilePlus" size="var(--action-icon)" /> <ng-icon name="tdesignFileAdd" size="var(--action-icon)" />
</button> </button>
@if (chmodAvailable()) { @if (chmodAvailable()) {
<button <button
@@ -69,7 +69,7 @@
[title]="i18n.t('panel.permissions')" [title]="i18n.t('panel.permissions')"
class="grid size-(--action-h) shrink-0 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground" class="grid size-(--action-h) shrink-0 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaLock" size="var(--action-icon)" /> <ng-icon name="tdesignLockOn" size="var(--action-icon)" />
</button> </button>
} }
<button <button
@@ -77,7 +77,7 @@
[title]="i18n.t('panel.deleteHint')" [title]="i18n.t('panel.deleteHint')"
class="flex h-(--action-h) shrink-0 items-center rounded-md px-1 text-muted-foreground hover:bg-accent hover:text-destructive" class="flex h-(--action-h) shrink-0 items-center rounded-md px-1 text-muted-foreground hover:bg-accent hover:text-destructive"
> >
<ng-icon name="mynaTrash" size="var(--action-icon)" /> <ng-icon name="tdesignDelete" size="var(--action-icon)" />
<span class="ml-1 hidden text-(length:--action-font) @[30rem]:inline">{{ i18n.t('common.delete') }}</span> <span class="ml-1 hidden text-(length:--action-font) @[30rem]:inline">{{ i18n.t('common.delete') }}</span>
</button> </button>
@@ -90,10 +90,10 @@
(click)="pickLocal()" (click)="pickLocal()"
class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-(length:--path-font) hover:bg-accent" class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-(length:--path-font) hover:bg-accent"
> >
<ng-icon name="mynaHardDrive" size="var(--action-icon)" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignHardDrive" size="var(--action-icon)" class="shrink-0 text-muted-foreground" />
<span class="flex-1">{{ i18n.t('common.local') }}</span> <span class="flex-1">{{ i18n.t('common.local') }}</span>
@if (!isRemote()) { @if (!isRemote()) {
<ng-icon name="mynaCheck" size="0.85rem" class="shrink-0 text-primary" /> <ng-icon name="tdesignCheck" size="0.85rem" class="shrink-0 text-primary" />
} }
</button> </button>
@@ -103,7 +103,7 @@
(click)="pickDrive(drive)" (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" class="flex w-full items-center gap-2 py-1.5 pr-3 pl-6 text-left text-(length:--path-font) hover:bg-accent"
> >
<ng-icon name="mynaHardDrive" size="var(--action-icon)" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignHardDrive" size="var(--action-icon)" class="shrink-0 text-muted-foreground" />
<span class="flex-1 font-mono">{{ drive }}</span> <span class="flex-1 font-mono">{{ drive }}</span>
</button> </button>
} }
@@ -116,7 +116,7 @@
(click)="pickConnection(connection)" (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" class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-(length:--path-font) hover:bg-accent"
> >
<ng-icon name="mynaServers" size="var(--action-icon)" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignServer" size="var(--action-icon)" class="shrink-0 text-muted-foreground" />
<span class="flex-1 truncate">{{ connection.name }}</span> <span class="flex-1 truncate">{{ connection.name }}</span>
</button> </button>
} }
@@ -129,7 +129,7 @@
(click)="pickConnection(connection)" (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" class="flex w-full items-center gap-2 py-1.5 pr-3 pl-5 text-left text-(length:--path-font) hover:bg-accent"
> >
<ng-icon name="mynaServers" size="var(--action-icon)" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignServer" size="var(--action-icon)" class="shrink-0 text-muted-foreground" />
<span class="flex-1 truncate">{{ connection.name }}</span> <span class="flex-1 truncate">{{ connection.name }}</span>
</button> </button>
} }
@@ -147,7 +147,7 @@
[title]="sshHostTitle(host)" [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" 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"
> >
<ng-icon name="mynaServers" size="var(--action-icon)" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignServer" size="var(--action-icon)" class="shrink-0 text-muted-foreground" />
<span class="flex-1 truncate">{{ host.name }}</span> <span class="flex-1 truncate">{{ host.name }}</span>
</button> </button>
} }
@@ -165,7 +165,7 @@
[title]="i18n.t('panel.parentDir')" [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" 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"
> >
<ng-icon name="mynaArrowUp" size="1rem" /> <ng-icon name="tdesignArrowUp" size="1rem" />
</button> </button>
<input <input
[value]="pathDraft()" [value]="pathDraft()"
@@ -184,9 +184,9 @@
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" 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()) { @if (panel().loading()) {
<ng-icon name="mynaSpinner" size="1rem" class="animate-spin" /> <ng-icon name="tdesignLoading" size="1rem" class="animate-spin" />
} @else { } @else {
<ng-icon name="mynaRefresh" size="1rem" /> <ng-icon name="tdesignRefresh" size="1rem" />
} }
</button> </button>
</div> </div>
@@ -215,7 +215,7 @@
<!-- type-to-filter bar (appears while a query is active) --> <!-- type-to-filter bar (appears while a query is active) -->
@if (panel().filter(); as query) { @if (panel().filter(); as query) {
<div class="flex items-center gap-1.5 border-b border-border bg-accent/50 px-2 py-1"> <div class="flex items-center gap-1.5 border-b border-border bg-accent/50 px-2 py-1">
<ng-icon name="mynaSearch" size="0.85rem" class="shrink-0 text-muted-foreground" /> <ng-icon name="tdesignSearch" size="0.85rem" class="shrink-0 text-muted-foreground" />
<span class="min-w-0 flex-1 truncate font-mono text-xs">{{ query }}</span> <span class="min-w-0 flex-1 truncate font-mono text-xs">{{ query }}</span>
<span class="shrink-0 text-[0.6875rem] text-muted-foreground"> <span class="shrink-0 text-[0.6875rem] text-muted-foreground">
{{ i18n.t('panel.matches', { count: filterMatches() }) }} {{ i18n.t('panel.matches', { count: filterMatches() }) }}
@@ -225,7 +225,7 @@
[title]="i18n.t('panel.clearFilter')" [title]="i18n.t('panel.clearFilter')"
class="grid size-5 shrink-0 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground" class="grid size-5 shrink-0 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaX" size="0.8rem" /> <ng-icon name="tdesignClose" size="0.8rem" />
</button> </button>
</div> </div>
} }
@@ -243,7 +243,7 @@
@if (panel().connecting()) { @if (panel().connecting()) {
<div class="panel-fade-in grid h-full place-items-center"> <div class="panel-fade-in grid h-full place-items-center">
<div class="flex flex-col items-center gap-3"> <div class="flex flex-col items-center gap-3">
<ng-icon name="mynaSpinner" size="1.4rem" class="animate-spin text-primary" /> <ng-icon name="tdesignLoading" size="1.4rem" class="animate-spin text-primary" />
<span class="text-xs text-muted-foreground"> <span class="text-xs text-muted-foreground">
{{ i18n.t('panel.connectingTo', { name: panel().connectingTo() ?? '' }) }} {{ i18n.t('panel.connectingTo', { name: panel().connectingTo() ?? '' }) }}
</span> </span>
@@ -321,7 +321,7 @@
</div> </div>
@if (panel().slowLoad() && !panel().connecting()) { @if (panel().slowLoad() && !panel().connecting()) {
<div class="panel-fade-in absolute inset-0 z-10 grid place-items-center bg-background/60"> <div class="panel-fade-in absolute inset-0 z-10 grid place-items-center bg-background/60">
<ng-icon name="mynaSpinner" size="1.4rem" class="animate-spin text-primary" /> <ng-icon name="tdesignLoading" size="1.4rem" class="animate-spin text-primary" />
</div> </div>
} }
</div> </div>
@@ -59,7 +59,7 @@ export class FilePanel {
/** Input is ignored while the panel is connecting or a listing is in flight. */ /** Input is ignored while the panel is connecting or a listing is in flight. */
readonly blocked = computed(() => this.panel().busy()); readonly blocked = computed(() => this.panel().busy());
/** The copy button points toward the other panel. */ /** 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 pathDraft = signal('');
readonly menuOpen = signal(false); readonly menuOpen = signal(false);
@@ -21,7 +21,7 @@ import { TransfersService } from '@core/transfers.service';
[title]="i18n.t('transfer.showDetails')" [title]="i18n.t('transfer.showDetails')"
> >
@if (transfers.currentJob(); as job) { @if (transfers.currentJob(); as job) {
<ng-icon name="mynaSpinner" size="0.8rem" class="shrink-0 animate-spin text-primary" /> <ng-icon name="tdesignLoading" size="0.8rem" class="shrink-0 animate-spin text-primary" />
<span class="truncate"> <span class="truncate">
{{ i18n.t('transfer.copying', { name: job.name, percent: percent(job), speed: speedSuffix(job) }) }} {{ i18n.t('transfer.copying', { name: job.name, percent: percent(job), speed: speedSuffix(job) }) }}
@if (transfers.queuedCount(); as queued) { @if (transfers.queuedCount(); as queued) {
@@ -29,12 +29,12 @@ import { TransfersService } from '@core/transfers.service';
} }
</span> </span>
} @else if (transfers.failedJobs().length; as failed) { } @else if (transfers.failedJobs().length; as failed) {
<ng-icon name="mynaXCircle" size="0.8rem" class="shrink-0 text-destructive" /> <ng-icon name="tdesignCloseCircle" size="0.8rem" class="shrink-0 text-destructive" />
<span class="text-destructive"> <span class="text-destructive">
{{ i18n.t('transfer.failed', { count: failed }) }} {{ i18n.t('transfer.failed', { count: failed }) }}
</span> </span>
} @else if (transfers.hasJobs()) { } @else if (transfers.hasJobs()) {
<ng-icon name="mynaCheckCircle" size="0.8rem" class="shrink-0 text-success" /> <ng-icon name="tdesignCheckCircle" size="0.8rem" class="shrink-0 text-success" />
<span>{{ i18n.t('transfer.finished') }}</span> <span>{{ i18n.t('transfer.finished') }}</span>
} @else { } @else {
<span>{{ i18n.t('transfer.ready') }}</span> <span>{{ i18n.t('transfer.ready') }}</span>
@@ -44,7 +44,7 @@ import { TransfersService } from '@core/transfers.service';
<!-- active panel info --> <!-- active panel info -->
<div class="flex shrink-0 items-center gap-1.5"> <div class="flex shrink-0 items-center gap-1.5">
<ng-icon <ng-icon
[name]="activePanel().sessionId() === 'local' ? 'mynaHardDrive' : 'mynaServers'" [name]="activePanel().sessionId() === 'local' ? 'tdesignHardDrive' : 'tdesignServer'"
size="0.8rem" size="0.8rem"
[class.text-primary]="activePanel().sessionId() !== 'local'" [class.text-primary]="activePanel().sessionId() !== 'local'"
/> />
+9 -9
View File
@@ -77,7 +77,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const;
[title]="panels.workspaceName(ws)" [title]="panels.workspaceName(ws)"
> >
<ng-icon <ng-icon
[name]="panels.workspaceIsRemote(ws) ? 'mynaServers' : 'mynaHardDrive'" [name]="panels.workspaceIsRemote(ws) ? 'tdesignServer' : 'tdesignHardDrive'"
size="0.85rem" size="0.85rem"
class="shrink-0" class="shrink-0"
[class.text-primary]="panels.workspaceIsRemote(ws)" [class.text-primary]="panels.workspaceIsRemote(ws)"
@@ -92,7 +92,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const;
[title]="i18n.t('tabBar.closeTab', { mod: modLabel })" [title]="i18n.t('tabBar.closeTab', { mod: modLabel })"
class="mr-1 grid size-4 shrink-0 place-items-center rounded text-muted-foreground opacity-0 group-hover:opacity-100 hover:bg-border hover:text-foreground" class="mr-1 grid size-4 shrink-0 place-items-center rounded text-muted-foreground opacity-0 group-hover:opacity-100 hover:bg-border hover:text-foreground"
> >
<ng-icon name="mynaX" size="0.7rem" /> <ng-icon name="tdesignClose" size="0.7rem" />
</button> </button>
} @else { } @else {
<span class="mr-1 size-4 shrink-0"></span> <span class="mr-1 size-4 shrink-0"></span>
@@ -108,7 +108,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const;
[title]="i18n.t('tabBar.newTab', { mod: modLabel })" [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" 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"
> >
<ng-icon name="mynaPlus" size=".8rem" /> <ng-icon name="tdesignAdd" size=".8rem" />
</button> </button>
<div class="flex-1"></div> <div class="flex-1"></div>
@@ -131,13 +131,13 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const;
<span class="relative flex items-center gap-1.5"> <span class="relative flex items-center gap-1.5">
@switch (updater.state()) { @switch (updater.state()) {
@case ('available') { @case ('available') {
<ng-icon name="mynaDownload" size=".8rem" />{{ i18n.t('tabBar.update') }} <ng-icon name="tdesignDownload" size=".8rem" />{{ i18n.t('tabBar.update') }}
} }
@case ('downloading') { @case ('downloading') {
<ng-icon name="mynaSpinner" size=".8rem" class="animate-spin" />{{ i18n.t('tabBar.updating') }} {{ updater.progress() }}% <ng-icon name="tdesignLoading" size=".8rem" class="animate-spin" />{{ i18n.t('tabBar.updating') }} {{ updater.progress() }}%
} }
@case ('ready') { @case ('ready') {
<ng-icon name="mynaRefresh" size=".8rem" />{{ i18n.t('tabBar.restartToUpdate') }} <ng-icon name="tdesignRefresh" size=".8rem" />{{ i18n.t('tabBar.restartToUpdate') }}
} }
} }
</span> </span>
@@ -150,7 +150,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const;
[title]="i18n.t('tabBar.manageConnections')" [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" 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"
> >
<!-- <ng-icon name="mynaCog" size="0.9rem" /> --> <!-- <ng-icon name="tdesignSetting" size="0.9rem" /> -->
{{ i18n.t('tabBar.connections') }} {{ i18n.t('tabBar.connections') }}
</button> </button>
@@ -160,7 +160,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const;
[title]="i18n.t('tabBar.options')" [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" class="grid size-6 place-items-center rounded-md text-muted-foreground electrobun-webkit-app-region-no-drag hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaDots" size="1.5rem" /> <ng-icon name="tdesignEllipsis" size="0.8rem" />
</button> </button>
@if (settingsOpen()) { @if (settingsOpen()) {
@@ -368,7 +368,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const;
[title]="i18n.t('options.resetDefault')" [title]="i18n.t('options.resetDefault')"
class="grid size-5 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground" class="grid size-5 place-items-center rounded text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaX" size="0.7rem" /> <ng-icon name="tdesignClose" size="0.7rem" />
</button> </button>
} }
</div> </div>
+4 -4
View File
@@ -24,7 +24,7 @@ import { ToastService } from '@core/toast.service';
(click)="toast.dismiss(t.id)" (click)="toast.dismiss(t.id)"
class="shrink-0 text-muted-foreground hover:text-foreground" class="shrink-0 text-muted-foreground hover:text-foreground"
> >
<ng-icon name="mynaX" size="0.9rem" /> <ng-icon name="tdesignClose" size="0.9rem" />
</button> </button>
<!-- auto-dismiss countdown; freezes with the timer while hovered --> <!-- auto-dismiss countdown; freezes with the timer while hovered -->
<div <div
@@ -43,8 +43,8 @@ export class Toasts {
readonly toast = inject(ToastService); readonly toast = inject(ToastService);
toastIcon(kind: 'error' | 'info' | 'success'): string { toastIcon(kind: 'error' | 'info' | 'success'): string {
if (kind === 'error') return 'mynaXCircle'; if (kind === 'error') return 'tdesignCloseCircle';
if (kind === 'success') return 'mynaCheckCircle'; if (kind === 'success') return 'tdesignCheckCircle';
return 'mynaCheck'; return 'tdesignCheck';
} }
} }
@@ -8,7 +8,7 @@
[disabled]="!transfers.finishedJobs().length" [disabled]="!transfers.finishedJobs().length"
class="flex items-center gap-1 rounded px-1.5 py-0.5 hover:bg-accent hover:text-foreground disabled:opacity-40 disabled:hover:bg-transparent" class="flex items-center gap-1 rounded px-1.5 py-0.5 hover:bg-accent hover:text-foreground disabled:opacity-40 disabled:hover:bg-transparent"
> >
<ng-icon name="mynaTrash" size="0.75rem" /> {{ i18n.t('transfer.clearFinished') }} <ng-icon name="tdesignDelete" size="0.75rem" /> {{ i18n.t('transfer.clearFinished') }}
</button> </button>
</div> </div>
<div class="max-h-40 overflow-y-auto border-t border-border bg-chrome"> <div class="max-h-40 overflow-y-auto border-t border-border bg-chrome">
@@ -40,7 +40,7 @@
[title]="i18n.t('transfer.cancel')" [title]="i18n.t('transfer.cancel')"
class="shrink-0 rounded p-1 text-muted-foreground hover:bg-accent hover:text-destructive" class="shrink-0 rounded p-1 text-muted-foreground hover:bg-accent hover:text-destructive"
> >
<ng-icon name="mynaX" size="0.9rem" /> <ng-icon name="tdesignClose" size="0.9rem" />
</button> </button>
} @else { } @else {
<button <button
@@ -48,7 +48,7 @@
[title]="i18n.t('transfer.dismiss')" [title]="i18n.t('transfer.dismiss')"
class="shrink-0 rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground" class="shrink-0 rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground"
> >
<ng-icon name="mynaX" size="0.9rem" /> <ng-icon name="tdesignClose" size="0.9rem" />
</button> </button>
} }
</div> </div>
@@ -33,12 +33,12 @@ export class TransferBar {
stateIcon(job: TransferSnapshot): string { stateIcon(job: TransferSnapshot): string {
switch (job.state) { switch (job.state) {
case 'completed': case 'completed':
return 'mynaCheckCircle'; return 'tdesignCheckCircle';
case 'failed': case 'failed':
case 'cancelled': case 'cancelled':
return 'mynaXCircle'; return 'tdesignCloseCircle';
default: default:
return 'mynaSpinner'; return 'tdesignLoading';
} }
} }