Spaces:
Build error
Build error
<html lang="fr"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AI Flashcards Generator</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.2/axios.min.js"></script> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" rel="stylesheet"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap'); | |
body { | |
font-family: 'Space Grotesk', sans-serif; | |
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%); | |
} | |
.glass-morph { | |
background: rgba(255, 255, 255, 0.05); | |
backdrop-filter: blur(10px); | |
border: 1px solid rgba(255, 255, 255, 0.1); | |
} | |
.card-hover { | |
transition: all 0.3s ease; | |
} | |
.card-hover:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2); | |
} | |
.gradient-text { | |
background: linear-gradient(45deg, #60a5fa, #a855f7); | |
-webkit-background-clip: text; | |
background-clip: text; | |
color: transparent; | |
} | |
.custom-loader { | |
width: 50px; | |
height: 50px; | |
border: 3px solid #fff; | |
border-radius: 50%; | |
display: inline-block; | |
position: relative; | |
box-sizing: border-box; | |
animation: rotation 1s linear infinite; | |
} | |
.custom-loader::after { | |
content: ''; | |
box-sizing: border-box; | |
position: absolute; | |
left: 50%; | |
top: 50%; | |
transform: translate(-50%, -50%); | |
width: 40px; | |
height: 40px; | |
border-radius: 50%; | |
border: 3px solid transparent; | |
border-bottom-color: #60a5fa; | |
} | |
@keyframes rotation { | |
0% { transform: rotate(0deg) } | |
100% { transform: rotate(360deg) } | |
} | |
.fade-enter-active, .fade-leave-active { | |
transition: opacity 0.5s ease; | |
} | |
.fade-enter-from, .fade-leave-to { | |
opacity: 0; | |
} | |
</style> | |
</head> | |
<body class="min-h-screen text-gray-100"> | |
<div id="app" class="container mx-auto px-4 py-12"> | |
<!-- Hero Section --> | |
<div class="text-center mb-16 animate__animated animate__fadeIn"> | |
<h1 class="text-5xl font-bold mb-4 gradient-text">AI Flashcards Generator</h1> | |
<p class="text-xl text-gray-400 mb-8">Transformez vos sujets en cartes d'apprentissage intelligentes</p> | |
</div> | |
<!-- Main Content --> | |
<div class="max-w-4xl mx-auto"> | |
<!-- Input Section --> | |
<div class="glass-morph rounded-2xl p-8 mb-12 card-hover"> | |
<div class="mb-6"> | |
<label for="topic" class="block text-lg font-medium mb-3 text-gray-300">Quel sujet souhaitez-vous explorer ?</label> | |
<div class="relative"> | |
<input | |
type="text" | |
id="topic" | |
v-model="topic" | |
class="w-full px-6 py-4 bg-gray-800/50 rounded-xl border border-gray-700 focus:ring-2 focus:ring-blue-500 focus:border-transparent text-lg transition-all duration-300" | |
placeholder="Ex: Intelligence Artificielle, Quantum Computing..." | |
:disabled="isLoading" | |
> | |
</div> | |
</div> | |
<button | |
@click="generateFlashcards" | |
:disabled="isLoading" | |
class="w-full bg-gradient-to-r from-blue-500 to-purple-600 text-white py-4 px-8 rounded-xl font-medium text-lg hover:opacity-90 transition-all duration-300 flex items-center justify-center space-x-3" | |
> | |
<span v-if="!isLoading">Générer les Flashcards</span> | |
<span v-else class="custom-loader"></span> | |
</button> | |
</div> | |
<!-- Error Message --> | |
<transition name="fade"> | |
<div v-if="error" class="mb-8 animate__animated animate__shakeX"> | |
<div class="bg-red-500/20 border border-red-500/50 text-red-300 px-6 py-4 rounded-xl"> | |
[[error]] | |
</div> | |
</div> | |
</transition> | |
<!-- Results Section --> | |
<transition name="fade"> | |
<div v-if="flashcards.length > 0" class="glass-morph rounded-2xl overflow-hidden"> | |
<!-- Tabs --> | |
<div class="border-b border-gray-700/50"> | |
<div class="flex"> | |
<button | |
v-for="tab in ['study', 'json']" | |
:key="tab" | |
@click="activeTab = tab" | |
:class="[ | |
'px-8 py-4 font-medium text-lg transition-all duration-300', | |
activeTab === tab | |
? 'gradient-text border-b-2 border-blue-500' | |
: 'text-gray-400 hover:text-gray-300' | |
]" | |
> | |
[[tab === 'study' ? 'Mode Étude' : 'Mode JSON']] | |
</button> | |
</div> | |
</div> | |
<!-- Tab Content --> | |
<div class="p-6"> | |
<!-- Study Mode --> | |
<div v-if="activeTab === 'study'" class="space-y-6"> | |
<div | |
v-for="(card, index) in flashcards" | |
:key="index" | |
class="glass-morph rounded-xl p-6 card-hover cursor-pointer transition-all duration-300" | |
@click="card.showAnswer = !card.showAnswer" | |
> | |
<div class="flex items-start space-x-4"> | |
<div class="w-12 h-12 flex items-center justify-center rounded-full bg-blue-500/20 text-blue-400 font-bold"> | |
[[index + 1]] | |
</div> | |
<div class="flex-1"> | |
<h3 class="text-xl font-medium mb-4">[[card.question]]</h3> | |
<transition name="fade"> | |
<div v-if="card.showAnswer" class="mt-4 pt-4 border-t border-gray-700/50"> | |
<p class="text-gray-300">[[card.answer]]</p> | |
</div> | |
</transition> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- JSON Mode --> | |
<div v-if="activeTab === 'json'" class="bg-gray-800/50 rounded-xl p-6 overflow-x-auto"> | |
<pre class="text-gray-300">[[JSON.stringify(flashcards, null, 2)]]</pre> | |
</div> | |
</div> | |
</div> | |
</transition> | |
</div> | |
</div> | |
<script> | |
const { createApp } = Vue | |
createApp({ | |
delimiters: ['[[', ']]'], | |
data() { | |
return { | |
topic: '', | |
flashcards: [], | |
activeTab: 'study', | |
isLoading: false, | |
error: null | |
} | |
}, | |
methods: { | |
async generateFlashcards() { | |
if (!this.topic) { | |
this.error = 'Veuillez entrer un sujet.' | |
return | |
} | |
this.isLoading = true | |
this.error = null | |
this.flashcards = [] | |
try { | |
const response = await axios.post('/generate', { | |
topic: this.topic | |
}) | |
if (response.data.success) { | |
const cards = response.data.flashcards.map(card => ({ | |
...card, | |
showAnswer: false | |
})) | |
// Animation des cartes à leur apparition | |
setTimeout(() => { | |
this.flashcards = cards | |
this.$nextTick(() => { | |
gsap.from('.card-hover', { | |
y: 30, | |
opacity: 0, | |
duration: 0.5, | |
stagger: 0.1 | |
}) | |
}) | |
}, 300) | |
} | |
} catch (error) { | |
this.error = error.response?.data?.error || 'Une erreur est survenue lors de la génération.' | |
} finally { | |
this.isLoading = false | |
} | |
} | |
}, | |
mounted() { | |
// Animation du titre à l'entrée | |
gsap.from('.gradient-text', { | |
y: -50, | |
opacity: 0, | |
duration: 1, | |
ease: 'power3.out' | |
}) | |
} | |
}).mount('#app') | |
</script> | |
</body> | |
</html> |