Files
Portfolio-Game/frontend/app/components/feature/ProjectListItem.vue
skycel 2b043674ca Add skill projects modal with Headless UI (Story 2.5)
- Add GET /skills/{slug}/projects endpoint with level progression
- Install @headlessui/vue for accessible modal
- Create SkillProjectsModal with Dialog component:
  - Focus trap and keyboard navigation (automatic)
  - Fade + scale transitions with backdrop blur
  - prefers-reduced-motion support
- Create ProjectListItem with thumbnail and level display
- Integrate modal in competences.vue page
- Add translations for related projects UI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 10:44:45 +01:00

69 lines
2.1 KiB
Vue

<template>
<NuxtLink
:to="localePath(`/projets/${project.slug}`)"
class="block bg-sky-dark/50 rounded-lg p-4 hover:bg-sky-dark transition-colors group"
@click="emit('click')"
>
<div class="flex items-start gap-4">
<!-- Image thumbnail -->
<div v-if="project.image" class="shrink-0 w-20 h-14 rounded overflow-hidden bg-sky-text/5">
<NuxtImg
:src="project.image"
:alt="project.title"
format="webp"
width="80"
height="56"
class="w-full h-full object-cover"
/>
</div>
<!-- Content -->
<div class="flex-1 min-w-0">
<h4 class="font-ui font-medium text-sky-text group-hover:text-sky-accent transition-colors truncate">
{{ project.title }}
</h4>
<p class="text-sm text-sky-text/60 line-clamp-2 mt-1">
{{ project.short_description }}
</p>
</div>
<!-- Level progress -->
<div class="shrink-0 text-right">
<div class="text-xs text-sky-text/40 font-ui">{{ $t('skills.level') }}</div>
<div class="flex items-center gap-1 mt-1">
<span class="text-sky-text text-sm">{{ project.level_before }}</span>
<span class="text-sky-accent"></span>
<span class="text-sky-accent font-semibold text-sm">{{ project.level_after }}</span>
</div>
<div class="text-xs text-sky-accent/80 font-medium">
({{ levelProgress }})
</div>
</div>
</div>
<!-- Level description if available -->
<p v-if="project.level_description" class="mt-3 text-xs text-sky-text/50 italic border-t border-sky-text/10 pt-3">
{{ project.level_description }}
</p>
</NuxtLink>
</template>
<script setup lang="ts">
import type { SkillProject } from '~/composables/useFetchSkillProjects'
const props = defineProps<{
project: SkillProject
}>()
const emit = defineEmits<{
click: []
}>()
const localePath = useLocalePath()
const levelProgress = computed(() => {
const diff = props.project.level_after - props.project.level_before
return diff > 0 ? `+${diff}` : diff.toString()
})
</script>