Files
miniSCP/ui/src/app/skins/7like/toasts/toasts.ts
T
jgamboaandClaude 39e019af9f Stage 2: move the win7 component tree into app/skins/7like/
All 14 components (including title-bar/, which has no modern counterpart)
move under app/skins/7like/. git records every one as a rename — no content
changed except main.ts.

The @core alias from stage 1 paid off exactly as intended: not one of the 67
service imports needed touching despite every file changing depth. The only
relative imports left inside the tree are skin-internal (app -> its dialogs,
connection-manager -> title-bar), and those survived because the move
preserved their relative structure.

Added skins/7like/index.ts exporting SEVEN_ROOTS { main, manager, editor }.
Every skin will export that same shape, so main.ts can pick a tree by skin
and then a root by APP_MODE without knowing either skin's internals. main.ts
selects from that barrel now, with the second axis still hardcoded until the
shadlike tree lands.

Verified: tsc clean, build:ui clean, opaque interior pixel-identical to the
pre-refactor baseline. That last check also proves Tailwind still scans the
templates from their new skins/** paths — a silent utility purge would have
collapsed the layout rather than reproducing it exactly.

The three structural 7.css contracts that a careless move breaks silently are
intact by construction, since no markup changed: app-title-bar is still a
direct child of .window.w7-frame, nothing new nests inside menu[role=tablist],
and the context menu still emits ul[role=menu] > li[role=menuitem] > button.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-16 04:50:53 +02:00

51 lines
1.9 KiB
TypeScript

import { Component, inject } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { ToastService } from '@core/toast.service';
/** Toast stack overlay; shared by the main window and editor windows. */
@Component({
selector: 'app-toasts',
imports: [NgIcon],
template: `
<div class="pointer-events-none fixed right-3 bottom-8 z-50 flex w-80 flex-col gap-2">
@for (t of toast.toasts(); track t.id) {
<div
(mouseenter)="toast.pause(t.id)"
(mouseleave)="toast.resume(t.id)"
class="group pointer-events-auto relative flex items-start gap-2 overflow-hidden rounded-lg border border-border bg-card p-3 text-xs text-card-foreground shadow-lg"
>
<ng-icon
[name]="toastIcon(t.kind)"
size="1rem"
[class]="t.kind === 'error' ? 'shrink-0 text-destructive' : 'shrink-0 text-success'"
/>
<span class="min-w-0 flex-1 wrap-break-word">{{ t.text }}</span>
<button
(click)="toast.dismiss(t.id)"
class="shrink-0 text-muted-foreground hover:text-foreground"
>
<ng-icon name="mynaX" size="0.9rem" />
</button>
<!-- auto-dismiss countdown; freezes with the timer while hovered -->
<div
class="toast-countdown absolute inset-x-0 bottom-0 h-0.5 origin-left"
[class.bg-destructive]="t.kind === 'error'"
[class.bg-success]="t.kind === 'success'"
[class.bg-primary]="t.kind === 'info'"
[style.animation-duration.ms]="t.ttlMs"
></div>
</div>
}
</div>
`,
})
export class Toasts {
readonly toast = inject(ToastService);
toastIcon(kind: 'error' | 'info' | 'success'): string {
if (kind === 'error') return 'mynaXCircle';
if (kind === 'success') return 'mynaCheckCircle';
return 'mynaCheck';
}
}