mirror of
https://github.com/ArthurDanjou/spanish-learner.git
synced 2026-01-14 12:14:39 +01:00
Working
This commit is contained in:
@@ -3,9 +3,14 @@ export default defineAppConfig({
|
|||||||
gray: 'neutral',
|
gray: 'neutral',
|
||||||
primary: 'red',
|
primary: 'red',
|
||||||
container: {
|
container: {
|
||||||
constrained: 'max-w-xl',
|
|
||||||
padding: 'px-4 sm:px-6 lg:px-8 py-4',
|
padding: 'px-4 sm:px-6 lg:px-8 py-4',
|
||||||
},
|
},
|
||||||
|
card: {
|
||||||
|
background: 'bg-neutral-900',
|
||||||
|
header: {
|
||||||
|
base: 'uppercase font-bold tracking-widest text-white',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
collections: ['heroicons', 'ph'],
|
collections: ['heroicons', 'ph'],
|
||||||
|
|||||||
22
app/app.vue
22
app/app.vue
@@ -12,22 +12,22 @@ mode.value = mode.value || 'Spanish'
|
|||||||
<div>
|
<div>
|
||||||
<NuxtLoadingIndicator />
|
<NuxtLoadingIndicator />
|
||||||
<UContainer>
|
<UContainer>
|
||||||
<div class="my-4 flex items-center justify-between">
|
<div class="grid grid-cols-1 md:grid-cols-6 gap-4 auto-rows-max">
|
||||||
<p>Mode: {{ mode }}</p>
|
<UCard
|
||||||
<UButton
|
class="order-first"
|
||||||
:color="mode === 'Spanish' ? 'cyan' : 'yellow'"
|
|
||||||
variant="solid"
|
|
||||||
:label="mode === 'Spanish' ? 'Switch to French' : 'Switch to Spanish'"
|
|
||||||
@click="mode === 'Spanish' ? mode = 'French' : mode = 'Spanish'"
|
@click="mode === 'Spanish' ? mode = 'French' : mode = 'Spanish'"
|
||||||
/>
|
>
|
||||||
</div>
|
<p class="text-lg font-bold uppercase" :class="mode === 'Spanish' ? 'text-red-500' : 'text-blue-500'">
|
||||||
<div class="bg-neutral-900 rounded-lg max-h-[90vh] h-[90vh] overflow-scroll p-4">
|
Mode: {{ mode }}
|
||||||
|
</p>
|
||||||
|
</UCard>
|
||||||
|
<Translation />
|
||||||
<Verbs />
|
<Verbs />
|
||||||
<Words />
|
<Words />
|
||||||
<Demonstratifs />
|
|
||||||
<Modals />
|
<Modals />
|
||||||
<Terminaisons />
|
<Demonstratifs />
|
||||||
<Prononciation />
|
<Prononciation />
|
||||||
|
<Terminaisons />
|
||||||
</div>
|
</div>
|
||||||
</UContainer>
|
</UContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ const rows = [
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UDivider class="mt-12 mb-8" size="lg" label="Démonstratifs" />
|
<UCard class="md:col-span-4">
|
||||||
|
<template #header>
|
||||||
|
<h1>Démonstratifs</h1>
|
||||||
|
</template>
|
||||||
<UTable :rows="rows" :columns="columns" />
|
<UTable :rows="rows" :columns="columns" />
|
||||||
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -59,10 +59,10 @@ const ModalRows = [
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UDivider class="mt-12 mb-8" size="lg" label="Ser, Estar, Tener, Haber" />
|
<UCard class="md:col-span-2 md:row-span-2">
|
||||||
|
<template #header>
|
||||||
|
<h1>Modaux</h1>
|
||||||
|
</template>
|
||||||
<UTable :columns="ModalColumns" :rows="ModalRows" />
|
<UTable :columns="ModalColumns" :rows="ModalRows" />
|
||||||
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -59,10 +59,10 @@ const PrononciationRows = [
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UDivider class="mt-12 mb-8" size="lg" label="Prononciation" />
|
<UCard class="md:row-span-2 md:col-span-2">
|
||||||
|
<template #header>
|
||||||
|
<h1>Prononciation</h1>
|
||||||
|
</template>
|
||||||
<UTable :rows="PrononciationRows" />
|
<UTable :rows="PrononciationRows" />
|
||||||
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -58,10 +58,10 @@ const VerbColumns = [
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UDivider class="mt-12 mb-8" size="lg" label="Terminaisons" />
|
<UCard class="md:col-span-4 md:row-span-2">
|
||||||
|
<template #header>
|
||||||
|
<h1>Terminaisons</h1>
|
||||||
|
</template>
|
||||||
<UTable :columns="VerbColumns" :rows="VerbRows" />
|
<UTable :columns="VerbColumns" :rows="VerbRows" />
|
||||||
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
68
app/components/Translation.vue
Normal file
68
app/components/Translation.vue
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { z } from 'zod'
|
||||||
|
import type { FormSubmitEvent } from '#ui/types'
|
||||||
|
|
||||||
|
const mode = useCookie('mode')
|
||||||
|
const sent = ref(false)
|
||||||
|
|
||||||
|
const schema = z.object({
|
||||||
|
text: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
type Schema = z.output<typeof schema>
|
||||||
|
const state = reactive({
|
||||||
|
text: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = ref()
|
||||||
|
async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||||
|
const body = {
|
||||||
|
text: event.data.text,
|
||||||
|
target_lang: mode.value === 'Spanish' ? 'French' : 'Spanish',
|
||||||
|
source_lang: mode.value === 'Spanish' ? 'Spanish' : 'French',
|
||||||
|
}
|
||||||
|
sent.value = true
|
||||||
|
response.value = await $fetch('/api/translate', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
response.value = null
|
||||||
|
sent.value = false
|
||||||
|
state.text = undefined
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UCard class="md:row-span-1 md:col-span-5 order-first">
|
||||||
|
<template #header>
|
||||||
|
<h1>Translation</h1>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<UForm v-if="!sent" :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
||||||
|
<UFormGroup label="Text to translate" name="text">
|
||||||
|
<UTextarea v-model="state.text" type="text" />
|
||||||
|
</UFormGroup>
|
||||||
|
<UButton type="submit">
|
||||||
|
Translate in {{ mode === 'Spanish' ? 'French' : 'Spanish' }}
|
||||||
|
</UButton>
|
||||||
|
</UForm>
|
||||||
|
<div v-else>
|
||||||
|
<div v-if="response" class="mb-4 flex gap-2">
|
||||||
|
<h1 class="font-bold">
|
||||||
|
Translated Text:
|
||||||
|
</h1>
|
||||||
|
<p class="italic">
|
||||||
|
{{ response.translated_text }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<h1 v-else class="mb-4 italic">
|
||||||
|
Loading translation...
|
||||||
|
</h1>
|
||||||
|
<UButton label="Translate again" @click.prevent="resetForm()" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UCard>
|
||||||
|
</template>
|
||||||
@@ -10,7 +10,11 @@ const mode = useCookie('mode')
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="verb" class="space-y-4 mx-auto flex flex-col justify-center">
|
<UCard class="md:col-span-2 md:row-span-1">
|
||||||
|
<template #header>
|
||||||
|
<h1>Verbos</h1>
|
||||||
|
</template>
|
||||||
|
<div v-if="verb" class="space-y-4 flex flex-col justify-center">
|
||||||
<div class="flex gap-2 items-center">
|
<div class="flex gap-2 items-center">
|
||||||
<h3 class="text-neutral-500">
|
<h3 class="text-neutral-500">
|
||||||
Verbos:
|
Verbos:
|
||||||
@@ -49,8 +53,5 @@ const mode = useCookie('mode')
|
|||||||
@click.prevent="revealedVerb ? refreshVerb() : revealedVerb = true"
|
@click.prevent="revealedVerb ? refreshVerb() : revealedVerb = true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ const mode = useCookie('mode')
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UDivider class="mt-12 mb-8" size="lg" label="Palabras" />
|
<UCard class="md:col-span-2 md:row-span-1">
|
||||||
|
<template #header>
|
||||||
|
<h1>Palabras</h1>
|
||||||
|
</template>
|
||||||
<div v-if="word" class="space-y-4 mx-auto flex flex-col justify-center">
|
<div v-if="word" class="space-y-4 mx-auto flex flex-col justify-center">
|
||||||
<div class="flex gap-2 items-center">
|
<div class="flex gap-2 items-center">
|
||||||
<h3 class="text-neutral-500">
|
<h3 class="text-neutral-500">
|
||||||
@@ -43,8 +46,5 @@ const mode = useCookie('mode')
|
|||||||
@click.prevent="revealedWord ? refreshWord() : revealedWord = true"
|
@click.prevent="revealedWord ? refreshWord() : revealedWord = true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export default defineNuxtConfig({
|
|||||||
cache: true,
|
cache: true,
|
||||||
database: true,
|
database: true,
|
||||||
analytics: true,
|
analytics: true,
|
||||||
|
ai: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Nuxt Color Mode
|
// Nuxt Color Mode
|
||||||
|
|||||||
26
package.json
26
package.json
@@ -14,27 +14,27 @@
|
|||||||
"db:generate": "drizzle-kit generate"
|
"db:generate": "drizzle-kit generate"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iconify/json": "^2.2.232",
|
"@iconify/json": "^2.2.237",
|
||||||
"@nuxt/ui": "^2.18.3",
|
"@nuxt/ui": "^2.18.4",
|
||||||
"@nuxthub/core": "^0.7.1",
|
"@nuxthub/core": "^0.7.2",
|
||||||
"@nuxtjs/google-fonts": "^3.2.0",
|
"@nuxtjs/google-fonts": "^3.2.0",
|
||||||
"drizzle-orm": "^0.32.1",
|
"drizzle-orm": "^0.32.2",
|
||||||
"h3-zod": "^0.5.3",
|
"h3-zod": "^0.5.3",
|
||||||
"nuxt": "^3.12.4",
|
"nuxt": "^3.12.4",
|
||||||
"vue": "^3.4.35",
|
"vue": "^3.4.38",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "^2.23.2",
|
"@antfu/eslint-config": "^2.25.2",
|
||||||
"@nuxt/devtools": "^1.3.9",
|
"@nuxt/devtools": "^1.3.9",
|
||||||
"@nuxt/ui": "^2.18.3",
|
"@nuxt/ui": "^2.18.3",
|
||||||
"@types/node": "^22.0.0",
|
"@types/node": "^22.3.0",
|
||||||
"@vueuse/core": "^10.11.0",
|
"@vueuse/core": "^10.11.1",
|
||||||
"@vueuse/nuxt": "^10.11.0",
|
"@vueuse/nuxt": "^10.11.1",
|
||||||
"drizzle-kit": "^0.23.1",
|
"drizzle-kit": "^0.23.2",
|
||||||
"eslint": "^9.7.0",
|
"eslint": "^9.9.0",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"vue-tsc": "^2.0.28",
|
"vue-tsc": "^2.0.29",
|
||||||
"wrangler": "^3.67.1"
|
"wrangler": "^3.72.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2054
pnpm-lock.yaml
generated
2054
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
17
server/api/translate.post.ts
Normal file
17
server/api/translate.post.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { z, zh } from 'h3-zod'
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const ai = hubAI()
|
||||||
|
|
||||||
|
const { source_lang, target_lang, text } = await zh.useValidatedBody(event, z.object({
|
||||||
|
source_lang: z.enum(['French', 'Spanish']),
|
||||||
|
target_lang: z.enum(['French', 'Spanish']),
|
||||||
|
text: z.string(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
return await ai.run('@cf/meta/m2m100-1.2b', {
|
||||||
|
source_lang: source_lang.toLowerCase(),
|
||||||
|
target_lang: target_lang.toLowerCase(),
|
||||||
|
text,
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user