Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Carousel boxers #658

Closed
wants to merge 12 commits into from
18 changes: 18 additions & 0 deletions src/components/ChevronIcon.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
import type { HTMLAttributes } from "astro/types"

type Props = HTMLAttributes<"svg">
---

<svg
{...Astro.props}
width="80"
height="80"
viewBox="0 0 80 80"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g style="mix-blend-mode:screen">
<path d="M55 40L30 65L26.5 61.5L48 40L26.5 18.5L30 15L55 40Z" fill="currentColor"></path>
</g>
</svg>
95 changes: 95 additions & 0 deletions src/components/CombatCarousel.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
import CombatSlideCarousel from "@/components/CombatSlideCarousel.astro"
import ChevronIcon from "@/components/ChevronIcon.astro"
import LVDALogo from "@/components/LVDALogo.astro"
import { BOXERS, type Boxer } from "@/consts/boxers"
import { COMBATS } from "@/consts/combats"
---

<section id="carousel-boxers" class="relative h-min w-full overflow-hidden sm:mx-0">
<div
id="carousel-wrapper"
class="h-[30rem] w-full animate-fade-in whitespace-nowrap text-[0px] transition-transform md:h-[38rem]"
>
{
COMBATS.map((combat) => {
return <CombatSlideCarousel combat={combat} />
})
}
</div>
<hr
class="h-[2px] w-full border-t-0"
style="background:linear-gradient(to right, transparent 0%, white 50%, transparent 100%)"
/>
<div class="absolute inset-0 -z-10 flex items-start justify-center">
<LVDALogo
style={`
filter: drop-shadow(0 0 14px rgba(var(--color-accent-rgb), 0.4));
`}
className="w-full min-w-[600px] max-w-4xl items-center opacity-70"
/>
</div>
<div class="flex w-full items-center justify-center">
<button id="prev-button" class="button-action text-white"
><ChevronIcon class="rotate-180" /></button
>
<div id="number-figth" class="min-w-32 text-center">
<span>Primer</span> combate
</div>
<button id="next-button" class="button-action text-white"><ChevronIcon /></button>
</div>
</section>

<style>
.button-action:hover {
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 0%, transparent 100%);
transition: all 0.3s ease;
}
</style>

<script>
// import { $ } from "@/lib/dom-selector"
import { $ } from "@/lib/dom-selector"

document.addEventListener("astro:page-load", () => {
const $prevButton = $("#prev-button")
const $nextButton = $("#next-button")
const $wrapper = $("#carousel-wrapper")
const $fightBox = $("#number-figth")
const $fight = $fightBox.querySelector("span")!
const $slides = Array.from($wrapper.querySelectorAll("article"))
let index: number = 0
const slidesLength = $slides.length

const figthText: Record<number, string> = [
"Primer",
"Segundo",
"Tercer",
"Cuarto",
"Quinto",
"Sexto",
"Septimo",
"Octavo",
]

$prevButton.addEventListener("click", () => {
// fadeInOutEffect()
index--
if (index < 0) index = slidesLength - 1
const translatedX = index * -100
console.log({ translatedX, index })
$wrapper.style.transform = `translateX(${translatedX}%)`
$fight.innerText = `${figthText[index]}`
})

$nextButton.addEventListener("click", () => {
// fadeInOutEffect()
index++
if (index === slidesLength) index = 0
const translatedX = index * -100
console.log({ translatedX, index })
$wrapper.style.transform = `translateX(${translatedX}%)`
$fight.innerText = `${figthText[index]}`
})
})
</script>
183 changes: 183 additions & 0 deletions src/components/CombatSlideCarousel.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
import { BOXERS } from "@/consts/boxers"
import type { Combat } from "@/consts/combats"
import type { Boxer } from "@/types/Boxer"

interface Props {
combat: Combat
}

const { combat } = Astro.props

const boxers = BOXERS.filter((boxer) => combat.boxers.includes(boxer.id))

const groupAllies = (boxers: Boxer[]): Boxer[][] => {
const teams: Boxer[][] = []
const boxersClone = [...boxers]

while (boxersClone.length > 0) {
const boxer = boxersClone.pop()
if (boxer) {
const allies: Boxer[] = [boxer]

for (let i = boxersClone.length - 1; i >= 0; i--) {
const otherBoxer = boxersClone[i]
if (boxer.allies?.includes(otherBoxer.id)) {
allies.push(otherBoxer)
boxersClone.splice(i, 1)
}
}

teams.push(allies) // Add the formed team to the list of teams
}
}

return teams
}

const teams = groupAllies(boxers)
---

