diff --git a/components/service/base/Index.vue b/components/service/base/Index.vue index 31e8c52..87779c4 100644 --- a/components/service/base/Index.vue +++ b/components/service/base/Index.vue @@ -23,6 +23,13 @@ {{ description }}

+ diff --git a/components/service/base/Tag.vue b/components/service/base/Tag.vue new file mode 100644 index 0000000..58f588b --- /dev/null +++ b/components/service/base/Tag.vue @@ -0,0 +1,30 @@ + + + diff --git a/server/utils/config.ts b/server/utils/config.ts index 618f798..9d7b063 100644 --- a/server/utils/config.ts +++ b/server/utils/config.ts @@ -2,14 +2,26 @@ import crypto from 'node:crypto' import yaml from 'yaml' import defu from 'defu' import { ZodError, z } from 'zod' -import type { CompleteConfig, Service } from '~/types' +import type { CompleteConfig, Service, Tag } from '~/types' type DraftService = Omit -function determineServiceId(items: DraftService[]): Service[] { +type TagMap = Map + +function determineService(items: DraftService[], tags: TagMap): Service[] { return items.map((item) => ({ - id: crypto.randomUUID(), ...item, + id: crypto.randomUUID(), + tags: (item.tags || []).map((tag): Tag => { + if (typeof tag === 'string') { + return tags.get(tag) || { + name: tag, + color: 'blue', + } + } + + return tag + }), })) } @@ -22,6 +34,7 @@ export function getDefaultConfig(): CompleteConfig { behaviour: { target: '_blank', }, + tags: [], services: [], } } @@ -40,6 +53,11 @@ export function validateConfigSchema(config: any) { color: z.string().optional(), }) + const tag = z.object({ + name: z.string(), + color: z.string(), + }) + const service = z.object({ title: z.string().nullish().optional(), description: z.string().nullish().optional(), @@ -57,6 +75,7 @@ export function validateConfigSchema(config: any) { lang: z.string().optional(), theme: z.string().optional(), checkUpdates: z.boolean().optional(), + tags: z.array(tag).optional(), services: z.union([ z.array(service), z.record(z.array(service)), @@ -66,6 +85,14 @@ export function validateConfigSchema(config: any) { return schema.parse(config) } +function createTagMap(tags: Tag[]): TagMap { + return tags.reduce((acc, tag) => { + acc.set(tag.name, tag) + + return acc + }, new Map()) +} + export async function loadLocalConfig(): Promise { const defaultConfig = getDefaultConfig() const storage = useStorage('data') @@ -79,12 +106,13 @@ export async function loadLocalConfig(): Promise { const raw = await storage.getItem(file) const config = yaml.parse(raw || '') || {} const services: CompleteConfig['services'] = [] + const tags: TagMap = createTagMap(config.tags || []) validateConfigSchema(config) if (Array.isArray(config.services)) { services.push({ - items: determineServiceId(config.services), + items: determineService(config.services, tags), }) } else { const entries = Object.entries(config.services || []) @@ -92,7 +120,7 @@ export async function loadLocalConfig(): Promise { for (const [title, items] of entries) { services.push({ title, - items: determineServiceId(items), + items: determineService(items, tags), }) } } diff --git a/tailwind.config.ts b/tailwind.config.ts index 714cd62..62667a6 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -2,6 +2,12 @@ import type { Config } from 'tailwindcss' export default >{ darkMode: 'class', + safelist: [ + { + pattern: /(bg|text)-./, + variants: ['dark'], + }, + ], theme: { extend: { colors: { diff --git a/types/config.d.ts b/types/config.d.ts index 63bfa14..71b0386 100644 --- a/types/config.d.ts +++ b/types/config.d.ts @@ -5,6 +5,11 @@ export interface ServicesGroup { items: Service[] } +export interface Tag { + name: string + color: 'red' | 'orange' | 'amber' | 'yellow' | 'lime' | 'green' | 'emerald' | 'teal' | 'cyan' | 'sky' | 'blue' | 'indigo' | 'violet' | 'purple' | 'fuchsia' | 'pink' | 'rose' +} + export interface Behaviour { target?: '_blank' | '_self' | '_parent' | '_top' } @@ -14,6 +19,7 @@ export interface Config { lang: 'en' | 'ru' theme?: 'system' | 'light' | 'dark' | 'deep' | 'sepia' behaviour?: Behaviour + tags: Tag[] services: ServicesGroup[] checkUpdates: boolean } diff --git a/types/services.d.ts b/types/services.d.ts index 2e4fbf2..a266911 100644 --- a/types/services.d.ts +++ b/types/services.d.ts @@ -1,3 +1,5 @@ +import type { Tag } from '~/types/config' + export interface ServiceStatus { enabled?: boolean interval?: number @@ -20,6 +22,7 @@ export interface Service { target?: '_blank' | '_self' | '_parent' | '_top' icon?: ServiceIcon status?: ServiceStatus + tags: Tag['name'][] | Tag[] options?: Record secrets?: Record server?: Record