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
47 changes: 43 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
"@astrojs/vue": "^5.1.1",
"@tailwindcss/vite": "^4.1.11",
"@vueuse/core": "^13.9.0",
"astro": "^5.14.1",
"astro": "^5.13.10",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"embla-carousel-autoplay": "^8.6.0",
"embla-carousel-vue": "^8.6.0",
"lucide-vue-next": "^0.539.0",
"reka-ui": "^2.5.0",
"tailwind-merge": "^3.3.1",
Expand Down
Binary file added src/assets/marketing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mentor.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/open-source.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions src/components/CarouselTestimonials.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup lang="ts">
import Autoplay from "embla-carousel-autoplay"
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel"
import testimonialData from "src/data/testimonials.json"
import Testimonial from "./Testimonial.vue"

const plugin = Autoplay({
delay: 9000,
stopOnMouseEnter: true,
stopOnInteraction: false,
})
</script>

<template>
<Carousel
class="container mx-auto lg:w-5/6 max-sm:w-5/6"
:plugins="[plugin]"
@mouseenter="plugin.stop"
@mouseleave="[plugin.reset(), plugin.play(), console.log('Running')];"
>
<CarouselContent>
<CarouselItem v-for="(t, index) in testimonialData" :key="index">
<div class="p-1">
<Testimonial :testimonial="t.testimonial" :author="t.author" :major="t.major" />
</div>
</CarouselItem>
</CarouselContent>
<div class="max-md:hidden">
<CarouselPrevious />
<CarouselNext />
</div>
</Carousel>
</template>
20 changes: 20 additions & 0 deletions src/components/CarouselTimeline.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
import CarouselTimelineVue from "./CarouselTimeline.vue";
import Mentor from "./Mentor.astro";
import Communication from "./Communication.astro";
import Developer from "./Developer.astro";
---

<div class="md:hidden p-5 pb-14">
<CarouselTimelineVue client:idle>
<div slot="mentor">
<Mentor />
</div>
<div slot="developer">
<Developer />
</div>
<div slot="communication" class="pl-3">
<Communication />
</div>
</CarouselTimelineVue>
</div>
112 changes: 112 additions & 0 deletions src/components/CarouselTimeline.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<script setup lang="ts">
import Autoplay from "embla-carousel-autoplay"
import { Carousel, CarouselContent, CarouselItem } from "@/components/ui/carousel"
import type { CarouselApi } from "@/components/ui/carousel"
import { GitPullRequestCreateArrow, UserPlus, Highlighter } from "lucide-vue-next"

const plugin = Autoplay({
delay: 9000,
stopOnMouseEnter: true,
stopOnInteraction: false,
})

import { ref } from "vue"

const emblaApi = ref<CarouselApi | null>(null)
const currentIndex = ref(0)
const icons = [
{ title: "Mentor", comp: UserPlus },
{ title: "Developer", comp: GitPullRequestCreateArrow },
{ title: "Design & Marketing", comp: Highlighter },
]

function onInitApi(api: CarouselApi) {
emblaApi.value = api

try {
const idx = (api as any).selectedScrollSnap?.()
currentIndex.value = typeof idx === "number" ? idx : 0
} catch (e) {
currentIndex.value = 0
}

if (api && typeof api.on === "function") {
api.on("select", () => {
try {
const i = (api as any).selectedScrollSnap?.()
currentIndex.value = typeof i === "number" ? i : currentIndex.value
} catch (e) {}
})
}

try {
const slideNodes = (api as any).slideNodes || []
const snapList = (api as any).scrollSnapList || []
console.debug("Embla slides:", slideNodes.length, "snapList:", snapList)
} catch (e) {
console.debug("Embla debug read failed", e)
}
}

function onTimelineClick(idx: number) {
if (!emblaApi.value) return
try {
emblaApi.value.scrollTo(idx)
} catch (e) {}

try {
plugin.stop()
} catch (e) {}
}
</script>

<template>
<div class="container mx-auto lg:w-5/6 w-full">

<div class="w-full flex justify-center mb-6">
<div class="relative w-5/6 max-w-md flex items-center justify-center">
<div class="absolute left-8 right-8 top-1/2 -translate-y-1/2 h-0.5 bg-slate-200"></div>

