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:
@@ -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
|
||||||
|
|||||||
@@ -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=="],
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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
@@ -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,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>
|
||||||
|
|||||||
@@ -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'"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user