Add partners section
This commit is contained in:
20
package-lock.json
generated
20
package-lock.json
generated
@ -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",
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
31
src/app.tsx
31
src/app.tsx
@ -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>
|
||||||
|
|||||||
15
src/components/navbar/navbar.tsx
Normal file
15
src/components/navbar/navbar.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
48
src/components/partners-marquee/partners-marquee.tsx
Normal file
48
src/components/partners-marquee/partners-marquee.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
74
src/components/ui/marquee.tsx
Normal file
74
src/components/ui/marquee.tsx
Normal 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
3
src/globals.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
declare module "*.css";
|
||||||
|
declare module "@fontsource/*" {}
|
||||||
|
declare module "@fontsource-variable/*" {}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user