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;
|
||||
}
|
||||
.value {
|
||||
color: var(--some-brown-color, #4d001b);
|
||||
color: var(--Theme-Primary-Light-On-Surface-Text);
|
||||
}
|
||||
|
||||
.cardContainer {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.cardSubtitle {
|
||||
font-family: var(--ff-fira-sans);
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 14.4px;
|
||||
text-align: center;
|
||||
color: #b05b65;
|
||||
color: var(--Theme-Primary-Light-On-Surface-Accent);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -47,12 +48,16 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
min-height: 280px;
|
||||
background-color: var(--Base-Fill-Normal);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 30px;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -60,16 +65,4 @@
|
||||
.card:nth-child(2) {
|
||||
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 { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||
import Title from "@/components/Title"
|
||||
|
||||
import levelsData from "../data"
|
||||
@@ -53,8 +54,8 @@ export default async function CurrentBenefitsBlock({
|
||||
</header>
|
||||
{subtitle && <p className={styles.subtitle}>{subtitle}</p>}
|
||||
|
||||
<div className={styles.cardContainer}>
|
||||
{currentLevel.benefits.map((benefit, idx) => (
|
||||
<CardGrid>
|
||||
{currentLevel.benefits.map((benefit, idx) => (
|
||||
<Link
|
||||
href={benefit.href}
|
||||
key={`${currentLevel}-${idx}`}
|
||||
@@ -67,7 +68,7 @@ export default async function CurrentBenefitsBlock({
|
||||
<p className={styles.cardSubtitle}>{benefit.description}</p>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</CardGrid>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export default async function NextLevelBenefitsBlock({
|
||||
)}
|
||||
</header>
|
||||
{subtitle && <p className={styles.subtitle}>{subtitle}</p>}
|
||||
<CardGrid>
|
||||
<CardGrid variant="twoColumnGrid">
|
||||
{perks.map((perk) => (
|
||||
<article key={perk.id} className={styles.card}>
|
||||
<Button type="button" intent="secondary" disabled>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
import { trpc } from "@/lib/trpc/client"
|
||||
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||
|
||||
import Container from "../Container"
|
||||
@@ -40,8 +41,9 @@ export default function PreviousStays({
|
||||
return (
|
||||
<Container>
|
||||
<Header title={title} subtitle={subtitle} link={link} />
|
||||
{isLoading ? <p>{_("Loading")}</p> : null}
|
||||
{stays.length && !isLoading ? (
|
||||
{isLoading ? (
|
||||
<LoadingSpinner />
|
||||
) : stays.length ? (
|
||||
<ListContainer>
|
||||
<CardGrid>
|
||||
{stays.map((stay) => (
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
import { trpc } from "@/lib/trpc/client"
|
||||
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||
|
||||
import Container from "../Container"
|
||||
@@ -40,9 +41,9 @@ export default function UpcomingStays({
|
||||
return (
|
||||
<Container>
|
||||
<Header title={title} subtitle={subtitle} link={link} />
|
||||
|
||||
{isLoading ? <p>{_("Loading")}</p> : null}
|
||||
{stays.length && !isLoading ? (
|
||||
{isLoading ? (
|
||||
<LoadingSpinner />
|
||||
) : stays.length ? (
|
||||
<ListContainer>
|
||||
<CardGrid>
|
||||
{stays.map((stay) => (
|
||||
|
||||
@@ -7,17 +7,8 @@ export default function CardGrid({
|
||||
children,
|
||||
isMobileCarousel = false,
|
||||
className,
|
||||
variant,
|
||||
}: 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 (
|
||||
<section
|
||||
className={cardGridVariants({
|
||||
|
||||
@@ -12,4 +12,7 @@ export const cardGridVariants = cva(styles.gridContainer, {
|
||||
treeColumnGrid: styles.treeColumnGrid,
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "treeColumnGrid",
|
||||
},
|
||||
})
|
||||
|
||||
@@ -88,6 +88,6 @@ export const getStaysSchema = z.object({
|
||||
.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