(demo) new demo

This new demo aims to take advantage of all the new Cunningham's
components. The old demo was kind of a draft, this new one gives
a better overview of what Cunningham is capable of.
This commit is contained in:
Nathan Vasse
2024-01-18 16:49:47 +01:00
committed by NathanVss
parent b870fbb760
commit 3616c72673
13 changed files with 598 additions and 81 deletions

View File

@@ -1,14 +1,5 @@
import { Configuration } from "@openfun/cunningham-react";
const config: Configuration = {
themes: {
default: {
components: {
button: {
"border-radius": "30px",
},
},
},
},
};
export default config;
const defaultConfig: Configuration = { themes: {} };
export default defaultConfig;

View File

@@ -11,6 +11,7 @@
"preview": "vite preview"
},
"dependencies": {
"@faker-js/faker": "8.3.1",
"@openfun/cunningham-react": "*",
"@openfun/cunningham-tokens": "*",
"@openfun/typescript-configs": "*",

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -1,62 +1,69 @@
import {
Button,
CunninghamProvider,
Pagination,
Select,
SUPPORTED_LOCALES,
Switch,
usePagination,
} from "@openfun/cunningham-react";
import React, { useState } from "react";
import { tokens } from "./cunningham-tokens";
import { Button, CunninghamProvider } from "@openfun/cunningham-react";
import React, { useEffect, useState } from "react";
import { Create } from "./Create";
import { Home } from "./Home";
enum Theme {
DEFAULT = "default",
DARK = "dark",
}
const THEMES: Theme[] = [Theme.DEFAULT, Theme.DARK];
export enum Page {
HOME,
CREATE,
}
export interface PageProps {
changePage: (page: Page) => void;
}
const preferredScheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? Theme.DARK
: Theme.DEFAULT;
export const App = () => {
const pagination = usePagination({ defaultPage: 50, defaultPagesCount: 100 });
const [locale, setLocale] = useState("en-US");
const [theme, setTheme] = useState<Theme>(Theme.DEFAULT);
const [locale] = useState("en-US");
const [theme, setTheme] = useState<Theme>(preferredScheme);
const [page, setPage] = useState<Page>(Page.HOME);
const handleThemeChange = (event: MediaQueryListEvent) =>
setTheme(event.matches ? Theme.DARK : Theme.DEFAULT);
useEffect(() => {
const query = window.matchMedia("(prefers-color-scheme: dark)");
query.addEventListener("change", handleThemeChange);
return () => {
query.removeEventListener("change", handleThemeChange);
};
}, []);
return (
<CunninghamProvider currentLocale={locale} theme={theme}>
<div className="center">
<h1 className="clr-greyscale-900">Cunningham Demo.</h1>
<div className="mb-s">
<Select
label="Locale"
options={SUPPORTED_LOCALES.map((v) => ({
label: v,
}))}
clearable={false}
value={locale}
onChange={(e) => setLocale(e.target.value as string)}
/>
</div>
<Select
label="Theme"
options={THEMES.map((v) => ({
label: v,
}))}
clearable={false}
value={THEMES[0]}
onChange={(e) => setTheme(e.target.value as Theme)}
<div className="container">
<img
className="pattern"
src={
theme === Theme.DARK ? "pattern_dark.png" : "pattern_default.png"
}
alt="Background pattern"
/>
{page === Page.HOME && <Home changePage={(p) => setPage(p)} />}
{page === Page.CREATE && <Create changePage={(p) => setPage(p)} />}
</div>
<div className="p-s">
<Switch defaultChecked={true} label="Switch" />
</div>
<Button>World best button.</Button>
<h3 className="clr-greyscale-900">
Primary-500 color is{" "}
{tokens.themes[theme].theme.colors["primary-500"]}
</h3>
<Pagination {...pagination} />
<div className="theme-switch">
<Button
color="tertiary"
icon={
<span className="material-icons">
{theme === Theme.DARK ? "light_mode" : "dark_mode"}
</span>
}
onClick={() => {
setTheme(theme === Theme.DARK ? Theme.DEFAULT : Theme.DARK);
}}
/>
</div>
</CunninghamProvider>
);

168
apps/demo/src/Character.ts Normal file
View File

@@ -0,0 +1,168 @@
import { faker } from "@faker-js/faker";
export interface Character {
id: string;
name: string;
gender: "male" | "female" | "other";
birthDate: Date;
firstAppearanceDate: Date;
lastAppearanceDate: Date;
isGuest: boolean;
}
export const randomDates = () => {
return {
birthDate: faker.date.between({
from: "1950-01-01T00:00:00.000Z",
to: "1970-01-01T00:00:00.000Z",
}),
firstAppearanceDate: faker.date.between({
from: "1974-01-01T00:00:00.000Z",
to: "1984-01-01T00:00:00.000Z",
}),
lastAppearanceDate: faker.date.past(),
};
};
export const database: Character[] = [
{
id: faker.string.uuid(),
name: "Richie Cunningham",
gender: "male",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Joanie Cunningham",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Arthur Fonzarelli",
gender: "male",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Marion Cunningham",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Ralph Malph",
gender: "male",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Howard Cunningham",
gender: "male",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Marsha Simms",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Warren Berlinger",
gender: "male",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Al Molinaro",
gender: "male",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Verna LaVerne",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Arnold Takahashi",
gender: "male",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Linda Purl",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Crystal Bernard",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Heather O'Rourke",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Scott Bernstein",
gender: "male",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Ed Peck",
gender: "male",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Beatrice Colen",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Dody Goodman",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Linda Dano",
gender: "female",
isGuest: false,
...randomDates(),
},
{
id: faker.string.uuid(),
name: "Gavan O'Herlihy",
gender: "male",
isGuest: false,
...randomDates(),
},
];

132
apps/demo/src/Create.tsx Normal file
View File

@@ -0,0 +1,132 @@
import React from "react";
import {
Alert,
AlertType,
Button,
Checkbox,
DatePicker,
DateRangePicker,
FileUploader,
Input,
Radio,
RadioGroup,
Select,
Switch,
TextArea,
ToastType,
useToastProvider,
} from "@openfun/cunningham-react";
import { faker } from "@faker-js/faker";
import { Character, database, randomDates } from "./Character";
import { Page, PageProps } from "./App";
export const Create = ({ changePage }: PageProps) => {
const { toast } = useToastProvider();
const inputRef = React.useRef<HTMLInputElement>(null);
const submit = () => {
const character: Character = {
id: faker.string.uuid(),
name: inputRef.current?.value || "",
gender: "male",
isGuest: false,
...randomDates(),
};
database.unshift(character);
changePage(Page.HOME);
toast("Character created successfully", ToastType.SUCCESS);
};
return (
<div className="page__create clr-greyscale-900">
<h1>Add a character</h1>
<div className="card">
<h3 className="fw-bold fs-h3">General Information</h3>
<Alert type={AlertType.INFO}>
You are about to add a new character to the collection
</Alert>
<Input
ref={inputRef}
label="Name"
text="Enter first and last name"
fullWidth={true}
/>
<Select
label="Gender"
fullWidth={true}
options={[
{
label: "Male",
},
{
label: "Female",
},
{
label: "Other",
},
]}
/>
<DatePicker label="Birth Date" fullWidth={true} />
<DateRangePicker
startLabel="First appearance"
endLabel="Last appearance"
fullWidth={true}
/>
<Checkbox label="This character is a guest" />
</div>
<div className="card mt-l">
<h3 className="fw-bold fs-h3">Bio</h3>
<Alert type={AlertType.WARNING}>
Please be exhaustive, every detail counts!
</Alert>
<TextArea
label="Biography"
text="Enter a detailed biography"
fullWidth={true}
rows={8}
/>
<RadioGroup>
<Radio
label="Appeared between 0 and 5 times"
name="occurences"
value="A"
/>
<Radio
label="Appeared between 6 and 10 times"
name="occurences"
value="B"
/>
<Radio
label="Appeared between 10 and 20 times"
name="occurences"
value="C"
/>
<Radio
label="Appeared between 20+ times"
name="occurences"
value="D"
/>
</RadioGroup>
<Switch label="Make this character public" />
<div>
<h4>Add pictures</h4>
<div className="mt-s">
<FileUploader
fullWidth={true}
text="JPG, PNG or GIF - Max file size 2MB"
multiple={true}
/>
</div>
</div>
</div>
<div className="mt-l">
<Button fullWidth={true} onClick={() => submit()}>
Add character
</Button>
</div>
</div>
);
};

141
apps/demo/src/Home.tsx Normal file
View File

@@ -0,0 +1,141 @@
import React, { useEffect, useState } from "react";
import {
Button,
DataGrid,
SortModel,
ToastType,
usePagination,
useToastProvider,
} from "@openfun/cunningham-react";
import { Page, PageProps } from "./App";
import { database } from "./Character";
export const Home = ({ changePage }: PageProps) => {
const { toast } = useToastProvider();
const [rowSelection, setRowSelection] = useState({});
const [isLoading, setIsLoading] = useState(true);
const pagination = usePagination({ defaultPage: 1 });
const [sortModel, setSortModel] = useState<SortModel>([
{
field: "lastName",
sort: "desc",
},
]);
const [rows, setRows] = useState<typeof database>([]);
const [refresh, setRefresh] = useState(1);
useEffect(() => {
// Sort database. On your side this is supposed to be done on the server.
const sortKey = sortModel.length > 0 ? sortModel[0].field : "id";
const sortPolarity =
sortModel.length > 0 && sortModel[0].sort === "asc" ? 1 : -1;
const sortedDatabase = [...database].sort((a: any, b: any) => {
if (a[sortKey] < b[sortKey]) return -sortPolarity;
if (a[sortKey] > b[sortKey]) return sortPolarity;
return 0;
});
setIsLoading(true);
// Set the pagination length.
pagination.setPagesCount(
Math.ceil(sortedDatabase.length / pagination.pageSize),
);
// Select the rows to display on the current page.
setRows(
sortedDatabase.slice(
(pagination.page - 1) * pagination.pageSize,
pagination.page * pagination.pageSize,
),
);
setIsLoading(false);
}, [pagination.page, sortModel, refresh]);
return (
<div className="page__home">
<div className="page__home__title">
<h1 className="clr-greyscale-900">
{/* eslint-disable-next-line react/no-unescaped-entities */}
🍿Cunningham's <span className="clr-primary-400">Cast</span>
</h1>
<p className="clr-greyscale-600 fs-m fw-regular">
Happy Days is an American television sitcom that aired first-run from
January 15, 1974, to September 24, 1984, on ABC-TV
<br /> with a total of 255 half-hour episodes spanning over eleven
seasons. <br />
<br />
Created by Garry Marshall, the series presented an idealized vision of
life in the mid-1950s to mid-1960s Midwestern United States.
</p>
<Button
color="primary"
icon={<span className="material-icons">movie</span>}
onClick={() => changePage(Page.CREATE)}
>
Add character
</Button>
</div>
<div className="card">
<DataGrid
columns={[
{
field: "name",
headerName: "Name",
},
{
field: "gender",
headerName: "Gender",
},
{
id: "birthDate",
headerName: "Birth Date",
renderCell: (params) => {
return params.row.birthDate.toLocaleDateString();
},
},
{
id: "firstAppearanceDate",
headerName: "First Appearance",
renderCell: (params) => {
return params.row.firstAppearanceDate.toLocaleDateString();
},
},
{
id: "isGuest",
headerName: "Is Guest",
renderCell: (params) => {
return params.row.isGuest ? "yes" : "no";
},
},
{
id: "actions",
renderCell: (params) => (
<Button
color="tertiary-text"
size="small"
onClick={() => {
const index = database.findIndex(
(character) => character.id === params.row.id,
);
database.splice(index, 1);
setRefresh(refresh + 1);
toast("Character deleted successfully", ToastType.WARNING);
}}
icon={<span className="material-icons">delete</span>}
/>
),
},
]}
rows={rows}
pagination={pagination}
sortModel={sortModel}
onSortModelChange={setSortModel}
isLoading={isLoading}
enableRowSelection={true}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}
/>
</div>
</div>
);
};

View File

@@ -106,7 +106,12 @@
--c--theme--transitions--ease-out: cubic-bezier(0.33, 1, 0.68, 1);
--c--theme--transitions--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
--c--theme--transitions--duration: 250ms;
--c--components--button--border-radius: 30px;
--c--theme--breakpoints--xs: 0;
--c--theme--breakpoints--sm: 576px;
--c--theme--breakpoints--md: 768px;
--c--theme--breakpoints--lg: 992px;
--c--theme--breakpoints--xl: 1200px;
--c--theme--breakpoints--xxl: 1400px;
}
.cunningham-theme--dark{
--c--theme--colors--greyscale-100: #182536;

View File

@@ -1 +1 @@
export const tokens = {"themes":{"default":{"theme":{"colors":{"secondary-text":"#555F6B","secondary-100":"#F2F7FC","secondary-200":"#EBF3FA","secondary-300":"#E2EEF8","secondary-400":"#DDEAF7","secondary-500":"#D4E5F5","secondary-600":"#C1D0DF","secondary-700":"#97A3AE","secondary-800":"#757E87","secondary-900":"#596067","info-text":"#FFFFFF","info-100":"#EBF2FC","info-200":"#8CB5EA","info-300":"#5894E1","info-400":"#377FDB","info-500":"#055FD2","info-600":"#0556BF","info-700":"#044395","info-800":"#033474","info-900":"#022858","greyscale-100":"#FAFAFB","greyscale-200":"#F3F4F4","greyscale-300":"#E7E8EA","greyscale-400":"#C2C6CA","greyscale-500":"#9EA3AA","greyscale-600":"#79818A","greyscale-700":"#555F6B","greyscale-800":"#303C4B","greyscale-900":"#0C1A2B","greyscale-000":"#FFFFFF","primary-100":"#EBF2FC","primary-200":"#8CB5EA","primary-300":"#5894E1","primary-400":"#377FDB","primary-500":"#055FD2","primary-600":"#0556BF","primary-700":"#044395","primary-800":"#033474","primary-900":"#022858","success-100":"#EFFCD3","success-200":"#DBFAA9","success-300":"#BEF27C","success-400":"#A0E659","success-500":"#76D628","success-600":"#5AB81D","success-700":"#419A14","success-800":"#2C7C0C","success-900":"#1D6607","warning-100":"#FFF8CD","warning-200":"#FFEF9B","warning-300":"#FFE469","warning-400":"#FFDA43","warning-500":"#FFC805","warning-600":"#DBA603","warning-700":"#B78702","warning-800":"#936901","warning-900":"#7A5400","danger-100":"#F4B0B0","danger-200":"#EE8A8A","danger-300":"#E65454","danger-400":"#E13333","danger-500":"#DA0000","danger-600":"#C60000","danger-700":"#9B0000","danger-800":"#780000","danger-900":"#5C0000","primary-text":"#FFFFFF","success-text":"#FFFFFF","warning-text":"#FFFFFF","danger-text":"#FFFFFF"},"font":{"sizes":{"h1":"1.75rem","h2":"1.375rem","h3":"1.125rem","h4":"0.8125rem","h5":"0.625rem","h6":"0.5rem","l":"1rem","m":"0.8125rem","s":"0.6875rem"},"weights":{"thin":200,"light":300,"regular":400,"medium":500,"bold":600,"extrabold":700,"black":800},"families":{"base":"\"Roboto Flex Variable\", sans-serif","accent":"\"Roboto Flex Variable\", sans-serif"},"letterSpacings":{"h1":"normal","h2":"normal","h3":"normal","h4":"normal","h5":"1px","h6":"normal","l":"normal","m":"normal","s":"normal"}},"spacings":{"xl":"4rem","l":"3rem","b":"1.625rem","s":"1rem","t":"0.5rem","st":"0.25rem"},"transitions":{"ease-in":"cubic-bezier(0.32, 0, 0.67, 0)","ease-out":"cubic-bezier(0.33, 1, 0.68, 1)","ease-in-out":"cubic-bezier(0.65, 0, 0.35, 1)","duration":"250ms"}},"components":{"button":{"border-radius":"30px"}}},"dark":{"theme":{"colors":{"greyscale-100":"#182536","greyscale-200":"#303C4B","greyscale-300":"#555F6B","greyscale-400":"#79818A","greyscale-500":"#9EA3AA","greyscale-600":"#C2C6CA","greyscale-700":"#E7E8EA","greyscale-800":"#F3F4F4","greyscale-900":"#FAFAFB","greyscale-000":"#0C1A2B","primary-100":"#3B4C62","primary-200":"#4D6481","primary-300":"#6381A6","primary-400":"#7FA5D5","primary-500":"#8CB5EA","primary-600":"#A3C4EE","primary-700":"#C3D8F4","primary-800":"#DDE9F8","primary-900":"#F4F8FD","success-100":"#EEF8D7","success-200":"#D9F1B2","success-300":"#BDE985","success-400":"#A0E25D","success-500":"#76D628","success-600":"#5BB520","success-700":"#43941A","success-800":"#307414","success-900":"#225D10","warning-100":"#F7F3D5","warning-200":"#F0E5AA","warning-300":"#E8D680","warning-400":"#E3C95F","warning-500":"#D9B32B","warning-600":"#BD9721","warning-700":"#9D7B1C","warning-800":"#7E6016","warning-900":"#684D12","danger-100":"#F8D0D0","danger-200":"#F09898","danger-300":"#F09898","danger-400":"#ED8585","danger-500":"#E96666","danger-600":"#DD6666","danger-700":"#C36666","danger-800":"#AE6666","danger-900":"#9D6666"}}}}};
export const tokens = {"themes":{"default":{"theme":{"colors":{"secondary-text":"#555F6B","secondary-100":"#F2F7FC","secondary-200":"#EBF3FA","secondary-300":"#E2EEF8","secondary-400":"#DDEAF7","secondary-500":"#D4E5F5","secondary-600":"#C1D0DF","secondary-700":"#97A3AE","secondary-800":"#757E87","secondary-900":"#596067","info-text":"#FFFFFF","info-100":"#EBF2FC","info-200":"#8CB5EA","info-300":"#5894E1","info-400":"#377FDB","info-500":"#055FD2","info-600":"#0556BF","info-700":"#044395","info-800":"#033474","info-900":"#022858","greyscale-100":"#FAFAFB","greyscale-200":"#F3F4F4","greyscale-300":"#E7E8EA","greyscale-400":"#C2C6CA","greyscale-500":"#9EA3AA","greyscale-600":"#79818A","greyscale-700":"#555F6B","greyscale-800":"#303C4B","greyscale-900":"#0C1A2B","greyscale-000":"#FFFFFF","primary-100":"#EBF2FC","primary-200":"#8CB5EA","primary-300":"#5894E1","primary-400":"#377FDB","primary-500":"#055FD2","primary-600":"#0556BF","primary-700":"#044395","primary-800":"#033474","primary-900":"#022858","success-100":"#EFFCD3","success-200":"#DBFAA9","success-300":"#BEF27C","success-400":"#A0E659","success-500":"#76D628","success-600":"#5AB81D","success-700":"#419A14","success-800":"#2C7C0C","success-900":"#1D6607","warning-100":"#FFF8CD","warning-200":"#FFEF9B","warning-300":"#FFE469","warning-400":"#FFDA43","warning-500":"#FFC805","warning-600":"#DBA603","warning-700":"#B78702","warning-800":"#936901","warning-900":"#7A5400","danger-100":"#F4B0B0","danger-200":"#EE8A8A","danger-300":"#E65454","danger-400":"#E13333","danger-500":"#DA0000","danger-600":"#C60000","danger-700":"#9B0000","danger-800":"#780000","danger-900":"#5C0000","primary-text":"#FFFFFF","success-text":"#FFFFFF","warning-text":"#FFFFFF","danger-text":"#FFFFFF"},"font":{"sizes":{"h1":"1.75rem","h2":"1.375rem","h3":"1.125rem","h4":"0.8125rem","h5":"0.625rem","h6":"0.5rem","l":"1rem","m":"0.8125rem","s":"0.6875rem"},"weights":{"thin":200,"light":300,"regular":400,"medium":500,"bold":600,"extrabold":700,"black":800},"families":{"base":"\"Roboto Flex Variable\", sans-serif","accent":"\"Roboto Flex Variable\", sans-serif"},"letterSpacings":{"h1":"normal","h2":"normal","h3":"normal","h4":"normal","h5":"1px","h6":"normal","l":"normal","m":"normal","s":"normal"}},"spacings":{"xl":"4rem","l":"3rem","b":"1.625rem","s":"1rem","t":"0.5rem","st":"0.25rem"},"transitions":{"ease-in":"cubic-bezier(0.32, 0, 0.67, 0)","ease-out":"cubic-bezier(0.33, 1, 0.68, 1)","ease-in-out":"cubic-bezier(0.65, 0, 0.35, 1)","duration":"250ms"},"breakpoints":{"xs":0,"sm":"576px","md":"768px","lg":"992px","xl":"1200px","xxl":"1400px"}}},"dark":{"theme":{"colors":{"greyscale-100":"#182536","greyscale-200":"#303C4B","greyscale-300":"#555F6B","greyscale-400":"#79818A","greyscale-500":"#9EA3AA","greyscale-600":"#C2C6CA","greyscale-700":"#E7E8EA","greyscale-800":"#F3F4F4","greyscale-900":"#FAFAFB","greyscale-000":"#0C1A2B","primary-100":"#3B4C62","primary-200":"#4D6481","primary-300":"#6381A6","primary-400":"#7FA5D5","primary-500":"#8CB5EA","primary-600":"#A3C4EE","primary-700":"#C3D8F4","primary-800":"#DDE9F8","primary-900":"#F4F8FD","success-100":"#EEF8D7","success-200":"#D9F1B2","success-300":"#BDE985","success-400":"#A0E25D","success-500":"#76D628","success-600":"#5BB520","success-700":"#43941A","success-800":"#307414","success-900":"#225D10","warning-100":"#F7F3D5","warning-200":"#F0E5AA","warning-300":"#E8D680","warning-400":"#E3C95F","warning-500":"#D9B32B","warning-600":"#BD9721","warning-700":"#9D7B1C","warning-800":"#7E6016","warning-900":"#684D12","danger-100":"#F8D0D0","danger-200":"#F09898","danger-300":"#F09898","danger-400":"#ED8585","danger-500":"#E96666","danger-600":"#DD6666","danger-700":"#C36666","danger-800":"#AE6666","danger-900":"#9D6666"}}}}};

View File

@@ -3,28 +3,95 @@
@use "@openfun/cunningham-react/style";
@use "cunningham-tokens";
:root {
font-family: Roboto, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem;
background-color: var(--c--theme--colors--greyscale-000);
// Reset
h1 {
font-family: var(--c--theme--font--families--accent);
font-size: 4rem;
margin: 0;
}
p {
margin: 0;
}
.center {
display: flex;
flex-direction: column;
align-items: center;
padding: 2rem;
background-color: var(--c--theme--colors--greyscale-100);
border-radius: 1rem;
// App
html {
min-height: 100vh;
padding-bottom: 5rem;
background: linear-gradient(153deg, var(--c--theme--colors--greyscale-100) 0%, var(--c--theme--colors--greyscale-000) 100%);
}
h1, h3 {
margin-bottom: 40px;
.pattern {
position: absolute;
z-index: -1;
top: -200px;
left: -290px;
transform: rotate(335deg);
}
.theme-switch {
position: fixed;
right: 1rem;
top: 0.75rem;
}
.card {
background-color: var(--c--theme--colors--greyscale-000);
padding: 2rem;
border-radius: 4px;
border: 1px var(--c--theme--colors--greyscale-300) solid;
box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
}
.cunningham-theme--dark {
.card {
box-shadow: none;
border: none;
}
}
.container {
margin: auto;
position: relative;
width: 1100px;
@media (max-width: 1200px) {
width: calc(100% - 2rem);
}
}
// Home
.page__home {
&__title {
gap: 1.5rem;
margin: 4rem 0;
h1 {
}
button {
margin-top: 1.5rem;
}
}
}
// Create
.page__create {
h1 {
text-align: center;
margin: 4rem 0;
}
.card {
display: flex;
flex-direction: column;
gap: 1.5rem;
h3, h4 {
margin: 0;
}
}
}