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 @@
+
+
+ {{ tag.name }}
+
+
+
+
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