feat: add workspace view command service and related types

This commit is contained in:
4gray committed 2026-04-22 22:22:22 +02:00
1 parent a5b26065c9
commit 8d6a387a9f
5 files changed
+127

No files matched your search

+1
View File
@@ -1,5 +1,6 @@
export * from './lib/components/category-view/category-view.component';
export * from './lib/components/content-card/content-card.component';
export * from './lib/components/content-rail-shell/content-rail-shell.component';
export * from './lib/components/favorites-layout/favorites-layout.component';
export * from './lib/components/global-favorites-list/global-favorites-list.component';
export * from './lib/components/grid-list/grid-list.component';
@@ -86,3 +86,11 @@ export function buildCollectionUid(
): string {
return `${sourceType}::${playlistId}::${sourceItemId}`;
}
export function buildXtreamCollectionUid(
playlistId: string,
contentType: CollectionContentType,
xtreamId: string | number
): string {
return buildCollectionUid('xtream', playlistId, `${contentType}:${xtreamId}`);
}
@@ -1,4 +1,5 @@
import { Injectable, signal } from '@angular/core';
import { WorkspaceHeaderCommandMetadata } from './workspace-view-command.types';
export interface WorkspaceHeaderAction {
id: string;
@@ -6,6 +7,7 @@ export interface WorkspaceHeaderAction {
tooltipKey: string;
ariaLabelKey: string;
run: () => void;
palette?: WorkspaceHeaderCommandMetadata;
}
@Injectable({ providedIn: 'root' })
@@ -0,0 +1,63 @@
import { Injectable, computed, inject, signal } from '@angular/core';
import {
WorkspaceHeaderAction,
WorkspaceHeaderContextService,
} from './workspace-header-context.service';
import { WorkspaceCommandContribution } from './workspace-view-command.types';
interface RegisteredWorkspaceCommand {
token: symbol;
command: WorkspaceCommandContribution;
}
@Injectable({ providedIn: 'root' })
export class WorkspaceViewCommandService {
private readonly headerContext = inject(WorkspaceHeaderContextService);
private readonly registeredCommands = signal<RegisteredWorkspaceCommand[]>(
[]
);
readonly commands = computed<readonly WorkspaceCommandContribution[]>(() => {
const commands = this.registeredCommands().map(
(entry) => entry.command
);
const headerAction = this.headerContext.action();
const headerCommand = headerAction
? this.toHeaderCommand(headerAction)
: null;
return headerCommand ? [headerCommand, ...commands] : commands;
});
registerCommand(command: WorkspaceCommandContribution): () => void {
const token = Symbol(command.id);
this.registeredCommands.update((entries) => [...entries, { token, command }]);
return () => {
this.registeredCommands.update((entries) =>
entries.filter((entry) => entry.token !== token)
);
};
}
private toHeaderCommand(
action: WorkspaceHeaderAction
): WorkspaceCommandContribution {
const palette = action.palette;
return {
id: action.id,
group: palette?.group ?? 'view',
icon: action.icon,
labelKey: palette?.labelKey ?? action.tooltipKey,
labelParams: palette?.labelParams,
descriptionKey: palette?.descriptionKey,
descriptionParams: palette?.descriptionParams,
priority: palette?.priority ?? 0,
keywords: palette?.keywords,
visible: palette?.visible,
enabled: palette?.enabled,
run: () => action.run(),
};
}
}
@@ -0,0 +1,53 @@
export type WorkspaceCommandGroup = 'view' | 'playlist' | 'global';
export interface WorkspaceCommandActionContext {
query: string;
}
export type WorkspaceCommandParams = Record<string, string | number>;
export type WorkspaceCommandValue<T> = T | (() => T);
export interface WorkspaceCommandMetadata {
labelKey: string;
labelParams?:
| WorkspaceCommandParams
| (() => WorkspaceCommandParams | undefined);
descriptionKey?: string;
descriptionParams?:
| WorkspaceCommandParams
| (() => WorkspaceCommandParams | undefined);
priority?: number;
keywords?: readonly string[] | (() => readonly string[] | undefined);
visible?: boolean | (() => boolean | undefined);
enabled?: boolean | (() => boolean | undefined);
}
export interface WorkspaceCommandContribution extends WorkspaceCommandMetadata {
id: string;
group: WorkspaceCommandGroup;
icon: string;
run: (context: WorkspaceCommandActionContext) => void;
}
export interface WorkspaceHeaderCommandMetadata extends WorkspaceCommandMetadata {
group?: WorkspaceCommandGroup;
}
export interface WorkspaceResolvedCommandItem {
id: string;
group: WorkspaceCommandGroup;
icon: string;
label: string;
description: string;
keywords: readonly string[];
priority: number;
visible: boolean;
enabled: boolean;
run: (context: WorkspaceCommandActionContext) => void;
}
export interface WorkspaceCommandSelection {
commandId: string;
query: string;
}