82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
import { Injectable, computed, signal } from '@angular/core';
|
|
import { ThemeDef, THEMES } from '../models/theme.model';
|
|
import { I18nService } from './i18n.service';
|
|
|
|
export interface ThemeCategory {
|
|
key: string;
|
|
label: string;
|
|
emoji?: string;
|
|
}
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class ThemesService {
|
|
private readonly list = signal<ThemeDef[]>(THEMES);
|
|
// Active theme slug derived from router (set externally by the theme bar)
|
|
readonly activeSlug = signal<string>('trending');
|
|
// Controls whether the themes nav should show all themes or only a subset (e.g., 8)
|
|
readonly showAll = signal<boolean>(false);
|
|
|
|
constructor(private i18n: I18nService) {}
|
|
|
|
themes() { return this.list(); }
|
|
|
|
setShowAll(v: boolean) { this.showAll.set(!!v); }
|
|
toggleShowAll() { this.showAll.update(x => !x); }
|
|
|
|
bySlug(slug: string | null | undefined): ThemeDef | undefined {
|
|
if (!slug) return undefined;
|
|
const s = String(slug).toLowerCase();
|
|
return this.list().find(t => t.slug === s);
|
|
}
|
|
|
|
label(t: ThemeDef): string {
|
|
// Full label including emoji
|
|
const v = this.i18nLabel(t);
|
|
return `${t.emoji} ${v}`;
|
|
}
|
|
|
|
// Label without emoji, i18n-aware
|
|
i18nLabel(t: ThemeDef): string {
|
|
const key = `theme.${t.slug}`;
|
|
const v = this.i18n.t(key);
|
|
return v && v !== key ? v : t.label;
|
|
}
|
|
|
|
tokensFor(slug: string): string[] {
|
|
const t = this.bySlug(slug);
|
|
if (!t) return [];
|
|
const base = t.tokens && t.tokens.length ? t.tokens : [t.label];
|
|
return base;
|
|
}
|
|
|
|
// Best-effort suggested categories per theme (static for now)
|
|
categoriesFor(slug: string): ThemeCategory[] {
|
|
switch (slug) {
|
|
case 'finance-crypto':
|
|
return [
|
|
{ key: 'stock-market', label: 'Stock Market', emoji: '📈' },
|
|
{ key: 'crypto', label: 'Crypto', emoji: '🪙' },
|
|
{ key: 'economy', label: 'Economy', emoji: '🏦' },
|
|
];
|
|
case 'gaming':
|
|
return [
|
|
{ key: 'esports', label: 'Esports', emoji: '🎮' },
|
|
{ key: 'retro', label: 'Retro', emoji: '🕹️' },
|
|
{ key: 'fps', label: 'FPS', emoji: '🎯' },
|
|
];
|
|
case 'news':
|
|
return [
|
|
{ key: 'politics', label: 'Politics', emoji: '🏛️' },
|
|
{ key: 'world', label: 'World', emoji: '🌍' },
|
|
{ key: 'tech', label: 'Tech', emoji: '🧠' },
|
|
];
|
|
default:
|
|
return [
|
|
{ key: 'featured', label: 'Featured', emoji: '⭐' },
|
|
{ key: 'popular', label: 'Popular', emoji: '🔥' },
|
|
{ key: 'recent', label: 'Recent', emoji: '🕒' },
|
|
];
|
|
}
|
|
}
|
|
}
|