Fix lint, make design more consistent, add license texts,
All checks were successful
Queue Release Build / prepare (push) Successful in 11s
Deploy Web Apps / deploy (push) Successful in 14m0s
Queue Release Build / build-linux (push) Successful in 35m41s
Queue Release Build / build-windows (push) Successful in 28m53s
Queue Release Build / finalize (push) Successful in 2m6s
All checks were successful
Queue Release Build / prepare (push) Successful in 11s
Deploy Web Apps / deploy (push) Successful in 14m0s
Queue Release Build / build-linux (push) Successful in 35m41s
Queue Release Build / build-windows (push) Successful in 28m53s
Queue Release Build / finalize (push) Successful in 2m6s
This commit is contained in:
@@ -39,7 +39,7 @@
|
||||
@if (canManageChannels()) {
|
||||
<button
|
||||
(click)="createChannel('text')"
|
||||
class="rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
|
||||
class="grid h-7 w-7 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
|
||||
title="Create Text Channel"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -98,7 +98,7 @@
|
||||
@if (canManageChannels()) {
|
||||
<button
|
||||
(click)="createChannel('voice')"
|
||||
class="rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
|
||||
class="grid h-7 w-7 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
|
||||
title="Create Voice Channel"
|
||||
>
|
||||
<ng-icon
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@if (server()) {
|
||||
<div class="space-y-3 max-w-xl">
|
||||
<div class="max-w-2xl space-y-3">
|
||||
@if (bannedUsers().length === 0) {
|
||||
<p class="text-sm text-muted-foreground text-center py-8">No banned users</p>
|
||||
} @else {
|
||||
@@ -25,7 +25,7 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="unbanUser(ban)"
|
||||
class="p-2 hover:bg-secondary rounded-lg transition-colors text-muted-foreground hover:text-foreground"
|
||||
class="grid h-8 w-8 place-items-center rounded-lg text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
|
||||
>
|
||||
<ng-icon
|
||||
name="lucideX"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div class="max-w-3xl space-y-6">
|
||||
<section class="rounded-xl border border-border bg-card/40 p-5">
|
||||
<div class="max-w-4xl space-y-5">
|
||||
<section class="rounded-lg border border-border bg-card/40 p-5">
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="rounded-xl bg-primary/10 p-2 text-primary">
|
||||
<div class="grid h-9 w-9 shrink-0 place-items-center rounded-lg bg-primary/10 text-primary">
|
||||
<ng-icon
|
||||
name="lucideBug"
|
||||
class="h-5 w-5"
|
||||
@@ -32,7 +32,7 @@
|
||||
</section>
|
||||
|
||||
<section class="grid gap-3 sm:grid-cols-3">
|
||||
<div class="rounded-xl border border-border bg-secondary/20 p-4">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<div class="flex items-center gap-2 text-muted-foreground">
|
||||
<ng-icon
|
||||
name="lucideClock3"
|
||||
@@ -44,7 +44,7 @@
|
||||
<p class="mt-1 text-xs text-muted-foreground">Last update: {{ lastUpdatedLabel() }}</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-secondary/20 p-4">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<div class="flex items-center gap-2 text-muted-foreground">
|
||||
<ng-icon
|
||||
name="lucideCircleAlert"
|
||||
@@ -56,7 +56,7 @@
|
||||
<p class="mt-1 text-xs text-muted-foreground">Unhandled runtime failures and rejected promises.</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-secondary/20 p-4">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<div class="flex items-center gap-2 text-muted-foreground">
|
||||
<ng-icon
|
||||
name="lucideTriangleAlert"
|
||||
@@ -69,7 +69,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="rounded-xl border border-border bg-card/40 p-5">
|
||||
<section class="rounded-lg border border-border bg-card/40 p-5">
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h5 class="text-sm font-semibold text-foreground">Floating debug console</h5>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="space-y-6 max-w-xl">
|
||||
<div class="max-w-3xl space-y-5">
|
||||
<section>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<ng-icon
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
@if (canKickMembers(member)) {
|
||||
<button
|
||||
(click)="kickMember(member)"
|
||||
class="rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/20 hover:text-destructive"
|
||||
class="grid h-8 w-8 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-destructive/20 hover:text-destructive"
|
||||
title="Kick"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -38,7 +38,7 @@
|
||||
@if (canBanMembers(member)) {
|
||||
<button
|
||||
(click)="banMember(member)"
|
||||
class="rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/20 hover:text-destructive"
|
||||
class="grid h-8 w-8 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-destructive/20 hover:text-destructive"
|
||||
title="Ban"
|
||||
>
|
||||
<ng-icon
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="space-y-6 max-w-xl">
|
||||
<div class="max-w-3xl space-y-5">
|
||||
<!-- Server Endpoints -->
|
||||
<section>
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
@@ -77,7 +77,7 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="setActiveServer(server.id)"
|
||||
class="p-1.5 hover:bg-secondary rounded-lg transition-colors"
|
||||
class="grid h-8 w-8 place-items-center rounded-lg transition-colors hover:bg-secondary"
|
||||
title="Activate"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -90,7 +90,7 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="deactivateServer(server.id)"
|
||||
class="p-1.5 hover:bg-secondary rounded-lg transition-colors"
|
||||
class="grid h-8 w-8 place-items-center rounded-lg transition-colors hover:bg-secondary"
|
||||
title="Deactivate"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -103,7 +103,7 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="removeServer(server.id)"
|
||||
class="p-1.5 hover:bg-destructive/10 rounded-lg transition-colors"
|
||||
class="grid h-8 w-8 place-items-center rounded-lg transition-colors hover:bg-destructive/10"
|
||||
title="Remove"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -139,7 +139,7 @@
|
||||
type="button"
|
||||
(click)="addServer()"
|
||||
[disabled]="!newServerName || !newServerUrl"
|
||||
class="px-3 py-1.5 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed self-end"
|
||||
class="grid h-9 w-9 place-items-center self-end rounded-lg bg-primary text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
<ng-icon
|
||||
name="lucidePlus"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@if (serverData()) {
|
||||
<div class="space-y-5 max-w-xl">
|
||||
<div class="max-w-2xl space-y-5">
|
||||
<section>
|
||||
<h4 class="text-sm font-semibold text-foreground mb-3">Room Settings</h4>
|
||||
@if (!isAdmin()) {
|
||||
@@ -49,7 +49,7 @@
|
||||
<button
|
||||
(click)="togglePrivate()"
|
||||
type="button"
|
||||
class="p-2 rounded-lg transition-colors"
|
||||
class="grid h-9 w-9 place-items-center rounded-lg transition-colors"
|
||||
[class.bg-primary]="isPrivate()"
|
||||
[class.text-primary-foreground]="isPrivate()"
|
||||
[class.bg-secondary]="!isPrivate()"
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<!-- Modal -->
|
||||
<div class="fixed inset-0 z-[91] flex items-center justify-center p-4 pointer-events-none">
|
||||
<div
|
||||
class="pointer-events-auto relative flex w-full max-w-4xl overflow-hidden rounded-xl border border-border bg-card shadow-2xl transition-all duration-200"
|
||||
style="height: min(680px, 85vh)"
|
||||
class="pointer-events-auto relative flex w-full max-w-5xl overflow-hidden rounded-lg border border-border bg-card shadow-lg transition-all duration-200"
|
||||
style="height: min(720px, 88vh)"
|
||||
[class.scale-100]="animating()"
|
||||
[class.opacity-100]="animating()"
|
||||
[class.scale-95]="!animating()"
|
||||
@@ -30,24 +30,25 @@
|
||||
tabindex="-1"
|
||||
>
|
||||
<!-- Side Navigation -->
|
||||
<nav class="flex w-52 flex-shrink-0 flex-col border-r border-border bg-secondary/40">
|
||||
<div class="p-4 border-b border-border">
|
||||
<nav class="flex w-56 flex-shrink-0 flex-col border-r border-border bg-card">
|
||||
<div class="border-b border-border px-3 py-3">
|
||||
<h2 class="text-lg font-semibold text-foreground">Settings</h2>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-y-auto py-2">
|
||||
<!-- Global section -->
|
||||
<p class="px-4 py-1.5 text-[11px] font-semibold text-muted-foreground/70 uppercase tracking-wider">General</p>
|
||||
<p class="px-3 py-1.5 text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">General</p>
|
||||
@for (page of globalPages; track page.id) {
|
||||
<button
|
||||
(click)="navigate(page.id)"
|
||||
type="button"
|
||||
class="w-full flex items-center gap-2.5 px-4 py-2 text-sm transition-colors"
|
||||
[class.bg-primary/10]="activePage() === page.id"
|
||||
[class.text-primary]="activePage() === page.id"
|
||||
class="mx-2 flex w-[calc(100%-1rem)] items-center gap-2.5 rounded-md px-2.5 py-1.5 text-sm transition-colors"
|
||||
[class.bg-secondary]="activePage() === page.id"
|
||||
[class.text-foreground]="activePage() === page.id"
|
||||
[class.font-medium]="activePage() === page.id"
|
||||
[class.text-foreground]="activePage() !== page.id"
|
||||
[class.hover:bg-secondary]="activePage() !== page.id"
|
||||
[class.text-muted-foreground]="activePage() !== page.id"
|
||||
[class.hover:bg-secondary/70]="activePage() !== page.id"
|
||||
[class.hover:text-foreground]="activePage() !== page.id"
|
||||
>
|
||||
<ng-icon
|
||||
[name]="page.icon"
|
||||
@@ -60,12 +61,12 @@
|
||||
<!-- Server section -->
|
||||
@if (manageableRooms().length > 0) {
|
||||
<div class="mt-3 pt-3 border-t border-border">
|
||||
<p class="px-4 py-1.5 text-[11px] font-semibold text-muted-foreground/70 uppercase tracking-wider">Server</p>
|
||||
<p class="px-3 py-1.5 text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">Server</p>
|
||||
|
||||
<!-- Server selector -->
|
||||
<div class="px-3 pb-2">
|
||||
<select
|
||||
class="w-full px-2 py-1.5 bg-secondary rounded-lg border border-border text-foreground text-xs focus:outline-none focus:ring-1 focus:ring-primary"
|
||||
class="w-full rounded-lg border border-border bg-secondary px-3 py-2 text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-primary"
|
||||
[value]="selectedServerId() || ''"
|
||||
(change)="onServerSelect($event)"
|
||||
>
|
||||
@@ -81,12 +82,13 @@
|
||||
<button
|
||||
(click)="navigate(page.id)"
|
||||
type="button"
|
||||
class="w-full flex items-center gap-2.5 px-4 py-2 text-sm transition-colors"
|
||||
[class.bg-primary/10]="activePage() === page.id"
|
||||
[class.text-primary]="activePage() === page.id"
|
||||
class="mx-2 flex w-[calc(100%-1rem)] items-center gap-2.5 rounded-md px-2.5 py-1.5 text-sm transition-colors"
|
||||
[class.bg-secondary]="activePage() === page.id"
|
||||
[class.text-foreground]="activePage() === page.id"
|
||||
[class.font-medium]="activePage() === page.id"
|
||||
[class.text-foreground]="activePage() !== page.id"
|
||||
[class.hover:bg-secondary]="activePage() !== page.id"
|
||||
[class.text-muted-foreground]="activePage() !== page.id"
|
||||
[class.hover:bg-secondary/70]="activePage() !== page.id"
|
||||
[class.hover:text-foreground]="activePage() !== page.id"
|
||||
>
|
||||
<ng-icon
|
||||
[name]="page.icon"
|
||||
@@ -100,15 +102,7 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mt-auto space-y-3 border-t border-border px-4 py-3">
|
||||
<button
|
||||
type="button"
|
||||
(click)="restoreDefaultTheme()"
|
||||
class="w-full rounded-lg border border-destructive/25 bg-destructive/10 px-3 py-2 text-left text-xs font-medium text-destructive transition-colors hover:bg-destructive/15"
|
||||
>
|
||||
Restore default theme
|
||||
</button>
|
||||
|
||||
<div class="mt-auto border-t border-border px-3 py-3">
|
||||
<button
|
||||
type="button"
|
||||
(click)="openThirdPartyLicenses()"
|
||||
@@ -122,7 +116,7 @@
|
||||
<!-- Content -->
|
||||
<div class="flex-1 flex flex-col min-w-0">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between px-6 py-4 border-b border-border flex-shrink-0">
|
||||
<div class="flex items-center justify-between border-b border-border px-5 py-3 flex-shrink-0">
|
||||
<h3 class="text-lg font-semibold text-foreground">
|
||||
@switch (activePage()) {
|
||||
@case ('general') {
|
||||
@@ -164,7 +158,7 @@
|
||||
<button
|
||||
(click)="close()"
|
||||
type="button"
|
||||
class="p-2 hover:bg-secondary rounded-lg transition-colors text-muted-foreground hover:text-foreground"
|
||||
class="grid h-9 w-9 place-items-center rounded-lg text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
|
||||
>
|
||||
<ng-icon
|
||||
name="lucideX"
|
||||
@@ -175,7 +169,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Scrollable Content Area -->
|
||||
<div class="flex-1 overflow-y-auto p-6">
|
||||
<div class="flex-1 overflow-y-auto bg-background px-4 py-4 sm:px-5 sm:py-4">
|
||||
@switch (activePage()) {
|
||||
@case ('general') {
|
||||
<app-general-settings />
|
||||
@@ -184,70 +178,79 @@
|
||||
<app-network-settings />
|
||||
}
|
||||
@case ('theme') {
|
||||
<div class="mx-auto flex h-full max-w-3xl items-center justify-center">
|
||||
<div class="w-full rounded-[1.5rem] border border-border bg-card/90 p-6 shadow-sm">
|
||||
<div class="flex flex-wrap items-start justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.18em] text-primary">Active Theme</p>
|
||||
<h4 class="mt-2 text-xl font-semibold text-foreground">{{ activeThemeName() }}</h4>
|
||||
</div>
|
||||
|
||||
@if (themeStudioMinimized()) {
|
||||
<span class="rounded-full border border-primary/25 bg-primary/10 px-3 py-1 text-xs font-semibold text-primary">Minimized</span>
|
||||
}
|
||||
<div class="max-w-3xl space-y-5">
|
||||
<div class="flex flex-wrap items-start justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.18em] text-primary">Active Theme</p>
|
||||
<h4 class="mt-2 text-lg font-semibold text-foreground">{{ activeThemeName() }}</h4>
|
||||
<p class="mt-2 max-w-2xl text-sm text-muted-foreground">
|
||||
Launch Theme Studio to edit the live draft, inspect themeable regions, or switch to a saved theme.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@if (savedThemesAvailable()) {
|
||||
<div class="mt-5">
|
||||
<label class="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">Saved Theme</label>
|
||||
|
||||
<div class="mt-2 flex flex-wrap gap-2">
|
||||
<select
|
||||
class="min-w-[16rem] flex-1 rounded-full border border-border bg-background px-3 py-2 text-sm font-medium text-foreground outline-none transition-colors focus:border-primary/40 focus:ring-2 focus:ring-primary/15"
|
||||
[value]="selectedSavedTheme()?.fileName || ''"
|
||||
[disabled]="savedThemesBusy() && savedThemes().length === 0"
|
||||
(change)="onSavedThemeSelect($event)"
|
||||
>
|
||||
<option value="">{{ savedThemes().length > 0 ? 'Choose saved theme' : 'No saved themes' }}</option>
|
||||
@for (savedTheme of savedThemes(); track savedTheme.fileName) {
|
||||
<option
|
||||
[value]="savedTheme.fileName"
|
||||
[disabled]="!savedTheme.isValid"
|
||||
>
|
||||
{{ savedTheme.themeName }}
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
(click)="editSelectedSavedTheme()"
|
||||
[disabled]="!selectedSavedTheme()?.isValid || (savedThemesBusy() && savedThemes().length === 0)"
|
||||
class="inline-flex items-center rounded-full border border-border bg-background px-3 py-2 text-sm font-medium text-foreground transition-colors hover:bg-secondary disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
Edit In Studio
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@if (themeStudioMinimized()) {
|
||||
<span class="rounded-full bg-primary/10 px-2.5 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-primary"
|
||||
>Minimized</span
|
||||
>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mt-5 flex flex-wrap gap-2">
|
||||
<button
|
||||
type="button"
|
||||
(click)="openThemeStudio()"
|
||||
class="inline-flex items-center rounded-full bg-primary px-4 py-2 text-sm font-semibold text-primary-foreground transition-colors hover:bg-primary/90"
|
||||
@if (savedThemesAvailable()) {
|
||||
<div class="space-y-2">
|
||||
<label
|
||||
for="settings-saved-theme-select"
|
||||
class="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground"
|
||||
>
|
||||
{{ themeStudioMinimized() ? 'Re-open Theme Studio' : 'Open Theme Studio' }}
|
||||
</button>
|
||||
Saved Theme
|
||||
</label>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
(click)="restoreDefaultTheme()"
|
||||
class="inline-flex items-center rounded-full border border-destructive/25 bg-destructive/10 px-3 py-2 text-sm font-medium text-destructive transition-colors hover:bg-destructive/15"
|
||||
>
|
||||
Restore Default
|
||||
</button>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<select
|
||||
id="settings-saved-theme-select"
|
||||
class="min-w-[16rem] flex-1 rounded-lg border border-border bg-secondary px-3 py-2 text-sm text-foreground outline-none transition-colors focus:border-primary/40 focus:ring-1 focus:ring-primary"
|
||||
[value]="selectedSavedTheme()?.fileName || ''"
|
||||
[disabled]="savedThemesBusy() && savedThemes().length === 0"
|
||||
(change)="onSavedThemeSelect($event)"
|
||||
>
|
||||
<option value="">{{ savedThemes().length > 0 ? 'Choose saved theme' : 'No saved themes' }}</option>
|
||||
@for (savedTheme of savedThemes(); track savedTheme.fileName) {
|
||||
<option
|
||||
[value]="savedTheme.fileName"
|
||||
[disabled]="!savedTheme.isValid"
|
||||
>
|
||||
{{ savedTheme.themeName }}
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
(click)="editSelectedSavedTheme()"
|
||||
[disabled]="!selectedSavedTheme()?.isValid || (savedThemesBusy() && savedThemes().length === 0)"
|
||||
class="inline-flex items-center rounded-lg border border-border bg-secondary px-3 py-2 text-sm font-medium text-foreground transition-colors hover:bg-secondary/80 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
Edit In Studio
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button
|
||||
type="button"
|
||||
(click)="openThemeStudio()"
|
||||
class="inline-flex items-center rounded-lg bg-primary px-4 py-2 text-sm font-semibold text-primary-foreground transition-colors hover:bg-primary/90"
|
||||
>
|
||||
{{ themeStudioMinimized() ? 'Re-open Theme Studio' : 'Open Theme Studio' }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
(click)="restoreDefaultTheme()"
|
||||
class="inline-flex items-center rounded-lg border border-destructive/25 bg-destructive/10 px-3 py-2 text-sm font-medium text-destructive transition-colors hover:bg-destructive/15"
|
||||
>
|
||||
Restore Default
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -304,18 +307,20 @@
|
||||
aria-label="Close third-party licenses"
|
||||
></div>
|
||||
|
||||
<div class="pointer-events-none absolute inset-0 z-[11] flex items-center justify-center p-4 sm:p-6">
|
||||
<div class="pointer-events-auto w-full max-w-2xl max-h-full overflow-hidden rounded-xl border border-border bg-card shadow-2xl">
|
||||
<div class="pointer-events-none absolute inset-0 z-[11] flex justify-center p-4 sm:p-6">
|
||||
<div
|
||||
class="pointer-events-auto flex min-h-0 w-full max-w-2xl self-stretch flex-col overflow-hidden rounded-lg border border-border bg-card shadow-lg"
|
||||
>
|
||||
<div class="flex items-start justify-between gap-4 border-b border-border px-5 py-4">
|
||||
<div>
|
||||
<h4 class="text-base font-semibold text-foreground">Third-party licenses</h4>
|
||||
<p class="mt-1 text-sm text-muted-foreground">License notices for bundled third-party libraries used by the app.</p>
|
||||
<p class="mt-1 text-sm text-muted-foreground">License information for bundled third-party libraries used by the app.</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
(click)="closeThirdPartyLicenses()"
|
||||
class="p-2 hover:bg-secondary rounded-lg transition-colors text-muted-foreground hover:text-foreground"
|
||||
class="grid h-9 w-9 place-items-center rounded-lg text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
|
||||
aria-label="Close third-party licenses"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -325,7 +330,7 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="max-h-[min(70vh,42rem)] overflow-y-auto px-5 py-4 space-y-4">
|
||||
<div class="min-h-0 flex-1 overflow-y-auto px-5 py-4 space-y-4">
|
||||
@for (license of thirdPartyLicenses; track license.id) {
|
||||
<section class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
@@ -340,14 +345,32 @@
|
||||
rel="noopener noreferrer"
|
||||
class="text-xs font-medium text-primary hover:underline underline-offset-4"
|
||||
>
|
||||
Source
|
||||
View license
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<pre
|
||||
class="mt-4 whitespace-pre-wrap break-words rounded-md bg-background/80 px-3 py-2 text-[11px] leading-5 text-muted-foreground"
|
||||
>{{ license.text }}</pre
|
||||
>
|
||||
<div class="mt-4 rounded-md bg-background/80 px-3 py-3">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">Packages</p>
|
||||
<div class="mt-3 flex flex-wrap gap-2">
|
||||
@for (packageName of license.packages; track packageName) {
|
||||
<span class="rounded-full border border-border bg-card px-2.5 py-1 text-[11px] font-medium leading-4 text-foreground">
|
||||
{{ packageName }}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (license.note) {
|
||||
<p class="mt-3 text-xs leading-5 text-muted-foreground">{{ license.note }}</p>
|
||||
}
|
||||
|
||||
<div class="mt-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">License text</p>
|
||||
<pre
|
||||
class="mt-2 whitespace-pre-wrap break-words rounded-md border border-border/70 bg-card px-3 py-3 text-[11px] leading-5 text-muted-foreground"
|
||||
>{{ license.text }}</pre
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -3,42 +3,345 @@ export interface ThirdPartyLicense {
|
||||
name: string;
|
||||
licenseName: string;
|
||||
sourceUrl: string;
|
||||
packages: readonly string[];
|
||||
text: string;
|
||||
note?: string;
|
||||
}
|
||||
|
||||
const toLicenseText = (lines: readonly string[]): string => lines.join('\n');
|
||||
|
||||
const GROUPED_LICENSE_NOTE = 'Grouped by the license declared in the installed package metadata for the packages below. Some upstream packages include their own copyright notices in addition to this standard license text.';
|
||||
|
||||
const MIT_LICENSE_TEXT = toLicenseText([
|
||||
'MIT License',
|
||||
'',
|
||||
'Copyright <YEAR> <COPYRIGHT HOLDER>',
|
||||
'',
|
||||
'Permission is hereby granted, free of charge, to any person obtaining a copy',
|
||||
'of this software and associated documentation files (the "Software"), to deal',
|
||||
'in the Software without restriction, including without limitation the rights',
|
||||
'to use, copy, modify, merge, publish, distribute, sublicense, and/or sell',
|
||||
'copies of the Software, and to permit persons to whom the Software is',
|
||||
'furnished to do so, subject to the following conditions:',
|
||||
'',
|
||||
'The above copyright notice and this permission notice shall be included in all',
|
||||
'copies or substantial portions of the Software.',
|
||||
'',
|
||||
'THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR',
|
||||
'IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,',
|
||||
'FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE',
|
||||
'AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER',
|
||||
'LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,',
|
||||
'OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE',
|
||||
'SOFTWARE.'
|
||||
]);
|
||||
|
||||
const APACHE_LICENSE_TEXT = toLicenseText([
|
||||
'Apache License',
|
||||
'Version 2.0, January 2004',
|
||||
'http://www.apache.org/licenses/',
|
||||
'',
|
||||
'TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION',
|
||||
'',
|
||||
'1. Definitions.',
|
||||
'',
|
||||
'"License" shall mean the terms and conditions for use, reproduction, and distribution as',
|
||||
'defined by Sections 1 through 9 of this document.',
|
||||
'',
|
||||
'"Licensor" shall mean the copyright owner or entity authorized by the copyright owner',
|
||||
'that is granting the License.',
|
||||
'',
|
||||
'"Legal Entity" shall mean the union of the acting entity and all other entities that',
|
||||
'control, are controlled by, or are under common control with that entity. For the',
|
||||
'purposes of this definition, "control" means (i) the power, direct or indirect, to cause',
|
||||
'the direction or management of such entity, whether by contract or otherwise, or (ii)',
|
||||
'ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial',
|
||||
'ownership of such entity.',
|
||||
'',
|
||||
'"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted',
|
||||
'by this License.',
|
||||
'',
|
||||
'"Source" form shall mean the preferred form for making modifications, including but',
|
||||
'not limited to software source code, documentation source, and configuration files.',
|
||||
'',
|
||||
'"Object" form shall mean any form resulting from mechanical transformation or',
|
||||
'translation of a Source form, including but not limited to compiled object code,',
|
||||
'generated documentation, and conversions to other media types.',
|
||||
'',
|
||||
'"Work" shall mean the work of authorship, whether in Source or Object form, made',
|
||||
'available under the License, as indicated by a copyright notice that is included in or',
|
||||
'attached to the Work (an example is provided in the Appendix below).',
|
||||
'',
|
||||
'"Derivative Works" shall mean any work, whether in Source or Object form, that is based',
|
||||
'on (or derived from) the Work and for which the editorial revisions, annotations,',
|
||||
'elaborations, or other modifications represent, as a whole, an original work of',
|
||||
'authorship. For the purposes of this License, Derivative Works shall not include works',
|
||||
'that remain separable from, or merely link (or bind by name) to the interfaces of,',
|
||||
'the Work and Derivative Works thereof.',
|
||||
'',
|
||||
'"Contribution" shall mean any work of authorship, including the original version of the',
|
||||
'Work and any modifications or additions to that Work or Derivative Works thereof, that',
|
||||
'is intentionally submitted to Licensor for inclusion in the Work by the copyright owner',
|
||||
'or by an individual or Legal Entity authorized to submit on behalf of the copyright',
|
||||
'owner. For the purposes of this definition, "submitted" means any form of electronic,',
|
||||
'verbal, or written communication sent to the Licensor or its representatives, including',
|
||||
'but not limited to communication on electronic mailing lists, source code control',
|
||||
'systems, and issue tracking systems that are managed by, or on behalf of, the Licensor',
|
||||
'for the purpose of discussing and improving the Work, but excluding communication that',
|
||||
'is conspicuously marked or otherwise designated in writing by the copyright owner as',
|
||||
'"Not a Contribution."',
|
||||
'',
|
||||
'"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a',
|
||||
'Contribution has been received by Licensor and subsequently incorporated within the',
|
||||
'Work.',
|
||||
'',
|
||||
'2. Grant of Copyright License. Subject to the terms and conditions of this License, each',
|
||||
'Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,',
|
||||
'royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of,',
|
||||
'publicly display, publicly perform, sublicense, and distribute the Work and such',
|
||||
'Derivative Works in Source or Object form.',
|
||||
'',
|
||||
'3. Grant of Patent License. Subject to the terms and conditions of this License, each',
|
||||
'Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,',
|
||||
'royalty-free, irrevocable (except as stated in this section) patent license to make,',
|
||||
'have made, use, offer to sell, sell, import, and otherwise transfer the Work, where',
|
||||
'such license applies only to those patent claims licensable by such Contributor that',
|
||||
'are necessarily infringed by their Contribution(s) alone or by combination of their',
|
||||
'Contribution(s) with the Work to which such Contribution(s) was submitted. If You',
|
||||
'institute patent litigation against any entity (including a cross-claim or counterclaim',
|
||||
'in a lawsuit) alleging that the Work or a Contribution incorporated within the Work',
|
||||
'constitutes direct or contributory patent infringement, then any patent licenses',
|
||||
'granted to You under this License for that Work shall terminate as of the date such',
|
||||
'litigation is filed.',
|
||||
'',
|
||||
'4. Redistribution. You may reproduce and distribute copies of the Work or Derivative',
|
||||
'Works thereof in any medium, with or without modifications, and in Source or Object',
|
||||
'form, provided that You meet the following conditions:',
|
||||
'',
|
||||
' a. You must give any other recipients of the Work or Derivative Works a copy of',
|
||||
' this License; and',
|
||||
'',
|
||||
' b. You must cause any modified files to carry prominent notices stating that You',
|
||||
' changed the files; and',
|
||||
'',
|
||||
' c. You must retain, in the Source form of any Derivative Works that You distribute,',
|
||||
' all copyright, patent, trademark, and attribution notices from the Source form',
|
||||
' of the Work, excluding those notices that do not pertain to any part of the',
|
||||
' Derivative Works; and',
|
||||
'',
|
||||
' d. If the Work includes a "NOTICE" text file as part of its distribution, then any',
|
||||
' Derivative Works that You distribute must include a readable copy of the',
|
||||
' attribution notices contained within such NOTICE file, excluding those notices',
|
||||
' that do not pertain to any part of the Derivative Works, in at least one of',
|
||||
' the following places: within a NOTICE text file distributed as part of the',
|
||||
' Derivative Works; within the Source form or documentation, if provided along',
|
||||
' with the Derivative Works; or, within a display generated by the Derivative',
|
||||
' Works, if and wherever such third-party notices normally appear. The contents',
|
||||
' of the NOTICE file are for informational purposes only and do not modify the',
|
||||
' License. You may add Your own attribution notices within Derivative Works',
|
||||
' that You distribute, alongside or as an addendum to the NOTICE text from the',
|
||||
' Work, provided that such additional attribution notices cannot be construed',
|
||||
' as modifying the License.',
|
||||
'',
|
||||
'You may add Your own copyright statement to Your modifications and may provide',
|
||||
'additional or different license terms and conditions for use, reproduction, or',
|
||||
'distribution of Your modifications, or for any such Derivative Works as a whole,',
|
||||
'provided Your use, reproduction, and distribution of the Work otherwise complies with',
|
||||
'the conditions stated in this License.',
|
||||
'',
|
||||
'5. Submission of Contributions. Unless You explicitly state otherwise, any',
|
||||
'Contribution intentionally submitted for inclusion in the Work by You to the Licensor',
|
||||
'shall be under the terms and conditions of this License, without any additional terms',
|
||||
'or conditions. Notwithstanding the above, nothing herein shall supersede or modify',
|
||||
'the terms of any separate license agreement you may have executed with Licensor',
|
||||
'regarding such Contributions.',
|
||||
'',
|
||||
'6. Trademarks. This License does not grant permission to use the trade names,',
|
||||
'trademarks, service marks, or product names of the Licensor, except as required for',
|
||||
'reasonable and customary use in describing the origin of the Work and reproducing the',
|
||||
'content of the NOTICE file.',
|
||||
'',
|
||||
'7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing,',
|
||||
'Licensor provides the Work (and each Contributor provides its Contributions) on an',
|
||||
'"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or',
|
||||
'implied, including, without limitation, any warranties or conditions of TITLE,',
|
||||
'NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are',
|
||||
'solely responsible for determining the appropriateness of using or redistributing the',
|
||||
'Work and assume any risks associated with Your exercise of permissions under this',
|
||||
'License.',
|
||||
'',
|
||||
'8. Limitation of Liability. In no event and under no legal theory, whether in tort',
|
||||
'(including negligence), contract, or otherwise, unless required by applicable law',
|
||||
'(such as deliberate and grossly negligent acts) or agreed to in writing, shall any',
|
||||
'Contributor be liable to You for damages, including any direct, indirect, special,',
|
||||
'incidental, or consequential damages of any character arising as a result of this',
|
||||
'License or out of the use or inability to use the Work (including but not limited to',
|
||||
'damages for loss of goodwill, work stoppage, computer failure or malfunction, or any',
|
||||
'and all other commercial damages or losses), even if such Contributor has been',
|
||||
'advised of the possibility of such damages.',
|
||||
'',
|
||||
'9. Accepting Warranty or Additional Liability. While redistributing the Work or',
|
||||
'Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance',
|
||||
'of support, warranty, indemnity, or other liability obligations and/or rights',
|
||||
'consistent with this License. However, in accepting such obligations, You may act',
|
||||
'only on Your own behalf and on Your sole responsibility, not on behalf of any other',
|
||||
'Contributor, and only if You agree to indemnify, defend, and hold each Contributor',
|
||||
'harmless for any liability incurred by, or claims asserted against, such Contributor',
|
||||
'by reason of your accepting any such warranty or additional liability.',
|
||||
'',
|
||||
'END OF TERMS AND CONDITIONS'
|
||||
]);
|
||||
|
||||
const WAVESURFER_BSD_LICENSE_TEXT = toLicenseText([
|
||||
'BSD 3-Clause License',
|
||||
'',
|
||||
'Copyright (c) 2012-2023, katspaugh and contributors',
|
||||
'All rights reserved.',
|
||||
'',
|
||||
'Redistribution and use in source and binary forms, with or without modification, are permitted provided',
|
||||
'that the following conditions are met:',
|
||||
'',
|
||||
'* Redistributions of source code must retain the above copyright notice, this list of conditions and',
|
||||
' the following disclaimer.',
|
||||
'',
|
||||
'* Redistributions in binary form must reproduce the above copyright notice, this list of conditions',
|
||||
' and the following disclaimer in the documentation and/or other materials provided with the',
|
||||
' distribution.',
|
||||
'',
|
||||
'* Neither the name of the copyright holder nor the names of its contributors may be used to endorse',
|
||||
' or promote products derived from this software without specific prior written permission.',
|
||||
'',
|
||||
'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR',
|
||||
'IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND',
|
||||
'FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR',
|
||||
'CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL',
|
||||
'DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,',
|
||||
'DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER',
|
||||
'IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT',
|
||||
'OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'
|
||||
]);
|
||||
|
||||
const ISC_LICENSE_TEXT = toLicenseText([
|
||||
'ISC License',
|
||||
'',
|
||||
'Copyright <YEAR> <OWNER>',
|
||||
'',
|
||||
'Permission to use, copy, modify, and/or distribute this software for any purpose',
|
||||
'with or without fee is hereby granted, provided that the above copyright notice',
|
||||
'and this permission notice appear in all copies.',
|
||||
'',
|
||||
'THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH',
|
||||
'REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND',
|
||||
'FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,',
|
||||
'OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,',
|
||||
'DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS',
|
||||
'ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS',
|
||||
'SOFTWARE.'
|
||||
]);
|
||||
|
||||
const ZERO_BSD_LICENSE_TEXT = toLicenseText([
|
||||
'Zero-Clause BSD',
|
||||
'',
|
||||
'Permission to use, copy, modify, and/or distribute this software for any purpose',
|
||||
'with or without fee is hereby granted.',
|
||||
'',
|
||||
'THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH',
|
||||
'REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND',
|
||||
'FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,',
|
||||
'OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,',
|
||||
'DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS',
|
||||
'ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS',
|
||||
'SOFTWARE.'
|
||||
]);
|
||||
|
||||
export const THIRD_PARTY_LICENSES: ThirdPartyLicense[] = [
|
||||
{
|
||||
id: 'wavesurfer-js',
|
||||
name: 'wavesurfer.js',
|
||||
id: 'mit',
|
||||
name: 'MIT-licensed packages',
|
||||
licenseName: 'MIT License',
|
||||
sourceUrl: 'https://opensource.org/licenses/MIT',
|
||||
packages: [
|
||||
'@angular/common',
|
||||
'@angular/compiler',
|
||||
'@angular/core',
|
||||
'@angular/forms',
|
||||
'@angular/platform-browser',
|
||||
'@angular/router',
|
||||
'@codemirror/commands',
|
||||
'@codemirror/lang-json',
|
||||
'@codemirror/language',
|
||||
'@codemirror/state',
|
||||
'@codemirror/theme-one-dark',
|
||||
'@codemirror/view',
|
||||
'codemirror',
|
||||
'@ng-icons/core',
|
||||
'@ngrx/effects',
|
||||
'@ngrx/entity',
|
||||
'@ngrx/store',
|
||||
'@ngrx/store-devtools',
|
||||
'auto-launch',
|
||||
'clsx',
|
||||
'cytoscape',
|
||||
'electron-updater',
|
||||
'mermaid',
|
||||
'ngx-remark',
|
||||
'prismjs',
|
||||
'remark',
|
||||
'remark-breaks',
|
||||
'remark-gfm',
|
||||
'simple-peer',
|
||||
'sql.js',
|
||||
'typeorm',
|
||||
'uuid'
|
||||
],
|
||||
text: MIT_LICENSE_TEXT,
|
||||
note: GROUPED_LICENSE_NOTE
|
||||
},
|
||||
{
|
||||
id: 'apache-2-0',
|
||||
name: 'Apache-licensed packages',
|
||||
licenseName: 'Apache License 2.0',
|
||||
sourceUrl: 'https://www.apache.org/licenses/LICENSE-2.0',
|
||||
packages: [
|
||||
'rxjs',
|
||||
'@timephy/rnnoise-wasm',
|
||||
'class-variance-authority',
|
||||
'reflect-metadata'
|
||||
],
|
||||
text: APACHE_LICENSE_TEXT,
|
||||
note: GROUPED_LICENSE_NOTE
|
||||
},
|
||||
{
|
||||
id: 'bsd-3-clause',
|
||||
name: 'BSD-licensed packages',
|
||||
licenseName: 'BSD 3-Clause License',
|
||||
sourceUrl: 'https://github.com/katspaugh/wavesurfer.js/blob/main/LICENSE',
|
||||
text: [
|
||||
'BSD 3-Clause License',
|
||||
'',
|
||||
'Copyright (c) 2012-2023, katspaugh and contributors',
|
||||
'All rights reserved.',
|
||||
'',
|
||||
'Redistribution and use in source and binary forms, with or without modification, are permitted provided',
|
||||
'that the following conditions are met:',
|
||||
'',
|
||||
'* Redistributions of source code must retain the above copyright notice, this list of conditions and',
|
||||
' the following disclaimer.',
|
||||
'',
|
||||
'* Redistributions in binary form must reproduce the above copyright notice, this list of conditions',
|
||||
' and the following disclaimer in the documentation and/or other materials provided with the',
|
||||
' distribution.',
|
||||
'',
|
||||
'* Neither the name of the copyright holder nor the names of its contributors may be used to endorse',
|
||||
' or promote products derived from this software without specific prior written permission.',
|
||||
'',
|
||||
'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR',
|
||||
'IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND',
|
||||
'FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR',
|
||||
'CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL',
|
||||
'DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,',
|
||||
'DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER',
|
||||
'IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT',
|
||||
'OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'
|
||||
].join('\n')
|
||||
sourceUrl: 'https://opensource.org/licenses/BSD-3-Clause',
|
||||
packages: [
|
||||
'wavesurfer.js'
|
||||
],
|
||||
text: WAVESURFER_BSD_LICENSE_TEXT,
|
||||
note: 'License text reproduced from the bundled wavesurfer.js package license.'
|
||||
},
|
||||
{
|
||||
id: 'isc',
|
||||
name: 'ISC-licensed packages',
|
||||
licenseName: 'ISC License',
|
||||
sourceUrl: 'https://opensource.org/license/isc-license-txt',
|
||||
packages: [
|
||||
'@ng-icons/lucide'
|
||||
],
|
||||
text: ISC_LICENSE_TEXT,
|
||||
note: GROUPED_LICENSE_NOTE
|
||||
},
|
||||
{
|
||||
id: '0bsd',
|
||||
name: '0BSD-licensed packages',
|
||||
licenseName: '0BSD License',
|
||||
sourceUrl: 'https://opensource.org/license/0bsd',
|
||||
packages: [
|
||||
'tslib'
|
||||
],
|
||||
text: ZERO_BSD_LICENSE_TEXT,
|
||||
note: GROUPED_LICENSE_NOTE
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="space-y-6">
|
||||
<section class="rounded-xl border border-border bg-card/60 p-5">
|
||||
<section class="rounded-lg border border-border bg-card/60 p-5">
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div>
|
||||
<h4 class="text-base font-semibold text-foreground">Desktop app updates</h4>
|
||||
@@ -15,27 +15,27 @@
|
||||
</section>
|
||||
|
||||
@if (!isElectron) {
|
||||
<section class="rounded-xl border border-border bg-secondary/30 p-5">
|
||||
<section class="rounded-lg border border-border bg-secondary/30 p-5">
|
||||
<p class="text-sm text-muted-foreground">Automatic updates are only available in the packaged Electron desktop app.</p>
|
||||
</section>
|
||||
} @else {
|
||||
<section class="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||||
<div class="rounded-xl border border-border bg-secondary/20 p-4">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">Installed</p>
|
||||
<p class="mt-2 text-lg font-semibold text-foreground">{{ state().currentVersion }}</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-secondary/20 p-4">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">Latest in manifest</p>
|
||||
<p class="mt-2 text-lg font-semibold text-foreground">{{ state().latestVersion || 'Unknown' }}</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-secondary/20 p-4">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">Target version</p>
|
||||
<p class="mt-2 text-lg font-semibold text-foreground">{{ state().targetVersion || 'Automatic' }}</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-secondary/20 p-4">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">Last checked</p>
|
||||
<p class="mt-2 text-sm font-medium text-foreground">
|
||||
{{ state().lastCheckedAt ? (state().lastCheckedAt | date: 'medium') : 'Not checked yet' }}
|
||||
@@ -43,7 +43,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="space-y-4 rounded-xl border border-border bg-card/60 p-5">
|
||||
<section class="space-y-4 rounded-lg border border-border bg-card/60 p-5">
|
||||
<div>
|
||||
<h5 class="text-sm font-semibold text-foreground">Update policy</h5>
|
||||
<p class="mt-1 text-sm text-muted-foreground">
|
||||
@@ -81,7 +81,7 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-secondary/20 p-4">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-sm font-medium text-foreground">Status</p>
|
||||
<p class="mt-1 text-sm text-muted-foreground">
|
||||
{{ state().statusMessage || 'Waiting for release information from the active server.' }}
|
||||
@@ -109,7 +109,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="space-y-4 rounded-xl border border-border bg-card/60 p-5">
|
||||
<section class="space-y-4 rounded-lg border border-border bg-card/60 p-5">
|
||||
<div>
|
||||
<h5 class="text-sm font-semibold text-foreground">Manifest URL priority</h5>
|
||||
<p class="mt-1 text-sm text-muted-foreground">
|
||||
@@ -118,7 +118,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-secondary/20 p-4 text-sm text-muted-foreground">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4 text-sm text-muted-foreground">
|
||||
<p class="font-medium text-foreground">
|
||||
{{ isUsingConnectedServerDefaults() ? 'Using connected server defaults' : 'Using saved manifest URLs' }}
|
||||
</p>
|
||||
@@ -160,7 +160,7 @@
|
||||
</section>
|
||||
|
||||
@if (state().serverBlocked) {
|
||||
<section class="rounded-xl border border-red-500/30 bg-red-500/10 p-5">
|
||||
<section class="rounded-lg border border-red-500/30 bg-red-500/10 p-5">
|
||||
<h5 class="text-sm font-semibold text-foreground">Server update required</h5>
|
||||
<p class="mt-1 text-sm text-muted-foreground">{{ state().serverBlockMessage }}</p>
|
||||
<div class="mt-3 grid gap-2 text-xs text-muted-foreground sm:grid-cols-2">
|
||||
@@ -177,7 +177,7 @@
|
||||
</section>
|
||||
}
|
||||
|
||||
<section class="rounded-xl border border-border bg-secondary/20 p-4">
|
||||
<section class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">Resolved manifest URL</p>
|
||||
<p class="mt-2 break-all text-sm text-muted-foreground">{{ state().manifestUrl || 'No working manifest URL has been resolved yet.' }}</p>
|
||||
</section>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="space-y-6 max-w-xl">
|
||||
<div class="max-w-3xl space-y-5">
|
||||
<!-- Devices -->
|
||||
<section>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="goBack()"
|
||||
class="p-2 hover:bg-secondary rounded-lg transition-colors"
|
||||
class="grid h-9 w-9 place-items-center rounded-lg transition-colors hover:bg-secondary"
|
||||
title="Go back"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -102,7 +102,7 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="setActiveServer(server.id)"
|
||||
class="p-2 hover:bg-secondary rounded-lg transition-colors"
|
||||
class="grid h-9 w-9 place-items-center rounded-lg transition-colors hover:bg-secondary"
|
||||
title="Activate"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -115,7 +115,7 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="deactivateServer(server.id)"
|
||||
class="p-2 hover:bg-secondary rounded-lg transition-colors"
|
||||
class="grid h-9 w-9 place-items-center rounded-lg transition-colors hover:bg-secondary"
|
||||
title="Deactivate"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -128,7 +128,7 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="removeServer(server.id)"
|
||||
class="p-2 hover:bg-destructive/10 rounded-lg transition-colors"
|
||||
class="grid h-9 w-9 place-items-center rounded-lg transition-colors hover:bg-destructive/10"
|
||||
title="Remove server"
|
||||
>
|
||||
<ng-icon
|
||||
@@ -164,7 +164,7 @@
|
||||
type="button"
|
||||
(click)="addServer()"
|
||||
[disabled]="!newServerName || !newServerUrl"
|
||||
class="px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed self-end"
|
||||
class="grid h-10 w-10 place-items-center self-end rounded-lg bg-primary text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
<ng-icon
|
||||
name="lucidePlus"
|
||||
|
||||
Reference in New Issue
Block a user