Initial commit — Diabetix V2

Application Laravel 12 + Inertia + Vue 3 + Tailwind.
Fonctionnalités : dashboard glycémique, saisie de mesures, courbe SVG,
statistiques (jour/semaine/mois/trimestre), défis & badges, chat coach IA
(Gemini), paramètres profil avec palette de couleurs, pages auth redessinées,
emails transactionnels via Resend avec thème Diabetix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jeremy bayse
2026-04-29 07:01:41 +02:00
commit 26c6d8031c
150 changed files with 19863 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
<script setup>
import { ref, computed } from 'vue';
import { Head } from '@inertiajs/vue3';
import DiabetixLayout from '@/Layouts/DiabetixLayout.vue';
import ProgressBar from '@/Components/Diabetix/ProgressBar.vue';
import BadgeChip from '@/Components/Diabetix/BadgeChip.vue';
const props = defineProps({
challenges: Array,
badges: Array,
level: Object,
});
const tab = ref('defis');
const unlocked = computed(() => props.badges.filter(b => b.unlocked));
const locked = computed(() => props.badges.filter(b => !b.unlocked));
</script>
<template>
<Head title="Défis & Badges" />
<DiabetixLayout v-slot="{ tok, font }">
<div :style="{ background: tok.white, padding: '14px 20px 18px', borderBottom: '1px solid ' + tok.border }">
<div :style="{ fontFamily: font.title, fontSize: '20px', fontWeight: 600, color: tok.text, marginBottom: '14px' }">Défis & Badges</div>
<div :style="{ background: tok.light, borderRadius: '18px', padding: '16px' }">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">
<div>
<div :style="{ fontSize: '11px', color: tok.muted }">Niveau actuel</div>
<div :style="{ fontFamily: font.title, fontSize: '17px', fontWeight: 600, color: tok.text }">{{ level.icon }} {{ level.label }}</div>
</div>
<div style="text-align:right;">
<div :style="{ fontSize: '11px', color: tok.muted }">Points</div>
<div :style="{ fontSize: '22px', fontWeight: 800, color: tok.amber }">{{ level.points.toLocaleString('fr-FR') }}</div>
</div>
</div>
<ProgressBar :value="level.points" :max="level.next_at" :color="tok.amber" :tok="tok" :height="8" />
<div style="display:flex;justify-content:space-between;margin-top:5px;">
<span :style="{ fontSize: '10px', color: tok.muted }">{{ level.icon }} {{ level.label }}</span>
<span :style="{ fontSize: '10px', color: tok.amber }">{{ level.remaining }} pts {{ level.next_icon }} {{ level.next_label }}</span>
</div>
</div>
</div>
<div style="padding:14px 20px 0;">
<div :style="{ display: 'flex', gap: '4px', background: tok.bgAlt, borderRadius: '12px', padding: '4px' }">
<button v-for="t in [['defis','🎯 Défis actifs'],['badges','🏅 Badges']]" :key="t[0]"
@click="tab = t[0]"
:style="{
flex: 1, padding: '8px', borderRadius: '9px', border: 'none',
background: tab === t[0] ? tok.primary : 'transparent',
color: tab === t[0] ? '#fff' : tok.muted,
fontSize: '12px', fontWeight: tab === t[0] ? 600 : 400, cursor: 'pointer',
}">{{ t[1] }}</button>
</div>
</div>
<div style="padding:14px 20px;display:flex;flex-direction:column;gap:14px;">
<template v-if="tab === 'defis'">
<div v-for="c in challenges" :key="c.id"
:style="{ background: tok.white, borderRadius: '18px', padding: '16px', boxShadow: '0 2px 12px rgba(42,53,51,0.06)' }">
<div style="display:flex;align-items:flex-start;gap:12px;">
<div style="font-size:28px;">{{ c.icon }}</div>
<div style="flex:1;">
<div style="display:flex;justify-content:space-between;align-items:center;">
<div :style="{ fontSize: '14px', fontWeight: 600, color: tok.text }">{{ c.title }}</div>
<div :style="{ background: tok.amberLight, borderRadius: '20px', padding: '3px 8px', fontSize: '10px', color: tok.amber, fontWeight: 600 }">+{{ c.points }} pts</div>
</div>
<div :style="{ fontSize: '11px', color: tok.muted, marginBottom: '10px' }">{{ c.description }}</div>
<ProgressBar :value="c.progress" :tok="tok" :height="7" />
<div style="display:flex;justify-content:flex-end;margin-top:5px;">
<span :style="{ fontSize: '11px', color: tok.primary }">{{ c.progress }}%</span>
</div>
</div>
</div>
</div>
</template>
<template v-else>
<template v-if="unlocked.length">
<div :style="{ fontSize: '11px', color: tok.muted, fontWeight: 700, letterSpacing: '0.8px' }">DÉBLOQUÉS ({{ unlocked.length }})</div>
<div v-for="b in unlocked" :key="b.id"
:style="{ background: tok.white, borderRadius: '16px', padding: '14px 16px', boxShadow: '0 2px 10px rgba(42,53,51,0.06)', display: 'flex', alignItems: 'center', gap: '14px' }">
<div :style="{
width: '48px', height: '48px', borderRadius: '50%', flexShrink: 0,
background: tok.light, border: '2px solid ' + tok.primary,
display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '22px',
}">{{ b.icon }}</div>
<div style="flex:1;min-width:0;">
<div :style="{ fontSize: '13px', fontWeight: 700, color: tok.text }">{{ b.label }}</div>
<div :style="{ fontSize: '11px', color: tok.muted, marginTop: '2px', lineHeight: 1.4 }">{{ b.criteria }}</div>
</div>
<div :style="{ fontSize: '16px', flexShrink: 0 }"></div>
</div>
</template>
<template v-if="locked.length">
<div :style="{ fontSize: '11px', color: tok.muted, fontWeight: 700, letterSpacing: '0.8px', marginTop: unlocked.length ? '4px' : 0 }">À DÉBLOQUER ({{ locked.length }})</div>
<div v-for="b in locked" :key="b.id"
:style="{ background: tok.white, borderRadius: '16px', padding: '14px 16px', boxShadow: '0 2px 10px rgba(42,53,51,0.04)', display: 'flex', alignItems: 'center', gap: '14px', opacity: 0.7 }">
<div :style="{
width: '48px', height: '48px', borderRadius: '50%', flexShrink: 0,
background: tok.bgAlt, border: '2px solid ' + tok.border,
display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '22px',
filter: 'grayscale(1)',
}">{{ b.icon }}</div>
<div style="flex:1;min-width:0;">
<div :style="{ fontSize: '13px', fontWeight: 600, color: tok.muted }">{{ b.label }}</div>
<div :style="{ fontSize: '11px', color: tok.muted, marginTop: '2px', lineHeight: 1.4 }">{{ b.criteria }}</div>
</div>
<div :style="{ fontSize: '16px', flexShrink: 0 }">🔒</div>
</div>
</template>
</template>
</div>
</DiabetixLayout>
</template>