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
12 changes: 8 additions & 4 deletions app/assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
body {
font-family: var(--font-main);
background-color: var(--depth);
scroll-behavior: smooth;
}

.font-heading {
Expand All @@ -13,10 +14,13 @@ body {
@layer base {
:root {
/* Couleurs */
--primary: 59 130 246;
--secondary: 139 92 246;
--accent: 236 72 153;
--depth: #dadada;
--ui-primary: var(--color-indigo-900);
--ui-secondary: var(--color-indigo-400);
--depth: var(--color-slate-200);
--ui-success: var(--color-indigo-900);
--ui-info: var(--ui-color-teal-500);
--ui-warning: var(--ui-color-rose-500);
--ui-error: var(--ui-color-red-700);

/* Spacing */
--spacing-sm: 0.5rem;
Expand Down
22 changes: 20 additions & 2 deletions app/components/HeroItem.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div
v-if="data"
class="mx-auto w-[75%] flex flex-row gap-4 rounded-4xl bg-white/30 p-10 shadow-lg items-center mt-15 h-150"
class="mx-auto w-[75%] max-w-7xl flex flex-row gap-4 rounded-4xl bg-white/30 p-10 shadow-lg items-center mt-15 h-150"
>
<div class="w-[30%] h-full flex flex-col gap-4 text-center justify-center mx-12">
<h1 class="text-4xl font-heading">{{ data?.hero?.heading }}</h1>
Expand All @@ -11,8 +11,9 @@
<NuxtLink
v-for="(feature, index) in data.features"
:key="feature.title"
:to="`#${feature?.title.toLowerCase()}`"
:to="searchItem(feature?.search)"
:class="getGridClass(index)"
@click="addTypeFilter(feature?.search)"
>
<div class="absolute inset-0">
<NuxtImg
Expand All @@ -31,6 +32,10 @@
</template>

<script setup="ts">
import { useEntitesStore } from '../stores/entites.store'

const entitesStore = useEntitesStore()

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

const getGridClass = (index) => {
Expand All @@ -44,4 +49,17 @@
}
return `${baseClass} ${gridClasses[index] || ''}`
}

const addTypeFilter = async (filterToAdd) => {
entitesStore.typeFilter = filterToAdd
await entitesStore.searchEntites()
}

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

return '#search'
}
</script>
161 changes: 158 additions & 3 deletions app/components/SearchItem.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,162 @@
<template>
<div class="p-20">
<p>La recherche</p>
<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 class="mb-6 space-y-4">
<input
v-model="searchValue"
type="text"
placeholder="Rechercher..."
class="border px-4 py-2 rounded w-full"
/>

<div class="flex gap-2">
<UButton
:color="typeFilter === 'tous' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'tous'"
>
Tous
</UButton>
<UButton
:color="typeFilter === 'personnage' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'personnage'"
>
Personnages
</UButton>
<UButton
:color="typeFilter === 'lieu' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'lieu'"
>
Lieux
</UButton>
<UButton
:color="typeFilter === 'creature' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'creature'"
>
Créatures
</UButton>
<UButton
:color="typeFilter === 'peuple' ? 'primary' : 'secondary'"
class="text-white px-4 py-2 rounded"
@click="typeFilter = 'peuple'"
>
Peuples
</UButton>
</div>
</div>

<div v-if="isError" class="border border-red-300 bg-red-50 rounded-lg p-4 mb-6">
<div class="flex items-start gap-3">
<UIcon name="i-heroicons-exclamation-triangle" class="w-6 h-6 text-red-600 shrink-0" />
<div class="flex-1">
<h3 class="font-bold text-red-800">Erreur de chargement</h3>
<p class="text-red-700 text-sm mt-1">{{ errorMessage }}</p>
</div>
<button
class="bg-red-600 text-white px-3 py-1 rounded text-sm hover:bg-red-700"
@click="entitesStore.resetAndLoad()"
>
Réessayer
</button>
</div>
</div>

<div v-if="hasNoResults" class="flex flex-col items-center justify-center py-20">
<UIcon name="i-heroicons-magnifying-glass" class="w-16 h-16 text-gray-400 mb-4" />
<h3 class="text-xl font-semibold text-gray-700 mb-2">Aucun résultat</h3>
<p class="text-gray-500">Aucune entité ne correspond à vos critères de recherche.</p>
</div>

<div
v-if="entitesFilter.length > 0"
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
>
<NuxtLink
v-for="entite in entitesFilter"
:key="entite.id"
:to="formateLink(entite.id)"
class="border rounded-lg p-4 hover:shadow-lg hover:bg-white transition"
>
<div class="flex justify-between items-start mb-2">
<h3 class="font-bold text-lg">{{ entite.nom }}</h3>
<span class="text-xs bg-indigo-400 text-white px-2 py-1 rounded">
{{ entite.type }}
</span>
</div>

<p class="text-gray-600 text-sm mb-3">{{ entite.description }}</p>

<div class="flex flex-wrap gap-1">
<span
v-for="tag in entite.tags"
:key="tag"
class="text-xs bg-cyan-100 text-cyan-800 px-2 py-1 rounded"
>
{{ tag }}
</span>
</div>
</NuxtLink>
</div>

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

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

const entitesStore = useEntitesStore()
const { typeFilter, searchValue, entitesFilter, isLoading, isError, errorMessage } =
storeToRefs(entitesStore)

const loadMoreTrigger = ref<HTMLElement | null>(null)
const isVisible = ref(false)

let observer: IntersectionObserver | null = null

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

observer = new IntersectionObserver((entries) => {
const entry = entries[0]
if (entry) {
isVisible.value = entry.isIntersecting
}
})

if (loadMoreTrigger.value) {
observer.observe(loadMoreTrigger.value)
}
})

