Skip to content
Merged
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
142 changes: 142 additions & 0 deletions app/components/landing/CardsCourses.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<script setup lang="ts">
type HighlightColor =
| 'primary'
| 'secondary'
| 'success'
| 'warning'
| 'info'
| 'error'
| 'neutral'

interface Teacher {
name: string
description: string
avatar: {
src: string
alt: string
}
}

interface Course {
title: string
description: string
icon: string
to: string
highlightColor: HighlightColor
teacher: Teacher
}

const courses: Course[] = [
{
title: 'Inglés',
description:
'Mejora tus habilidades en el idioma inglés con ejercicios interactivos.',
icon: 'i-heroicons-language',
to: '#',
highlightColor: 'primary',
teacher: {
name: 'Dra. Laura López',
description: 'Responsable de Inglés',
avatar: {
src: 'https://randomuser.me/api/portraits/women/50.jpg',
alt: 'Dra. Laura López'
}
}
},
{
title: 'Física',
description:
'Aprende los principios de la física y resuelve problemas prácticos.',
icon: 'i-heroicons-cube-transparent',
to: '#',
highlightColor: 'neutral',
teacher: {
name: 'Mtro. Juan Pérez',
description: 'Responsable de Física',
avatar: {
src: 'https://randomuser.me/api/portraits/men/32.jpg',
alt: 'Mtro. Juan Pérez'
}
}
},
{
title: 'Química',
description: 'Explora el mundo de los elementos y las reacciones químicas.',
icon: 'i-heroicons-beaker',
to: '#',
highlightColor: 'success',
teacher: {
name: 'Dra. Alicia Mendoza',
description: 'Responsable de Química',
avatar: {
src: 'https://randomuser.me/api/portraits/women/45.jpg',
alt: 'Dra. Alicia Mendoza'
}
}
},
{
title: 'Matemáticas',
description: 'Desarrolla tu razonamiento lógico y matemático.',
icon: 'i-heroicons-calculator',
to: '#',
highlightColor: 'warning',
teacher: {
name: 'Ing. Carlos Ramírez',
description: 'Responsable de Matemáticas',
avatar: {
src: 'https://randomuser.me/api/portraits/men/23.jpg',
alt: 'Ing. Carlos Ramírez'
}
}
},
{
title: 'Historia',
description: 'Comprende los eventos y procesos históricos clave.',
icon: 'i-heroicons-book-open',
to: '#',
highlightColor: 'success',
teacher: {
name: 'Lic. Gabriela Suárez',
description: 'Responsable de Historia',
avatar: {
src: 'https://randomuser.me/api/portraits/women/65.jpg',
alt: 'Lic. Gabriela Suárez'
}
}
},
{
title: 'Computación',
description: 'Aprende fundamentos de computación y programación.',
icon: 'i-heroicons-computer-desktop',
to: '#',
highlightColor: 'error',
teacher: {
name: 'Dr. Emilio Torres',
description: 'Responsable de Computación',
avatar: {
src: 'https://randomuser.me/api/portraits/men/55.jpg',
alt: 'Dr. Emilio Torres'
}
}
}
]
</script>

<template>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 max-w-4xl mx-auto">
<UPageCard
v-for="(course, idx) in courses"
:key="idx"
:title="course.title"
:description="course.description"
:icon="course.icon"
:to="course.to"
target="_blank"
variant="soft"
>
<template #footer>
<UUser v-bind="course.teacher" />
</template>
</UPageCard>
</div>
</template>
190 changes: 34 additions & 156 deletions app/components/landing/Hero.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
<script setup lang="ts">
import type { IndexCollectionItem } from '@nuxt/content'

const { footer, global } = useAppConfig()
import WeeklyStreak from './WeeklyStreak.vue'
import CardsCourses from './CardsCourses.vue'

defineProps<{
page: IndexCollectionItem
}>()

const days = Array.from({ length: 31 }, (_, i) => i < 11)
</script>

