feat: add two and three column grid variants
This commit is contained in:
22
components/LoadingSpinner/index.tsx
Normal file
22
components/LoadingSpinner/index.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import styles from "./loading.module.css"
|
||||||
|
|
||||||
|
export default function LoadingSpinner() {
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={styles.spinner}>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
89
components/LoadingSpinner/loading.module.css
Normal file
89
components/LoadingSpinner/loading.module.css
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner div {
|
||||||
|
transform-origin: 40px 40px;
|
||||||
|
animation: spinnerAnimation 1.2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner div::after {
|
||||||
|
content: " ";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 37px;
|
||||||
|
width: 6px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 20%;
|
||||||
|
background: var(--Brand-Main-Strong);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner div:nth-child(1) {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
animation-delay: -1.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner div:nth-child(2) {
|
||||||
|
transform: rotate(30deg);
|
||||||
|
animation-delay: -1s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(3) {
|
||||||
|
transform: rotate(60deg);
|
||||||
|
animation-delay: -0.9s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(4) {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
animation-delay: -0.8s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(5) {
|
||||||
|
transform: rotate(120deg);
|
||||||
|
animation-delay: -0.7s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(6) {
|
||||||
|
transform: rotate(150deg);
|
||||||
|
animation-delay: -0.6s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(7) {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
animation-delay: -0.5s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(8) {
|
||||||
|
transform: rotate(210deg);
|
||||||
|
animation-delay: -0.4s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(9) {
|
||||||
|
transform: rotate(240deg);
|
||||||
|
animation-delay: -0.3s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(10) {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
animation-delay: -0.2s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(11) {
|
||||||
|
transform: rotate(300deg);
|
||||||
|
animation-delay: -0.1s;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(12) {
|
||||||
|
transform: rotate(330deg);
|
||||||
|
animation-delay: 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinnerAnimation {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,20 +24,21 @@
|
|||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
.value {
|
.value {
|
||||||
color: var(--some-brown-color, #4d001b);
|
color: var(--Theme-Primary-Light-On-Surface-Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardContainer {
|
.cardContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardSubtitle {
|
.cardSubtitle {
|
||||||
font-family: var(--ff-fira-sans);
|
font-family: var(--ff-fira-sans);
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 14.4px;
|
line-height: 14.4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #b05b65;
|
color: var(--Theme-Primary-Light-On-Surface-Accent);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,12 +48,16 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
min-height: 280px;
|
||||||
|
background-color: var(--Base-Fill-Normal);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: var(--Base-Fill-Normal);
|
|
||||||
|
|
||||||
|
text-decoration: none;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--Theme-Primary-Light-On-Surface-Text);
|
||||||
aspect-ratio: 1/1;
|
aspect-ratio: 1/1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,16 +65,4 @@
|
|||||||
.card:nth-child(2) {
|
.card:nth-child(2) {
|
||||||
grid-area: card2;
|
grid-area: card2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:last-of-type {
|
|
||||||
grid-area: card3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:nth-child(2) {
|
|
||||||
grid-area: card2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:last-of-type {
|
|
||||||
grid-area: card3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Link from "next/link"
|
|||||||
import { Lang } from "@/constants/languages"
|
import { Lang } from "@/constants/languages"
|
||||||
import { serverClient } from "@/lib/trpc/server"
|
import { serverClient } from "@/lib/trpc/server"
|
||||||
|
|
||||||
|
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||||
import Title from "@/components/Title"
|
import Title from "@/components/Title"
|
||||||
|
|
||||||
import levelsData from "../data"
|
import levelsData from "../data"
|
||||||
@@ -53,8 +54,8 @@ export default async function CurrentBenefitsBlock({
|
|||||||
</header>
|
</header>
|
||||||
{subtitle && <p className={styles.subtitle}>{subtitle}</p>}
|
{subtitle && <p className={styles.subtitle}>{subtitle}</p>}
|
||||||
|
|
||||||
<div className={styles.cardContainer}>
|
<CardGrid>
|
||||||
{currentLevel.benefits.map((benefit, idx) => (
|
{currentLevel.benefits.map((benefit, idx) => (
|
||||||
<Link
|
<Link
|
||||||
href={benefit.href}
|
href={benefit.href}
|
||||||
key={`${currentLevel}-${idx}`}
|
key={`${currentLevel}-${idx}`}
|
||||||
@@ -67,7 +68,7 @@ export default async function CurrentBenefitsBlock({
|
|||||||
<p className={styles.cardSubtitle}>{benefit.description}</p>
|
<p className={styles.cardSubtitle}>{benefit.description}</p>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</CardGrid>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export default async function NextLevelBenefitsBlock({
|
|||||||
)}
|
)}
|
||||||
</header>
|
</header>
|
||||||
{subtitle && <p className={styles.subtitle}>{subtitle}</p>}
|
{subtitle && <p className={styles.subtitle}>{subtitle}</p>}
|
||||||
<CardGrid>
|
<CardGrid variant="twoColumnGrid">
|
||||||
{perks.map((perk) => (
|
{perks.map((perk) => (
|
||||||
<article key={perk.id} className={styles.card}>
|
<article key={perk.id} className={styles.card}>
|
||||||
<Button type="button" intent="secondary" disabled>
|
<Button type="button" intent="secondary" disabled>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { _ } from "@/lib/translation"
|
import { _ } from "@/lib/translation"
|
||||||
import { trpc } from "@/lib/trpc/client"
|
import { trpc } from "@/lib/trpc/client"
|
||||||
|
|
||||||
|
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||||
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||||
|
|
||||||
import Container from "../Container"
|
import Container from "../Container"
|
||||||
@@ -40,8 +41,9 @@ export default function PreviousStays({
|
|||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Header title={title} subtitle={subtitle} link={link} />
|
<Header title={title} subtitle={subtitle} link={link} />
|
||||||
{isLoading ? <p>{_("Loading")}</p> : null}
|
{isLoading ? (
|
||||||
{stays.length && !isLoading ? (
|
<LoadingSpinner />
|
||||||
|
) : stays.length ? (
|
||||||
<ListContainer>
|
<ListContainer>
|
||||||
<CardGrid>
|
<CardGrid>
|
||||||
{stays.map((stay) => (
|
{stays.map((stay) => (
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { _ } from "@/lib/translation"
|
import { _ } from "@/lib/translation"
|
||||||
import { trpc } from "@/lib/trpc/client"
|
import { trpc } from "@/lib/trpc/client"
|
||||||
|
|
||||||
|
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||||
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||||
|
|
||||||
import Container from "../Container"
|
import Container from "../Container"
|
||||||
@@ -40,9 +41,9 @@ export default function UpcomingStays({
|
|||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Header title={title} subtitle={subtitle} link={link} />
|
<Header title={title} subtitle={subtitle} link={link} />
|
||||||
|
{isLoading ? (
|
||||||
{isLoading ? <p>{_("Loading")}</p> : null}
|
<LoadingSpinner />
|
||||||
{stays.length && !isLoading ? (
|
) : stays.length ? (
|
||||||
<ListContainer>
|
<ListContainer>
|
||||||
<CardGrid>
|
<CardGrid>
|
||||||
{stays.map((stay) => (
|
{stays.map((stay) => (
|
||||||
|
|||||||
@@ -7,17 +7,8 @@ export default function CardGrid({
|
|||||||
children,
|
children,
|
||||||
isMobileCarousel = false,
|
isMobileCarousel = false,
|
||||||
className,
|
className,
|
||||||
|
variant,
|
||||||
}: PropsWithChildren<CardGridProps>) {
|
}: PropsWithChildren<CardGridProps>) {
|
||||||
const amountOfChildren = React.Children.toArray(children).length
|
|
||||||
|
|
||||||
let variant: CardGridProps["variant"] = undefined
|
|
||||||
|
|
||||||
if (amountOfChildren % 3 === 0) {
|
|
||||||
variant = "treeColumnGrid"
|
|
||||||
} else if (amountOfChildren % 2 === 0) {
|
|
||||||
variant = "twoColumnGrid"
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
className={cardGridVariants({
|
className={cardGridVariants({
|
||||||
|
|||||||
@@ -12,4 +12,7 @@ export const cardGridVariants = cva(styles.gridContainer, {
|
|||||||
treeColumnGrid: styles.treeColumnGrid,
|
treeColumnGrid: styles.treeColumnGrid,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "treeColumnGrid",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -88,6 +88,6 @@ export const getStaysSchema = z.object({
|
|||||||
.nullable(),
|
.nullable(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export type GetStaysData = z.infer<typeof getStaysSchema>
|
type GetStaysData = z.infer<typeof getStaysSchema>
|
||||||
|
|
||||||
export type Stay = GetStaysData["data"][0]
|
export type Stay = GetStaysData["data"][number]
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
import type { Lang } from "@/constants/languages"
|
|
||||||
import type { Stay } from "@/server/routers/user/output"
|
|
||||||
|
|
||||||
export type StayListProps = {
|
|
||||||
stays: Stay[]
|
|
||||||
lang: Lang
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user