Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions app/components/HeroItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
:key="feature.title"
:to="searchItem(feature?.search)"
:class="getGridClass(index)"
@click="addTypeFilter(feature?.search)"
@click="addTypeFilter(feature?.search as typeFilter)"
>
<div class="absolute inset-0">
<NuxtImg
Expand All @@ -31,16 +31,17 @@
<div v-else>No data available</div>
</template>

<script setup="ts">
<script setup lang="ts">
import { useEntitesStore } from '../stores/entites.store'
import type { typeFilter } from '../types/database.types'

const entitesStore = useEntitesStore()

const { data } = await useAsyncData('home-hero', () => queryCollection('pages').first())

const getGridClass = (index) => {
const getGridClass = (index: number) => {
const baseClass = 'relative rounded-3xl overflow-hidden'
const gridClasses = {
const gridClasses: Record<number, string> = {
0: 'row-span-1 col-start-1 row-start-1 mt-24',
1: 'row-span-3 col-start-2 row-start-1',
2: 'row-span-1 col-start-3 row-start-1 mt-24',
Expand All @@ -50,16 +51,16 @@
return `${baseClass} ${gridClasses[index] || ''}`
}

const addTypeFilter = async (filterToAdd) => {
entitesStore.typeFilter = filterToAdd
await entitesStore.searchEntites()
const addTypeFilter = (filterToAdd: typeFilter) => {
if (filterToAdd !== ('genealogie' as typeFilter)) {
entitesStore.typeFilter = filterToAdd
}
}

const searchItem = (item) => {
const searchItem = (item: string) => {
if (item === 'genealogie') {
return '/genealogie'
}

return '#search'
}
</script>
30 changes: 19 additions & 11 deletions app/components/SearchItem.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div id="search" class="pt-30 pb-50 max-w-7xl mx-auto">
<h1 class="text-3xl font-bold mb-6">Encyclopédie</h1>
<div id="search" class="pt-30 pb-10 max-w-7xl mx-auto">
<h1 class="font-heading text-5xl mb-6">Encyclopédie</h1>

<div class="mb-6 space-y-4">
<input
Expand All @@ -14,35 +14,35 @@
<UButton
:color="typeFilter === 'tous' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'tous'"
@click="addTypeFilter('tous')"
>
Tous
</UButton>
<UButton
:color="typeFilter === 'personnage' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'personnage'"
@click="addTypeFilter('personnage')"
>
Personnages
</UButton>
<UButton
:color="typeFilter === 'lieu' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'lieu'"
@click="addTypeFilter('lieu')"
>
Lieux
</UButton>
<UButton
:color="typeFilter === 'creature' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'creature'"
@click="addTypeFilter('creature')"
>
Créatures
</UButton>
<UButton
:color="typeFilter === 'peuple' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'peuple'"
@click="addTypeFilter('peuple')"
>
Peuples
</UButton>
Expand Down Expand Up @@ -102,18 +102,19 @@
</NuxtLink>
</div>

<div ref="loadMoreTrigger" class="h-20 flex items-center justify-center">
<div ref="loadMoreTrigger" class="h-10 flex items-center justify-center">
<UIcon
v-if="isLoading"
name="i-heroicons-arrow-path"
class="w-8 h-8 animate-spin text-primary"
class="w-8 h-10 animate-spin text-primary"
/>
</div>
</div>
</template>

<script setup lang="ts">
import { useEntitesStore } from '../stores/entites.store'
import type { typeFilter } from '../types/database.types'
import { storeToRefs } from 'pinia'

const entitesStore = useEntitesStore()
Expand All @@ -123,12 +124,19 @@
const loadMoreTrigger = ref<HTMLElement | null>(null)
const isVisible = ref(false)

const addTypeFilter = (filterToAdd: typeFilter) => {
if (filterToAdd !== ('genealogie' as typeFilter)) {
entitesStore.typeFilter = filterToAdd
}
}

let observer: IntersectionObserver | null = null

onMounted(async () => {
await entitesStore.loadEntites()
entitesStore.resetFilters()
await entitesStore.getEntites()

observer = new IntersectionObserver((entries) => {
observer = new IntersectionObserver((entries: IntersectionObserverEntry[]) => {
const entry = entries[0]
if (entry) {
isVisible.value = entry.isIntersecting
Expand Down
9 changes: 9 additions & 0 deletions app/pages/entites/[id].vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<template>
<!-- TODO add breadcrumbs -->
<div class="mx-auto w-[75%] max-w-7xl">
<p v-if="pending">Chargement...</p>
<div v-else-if="entite" class="flex flex-col gap-1.5">
Expand All @@ -18,6 +19,14 @@
{{ relation }}
</p>
<p v-if="entite.lieu_id">Lieu : {{ entite.lieu_id }}</p>
<NuxtImg
v-if="entite.image_url"
format="webp"
provider="cloudinary"
:src="entite.image_url"
:alt="`Image de${entite.nom}`"
class="w-75 h-auto rounded-lg object-cover"
/>
</div>
<div v-else-if="error">"Entitée non trouvée !"</div>
<UButton
Expand Down
145 changes: 142 additions & 3 deletions app/pages/genealogie.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,146 @@
<template>
<div>
<p>La généalogie du personnage principal</p>
<div class="pt-15 pb-50 max-w-7xl mx-auto">
<h1 class="text-5xl mb-6 font-heading">Généalogie</h1>
<h2 class="text-1xl mb-6">Retrouvez les arbres généalogiques des personnages principaux</h2>

<div class="my-15">
<div v-if="pending" class="flex justify-center py-20">
<UIcon name="i-heroicons-arrow-path" class="w-12 h-12 animate-spin text-primary" />
</div>

<div v-else-if="error" class="text-red-600 text-center py-20">
Erreur lors du chargement de l'arbre généalogique
</div>

<div v-else-if="entite" class="flex flex-col items-center gap-8 p-5">
<!-- SOUCHE EN HAUT -->
<div class="text-center">
<h3 class="text-2xl font-bold mb-4">La Souche</h3>
<div class="flex gap-8 justify-center">
<template v-for="(generation, index) in entite.souche" :key="index">
<div class="flex gap-1.5 relative items-start">
<NuxtLink
v-for="personne in generation"
:key="personne.id"
:to="`/entites/${personne.id}`"
class="person-card"
:class="{ feminine: personne.espece === 'feminine' }"
>
<div class="name">{{ personne.nom }}</div>
<div class="role">{{ personne.espece || personne.type }}</div>
</NuxtLink>
<div v-if="generation.length === 2" class="marriage-line" />
</div>
</template>
</div>
</div>

<!-- LIGNE DE CONNEXION -->
<div class="connection-line-vertical" />

<!-- LES 3 BRANCHES CÔTE À CÔTE -->
<div class="flex gap-8 items-start justify-center">
<div
v-for="(branche, brancheNom) in entite.branches"
:key="brancheNom"
class="flex flex-col items-center gap-4"
>
<h3 class="text-xl font-bold capitalize">Branche {{ brancheNom }}</h3>

<template v-for="(generation, index) in branche" :key="index">
<div class="flex gap-8 content-center flex-wrap justify-center">
<div
v-for="(groupe, gIndex) in generation"
:key="gIndex"
class="flex gap-1.5 relative items-start"
>
<NuxtLink
v-for="personne in groupe"
:key="personne.id"
:to="`/entites/${personne.id}`"
class="person-card"
:class="{ feminine: personne.espece === 'feminine' }"
>
<div class="name">{{ personne.nom }}</div>
<div class="role">{{ personne.espece || personne.type }}</div>
</NuxtLink>
<div v-if="groupe.length === 2" class="marriage-line" />
</div>
</div>
<div v-if="index < branche.length - 1" class="connection-line" />
</template>
</div>
</div>
</div>
</div>
</div>
</template>

<script setup lang="ts"></script>
<script setup lang="ts">
const {
data: entite,
error,
pending,
} = await useAsyncData('tree', () => $fetch(`/api/genealogie/families`))
</script>

<style scoped>
.person-card {
width: 150px;
padding: 20px;
background: white;
border: 3px solid #3b82f6;
border-radius: 12px;
text-align: center;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: transform 0.2s;
text-decoration: none;
color: inherit;
}

.person-card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
cursor: pointer;
}

.person-card.feminine {
border-color: #a855f7;
background: #faf5ff;
}

.name {
font-size: 18px;
font-weight: bold;
color: #1f2937;
margin-bottom: 5px;
}

.role {
font-size: 14px;
color: #6b7280;
font-style: italic;
}

.marriage-line {
position: absolute;
width: 10px;
height: 3px;
background: #ef4444;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

.connection-line {
width: 2px;
height: 30px;
background: #9ca3af;
}

.connection-line-vertical {
width: 2px;
height: 50px;
background: #9ca3af;
}
</style>
3 changes: 3 additions & 0 deletions app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@

<script setup lang="ts">
const { data } = await useAsyncData('home', () => queryCollection('pages').first())

// TODO responsive design
// TODO SEO optimization
</script>
Loading