<template>
<UPageHero
:ui="{
headline: 'flex items-center justify-center',
title: 'text-shadow-md max-w-lg mx-auto',
links: 'mt-4 flex-col justify-center items-center'
}"
>
<UPageHero>
<template #headline>
<Motion
:initial="{
Expand All @@ -33,159 +29,41 @@ defineProps<{
delay: 0.1
}"
>
<UColorModeAvatar
class="size-18 ring ring-default ring-offset-3 ring-offset-(--ui-bg)"
:light="global.picture?.light!"
:dark="global.picture?.dark!"
:alt="global.picture?.alt!"
/>
</Motion>
</template>

<template #title>
<Motion
:initial="{
scale: 1.1,
opacity: 0,
filter: 'blur(20px)'
}"
:animate="{
scale: 1,
opacity: 1,
filter: 'blur(0px)'
}"
:transition="{
duration: 0.6,
delay: 0.1
}"
>
{{ page.title }}
</Motion>
</template>

<template #description>
<Motion
:initial="{
scale: 1.1,
opacity: 0,
filter: 'blur(20px)'
}"
:animate="{
scale: 1,
opacity: 1,
filter: 'blur(0px)'
}"
:transition="{
duration: 0.6,
delay: 0.3
}"
>
{{ page.description }}
</Motion>
</template>

<template #links>
<Motion
:initial="{
scale: 1.1,
opacity: 0,
filter: 'blur(20px)'
}"
:animate="{
scale: 1,
opacity: 1,
filter: 'blur(0px)'
}"
:transition="{
duration: 0.6,
delay: 0.5
}"
>
<div
v-if="page.hero.links"
class="flex items-center gap-2"
>
<UButton v-bind="page.hero.links[0]" />
<UButton
:color="global.available ? 'success' : 'error'"
variant="ghost"
class="gap-2"
:to="global.available ? global.meetingLink : ''"
:label="global.available ? 'Available for new projects' : 'Not available at the moment'"
>
<template #leading>
<span class="relative flex size-2">
<span
class="absolute inline-flex size-full rounded-full opacity-75"
:class="global.available ? 'bg-success animate-ping' : 'bg-error'"
/>
<span
class="relative inline-flex size-2 scale-90 rounded-full"
:class="global.available ? 'bg-success' : 'bg-error'"
/>
</span>
</template>
</UButton>
</div>
</Motion>

<div class="gap-x-4 inline-flex mt-4">
<Motion
v-for="(link, index) of footer?.links"
:key="index"

:initial="{
scale: 1.1,
opacity: 0,
filter: 'blur(20px)'
}"
:animate="{
scale: 1,
opacity: 1,
filter: 'blur(0px)'
}"
:transition="{
duration: 0.6,
delay: 0.5 + index * 0.1
<UPageSection
:ui="{
container: 'flex items-center justify-center !py-0 !my-0 min-h-0'
}"
>
<UButton
v-bind="{ size: 'md', color: 'neutral', variant: 'ghost', ...link }"
/>
</Motion>
</div>
<WeeklyStreak :days="days" />
</UPageSection>
</Motion>
</template>

<UPageMarquee
pause-on-hover
class="py-2 -mx-4 sm:-mx-6 lg:-mx-8 [--duration:40s]"
<Motion
:initial="{
scale: 1.1,
opacity: 0,
filter: 'blur(20px)'
}"
:animate="{
scale: 1,
opacity: 1,
filter: 'blur(0px)'
}"
:transition="{
duration: 0.6,
delay: 0.1
}"
>
<Motion
v-for="(img, index) in page.hero.images"
:key="index"
:initial="{
scale: 1.1,
opacity: 0,
filter: 'blur(20px)'
}"
:animate="{
scale: 1,
opacity: 1,
filter: 'blur(0px)'
}"
:transition="{
duration: 0.6,
delay: index * 0.1
<UPageSection
title="Cursos Generales"
:ui="{
container: 'flex items-center justify-center !py-0 !my-0 min-h-0',
title: 'text-left'
}"
>
<img
width="234"
height="234"
class="rounded-lg"
:class="index % 2 === 0 ? '-rotate-2' : 'rotate-2'"
v-bind="img"
>
</Motion>
</UPageMarquee>
<CardsCourses />
</UPageSection>
</Motion>
</UPageHero>
</template>
Loading