<article class="inline-block h-full w-full overflow-hidden">
{
boxers.length === 2 || boxers.length === 4 ? (
<>
<div class="relative flex h-full items-end justify-between gap-4 overflow-hidden sm:gap-12">
<div
class:list={[
"absolute inset-0 flex h-full w-full flex-row items-center justify-between",
]}
style={`mask-image: linear-gradient(to top, transparent 0%, #000 15%);`}
>
{boxers.length === 2
? boxers.map((boxer, key) => (
<picture
class:list={[
"absolute h-full w-[20rem] object-cover md:relative md:w-auto md:min-w-0 md:object-contain",
{ "-left-[25vw] xs:-left-[10vw] sm:left-0": key == 0 },
{ "-right-[25vw] xs:-right-[10vw] sm:right-0": key == 1 },
]}
>
<source srcset={`/img/boxers/${boxer.id}-big.webp`} type="image/webp" />
<img alt={boxer.name} src={`/img/boxers/${boxer.id}-big.webp`} />
</picture>
))
: boxers.length === 4 && (
<>
{teams.map((team, key1) => (
<div class:list={["relative h-full w-full"]}>
{team.map((boxer, key2) => (
<picture
class:list={[
"absolute top-0 h-full w-[100vw] object-cover sm:w-[70vw] md:w-[50vw] xl:w-[30rem] ",
{
"-left-[35vw] sm:-left-[20vw] md:-left-[10vw] xl:-left-[5rem]":
key2 == 0,
},
{
"-right-[35vw] sm:-right-[20vw] md:-right-[10vw] xl:-right-[5rem]":
key2 == 1,
},
]}
>
<source srcset={`/img/boxers/${boxer.id}-big.webp`} type="image/webp" />
<img alt={boxer.name} src={`/img/boxers/${boxer.id}-big.webp`} />
</picture>
))}
</div>
))}
</>
)}
</div>
<div
class:list={[
"absolute bottom-10 flex w-full font-atomic",
{ "-skew-y-12": boxers.length === 2 },
]}
>
<div class="mx-auto flex w-full max-w-xs items-center justify-center sm:max-w-md ">
{boxers.length === 2 ? (
<>
<span class="w-min text-3xl text-accent sm:text-5xl md:text-7xl">
{boxers[0].name.toLowerCase()}
</span>
<div class="ml-8 flex flex-col gap-y-2">
<span class="text-left text-xl text-primary sm:text-2xl md:text-5xl">
versus
</span>
<span class="w-min text-3xl text-accent sm:text-5xl md:text-7xl">
{boxers[1].name.toLowerCase()}
</span>
</div>
</>
) : (
boxers.length === 4 && (
<div class="mb-5 flex flex-col gap-y-2 text-center">
<span class="-skew-y-6 text-3xl text-accent sm:text-5xl md:text-7xl">
{teams[0].map((boxer) => boxer.name.toLowerCase()).join(" y ")}
</span>
<span class="-skew-y-6 text-xl text-primary sm:text-2xl md:text-5xl ">
versus
</span>
<span class="-skew-y-6 text-3xl text-accent sm:text-5xl md:text-7xl ">
{teams[1].map((boxer) => boxer.name.toLowerCase()).join(" y ")}
</span>
</div>
)
)}
</div>
</div>
</div>
</>
) : boxers.length > 4 ? (
<div class="flex h-full w-full items-center justify-center">
<div class="circle relative h-full w-full items-center justify-center">
<div class="absolute inset-0 flex h-full w-full items-center justify-center">
<div class="relative flex h-full w-full items-center justify-center">
{boxers.map((boxer) => (
<picture class="img absolute w-52 object-contain">
<source srcset={`/img/boxers/${boxer.id}-big.webp`} type="image/webp" />
<img alt={boxer.name} src={`/img/boxers/${boxer.id}-big.webp`} />
</picture>
))}
<div class="max-w-48 text-wrap text-center font-atomic text-3xl text-white text-opacity-90 drop-shadow-2xl backdrop-blur md:max-w-56 md:text-5xl">
el rey de la pista
</div>
</div>
</div>
</div>
</div>
) : (
<> </>
)
}
</article>

<script>
//import { $ } from "@/lib/dom-selector"
import { $, $$ } from "@/lib/dom-selector"

document.addEventListener("astro:page-load", () => {
const circle = $(".circle")
const images = $$(".circle .img")
const circleWidth = circle.clientWidth
const circleHeight = circle.clientHeight
const radius = 270 // Radio del círculo
const numImages = images.length

if (circle && images.length > 4) {
images.forEach((img, index) => {
const angle = (index / numImages) * Math.PI * 2 // Ángulo entre las imágenes
const centerX = circleWidth / 2
const centerY = circleHeight
const x = centerX + radius * Math.cos(angle) // Posición X
const y = centerY + radius * Math.sin(angle) - img.clientHeight // Posición Y
img.style.left = x + "px"
img.style.top = y + "px"

const rotationAngle = angle - Math.PI / 2 // Rotación de 90 grados para que la parte superior mire hacia el centro
img.style.transform = `translate(-50%, -50%) rotate(${rotationAngle}rad)`
})
}
})
</script>
16 changes: 16 additions & 0 deletions src/components/LVDALogo.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
import type { HTMLAttributes } from "astro/types"

type Props = {
className?: string
} & HTMLAttributes<"img">

const { className, ...props } = Astro.props
---

<img
src="/img/lvda.webp"
alt="lvda logo"
class:list={["accent-drop-shadow my-4 drop-shadow-lg", className]}
{...props}
/>
4 changes: 4 additions & 0 deletions src/pages/combates/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Image } from "astro:assets"
import Typography from "@/components/Typography.astro"
import { BOXERS } from "@/consts/boxers"
import { COMBATS, REY_DE_LA_PISTA_ID } from "@/consts/combats"
import CombatCarousel from "@/components/CombatCarousel.astro"
import Layout from "@/layouts/Layout.astro"
import type { BoxerGender } from "@/types/Boxer"

Expand Down Expand Up @@ -173,6 +174,9 @@ export const prerender = true
}
</ul>
</div>
<div class="w-full lg:flex lg:items-center">
<CombatCarousel />
</div>
</main>
</Layout>

Expand Down
24 changes: 12 additions & 12 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
},
"exclude": [
"public"
]
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
},
"exclude": [
"public"
]
}
Loading