feat(01-02): create useProjects() composable with i18n support

- useProjects() returns projects, featuredProjects, filterByCategory, search, findById
- Added title/description/longDescription fields to Project interface
- Uses Nuxt auto-imports (computed, useI18n, Ref)
- i18n keys follow projects.${id}.title pattern
This commit is contained in:
2026-04-08 14:59:29 +02:00
parent d139605704
commit cfb3fce2e1
3 changed files with 80 additions and 32 deletions
+51
View File
@@ -0,0 +1,51 @@
import { projects as projectsData } from '~/data/projects'
import type { Project } from '~~/shared/types'
/**
* Composable for accessing and filtering project data with i18n support.
* Titles, descriptions, and long descriptions are resolved via i18n keys.
*/
export function useProjects() {
const { t } = useI18n()
const projects = computed<Project[]>(() =>
projectsData.map((p) => ({
...p,
title: t(`projects.${p.id}.title`),
description: t(`projects.${p.id}.description`),
longDescription: t(`projects.${p.id}.longDescription`) || undefined,
})),
)
const featuredProjects = computed(() => projects.value.filter((p) => p.featured))
function filterByCategory(category: string) {
return computed(() => projects.value.filter((p) => p.category === category))
}
function search(query: Ref<string> | string) {
return computed(() => {
const q = typeof query === 'string' ? query : query.value
if (!q) return projects.value
const lower = q.toLowerCase()
return projects.value.filter(
(p) =>
p.title.toLowerCase().includes(lower) ||
p.description.toLowerCase().includes(lower) ||
p.technologies.some((tech) => tech.toLowerCase().includes(lower)),
)
})
}
function findById(id: string) {
return computed(() => projects.value.find((p) => p.id === id))
}
return {
projects,
featuredProjects,
filterByCategory,
search,
findById,
}
}