add programm page components
This commit is contained in:
parent
dedf6a0e94
commit
d770b6f266
@ -1,10 +1,12 @@
|
|||||||
import { Routes, Route } from "react-router-dom";
|
import { Routes, Route } from "react-router-dom";
|
||||||
import Home from "./pages/Home";
|
import Home from "./pages/Home";
|
||||||
|
import Programm from "./pages/Programm";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
|
<Route path="/programm" element={<Programm />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
relume-test/src/assets/program-header.png
Normal file
BIN
relume-test/src/assets/program-header.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 MiB |
86
relume-test/src/components/Banner15.tsx
Normal file
86
relume-test/src/components/Banner15.tsx
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
type ImageProps = {
|
||||||
|
src: string;
|
||||||
|
alt?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Section = {
|
||||||
|
title: string;
|
||||||
|
image: ImageProps;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
sections: Section[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Banner15Props = React.ComponentPropsWithoutRef<"section"> & Partial<Props>;
|
||||||
|
|
||||||
|
export const Banner15 = (props: Banner15Props) => {
|
||||||
|
const { sections } = {
|
||||||
|
...Banner15Defaults,
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<section id="relume" className="flex w-screen max-w-full justify-end overflow-hidden bg-cloud-white">
|
||||||
|
<div className="flex justify-end">
|
||||||
|
{Array(2)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="grid animate-marquee-right auto-cols-max grid-flow-col grid-cols-[max-content] items-center justify-around py-4"
|
||||||
|
>
|
||||||
|
{sections.map((section, index) => (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
<div className="flex items-center justify-center whitespace-nowrap px-8 text-center lg:text-left">
|
||||||
|
<h1 className="text-6xl font-bold md:text-9xl lg:text-10xl">{section.title}</h1>
|
||||||
|
</div>
|
||||||
|
<div className="relative aspect-[3/2] w-full overflow-hidden object-cover">
|
||||||
|
<img
|
||||||
|
src={section.image.src}
|
||||||
|
alt={section.image.alt}
|
||||||
|
className="aspect-[3/2] size-full h-16 max-h-24 object-cover md:h-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Banner15Defaults: Props = {
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: "Relume Library",
|
||||||
|
image: {
|
||||||
|
src: "https://relume-assets.s3.us-east-1.amazonaws.com/placeholder-image.svg",
|
||||||
|
alt: "Relume Library",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Relume Library",
|
||||||
|
image: {
|
||||||
|
src: "https://relume-assets.s3.us-east-1.amazonaws.com/placeholder-image.svg",
|
||||||
|
alt: "Relume Library",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Relume Library",
|
||||||
|
image: {
|
||||||
|
src: "https://relume-assets.s3.us-east-1.amazonaws.com/placeholder-image.svg",
|
||||||
|
alt: "Relume Library",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Relume Library",
|
||||||
|
image: {
|
||||||
|
src: "https://relume-assets.s3.us-east-1.amazonaws.com/placeholder-image.svg",
|
||||||
|
alt: "Relume Library",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
283
relume-test/src/components/Event33.tsx
Normal file
283
relume-test/src/components/Event33.tsx
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
import { Button, Tabs, TabsContent, TabsList, TabsTrigger } from "@relume_io/relume-ui";
|
||||||
|
import type { ButtonProps } from "@relume_io/relume-ui";
|
||||||
|
import { BiMap } from "react-icons/bi";
|
||||||
|
|
||||||
|
type ImageProps = {
|
||||||
|
src: string;
|
||||||
|
alt?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ScheduledEvent = {
|
||||||
|
url: string;
|
||||||
|
time: string;
|
||||||
|
image: ImageProps;
|
||||||
|
title: string;
|
||||||
|
speaker: string;
|
||||||
|
location: string;
|
||||||
|
button: ButtonProps;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Tab = {
|
||||||
|
value: string;
|
||||||
|
trigger: string;
|
||||||
|
content: ScheduledEvent[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
tagline: string;
|
||||||
|
heading: string;
|
||||||
|
description: string;
|
||||||
|
tabs: Tab[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Event33Props = React.ComponentPropsWithoutRef<"section"> & Partial<Props>;
|
||||||
|
|
||||||
|
export const Event33 = (props: Event33Props) => {
|
||||||
|
const { tagline, heading, description, tabs } = {
|
||||||
|
...Event33Defaults,
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="relume" className="px-[5%] py-16 md:py-24 lg:py-28 bg-cloud-white font-barlow">
|
||||||
|
<div className="container">
|
||||||
|
<div className="mb-12 md:mb-18 lg:mb-20">
|
||||||
|
<div className="max-w-lg">
|
||||||
|
<p className="mb-3 font-semibold md:mb-4">{tagline}</p>
|
||||||
|
<h1 className="mb-5 text-5xl font-bold md:mb-6 md:text-7xl lg:text-8xl">{heading}</h1>
|
||||||
|
<p className="md:text-md">{description}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Tabs defaultValue={tabs[0].value} className="flex flex-col justify-start">
|
||||||
|
<TabsList className="no-scrollbar mb-12 ml-[-5vw] flex w-screen items-center overflow-auto pl-[5vw] md:ml-0 md:w-full md:overflow-hidden md:pl-0">
|
||||||
|
{tabs.map((tab, index) => (
|
||||||
|
<TabsTrigger
|
||||||
|
key={index}
|
||||||
|
value={tab.value}
|
||||||
|
className="px-4 data-[state=active]:border data-[state=active]:border-border-primary data-[state=inactive]:border-transparent data-[state=active]:bg-transparent data-[state=active]:text-neutral-black"
|
||||||
|
>
|
||||||
|
{tab.trigger}
|
||||||
|
</TabsTrigger>
|
||||||
|
))}
|
||||||
|
</TabsList>
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
<TabsContent
|
||||||
|
key={tab.value}
|
||||||
|
value={tab.value}
|
||||||
|
className="data-[state=active]:animate-tabs"
|
||||||
|
>
|
||||||
|
{tab.content.map((event, index) => (
|
||||||
|
<ScheduledEvent key={index} {...event} />
|
||||||
|
))}
|
||||||
|
</TabsContent>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ScheduledEvent: React.FC<ScheduledEvent> = ({
|
||||||
|
url,
|
||||||
|
time,
|
||||||
|
image,
|
||||||
|
title,
|
||||||
|
speaker,
|
||||||
|
location,
|
||||||
|
button,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-1 items-center gap-4 border-t border-border-primary py-6 last-of-type:border-b md:grid-cols-[6rem_max-content_1fr_max-content] md:gap-8 md:py-8">
|
||||||
|
<div className="text-md md:text-lg">{time}</div>
|
||||||
|
<div className="w-full md:w-36">
|
||||||
|
<a href={url} className="relative block aspect-[3/2] md:aspect-square">
|
||||||
|
<img src={image.src} alt={image.alt} className="absolute size-full object-cover" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="grid auto-cols-fr grid-cols-1 items-center gap-4 lg:grid-cols-[1fr_.25fr]">
|
||||||
|
<div>
|
||||||
|
<h5 className="text-xl font-bold md:text-2xl">{title}</h5>
|
||||||
|
<div>{speaker}</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<BiMap className="size-6 flex-none" />
|
||||||
|
<span>{location}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button {...button} asChild>
|
||||||
|
<a href={url}>{button.title}</a>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Event33Defaults: Props = {
|
||||||
|
tagline: "Tagline",
|
||||||
|
heading: "Schedule",
|
||||||
|
description:
|
||||||
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique.",
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
value: "fri-09-feb",
|
||||||
|
trigger: "Fri 09 Feb",
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
url: "#",
|
||||||
|
time: "8:00 am",
|
||||||
|
image: {
|
||||||
|
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
|
||||||
|
alt: "Relume placeholder image 1",
|
||||||
|
},
|
||||||
|
title: "Event title heading",
|
||||||
|
speaker: "Speaker",
|
||||||
|
location: "Location",
|
||||||
|
button: {
|
||||||
|
variant: "secondary",
|
||||||
|
size: "primary",
|
||||||
|
title: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "#",
|
||||||
|
time: "9:00 am",
|
||||||
|
image: {
|
||||||
|
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
|
||||||
|
alt: "Relume placeholder image 2",
|
||||||
|
},
|
||||||
|
title: "Event title heading",
|
||||||
|
speaker: "Speaker",
|
||||||
|
location: "Location",
|
||||||
|
button: {
|
||||||
|
variant: "secondary",
|
||||||
|
size: "primary",
|
||||||
|
title: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "#",
|
||||||
|
time: "10:00 am",
|
||||||
|
image: {
|
||||||
|
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
|
||||||
|
alt: "Relume placeholder image 3",
|
||||||
|
},
|
||||||
|
title: "Event title heading",
|
||||||
|
speaker: "Speaker",
|
||||||
|
location: "Location",
|
||||||
|
button: {
|
||||||
|
variant: "secondary",
|
||||||
|
size: "primary",
|
||||||
|
title: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "sat-10-feb",
|
||||||
|
trigger: "Sat 10 Feb",
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
url: "#",
|
||||||
|
time: "8:00 am",
|
||||||
|
image: {
|
||||||
|
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
|
||||||
|
alt: "Relume placeholder image 4",
|
||||||
|
},
|
||||||
|
title: "Event title heading",
|
||||||
|
speaker: "Speaker",
|
||||||
|
location: "Location",
|
||||||
|
button: {
|
||||||
|
variant: "secondary",
|
||||||
|
size: "primary",
|
||||||
|
title: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "#",
|
||||||
|
time: "9:00 am",
|
||||||
|
image: {
|
||||||
|
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
|
||||||
|
alt: "Relume placeholder image 5",
|
||||||
|
},
|
||||||
|
title: "Event title heading",
|
||||||
|
speaker: "Speaker",
|
||||||
|
location: "Location",
|
||||||
|
button: {
|
||||||
|
variant: "secondary",
|
||||||
|
size: "primary",
|
||||||
|
title: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "#",
|
||||||
|
time: "10:00 am",
|
||||||
|
image: {
|
||||||
|
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
|
||||||
|
alt: "Relume placeholder image 6",
|
||||||
|
},
|
||||||
|
title: "Event title heading",
|
||||||
|
speaker: "Speaker",
|
||||||
|
location: "Location",
|
||||||
|
button: {
|
||||||
|
variant: "secondary",
|
||||||
|
size: "primary",
|
||||||
|
title: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "sun-11-feb",
|
||||||
|
trigger: "Sun 11 Feb",
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
url: "#",
|
||||||
|
time: "8:00 am",
|
||||||
|
image: {
|
||||||
|
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
|
||||||
|
alt: "Relume placeholder image 7",
|
||||||
|
},
|
||||||
|
title: "Event title heading",
|
||||||
|
speaker: "Speaker",
|
||||||
|
location: "Location",
|
||||||
|
button: {
|
||||||
|
variant: "secondary",
|
||||||
|
size: "primary",
|
||||||
|
title: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "#",
|
||||||
|
time: "9:00 am",
|
||||||
|
image: {
|
||||||
|
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
|
||||||
|
alt: "Relume placeholder image 8",
|
||||||
|
},
|
||||||
|
title: "Event title heading",
|
||||||
|
speaker: "Speaker",
|
||||||
|
location: "Location",
|
||||||
|
button: {
|
||||||
|
variant: "secondary",
|
||||||
|
size: "primary",
|
||||||
|
title: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "#",
|
||||||
|
time: "10:00 am",
|
||||||
|
image: {
|
||||||
|
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
|
||||||
|
alt: "Relume placeholder image 9",
|
||||||
|
},
|
||||||
|
title: "Event title heading",
|
||||||
|
speaker: "Speaker",
|
||||||
|
location: "Location",
|
||||||
|
button: {
|
||||||
|
variant: "secondary",
|
||||||
|
size: "primary",
|
||||||
|
title: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
316
relume-test/src/components/Filters5.tsx
Normal file
316
relume-test/src/components/Filters5.tsx
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { BiFilter, BiSearch } from "react-icons/bi";
|
||||||
|
import { RxChevronDown } from "react-icons/rx";
|
||||||
|
import { IoCloseOutline } from "react-icons/io5";
|
||||||
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
|
import type { Variants } from "framer-motion";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
Input,
|
||||||
|
Label,
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
Tabs,
|
||||||
|
TabsList,
|
||||||
|
TabsTrigger,
|
||||||
|
} from "@relume_io/relume-ui";
|
||||||
|
|
||||||
|
type FilterValues = {
|
||||||
|
filterOne: string;
|
||||||
|
filterTwo: string[];
|
||||||
|
filterThree: string[];
|
||||||
|
filterFour: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{ value: "View all", trigger: "View all" },
|
||||||
|
{ value: "Category one", trigger: "Category one" },
|
||||||
|
{ value: "Category two", trigger: "Category two" },
|
||||||
|
{ value: "Category three", trigger: "Category three" },
|
||||||
|
{ value: "Category four", trigger: "Category four" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{ value: "option-1", label: "Option one" },
|
||||||
|
{ value: "option-2", label: "Option two" },
|
||||||
|
{ value: "option-3", label: "Option three" },
|
||||||
|
{ value: "option-4", label: "Option four" },
|
||||||
|
{ value: "option-5", label: "Option five" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const containerVariants: Variants = {
|
||||||
|
initial: {
|
||||||
|
height: 0,
|
||||||
|
opacity: 0,
|
||||||
|
transition: { duration: 0.2, ease: "easeInOut" },
|
||||||
|
},
|
||||||
|
animate: {
|
||||||
|
height: "auto",
|
||||||
|
opacity: 1,
|
||||||
|
transition: { duration: 0.2, ease: "easeInOut" },
|
||||||
|
},
|
||||||
|
exit: {
|
||||||
|
height: 0,
|
||||||
|
opacity: 0,
|
||||||
|
transition: { duration: 0.2, ease: "easeInOut" },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Filters5 = () => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [selectedValues, setSelectedValues] = useState<FilterValues>({
|
||||||
|
filterOne: "",
|
||||||
|
filterTwo: ["option-1"],
|
||||||
|
filterThree: ["option-1"],
|
||||||
|
filterFour: ["option-1"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClear = (filter: keyof FilterValues) => {
|
||||||
|
setSelectedValues((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[filter]: Array.isArray(prev[filter]) ? [] : "",
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCheckboxChange = (filter: keyof Omit<FilterValues, "filterOne">, value: string) => {
|
||||||
|
setSelectedValues((prev) => {
|
||||||
|
const currentItems = prev[filter];
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[filter]: currentItems.includes(value)
|
||||||
|
? currentItems.filter((item) => item !== value)
|
||||||
|
: [...currentItems, value],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSelectedLabels = (filter: keyof FilterValues) => {
|
||||||
|
if (!selectedValues[filter].length) return "Select options";
|
||||||
|
if (selectedValues[filter].length === 1) {
|
||||||
|
return options.find((opt) => opt.value === selectedValues[filter][0])?.label;
|
||||||
|
}
|
||||||
|
return `${selectedValues[filter].length} selected`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="px-[5%] py-16 md:py-24 lg:py-28 bg-cloud-white font-barlow">
|
||||||
|
<div className="container">
|
||||||
|
<div className="mb-12 w-full text-center md:mb-18 lg:mb-20">
|
||||||
|
<h1 className="mb-5 text-5xl font-bold md:mb-6 md:text-7xl lg:text-8xl">Collection</h1>
|
||||||
|
<p className="md:text-md">Lorem ipsum dolor sit amet.</p>
|
||||||
|
</div>
|
||||||
|
<div className="mb-8 grid auto-cols-fr grid-cols-2 grid-rows-[auto_auto] items-center justify-between gap-x-6 gap-y-8 lg:grid-cols-[1fr_max-content_1fr] lg:gap-y-0">
|
||||||
|
<Button
|
||||||
|
className="w-fit gap-3 self-start bg-electric-violet text-cloud-white rounded-2xl px-6 py-3 border-electric-violet font-semibold"
|
||||||
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
|
>
|
||||||
|
<BiFilter className="size-6" />
|
||||||
|
<span>Filter</span>
|
||||||
|
</Button>
|
||||||
|
<Tabs
|
||||||
|
defaultValue={tabs[0].value}
|
||||||
|
className="no-scrollbar flex w-full flex-col items-center justify-center overflow-scroll [grid-area:2/1/3/3] md:overflow-auto lg:[grid-area:auto/auto/auto/auto]"
|
||||||
|
>
|
||||||
|
<TabsList className="flex w-screen items-center justify-start pl-[5vw] md:w-full md:justify-center md:overflow-hidden md:pl-0">
|
||||||
|
{tabs.map((tab, index) => (
|
||||||
|
<TabsTrigger
|
||||||
|
key={index}
|
||||||
|
value={tab.value}
|
||||||
|
className="px-4 data-[state=active]:border data-[state=active]:border-electric-violet data-[state=inactive]:border-transparent data-[state=active]:bg-transparent data-[state=active]:text-electric-violet font-barlow"
|
||||||
|
>
|
||||||
|
{tab.trigger}
|
||||||
|
</TabsTrigger>
|
||||||
|
))}
|
||||||
|
</TabsList>
|
||||||
|
</Tabs>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger className="-mr-2 flex items-center gap-2 justify-self-end">
|
||||||
|
<p className="whitespace-nowrap">Sort by</p>
|
||||||
|
<RxChevronDown className="shrink-0 text-text-primary transition-transform duration-300" />
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end">
|
||||||
|
{[
|
||||||
|
"Most Popular",
|
||||||
|
"Most Recent",
|
||||||
|
"Name: A to Z",
|
||||||
|
"Name: Z to A",
|
||||||
|
"Price: Low to High",
|
||||||
|
"Price: High to Low",
|
||||||
|
].map((option) => (
|
||||||
|
<DropdownMenuItem key={option}>{option}</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
<AnimatePresence initial={false} mode="wait">
|
||||||
|
{isOpen && (
|
||||||
|
<motion.div
|
||||||
|
variants={containerVariants}
|
||||||
|
initial="initial"
|
||||||
|
animate="animate"
|
||||||
|
exit="exit"
|
||||||
|
className="overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="mb-8 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-4">
|
||||||
|
<div>
|
||||||
|
<div className="mb-2 flex items-center justify-between">
|
||||||
|
<span>Filter One</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
size="link"
|
||||||
|
onClick={() => handleClear("filterOne")}
|
||||||
|
className="text-sm"
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Input
|
||||||
|
placeholder="Stichwortsuche"
|
||||||
|
icon={<BiSearch className="size-6" />}
|
||||||
|
value={selectedValues.filterOne}
|
||||||
|
onChange={(e) =>
|
||||||
|
setSelectedValues((prev) => ({
|
||||||
|
...prev,
|
||||||
|
filterOne: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className="border-electric-violet rounded-2xl"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-2 flex items-center justify-between">
|
||||||
|
<span>Filter Two</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
size="link"
|
||||||
|
onClick={() => handleClear("filterTwo")}
|
||||||
|
className="text-sm"
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Select value="" onValueChange={() => {}}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder={getSelectedLabels("filterTwo")} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{options.map((option) => (
|
||||||
|
<div key={option.value} className="flex items-center space-x-2 p-2">
|
||||||
|
<Checkbox
|
||||||
|
id={`filter-two-${option.value}`}
|
||||||
|
checked={selectedValues.filterTwo.includes(option.value)}
|
||||||
|
onCheckedChange={() => handleCheckboxChange("filterTwo", option.value)}
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
className="flex-grow cursor-pointer"
|
||||||
|
htmlFor={`filter-two-${option.value}`}
|
||||||
|
onClick={(e: React.MouseEvent<HTMLLabelElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleCheckboxChange("filterTwo", option.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-2 flex items-center justify-between">
|
||||||
|
<span>Filter Three</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
size="link"
|
||||||
|
onClick={() => handleClear("filterThree")}
|
||||||
|
className="text-sm"
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Select value="" onValueChange={() => {}}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder={getSelectedLabels("filterThree")} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{options.map((option) => (
|
||||||
|
<div key={option.value} className="flex items-center space-x-2 px-2 py-1.5">
|
||||||
|
<Checkbox
|
||||||
|
id={`filter-three-${option.value}`}
|
||||||
|
checked={selectedValues.filterThree.includes(option.value)}
|
||||||
|
onCheckedChange={() =>
|
||||||
|
handleCheckboxChange("filterThree", option.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
className="flex-grow cursor-pointer"
|
||||||
|
htmlFor={`filter-three-${option.value}`}
|
||||||
|
onClick={(e: React.MouseEvent<HTMLLabelElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleCheckboxChange("filterThree", option.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-2 flex items-center justify-between">
|
||||||
|
<span>Filter Four</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
size="link"
|
||||||
|
onClick={() => handleClear("filterFour")}
|
||||||
|
className="text-sm"
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Select value="" onValueChange={() => {}}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder={getSelectedLabels("filterFour")} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{options.map((option) => (
|
||||||
|
<div key={option.value} className="flex items-center space-x-2 px-2 py-1.5">
|
||||||
|
<Checkbox
|
||||||
|
id={`filter-four-${option.value}`}
|
||||||
|
checked={selectedValues.filterFour.includes(option.value)}
|
||||||
|
onCheckedChange={() => handleCheckboxChange("filterFour", option.value)}
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
className="flex-grow cursor-pointer"
|
||||||
|
htmlFor={`filter-four-${option.value}`}
|
||||||
|
onClick={(e: React.MouseEvent<HTMLLabelElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleCheckboxChange("filterFour", option.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
<div>
|
||||||
|
<div className="hidden" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
59
relume-test/src/components/Header23.tsx
Normal file
59
relume-test/src/components/Header23.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import headerBg from "../assets/program-header.png";
|
||||||
|
import { Button } from "@relume_io/relume-ui";
|
||||||
|
import type { ButtonProps } from "@relume_io/relume-ui";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
heading: string;
|
||||||
|
description: string;
|
||||||
|
buttons: ButtonProps[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Header23Props = React.ComponentPropsWithoutRef<"section"> & Partial<Props>;
|
||||||
|
|
||||||
|
export const Header23 = (props: Header23Props) => {
|
||||||
|
const { heading, description, buttons } = {
|
||||||
|
...Header23Defaults,
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<section className="px-[5%] py-16 md:py-24 lg:py-28 relative font-barlow overflow-hidden">
|
||||||
|
{/* Background image with overlay */}
|
||||||
|
<div className="absolute inset-0 pointer-events-none">
|
||||||
|
<div className="absolute inset-0 bg-neutral-dark opacity-90" />
|
||||||
|
<img
|
||||||
|
src={headerBg}
|
||||||
|
alt=""
|
||||||
|
className="absolute inset-0 w-full h-full object-cover opacity-40"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* Content */}
|
||||||
|
<div className="container relative z-10">
|
||||||
|
<div className="mx-auto w-full max-w-lg text-center">
|
||||||
|
<h1 className="mb-5 text-6xl font-bold text-cloud-white md:mb-6 md:text-9xl lg:text-10xl">
|
||||||
|
{heading}
|
||||||
|
</h1>
|
||||||
|
<p className="md:text-md text-cloud-white text-[18px] leading-[1.5]">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
{buttons.length > 0 && (
|
||||||
|
<div className="mt-6 flex items-center justify-center gap-x-4 md:mt-8">
|
||||||
|
{buttons.map((button, index) => (
|
||||||
|
<Button key={index} {...button}>
|
||||||
|
{button.title}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Header23Defaults: Props = {
|
||||||
|
heading: "UXplore 2026 Programm",
|
||||||
|
description: "Erfahre von den klügsten Köpfen der Branche, wie sie komplexe Design-Herausforderungen meistern. Von Schweizer Präzision im Interface bis hin zu globalen Strategien führender Tech-Giganten – unsere Speaker bringen handfeste Insights statt nur Buzzwords.",
|
||||||
|
buttons: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header23;
|
||||||
3
relume-test/src/declarations.d.ts
vendored
3
relume-test/src/declarations.d.ts
vendored
@ -2,4 +2,5 @@ declare module "*.png";
|
|||||||
declare module "*.jpg";
|
declare module "*.jpg";
|
||||||
declare module "*.jpeg";
|
declare module "*.jpeg";
|
||||||
declare module "*.svg";
|
declare module "*.svg";
|
||||||
declare module "*.webp";
|
declare module "*.webp";
|
||||||
|
declare module "*.css";
|
||||||
21
relume-test/src/pages/Programm.tsx
Normal file
21
relume-test/src/pages/Programm.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { Navbar3 } from "../components/Navbar";
|
||||||
|
import { Header23 } from "../components/Header23";
|
||||||
|
import { Filters5 } from "../components/Filters5";
|
||||||
|
import { Event33 } from "../components/Event33";
|
||||||
|
import { Banner15 } from "../components/Banner15";
|
||||||
|
import { Footer3 } from "../components/Footer";
|
||||||
|
|
||||||
|
const Programm = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Navbar3 />
|
||||||
|
<Header23 />
|
||||||
|
<Filters5 />
|
||||||
|
<Event33 />
|
||||||
|
<Banner15 />
|
||||||
|
<Footer3 />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Programm;
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user