onUnmounted(() => {
observer?.disconnect()
})

watch(isVisible, async (visible) => {
if (visible && !isLoading.value) {
await entitesStore.loadMore()
}
})

watch(typeFilter, async () => {
await entitesStore.resetAndLoad()
})

const formateLink = (id: string) => `/entites/${id}`

const hasNoResults = computed(() => {
return !isLoading.value && !isError.value && entitesFilter.value.length === 0
})
</script>
48 changes: 48 additions & 0 deletions app/pages/entites/[id].vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<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">
<p>Nom : {{ entite.nom }}</p>
<p>Type : {{ entite.type }}</p>
<p>Description : {{ entite.description }}</p>
<p v-if="entite.espece">Espèce : {{ entite.espece }}</p>
<p v-if="entite.vivant">Espèce vivante</p>
<p v-if="entite.dangereux">Espèce dangeureuse</p>
<p v-if="entite.hostile">Espèce hostile</p>
<div v-if="entite.tomes" class="flex flex-row gap-1.5">
<p v-if="entite.tomes.length > 1">Apparait dans les :</p>
<p v-if="entite.tomes.length == 1">Apparait dans le :</p>
<p v-for="(tome, index) in entite.tomes" :key="index">Tome {{ tome }}</p>
</div>
<p v-for="(relation, index) in entite.relations" :key="index">
{{ relation }}
</p>
<p v-if="entite.lieu_id">Lieu : {{ entite.lieu_id }}</p>
</div>
<div v-else-if="error">"Entitée non trouvée !"</div>
<UButton
aria-label="Retourner sur la page précédente"
class="mt-10 mx-auto"
@click="$router.back()"
>
<p>Retour</p>
</UButton>
</div>
</template>

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

const route = useRoute()
const idEntite = route.params.id
const entitesStore = useEntitesStore()

const {
data: entite,
error,
pending,
} = await useAsyncData<Entite>(`entite-${idEntite}`, () =>
entitesStore.getEntiteById(idEntite as string)
)
</script>
7 changes: 7 additions & 0 deletions app/pages/genealogie.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<template>
<div>
<p>La généalogie du personnage principal</p>
</div>
</template>

<script setup lang="ts"></script>
Loading