<div class="relative z-10 flex w-full justify-between items-center">
<button
v-for="(icon, idx) in icons"
:key="idx"
@click="onTimelineClick(idx)"
:aria-pressed="currentIndex === idx"
class="flex items-center justify-center w-14 h-14 rounded-full transition-transform"
:class="currentIndex === idx ? 'bg-primary text-white scale-110 shadow-lg' : 'bg-white text-slate-700 border border-slate-200'"
:aria-label="`Go to ${icon.title}`"
:title="icon.title"
>
<component :is="icon.comp" class="w-6 h-6" aria-hidden="true" />
</button>
</div>
</div>
</div>

<Carousel
class="w-full"
:plugins="[plugin]"
@init-api="onInitApi"
@mouseenter="plugin.stop"
@mouseleave="[plugin.reset(), plugin.play()]"
>

<CarouselContent class="p-3">
<CarouselItem>
<slot name="mentor" />
</CarouselItem>

<CarouselItem>
<slot name="developer" />
</CarouselItem>

<CarouselItem>
<slot name="communication" />
</CarouselItem>
</CarouselContent>

</Carousel>

</div>
</template>
52 changes: 52 additions & 0 deletions src/components/Communication.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "./ui/card";
import { Button } from "./ui/button";
import { Image } from "astro:assets";
import marketing from "src/assets/marketing.png";
---

<Card>
<CardContent>
<div class="flex max-sm:flex-col-reverse">
<div class="flex flex-col w-1/2 max-sm:w-full justify-center">
<p class="mt-4 mb-4 text-lg leading-relaxed font-light">
O design e marketing são essenciais para o CoderDojo Braga, pois
permitem expandir a nossa atuação, dando-nos a conhecer a mais
pessoas, sejam novos guardiões e ninjas, ou mentores e voluntários.
</p>
<p class="mt-0 mb-4 text-lg leading-relaxed font-light">
Junta-te à nossa equipa, e contribui para tornar este projeto nalgo
cada vez maior e melhor.
</p>
</div>
<div class="pt-4 ml-4 sm:w-3/4 md:w-6/12 max-sm:pt-4 max-sm:pb-8">
<Image
alt="Design e Marketing"
src={marketing}
class="rounded-2xl shadow-2xl"
loading={"eager"}
/>
</div>
</div>
</CardContent>
<CardFooter class="w-full clear-both">
<a
href="https://forms.gle/iEjGdnxfGYbk9rFy6"
target="_blank"
rel="noopener noreferrer"
class="block w-full sm:inline-block sm:w-auto"
>
<Button
class="w-full sm:w-auto whitespace-normal break-words text-center max-sm:py-6"
>
Quero ajudar com Design e Marketing
</Button>
</a>
</CardFooter>
</Card>
48 changes: 48 additions & 0 deletions src/components/Developer.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "./ui/card";
import { Button } from "./ui/button";
import { Image } from "astro:assets";
import openSource from "src/assets/open-source.jpg";
---

<Card
class="w-full min-h-[20rem] sm:min-h-[22rem] md:min-h-[26rem] lg:min-h-[30rem]"
>
<CardContent class="flex-1 p-0">
<div class="flex flex-col sm:flex-row h-full">
<div class="flex flex-col w-full sm:w-1/2 justify-center p-6">
<p class="mt-4 mb-4 text-lg leading-relaxed font-light">
O código-fonte destas plataformas é público, o que significa que
qualquer pessoa pode ver e contribuir para as mesmas.
</p>
<p class="mt-0 mb-4 text-lg leading-relaxed font-light">
Ao contribuires para as nossas plataformas, estás não só a ganhar
experiência profissional, como também a melhorar a qualidade do
trabalho que desenvolvemos.
</p>
</div>
<div class="w-full sm:w-1/2 flex items-center justify-center p-6">
<Image
alt="Plataforma Open Source"
src={openSource}
class="rounded-2xl shadow-2xl w-full h-56 sm:h-full object-cover"
loading={"eager"}
/>
</div>
</div>
</CardContent>
<CardFooter class="space-x-2">
<a href="https://github.com/coderdojobraga/kunai" target="_blank">
<Button>Kunai</Button>
</a>
<a href="https://github.com/coderdojobraga/katana" target="_blank">
<Button>Katana</Button>
</a>
</CardFooter>
</Card>
2 changes: 1 addition & 1 deletion src/components/Header.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import AppSidebar from "./AppSidebar.vue";

const pages = {
Equipa: "/team",
Recruitment: "/recruitment",
Recrutamento: "/recruitment",
FAQs: "/faqs",
};
---
Expand Down
Loading