Add partners section

This commit is contained in:
2025-11-02 17:26:51 -05:00
parent 602eabc7ba
commit c63b15d5d6
9 changed files with 212 additions and 15 deletions

20
package-lock.json generated
View File

@ -8,6 +8,8 @@
"name": "bcdigital-challenge", "name": "bcdigital-challenge",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@fontsource-variable/merriweather": "^5.2.6",
"@fontsource/alex-brush": "^5.2.8",
"@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-slot": "^1.2.3",
"@tailwindcss/vite": "^4.1.16", "@tailwindcss/vite": "^4.1.16",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
@ -894,6 +896,24 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@fontsource-variable/merriweather": {
"version": "5.2.6",
"resolved": "https://registry.npmjs.org/@fontsource-variable/merriweather/-/merriweather-5.2.6.tgz",
"integrity": "sha512-bHCDt99f/M48eUcFA86uh/oSPyn8r/ZxXR9l578wqLvjTwDzXx8A/XOAI05WfJ3LnH1rDufQX5RJwiZtbXUCkw==",
"license": "OFL-1.1",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"node_modules/@fontsource/alex-brush": {
"version": "5.2.8",
"resolved": "https://registry.npmjs.org/@fontsource/alex-brush/-/alex-brush-5.2.8.tgz",
"integrity": "sha512-ShSsZkWN7O6H6x56Jc2c1d+YXDTCGIRBvLKiVIa7r3tyg6Ern56fN2xriAjNNBmvn37Y96XCkavrpERm/IRCEQ==",
"license": "OFL-1.1",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"node_modules/@humanfs/core": { "node_modules/@humanfs/core": {
"version": "0.19.1", "version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",

View File

@ -16,6 +16,8 @@
"**/*": "prettier --write --ignore-unknown" "**/*": "prettier --write --ignore-unknown"
}, },
"dependencies": { "dependencies": {
"@fontsource-variable/merriweather": "^5.2.6",
"@fontsource/alex-brush": "^5.2.8",
"@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-slot": "^1.2.3",
"@tailwindcss/vite": "^4.1.16", "@tailwindcss/vite": "^4.1.16",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",

View File

@ -1,3 +1,5 @@
import { Navbar } from "./components/navbar/navbar";
import { PartnersMarquee } from "./components/partners-marquee/partners-marquee";
import { AuroraText } from "./components/ui/aurora-text"; import { AuroraText } from "./components/ui/aurora-text";
import { DotPattern } from "./components/ui/dot-pattern"; import { DotPattern } from "./components/ui/dot-pattern";
import { RainbowButton } from "./components/ui/rainbow-button"; import { RainbowButton } from "./components/ui/rainbow-button";
@ -5,18 +7,8 @@ import { TextAnimate } from "./components/ui/text-animate";
export function App() { export function App() {
return ( return (
<div className="h-screen w-screen flex flex-col"> <div className="h-screen w-screen flex flex-col font-merriweather">
<nav className="flex justify-between items-center p-4 px-6 shadow-md"> <Navbar />
<h1 className="text-2xl font-bold">Great Music LLM</h1>
<div className="hidden sm:flex gap-2">
<button className="bg-blue-500 text-white px-4 py-2 rounded">
Button 1
</button>
<button className="bg-green-500 text-white px-4 py-2 rounded">
Button 2
</button>
</div>
</nav>
<main className="flex-1 overflow-auto"> <main className="flex-1 overflow-auto">
<div <div
className="h-full bg-cover bg-center className="h-full bg-cover bg-center
@ -42,9 +34,18 @@ export function App() {
</div> </div>
</div> </div>
</div> </div>
<div className="relative overflow-hidden"> <div className="relative overflow-hidden py-5 flex flex-col gap-5">
<DotPattern /> <TextAnimate
Section 2 coming soon... animation="blurInUp"
by="character"
as="h3"
className="text-xl font-bold text-center"
>
Our Partners
</TextAnimate>
<PartnersMarquee />
<span></span> {/* Spacer for DotPattern */}
<DotPattern className="-z-10" />
</div> </div>
</main> </main>
</div> </div>

View File

@ -0,0 +1,15 @@
export function Navbar() {
return (
<nav className="flex justify-between items-center p-4 px-6 shadow-md">
<h1 className="text-2xl font-bold font-alex-brush">Great Music LLM</h1>
<div className="hidden sm:flex gap-2">
<button className="bg-blue-500 text-white px-4 py-2 rounded">
Button 1
</button>
<button className="bg-green-500 text-white px-4 py-2 rounded">
Button 2
</button>
</div>
</nav>
);
}

View File

@ -0,0 +1,48 @@
import { Marquee } from "../ui/marquee";
export function PartnersMarquee() {
const partners = [
{
name: "Conductor Orchestra",
logo: "https://t3.ftcdn.net/jpg/05/71/43/76/360_F_571437617_ZNppyF5qpbJn9dYifhjWEQkgjbZNBXP9.jpg",
},
{
name: "Chicago Symphony Orchestra",
logo: "https://upload.wikimedia.org/wikipedia/commons/1/1f/Wiki-CSO_logo2024_stacked-whitebg.png",
},
{
name: "Toronto Symphony Orchestra",
logo: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSfThsC3B2BGCKjnyr_IMiJmp-0jI9I9blZrw&s",
},
{
name: "Los Angeles Chamber Orchestra",
logo: "https://admin.itsnicethat.com/images/TOHFR2DIydoDTaGM6NbfVRFZfJU=/168760/format-webp%7Cwidth-2880/5d947a047fa44cbd2200fd0f.jpg",
},
{
name: "Richmond Symphony Orchestra",
logo: "https://richmondsymphony.org/wp-content/uploads/2021/07/rso-logo-2023.png",
},
];
return (
<div className="relative flex w-full flex-col items-center justify-center overflow-hidden">
<Marquee>
{partners.map((partner) => (
<div
key={partner.name}
className="flex flex-col items-center justify-center p-4 bg-white border-2 border-gray-300 rounded-lg shadow-md"
>
<img
src={partner.logo}
alt={`${partner.name} logo`}
className="max-h-24"
/>
<p>{partner.name}</p>
</div>
))}
</Marquee>
<div className="from-background pointer-events-none absolute inset-y-0 left-0 w-4 bg-linear-to-r"></div>
<div className="from-background pointer-events-none absolute inset-y-0 right-0 w-4 bg-linear-to-l"></div>
</div>
);
}

View File

@ -0,0 +1,74 @@
import type { ComponentPropsWithoutRef } from "react";
import { cn } from "@/lib/utils";
interface MarqueeProps extends ComponentPropsWithoutRef<"div"> {
/**
* Optional CSS class name to apply custom styles
*/
className?: string;
/**
* Whether to reverse the animation direction
* @default false
*/
reverse?: boolean;
/**
* Whether to pause the animation on hover
* @default false
*/
pauseOnHover?: boolean;
/**
* Content to be displayed in the marquee
*/
children: React.ReactNode;
/**
* Whether to animate vertically instead of horizontally
* @default false
*/
vertical?: boolean;
/**
* Number of times to repeat the content
* @default 4
*/
repeat?: number;
}
export function Marquee({
className,
reverse = false,
pauseOnHover = false,
children,
vertical = false,
repeat = 4,
...props
}: MarqueeProps) {
return (
<div
{...props}
className={cn(
"group flex [gap:var(--gap)] overflow-hidden p-2 [--duration:40s] [--gap:1rem]",
{
"flex-row": !vertical,
"flex-col": vertical,
},
className,
)}
>
{Array(repeat)
.fill(0)
.map((_, i) => (
<div
key={i}
className={cn("flex shrink-0 justify-around [gap:var(--gap)]", {
"animate-marquee flex-row": !vertical,
"animate-marquee-vertical flex-col": vertical,
"group-hover:[animation-play-state:paused]": pauseOnHover,
"[animation-direction:reverse]": reverse,
})}
>
{children}
</div>
))}
</div>
);
}

3
src/globals.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
declare module "*.css";
declare module "@fontsource/*" {}
declare module "@fontsource-variable/*" {}

View File

@ -4,6 +4,9 @@
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@theme inline { @theme inline {
--font-alex-brush: "Alex Brush", cursive;
--font-merriweather: "Merriweather Variable", serif;
--radius-sm: calc(var(--radius) - 4px); --radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px); --radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius); --radius-lg: var(--radius);
@ -40,42 +43,70 @@
--color-sidebar-border: var(--sidebar-border); --color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring); --color-sidebar-ring: var(--sidebar-ring);
--animate-aurora: aurora 8s ease-in-out infinite alternate; --animate-aurora: aurora 8s ease-in-out infinite alternate;
@keyframes aurora { @keyframes aurora {
0% { 0% {
background-position: 0% 50%; background-position: 0% 50%;
transform: rotate(-5deg) scale(0.9); transform: rotate(-5deg) scale(0.9);
} }
25% { 25% {
background-position: 50% 100%; background-position: 50% 100%;
transform: rotate(5deg) scale(1.1); transform: rotate(5deg) scale(1.1);
} }
50% { 50% {
background-position: 100% 50%; background-position: 100% 50%;
transform: rotate(-3deg) scale(0.95); transform: rotate(-3deg) scale(0.95);
} }
75% { 75% {
background-position: 50% 0%; background-position: 50% 0%;
transform: rotate(3deg) scale(1.05); transform: rotate(3deg) scale(1.05);
} }
100% { 100% {
background-position: 0% 50%; background-position: 0% 50%;
transform: rotate(-5deg) scale(0.9); transform: rotate(-5deg) scale(0.9);
} }
} }
--animate-rainbow: rainbow var(--speed, 2s) infinite linear; --animate-rainbow: rainbow var(--speed, 2s) infinite linear;
--color-color-5: var(--color-5); --color-color-5: var(--color-5);
--color-color-4: var(--color-4); --color-color-4: var(--color-4);
--color-color-3: var(--color-3); --color-color-3: var(--color-3);
--color-color-2: var(--color-2); --color-color-2: var(--color-2);
--color-color-1: var(--color-1); --color-color-1: var(--color-1);
@keyframes rainbow { @keyframes rainbow {
0% { 0% {
background-position: 0%; background-position: 0%;
} }
100% { 100% {
background-position: 200%; background-position: 200%;
} }
} }
--animate-marquee: marquee var(--duration) infinite linear;
--animate-marquee-vertical: marquee-vertical var(--duration) linear infinite;
@keyframes marquee {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
@keyframes marquee-vertical {
from {
transform: translateY(0);
}
to {
transform: translateY(calc(-100% - var(--gap)));
}
}
} }
:root { :root {
@ -161,6 +192,7 @@
* { * {
@apply border-border outline-ring/50; @apply border-border outline-ring/50;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }

View File

@ -2,6 +2,8 @@ import { StrictMode } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import "./index.css"; import "./index.css";
import { App } from "./app"; import { App } from "./app";
import "@fontsource/alex-brush";
import "@fontsource-variable/merriweather";
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<StrictMode> <StrictMode>