Improved CSS and design system
This commit is contained in:
parent
cffe26a29a
commit
fe24a77d6e
|
@ -34,13 +34,13 @@
|
||||||
- Support for Arbitrary React Components and Component Props!
|
- Support for Arbitrary React Components and Component Props!
|
||||||
- Autogenerated multi-level table of content and anchor links for the different headers
|
- Autogenerated multi-level table of content and anchor links for the different headers
|
||||||
- Styling: [Tailwind CSS](https://tailwindcss.com/)
|
- Styling: [Tailwind CSS](https://tailwindcss.com/)
|
||||||
- Manually added support for scrollbar styling to Tailwind CSS
|
|
||||||
- Support for [Material Icons](https://fonts.google.com/icons)
|
- Support for [Material Icons](https://fonts.google.com/icons)
|
||||||
- Support for creating any arbitrary theming mode by swapping CSS variables
|
- Support for creating any arbitrary theming mode by swapping CSS variables
|
||||||
- Support for Container Queries (media queries at the element level)
|
- Support for Container Queries (media queries at the element level)
|
||||||
- The website has a three-column layout, which turns into one-column + 2 toggleable side-menus if the screen is too narrow.
|
- The website has a three-column layout, which turns into one-column + 2 toggleable side-menus if the screen is too narrow.
|
||||||
|
- Show out the Design System Showcase [here](https://accords-library.com/dev/showcase/design-system)
|
||||||
- State Management: [React Context](https://reactjs.org/docs/context.html)
|
- State Management: [React Context](https://reactjs.org/docs/context.html)
|
||||||
- Persistent app state using LocalStorage
|
- Persistent app state using LocalStorage and SessionStorage
|
||||||
- Accessibility
|
- Accessibility
|
||||||
- Gestures using [react-swipeable](https://www.npmjs.com/package/react-swipeable)
|
- Gestures using [react-swipeable](https://www.npmjs.com/package/react-swipeable)
|
||||||
- Keyboard hotkeys using [react-hotkeys-hook](https://www.npmjs.com/package/react-hotkeys-hook)
|
- Keyboard hotkeys using [react-hotkeys-hook](https://www.npmjs.com/package/react-hotkeys-hook)
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
- Furthermore, the user can temporary select another language then the one that was automatically selected
|
- Furthermore, the user can temporary select another language then the one that was automatically selected
|
||||||
- SSG + ISR (Static Site Generation + Incremental Static Regeneration):
|
- SSG + ISR (Static Site Generation + Incremental Static Regeneration):
|
||||||
- The website is built before running in production
|
- The website is built before running in production
|
||||||
- Performances are great, and possibility to deploy the app using a CDN
|
- Performances are great, and possibility to deploy the app on a CDN
|
||||||
- On-Demand ISR to continuously update the website when new content is added or existing content is modified/deleted
|
- On-Demand ISR to continuously update the website when new content is added or existing content is modified/deleted
|
||||||
- SEO
|
- SEO
|
||||||
- Good defaults for the metadata and OpenGraph properties
|
- Good defaults for the metadata and OpenGraph properties
|
||||||
|
|
|
@ -8,6 +8,7 @@ const locales = ["en", "es", "fr", "pt-br", "ja"];
|
||||||
module.exports = {
|
module.exports = {
|
||||||
swcMinify: true,
|
swcMinify: true,
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
|
poweredByHeader: false,
|
||||||
i18n: {
|
i18n: {
|
||||||
locales: locales,
|
locales: locales,
|
||||||
defaultLocale: "en",
|
defaultLocale: "en",
|
||||||
|
|
|
@ -168,8 +168,7 @@ export const AppLayout = ({
|
||||||
id={Ids.SubPanel}
|
id={Ids.SubPanel}
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
`texture-paper-dots z-20 overflow-y-scroll border-r border-dark/50
|
`texture-paper-dots z-20 overflow-y-scroll border-r border-dark/50
|
||||||
bg-light transition-transform duration-300 [scrollbar-width:none]
|
bg-light transition-transform duration-300 scrollbar-none`,
|
||||||
webkit-scrollbar:w-0`,
|
|
||||||
cIf(
|
cIf(
|
||||||
is1ColumnLayout,
|
is1ColumnLayout,
|
||||||
"justify-self-end border-r-0 [grid-area:content]",
|
"justify-self-end border-r-0 [grid-area:content]",
|
||||||
|
@ -187,7 +186,7 @@ export const AppLayout = ({
|
||||||
<div
|
<div
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
`texture-paper-dots z-30 overflow-y-scroll border-r border-dark/50
|
`texture-paper-dots z-30 overflow-y-scroll border-r border-dark/50
|
||||||
bg-light transition-transform duration-300 [scrollbar-width:none] webkit-scrollbar:w-0`,
|
bg-light transition-transform duration-300 scrollbar-none`,
|
||||||
cIf(is1ColumnLayout, "justify-self-start [grid-area:content]", "[grid-area:main]"),
|
cIf(is1ColumnLayout, "justify-self-start [grid-area:content]", "[grid-area:main]"),
|
||||||
cIf(is1ColumnLayout && isScreenAtLeastXs, "w-[min(30rem,90%)]"),
|
cIf(is1ColumnLayout && isScreenAtLeastXs, "w-[min(30rem,90%)]"),
|
||||||
cIf(!mainPanelOpen && is1ColumnLayout, "-translate-x-full")
|
cIf(!mainPanelOpen && is1ColumnLayout, "-translate-x-full")
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { Link } from "components/Inputs/Link";
|
|
||||||
import { DatePickerFragment } from "graphql/generated";
|
import { DatePickerFragment } from "graphql/generated";
|
||||||
import { cIf, cJoin } from "helpers/className";
|
|
||||||
import { TranslatedProps } from "types/TranslatedProps";
|
import { TranslatedProps } from "types/TranslatedProps";
|
||||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||||
|
import { DownPressable } from "components/Containers/DownPressable";
|
||||||
|
import { isDefined } from "helpers/others";
|
||||||
|
import { cIf, cJoin } from "helpers/className";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭─────────────╮
|
* ╭─────────────╮
|
||||||
|
@ -14,25 +15,32 @@ interface Props {
|
||||||
date: DatePickerFragment;
|
date: DatePickerFragment;
|
||||||
title: string;
|
title: string;
|
||||||
url: string;
|
url: string;
|
||||||
isActive?: boolean;
|
active?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChroniclePreview = ({ date, url, title, isActive }: Props): JSX.Element => (
|
export const ChroniclePreview = ({ date, url, title, active, disabled }: Props): JSX.Element => (
|
||||||
<Link
|
<DownPressable
|
||||||
|
className="flex w-full gap-4 py-4 px-5"
|
||||||
href={url}
|
href={url}
|
||||||
className={cJoin(
|
active={active}
|
||||||
`flex w-full cursor-pointer gap-4 rounded-2xl py-4 px-5 text-left align-top outline outline-2
|
border
|
||||||
-outline-offset-2 outline-mid transition-all hover:bg-mid hover:shadow-inner-sm
|
disabled={disabled}>
|
||||||
hover:shadow-shade hover:outline-transparent hover:active:shadow-inner
|
{isDefined(date.year) && (
|
||||||
hover:active:shadow-shade`,
|
<div className="text-right">
|
||||||
cIf(isActive, "bg-mid shadow-inner-sm shadow-shade outline-transparent")
|
<p>{date.year}</p>
|
||||||
)}>
|
<p className="text-sm text-dark">{prettyMonthDay(date.month, date.day)}</p>
|
||||||
<div className="text-right">
|
</div>
|
||||||
<p>{date.year}</p>
|
)}
|
||||||
<p className="text-sm text-dark">{prettyMonthDay(date.month, date.day)}</p>
|
|
||||||
</div>
|
<p
|
||||||
<p className="text-lg leading-tight">{title}</p>
|
className={cJoin(
|
||||||
</Link>
|
"text-lg leading-tight",
|
||||||
|
cIf(isDefined(date.year), "text-left", "w-full text-center")
|
||||||
|
)}>
|
||||||
|
{title}
|
||||||
|
</p>
|
||||||
|
</DownPressable>
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -54,7 +54,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element
|
||||||
] as const).map((content, index) => (
|
] as const).map((content, index) => (
|
||||||
<TranslatedChroniclePreview
|
<TranslatedChroniclePreview
|
||||||
key={index}
|
key={index}
|
||||||
isActive={chronicle.attributes.slug === currentSlug}
|
active={chronicle.attributes.slug === currentSlug}
|
||||||
date={chronicle.attributes.date_start}
|
date={chronicle.attributes.date_start}
|
||||||
translations={filterHasAttributes(content.attributes.translations, [
|
translations={filterHasAttributes(content.attributes.translations, [
|
||||||
"language.data.attributes.code",
|
"language.data.attributes.code",
|
||||||
|
@ -80,7 +80,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element
|
||||||
: chronicle.attributes.translations.length > 0 && (
|
: chronicle.attributes.translations.length > 0 && (
|
||||||
<TranslatedChroniclePreview
|
<TranslatedChroniclePreview
|
||||||
date={chronicle.attributes.date_start}
|
date={chronicle.attributes.date_start}
|
||||||
isActive={chronicle.attributes.slug === currentSlug}
|
active={chronicle.attributes.slug === currentSlug}
|
||||||
translations={filterHasAttributes(chronicle.attributes.translations, [
|
translations={filterHasAttributes(chronicle.attributes.translations, [
|
||||||
"language.data.attributes.code",
|
"language.data.attributes.code",
|
||||||
"title",
|
"title",
|
||||||
|
|
|
@ -239,8 +239,7 @@ export const Terminal = ({
|
||||||
)}>
|
)}>
|
||||||
<div
|
<div
|
||||||
ref={terminalWindowRef}
|
ref={terminalWindowRef}
|
||||||
className="h-full overflow-scroll scroll-auto p-6
|
className="h-full overflow-scroll scroll-auto p-6 scrollbar-none">
|
||||||
[scrollbar-width:none] webkit-scrollbar:w-0">
|
|
||||||
{previousLines.map((previousLine, index) => (
|
{previousLines.map((previousLine, index) => (
|
||||||
<p key={index} className="whitespace-pre-line font-realmono">
|
<p key={index} className="whitespace-pre-line font-realmono">
|
||||||
{previousLine}
|
{previousLine}
|
||||||
|
@ -311,7 +310,7 @@ export const Terminal = ({
|
||||||
<span
|
<span
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
"whitespace-pre font-realmono",
|
"whitespace-pre font-realmono",
|
||||||
cIf(isTextAreaFocused, "animation-carret border-b-2 border-black")
|
cIf(isTextAreaFocused, "animate-carret border-b-2 border-black")
|
||||||
)}>
|
)}>
|
||||||
{line[carretPosition] ?? " "}
|
{line[carretPosition] ?? " "}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { MouseEventHandler, useState } from "react";
|
||||||
|
import { cJoin, cIf } from "helpers/className";
|
||||||
|
import { Link } from "components/Inputs/Link";
|
||||||
|
/*
|
||||||
|
* ╭─────────────╮
|
||||||
|
* ───────────────────────────────────────╯ COMPONENT ╰───────────────────────────────────────────
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
border?: boolean;
|
||||||
|
active?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
href: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
onFocusChanged?: (isFocused: boolean) => void;
|
||||||
|
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||||
|
|
||||||
|
export const DownPressable = ({
|
||||||
|
href,
|
||||||
|
border = false,
|
||||||
|
active = false,
|
||||||
|
disabled = false,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
onFocusChanged,
|
||||||
|
onClick,
|
||||||
|
}: Props): JSX.Element => {
|
||||||
|
const [isFocused, setFocused] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
href={href}
|
||||||
|
onClick={onClick}
|
||||||
|
onFocusChanged={(focus) => {
|
||||||
|
setFocused(focus);
|
||||||
|
onFocusChanged?.(focus);
|
||||||
|
}}
|
||||||
|
className={cJoin(
|
||||||
|
`rounded-2xl p-4 transition-all`,
|
||||||
|
cIf(border, "outline outline-2 -outline-offset-2 outline-mid"),
|
||||||
|
cIf(active, "!bg-mid shadow-inner-sm outline-transparent shadow-shade"),
|
||||||
|
cIf(
|
||||||
|
disabled,
|
||||||
|
"cursor-not-allowed select-none opacity-50 grayscale",
|
||||||
|
cJoin(
|
||||||
|
"cursor-pointer hover:bg-mid hover:shadow-inner-sm hover:shadow-shade",
|
||||||
|
cIf(isFocused, "!shadow-inner !shadow-shade"),
|
||||||
|
cIf(border, "hover:outline-transparent")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
disabled={disabled}>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Link } from "components/Inputs/Link";
|
||||||
|
import { cIf, cJoin } from "helpers/className";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: React.ReactNode;
|
||||||
|
href: string;
|
||||||
|
className?: string;
|
||||||
|
noBackground?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UpPressable = ({
|
||||||
|
children,
|
||||||
|
href,
|
||||||
|
className,
|
||||||
|
disabled = false,
|
||||||
|
noBackground = false,
|
||||||
|
}: Props): JSX.Element => {
|
||||||
|
const [isFocused, setFocused] = useState(false);
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
href={href}
|
||||||
|
onFocusChanged={setFocused}
|
||||||
|
className={cJoin(
|
||||||
|
`overflow-hidden rounded-md drop-shadow-lg transition-all duration-300 shadow-shade`,
|
||||||
|
cIf(!noBackground, "bg-highlight"),
|
||||||
|
cIf(
|
||||||
|
disabled,
|
||||||
|
"cursor-not-allowed opacity-50 grayscale",
|
||||||
|
cJoin(
|
||||||
|
"cursor-pointer hover:scale-102 hover:drop-shadow-xl",
|
||||||
|
cIf(isFocused, "hover:scale-105 hover:drop-shadow-2xl hover:duration-100")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
disabled={disabled}>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||||
|
import { TranslatedProps } from "types/TranslatedProps";
|
||||||
|
import { UpPressable } from "components/Containers/UpPressable";
|
||||||
|
import { cIf, cJoin } from "helpers/className";
|
||||||
|
|
||||||
|
interface PreviewFolderProps {
|
||||||
|
href: string;
|
||||||
|
title?: string | null;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PreviewFolder = ({ href, title, disabled }: PreviewFolderProps): JSX.Element => (
|
||||||
|
<UpPressable href={href} disabled={disabled}>
|
||||||
|
<div
|
||||||
|
className={cJoin(
|
||||||
|
`flex w-full cursor-pointer flex-row place-content-center place-items-center gap-4
|
||||||
|
p-6`,
|
||||||
|
cIf(disabled, "pointer-events-none touch-none select-none")
|
||||||
|
)}>
|
||||||
|
{title && <p className="text-center font-headers text-lg font-bold leading-none">{title}</p>}
|
||||||
|
</div>
|
||||||
|
</UpPressable>
|
||||||
|
);
|
||||||
|
|
||||||
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||||
|
|
||||||
|
export const TranslatedPreviewFolder = ({
|
||||||
|
translations,
|
||||||
|
fallback,
|
||||||
|
...otherProps
|
||||||
|
}: TranslatedProps<PreviewFolderProps, "title">): JSX.Element => {
|
||||||
|
const [selectedTranslation] = useSmartLanguage({
|
||||||
|
items: translations,
|
||||||
|
languageExtractor: useCallback((item: { language: string }): string => item.language, []),
|
||||||
|
});
|
||||||
|
return <PreviewFolder title={selectedTranslation?.title ?? fallback.title} {...otherProps} />;
|
||||||
|
};
|
|
@ -46,28 +46,32 @@ export const Button = ({
|
||||||
size = "normal",
|
size = "normal",
|
||||||
}: Props): JSX.Element => (
|
}: Props): JSX.Element => (
|
||||||
<ConditionalWrapper
|
<ConditionalWrapper
|
||||||
isWrapping={isDefinedAndNotEmpty(href)}
|
isWrapping={isDefinedAndNotEmpty(href) && !disabled}
|
||||||
wrapperProps={{ href: href ?? "", alwaysNewTab }}
|
wrapperProps={{ href: href ?? "", alwaysNewTab }}
|
||||||
wrapper={LinkWrapper}>
|
wrapper={LinkWrapper}>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div
|
<div
|
||||||
draggable={draggable}
|
draggable={draggable}
|
||||||
id={id}
|
id={id}
|
||||||
onClick={onClick}
|
onClick={(event) => !disabled && onClick?.(event)}
|
||||||
onMouseUp={onMouseUp}
|
onMouseUp={onMouseUp}
|
||||||
onFocus={(event) => event.target.blur()}
|
onFocus={(event) => event.target.blur()}
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
`group grid cursor-pointer select-none grid-flow-col place-content-center
|
`group grid cursor-pointer select-none grid-flow-col place-content-center
|
||||||
place-items-center gap-2 rounded-full border border-dark py-3 px-4
|
place-items-center gap-2 rounded-full border border-dark py-3 px-4
|
||||||
leading-none text-dark transition-all`,
|
leading-none text-dark transition-all`,
|
||||||
cIf(
|
|
||||||
active,
|
|
||||||
"!border-black bg-black !text-light drop-shadow-black-lg",
|
|
||||||
`hover:bg-dark hover:text-light hover:drop-shadow-shade-lg active:hover:!border-black
|
|
||||||
active:hover:bg-black active:hover:!text-light active:hover:drop-shadow-black-lg`
|
|
||||||
),
|
|
||||||
cIf(size === "small", "px-3 py-1 text-xs"),
|
cIf(size === "small", "px-3 py-1 text-xs"),
|
||||||
cIf(disabled, "cursor-not-allowed"),
|
cIf(active, "!border-black bg-black !text-light drop-shadow-lg shadow-black"),
|
||||||
|
cIf(
|
||||||
|
disabled,
|
||||||
|
"cursor-not-allowed opacity-50 grayscale",
|
||||||
|
cIf(
|
||||||
|
!active,
|
||||||
|
`shadow-shade hover:bg-dark hover:text-light hover:drop-shadow-lg
|
||||||
|
active:hover:!border-black active:hover:bg-black active:hover:!text-light
|
||||||
|
active:hover:drop-shadow-lg active:hover:shadow-black`
|
||||||
|
)
|
||||||
|
),
|
||||||
className
|
className
|
||||||
)}>
|
)}>
|
||||||
{isDefined(badgeNumber) && (
|
{isDefined(badgeNumber) && (
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import router from "next/router";
|
import router from "next/router";
|
||||||
import { MouseEventHandler, useState } from "react";
|
import { PointerEventHandler, useState } from "react";
|
||||||
import { isDefined } from "helpers/others";
|
import { isDefined } from "helpers/others";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -8,43 +8,56 @@ interface Props {
|
||||||
allowNewTab?: boolean;
|
allowNewTab?: boolean;
|
||||||
alwaysNewTab?: boolean;
|
alwaysNewTab?: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
onClick?: MouseEventHandler<HTMLDivElement>;
|
onClick?: PointerEventHandler<HTMLDivElement>;
|
||||||
|
onFocusChanged?: (isFocused: boolean) => void;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Link = ({
|
export const Link = ({
|
||||||
href,
|
href,
|
||||||
allowNewTab = true,
|
allowNewTab = true,
|
||||||
alwaysNewTab = false,
|
alwaysNewTab = false,
|
||||||
|
disabled = false,
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
onClick,
|
onClick,
|
||||||
|
onFocusChanged,
|
||||||
}: Props): JSX.Element => {
|
}: Props): JSX.Element => {
|
||||||
const [isValidClick, setIsValidClick] = useState(false);
|
const [isValidClick, setIsValidClick] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={className}
|
className={className}
|
||||||
onMouseLeave={() => setIsValidClick(false)}
|
onPointerLeave={() => {
|
||||||
onContextMenu={(event) => event.preventDefault()}
|
setIsValidClick(false);
|
||||||
onMouseDown={(event) => {
|
onFocusChanged?.(false);
|
||||||
event.preventDefault();
|
|
||||||
setIsValidClick(true);
|
|
||||||
}}
|
}}
|
||||||
onMouseUp={(event) => {
|
onContextMenu={(event) => event.preventDefault()}
|
||||||
if (isDefined(onClick)) {
|
onPointerDown={(event) => {
|
||||||
onClick(event);
|
if (!disabled) {
|
||||||
} else if (isValidClick && href) {
|
event.preventDefault();
|
||||||
if (event.button !== MouseButton.Right) {
|
onFocusChanged?.(true);
|
||||||
if (alwaysNewTab) {
|
setIsValidClick(true);
|
||||||
window.open(href, "_blank", "noopener");
|
}
|
||||||
} else if (event.button === MouseButton.Left) {
|
}}
|
||||||
if (href.startsWith("#")) {
|
onPointerUp={(event) => {
|
||||||
router.replace(href);
|
onFocusChanged?.(false);
|
||||||
} else {
|
if (!disabled) {
|
||||||
router.push(href);
|
if (isDefined(onClick)) {
|
||||||
|
onClick(event);
|
||||||
|
} else if (isValidClick && href) {
|
||||||
|
if (event.button !== MouseButton.Right) {
|
||||||
|
if (alwaysNewTab) {
|
||||||
|
window.open(href, "_blank", "noopener");
|
||||||
|
} else if (event.button === MouseButton.Left) {
|
||||||
|
if (href.startsWith("#")) {
|
||||||
|
router.replace(href);
|
||||||
|
} else {
|
||||||
|
router.push(href);
|
||||||
|
}
|
||||||
|
} else if (allowNewTab) {
|
||||||
|
window.open(href, "_blank");
|
||||||
}
|
}
|
||||||
} else if (allowNewTab) {
|
|
||||||
window.open(href, "_blank");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ export const OrderableList = ({ onChange, items, insertLabels }: Props): JSX.Ele
|
||||||
}}
|
}}
|
||||||
className="grid cursor-grab select-none grid-cols-[auto_1fr] place-content-center gap-2
|
className="grid cursor-grab select-none grid-cols-[auto_1fr] place-content-center gap-2
|
||||||
rounded-full border border-dark bg-light px-1 py-2 pr-4 text-dark transition-all
|
rounded-full border border-dark bg-light px-1 py-2 pr-4 text-dark transition-all
|
||||||
hover:bg-dark hover:text-light hover:drop-shadow-shade-lg"
|
hover:shadow-shade hover:bg-dark hover:text-light hover:shadow-lg"
|
||||||
draggable>
|
draggable>
|
||||||
<div className="grid grid-rows-[.8em_.8em] place-items-center">
|
<div className="grid grid-rows-[.8em_.8em] place-items-center">
|
||||||
{index > 0 && (
|
{index > 0 && (
|
||||||
|
|
|
@ -15,17 +15,34 @@ interface Props {
|
||||||
allowEmpty?: boolean;
|
allowEmpty?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
onChange: (value: number) => void;
|
onChange: (value: number) => void;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||||
|
|
||||||
export const Select = ({ className, value, options, allowEmpty, onChange }: Props): JSX.Element => {
|
export const Select = ({
|
||||||
|
className,
|
||||||
|
value,
|
||||||
|
options,
|
||||||
|
allowEmpty,
|
||||||
|
disabled = false,
|
||||||
|
onChange,
|
||||||
|
}: Props): JSX.Element => {
|
||||||
const { value: isOpened, setFalse: setClosed, toggle: toggleOpened } = useBoolean(false);
|
const { value: isOpened, setFalse: setClosed, toggle: toggleOpened } = useBoolean(false);
|
||||||
|
|
||||||
const tryToggling = useCallback(() => {
|
const tryToggling = useCallback(() => {
|
||||||
|
if (disabled) return;
|
||||||
const optionCount = options.length + (value === -1 ? 1 : 0);
|
const optionCount = options.length + (value === -1 ? 1 : 0);
|
||||||
if (optionCount > 1) toggleOpened();
|
if (optionCount > 1) toggleOpened();
|
||||||
}, [options.length, value, toggleOpened]);
|
}, [disabled, options.length, value, toggleOpened]);
|
||||||
|
|
||||||
|
const onSelectionChanged = useCallback(
|
||||||
|
(newIndex: number) => {
|
||||||
|
setClosed();
|
||||||
|
onChange(newIndex);
|
||||||
|
},
|
||||||
|
[onChange, setClosed]
|
||||||
|
);
|
||||||
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
useOnClickOutside(ref, setClosed);
|
useOnClickOutside(ref, setClosed);
|
||||||
|
@ -35,27 +52,29 @@ export const Select = ({ className, value, options, allowEmpty, onChange }: Prop
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
"relative text-center transition-filter",
|
"relative text-center transition-filter",
|
||||||
cIf(isOpened, "z-10 drop-shadow-shade-lg"),
|
cIf(isOpened, "z-10 drop-shadow-lg shadow-shade"),
|
||||||
className
|
className
|
||||||
)}>
|
)}>
|
||||||
<div
|
<div
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
`grid cursor-pointer grid-flow-col grid-cols-[1fr_auto_auto] place-items-center
|
`grid cursor-pointer select-none grid-flow-col grid-cols-[1fr_auto_auto]
|
||||||
rounded-[1em] bg-light p-1 outline outline-1 -outline-offset-1 outline-mid
|
place-items-center rounded-3xl p-1 outline outline-1 -outline-offset-1
|
||||||
transition-all hover:bg-mid hover:outline-transparent`,
|
outline-mid`,
|
||||||
cIf(isOpened, "rounded-b-none bg-highlight outline-transparent")
|
cIf(isOpened, "rounded-b-none bg-highlight outline-transparent"),
|
||||||
|
cIf(
|
||||||
|
disabled,
|
||||||
|
"cursor-not-allowed text-dark opacity-50 outline-dark/60 grayscale",
|
||||||
|
"transition-all hover:bg-mid hover:outline-transparent"
|
||||||
|
)
|
||||||
)}>
|
)}>
|
||||||
<p onClick={tryToggling} className="w-full">
|
<p onClick={tryToggling} className="w-full px-4 py-1">
|
||||||
{value === -1 ? "—" : options[value]}
|
{value === -1 ? "—" : options[value]}
|
||||||
</p>
|
</p>
|
||||||
{value >= 0 && allowEmpty && (
|
{value >= 0 && allowEmpty && (
|
||||||
<Ico
|
<Ico
|
||||||
icon={Icon.Close}
|
icon={Icon.Close}
|
||||||
className="!text-xs"
|
className="!text-xs"
|
||||||
onClick={() => {
|
onClick={() => !disabled && onSelectionChanged(-1)}
|
||||||
setClosed();
|
|
||||||
onChange(-1);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Ico onClick={tryToggling} icon={isOpened ? Icon.ArrowDropUp : Icon.ArrowDropDown} />
|
<Ico onClick={tryToggling} icon={isOpened ? Icon.ArrowDropUp : Icon.ArrowDropDown} />
|
||||||
|
@ -70,10 +89,7 @@ export const Select = ({ className, value, options, allowEmpty, onChange }: Prop
|
||||||
cIf(isOpened, "bg-highlight", "bg-light")
|
cIf(isOpened, "bg-highlight", "bg-light")
|
||||||
)}
|
)}
|
||||||
id={option}
|
id={option}
|
||||||
onClick={() => {
|
onClick={() => onSelectionChanged(index)}>
|
||||||
setClosed();
|
|
||||||
onChange(index);
|
|
||||||
}}>
|
|
||||||
{option}
|
{option}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -22,24 +22,21 @@ export const Switch = ({ value, onClick, className, disabled = false }: Props):
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
`relative grid h-6 w-12 content-center rounded-full border-mid outline
|
`relative grid h-6 w-12 content-center rounded-full border-mid outline
|
||||||
outline-1 -outline-offset-1 outline-mid transition-colors`,
|
outline-1 -outline-offset-1 outline-mid transition-colors`,
|
||||||
cIf(disabled, "cursor-not-allowed", "cursor-pointer"),
|
cIf(value, "border-none bg-mid shadow-inner-sm shadow-shade outline-transparent"),
|
||||||
cIf(
|
cIf(disabled, "cursor-not-allowed opacity-50 grayscale", "cursor-pointer"),
|
||||||
value,
|
cIf(disabled, cIf(value, "bg-dark/40 outline-transparent", "outline-dark/60")),
|
||||||
"border-none bg-mid shadow-inner-sm shadow-shade outline-transparent",
|
|
||||||
"bg-light"
|
|
||||||
),
|
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!disabled) onClick();
|
if (!disabled) onClick();
|
||||||
}}
|
}}
|
||||||
onPointerDown={() => setIsFocused(true)}
|
onPointerDown={() => !disabled && setIsFocused(true)}
|
||||||
onPointerOut={() => setIsFocused(false)}
|
onPointerOut={() => setIsFocused(false)}
|
||||||
onPointerLeave={() => setIsFocused(false)}
|
onPointerLeave={() => setIsFocused(false)}
|
||||||
onPointerUp={() => setIsFocused(false)}>
|
onPointerUp={() => setIsFocused(false)}>
|
||||||
<div
|
<div
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
"ml-1 h-4 w-4 rounded-full bg-dark transition-transform",
|
"ml-1 h-4 w-4 rounded-full bg-dark transition-transform touch-none pointer-events-none",
|
||||||
cIf(value, "translate-x-6"),
|
cIf(value, "translate-x-6"),
|
||||||
cIf(isFocused, cIf(value, "translate-x-5", "translate-x-1"))
|
cIf(isFocused, cIf(value, "translate-x-5", "translate-x-1"))
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Ico, Icon } from "components/Ico";
|
import { Ico, Icon } from "components/Ico";
|
||||||
import { cJoin } from "helpers/className";
|
import { cIf, cJoin } from "helpers/className";
|
||||||
import { isDefinedAndNotEmpty } from "helpers/others";
|
import { isDefinedAndNotEmpty } from "helpers/others";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -13,6 +13,7 @@ interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||||
|
@ -23,6 +24,7 @@ export const TextInput = ({
|
||||||
className,
|
className,
|
||||||
name,
|
name,
|
||||||
placeholder,
|
placeholder,
|
||||||
|
disabled = false,
|
||||||
}: Props): JSX.Element => (
|
}: Props): JSX.Element => (
|
||||||
<div className={cJoin("relative", className)}>
|
<div className={cJoin("relative", className)}>
|
||||||
<input
|
<input
|
||||||
|
@ -30,6 +32,7 @@ export const TextInput = ({
|
||||||
type="text"
|
type="text"
|
||||||
name={name}
|
name={name}
|
||||||
value={value}
|
value={value}
|
||||||
|
disabled={disabled}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
onChange(event.target.value);
|
onChange(event.target.value);
|
||||||
|
@ -38,11 +41,9 @@ export const TextInput = ({
|
||||||
{isDefinedAndNotEmpty(value) && (
|
{isDefinedAndNotEmpty(value) && (
|
||||||
<div className="absolute right-4 top-0 bottom-0 grid place-items-center">
|
<div className="absolute right-4 top-0 bottom-0 grid place-items-center">
|
||||||
<Ico
|
<Ico
|
||||||
className="cursor-pointer !text-xs"
|
className={cJoin("!text-xs", cIf(disabled, "opacity-30 grayscale", "cursor-pointer"))}
|
||||||
icon={Icon.Close}
|
icon={Icon.Close}
|
||||||
onClick={() => {
|
onClick={() => !disabled && onChange("")}
|
||||||
onChange("");
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -8,18 +8,13 @@ import { isDefinedAndNotEmpty } from "helpers/others";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
label: string | null | undefined;
|
label: string | null | undefined;
|
||||||
disabled?: boolean;
|
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||||
|
|
||||||
export const WithLabel = ({ label, children, disabled }: Props): JSX.Element => (
|
export const WithLabel = ({ label, children }: Props): JSX.Element => (
|
||||||
<div
|
<div className="flex flex-row place-content-between place-items-center gap-2">
|
||||||
className={cJoin(
|
|
||||||
"flex flex-row place-content-between place-items-center gap-2",
|
|
||||||
cIf(disabled, "text-dark brightness-150 contrast-75 grayscale")
|
|
||||||
)}>
|
|
||||||
{isDefinedAndNotEmpty(label) && (
|
{isDefinedAndNotEmpty(label) && (
|
||||||
<p className={cJoin("text-left", cIf(label.length < 10, "flex-shrink-0"))}>{label}:</p>
|
<p className={cJoin("text-left", cIf(label.length < 10, "flex-shrink-0"))}>{label}:</p>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -10,15 +10,16 @@ import { Ids } from "types/ids";
|
||||||
import { UploadImageFragment } from "graphql/generated";
|
import { UploadImageFragment } from "graphql/generated";
|
||||||
import { ImageQuality } from "helpers/img";
|
import { ImageQuality } from "helpers/img";
|
||||||
import { isDefined } from "helpers/others";
|
import { isDefined } from "helpers/others";
|
||||||
|
import { useContainerQueries } from "contexts/ContainerQueriesContext";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onCloseRequest: () => void;
|
onCloseRequest: () => void;
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
image?: UploadImageFragment | string;
|
image?: UploadImageFragment | string;
|
||||||
isNextImageAvailable?: boolean;
|
isNextImageAvailable: boolean;
|
||||||
isPreviousImageAvailable?: boolean;
|
isPreviousImageAvailable: boolean;
|
||||||
onPressNext?: () => void;
|
onPressNext: () => void;
|
||||||
onPressPrevious?: () => void;
|
onPressPrevious: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||||
|
@ -37,18 +38,15 @@ export const LightBox = ({
|
||||||
Ids.LightBox
|
Ids.LightBox
|
||||||
);
|
);
|
||||||
|
|
||||||
useHotkeys(
|
useHotkeys("left", () => onPressPrevious(), { enabled: isVisible && isPreviousImageAvailable }, [
|
||||||
"left",
|
onPressPrevious,
|
||||||
() => onPressPrevious?.(),
|
]);
|
||||||
{ enabled: isVisible && isPreviousImageAvailable },
|
|
||||||
[onPressPrevious]
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys("f", () => requestFullscreen(), { enabled: isVisible && !isFullscreen }, [
|
useHotkeys("f", () => requestFullscreen(), { enabled: isVisible && !isFullscreen }, [
|
||||||
requestFullscreen,
|
requestFullscreen,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useHotkeys("right", () => onPressNext?.(), { enabled: isVisible && isNextImageAvailable }, [
|
useHotkeys("right", () => onPressNext(), { enabled: isVisible && isNextImageAvailable }, [
|
||||||
onPressNext,
|
onPressNext,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -69,7 +67,7 @@ export const LightBox = ({
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
"absolute inset-8 grid transition-transform",
|
"absolute inset-0 grid transition-transform",
|
||||||
cIf(isVisible, "scale-100", "scale-0")
|
cIf(isVisible, "scale-100", "scale-0")
|
||||||
)}>
|
)}>
|
||||||
<TransformWrapper
|
<TransformWrapper
|
||||||
|
@ -87,46 +85,32 @@ export const LightBox = ({
|
||||||
}}>
|
}}>
|
||||||
{isDefined(src) && (
|
{isDefined(src) && (
|
||||||
<Img
|
<Img
|
||||||
className={`drop-shadow-shade-2xl-shade h-[calc(100vh-4rem)] w-full
|
className={`shadow-shade drop-shadow-2xl h-[calc(100vh-4rem)] w-full
|
||||||
object-contain`}
|
object-contain`}
|
||||||
src={src}
|
src={src}
|
||||||
quality={ImageQuality.Large}
|
quality={ImageQuality.Large}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</TransformComponent>
|
</TransformComponent>
|
||||||
|
<ControlButtons
|
||||||
{isPreviousImageAvailable && (
|
isNextImageAvailable={isNextImageAvailable}
|
||||||
<div
|
isPreviousImageAvailable={isPreviousImageAvailable}
|
||||||
className={`absolute top-1/2 left-0 grid gap-4 rounded-[2rem] p-4
|
isFullscreen={isFullscreen}
|
||||||
backdrop-blur-lg`}>
|
onCloseRequest={() => {
|
||||||
<Button icon={Icon.NavigateBefore} onClick={onPressPrevious} />
|
resetTransform();
|
||||||
</div>
|
exitFullscreen();
|
||||||
)}
|
onCloseRequest();
|
||||||
|
}}
|
||||||
{isNextImageAvailable && (
|
onPressPrevious={() => {
|
||||||
<div
|
resetTransform();
|
||||||
className={`absolute top-1/2 right-0 grid gap-4 rounded-[2rem] p-4
|
onPressPrevious();
|
||||||
backdrop-blur-lg`}>
|
}}
|
||||||
<Button icon={Icon.NavigateNext} onClick={onPressNext} />{" "}
|
onPressNext={() => {
|
||||||
</div>
|
resetTransform();
|
||||||
)}
|
onPressNext();
|
||||||
|
}}
|
||||||
<div
|
toggleFullscreen={toggleFullscreen}
|
||||||
className={`absolute top-0 right-0 grid gap-4 rounded-[2rem] p-4
|
/>
|
||||||
backdrop-blur-lg`}>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
resetTransform();
|
|
||||||
exitFullscreen();
|
|
||||||
onCloseRequest();
|
|
||||||
}}
|
|
||||||
icon={Icon.Close}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
icon={isFullscreen ? Icon.FullscreenExit : Icon.Fullscreen}
|
|
||||||
onClick={toggleFullscreen}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</TransformWrapper>
|
</TransformWrapper>
|
||||||
|
@ -134,3 +118,83 @@ export const LightBox = ({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface ControlButtonsProps {
|
||||||
|
isPreviousImageAvailable: boolean;
|
||||||
|
isNextImageAvailable: boolean;
|
||||||
|
isFullscreen: boolean;
|
||||||
|
onPressPrevious?: () => void;
|
||||||
|
onPressNext?: () => void;
|
||||||
|
onCloseRequest: () => void;
|
||||||
|
toggleFullscreen: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ControlButtons = ({
|
||||||
|
isFullscreen,
|
||||||
|
isPreviousImageAvailable,
|
||||||
|
isNextImageAvailable,
|
||||||
|
onPressPrevious,
|
||||||
|
onPressNext,
|
||||||
|
onCloseRequest,
|
||||||
|
toggleFullscreen,
|
||||||
|
}: ControlButtonsProps): JSX.Element => {
|
||||||
|
const { is1ColumnLayout } = useContainerQueries();
|
||||||
|
|
||||||
|
const PreviousButton = () => (
|
||||||
|
<Button
|
||||||
|
icon={Icon.NavigateBefore}
|
||||||
|
onClick={onPressPrevious}
|
||||||
|
disabled={!isPreviousImageAvailable}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
const NextButton = () => (
|
||||||
|
<Button icon={Icon.NavigateNext} onClick={onPressNext} disabled={!isNextImageAvailable} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const FullscreenButton = () => (
|
||||||
|
<Button
|
||||||
|
icon={isFullscreen ? Icon.FullscreenExit : Icon.Fullscreen}
|
||||||
|
onClick={toggleFullscreen}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const CloseButton = () => <Button onClick={onCloseRequest} icon={Icon.Close} />;
|
||||||
|
|
||||||
|
return is1ColumnLayout ? (
|
||||||
|
<>
|
||||||
|
<div className="absolute bottom-2 left-0 right-0 grid place-content-center">
|
||||||
|
<div className="grid grid-flow-col gap-4 rounded-4xl p-4 backdrop-blur-lg">
|
||||||
|
<PreviousButton />
|
||||||
|
<FullscreenButton />
|
||||||
|
<NextButton />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="absolute top-2 right-2 grid gap-4 rounded-4xl p-4 backdrop-blur-lg">
|
||||||
|
<CloseButton />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{isPreviousImageAvailable && (
|
||||||
|
<div
|
||||||
|
className={`absolute top-1/2 left-8 grid gap-4 rounded-4xl p-4
|
||||||
|
backdrop-blur-lg`}>
|
||||||
|
<PreviousButton />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isNextImageAvailable && (
|
||||||
|
<div
|
||||||
|
className={`absolute top-1/2 right-8 grid gap-4 rounded-4xl p-4
|
||||||
|
backdrop-blur-lg`}>
|
||||||
|
<NextButton />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className={`absolute top-4 right-8 grid gap-4 rounded-4xl p-4
|
||||||
|
backdrop-blur-lg`}>
|
||||||
|
<CloseButton />
|
||||||
|
<FullscreenButton />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ import React, { Fragment, useMemo } from "react";
|
||||||
import ReactDOMServer from "react-dom/server";
|
import ReactDOMServer from "react-dom/server";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { Img } from "components/Img";
|
import { Img } from "components/Img";
|
||||||
import { InsetBox } from "components/InsetBox";
|
import { InsetBox } from "components/Containers/InsetBox";
|
||||||
import { cIf, cJoin } from "helpers/className";
|
import { cIf, cJoin } from "helpers/className";
|
||||||
import { slugify } from "helpers/formatters";
|
import { slugify } from "helpers/formatters";
|
||||||
import { getAssetURL, ImageQuality } from "helpers/img";
|
import { getAssetURL, ImageQuality } from "helpers/img";
|
||||||
|
@ -204,7 +204,7 @@ export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Eleme
|
||||||
: compProps.src
|
: compProps.src
|
||||||
}
|
}
|
||||||
quality={ImageQuality.Medium}
|
quality={ImageQuality.Medium}
|
||||||
className="drop-shadow-shade-lg"
|
className="drop-shadow-lg shadow-shade"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { MouseEventHandler, useCallback, useMemo } from "react";
|
import { MouseEventHandler, useCallback, useMemo, useState } from "react";
|
||||||
import { Ico, Icon } from "components/Ico";
|
import { Ico, Icon } from "components/Ico";
|
||||||
import { ToolTip } from "components/ToolTip";
|
import { ToolTip } from "components/ToolTip";
|
||||||
import { cJoin, cIf } from "helpers/className";
|
import { cIf, cJoin } from "helpers/className";
|
||||||
import { isDefinedAndNotEmpty } from "helpers/others";
|
import { isDefinedAndNotEmpty } from "helpers/others";
|
||||||
import { Link } from "components/Inputs/Link";
|
|
||||||
import { TranslatedProps } from "types/TranslatedProps";
|
import { TranslatedProps } from "types/TranslatedProps";
|
||||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||||
|
import { DownPressable } from "components/Containers/DownPressable";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭─────────────╮
|
* ╭─────────────╮
|
||||||
|
@ -21,6 +21,7 @@ interface Props {
|
||||||
border?: boolean;
|
border?: boolean;
|
||||||
reduced?: boolean;
|
reduced?: boolean;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
onClick?: MouseEventHandler<HTMLDivElement>;
|
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ export const NavOption = ({
|
||||||
border = false,
|
border = false,
|
||||||
reduced = false,
|
reduced = false,
|
||||||
active = false,
|
active = false,
|
||||||
|
disabled = false,
|
||||||
onClick,
|
onClick,
|
||||||
}: Props): JSX.Element => {
|
}: Props): JSX.Element => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -41,6 +43,7 @@ export const NavOption = ({
|
||||||
() => active || router.asPath.startsWith(url),
|
() => active || router.asPath.startsWith(url),
|
||||||
[active, router.asPath, url]
|
[active, router.asPath, url]
|
||||||
);
|
);
|
||||||
|
const [isFocused, setFocused] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToolTip
|
<ToolTip
|
||||||
|
@ -52,27 +55,28 @@ export const NavOption = ({
|
||||||
}
|
}
|
||||||
placement="right"
|
placement="right"
|
||||||
className="text-left"
|
className="text-left"
|
||||||
disabled={!reduced}>
|
disabled={!reduced || disabled}>
|
||||||
<Link
|
<DownPressable
|
||||||
href={url}
|
|
||||||
onClick={onClick}
|
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
`relative grid w-full cursor-pointer auto-cols-fr grid-flow-col grid-cols-[auto]
|
"grid w-full auto-cols-fr grid-flow-col grid-cols-[auto] justify-center gap-x-5",
|
||||||
justify-center gap-x-5 rounded-2xl p-4 transition-all hover:bg-mid hover:shadow-inner-sm
|
cIf(icon, "text-left", "text-center")
|
||||||
hover:shadow-shade hover:active:shadow-inner hover:active:shadow-shade`,
|
)}
|
||||||
cIf(icon, "text-left", "text-center"),
|
href={url}
|
||||||
cIf(border, "outline outline-2 -outline-offset-2 outline-mid hover:outline-transparent"),
|
border={border}
|
||||||
cIf(isActive, "bg-mid shadow-inner-sm shadow-shade")
|
onClick={onClick}
|
||||||
)}>
|
active={isActive}
|
||||||
{icon && <Ico icon={icon} className="mt-[-.1em] !text-2xl" isFilled={isActive} />}
|
disabled={disabled}
|
||||||
|
onFocusChanged={setFocused}>
|
||||||
|
{icon && (
|
||||||
|
<Ico icon={icon} className="mt-[-.1em] !text-2xl" isFilled={isActive || isFocused} />
|
||||||
|
)}
|
||||||
{!reduced && (
|
{!reduced && (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-2xl">{title}</h3>
|
<h3 className="text-2xl">{title}</h3>
|
||||||
{isDefinedAndNotEmpty(subtitle) && <p className="col-start-2">{subtitle}</p>}
|
{isDefinedAndNotEmpty(subtitle) && <p className="col-start-2">{subtitle}</p>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</DownPressable>
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { useMemo } from "react";
|
||||||
import UAParser from "ua-parser-js";
|
import UAParser from "ua-parser-js";
|
||||||
import { useIsClient, useSessionStorage } from "usehooks-ts";
|
import { useIsClient, useSessionStorage } from "usehooks-ts";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { Popup } from "components/Popup";
|
import { Popup } from "components/Containers/Popup";
|
||||||
import { sendAnalytics } from "helpers/analytics";
|
import { sendAnalytics } from "helpers/analytics";
|
||||||
|
|
||||||
export const SafariPopup = (): JSX.Element => {
|
export const SafariPopup = (): JSX.Element => {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
||||||
import { OrderableList } from "components/Inputs/OrderableList";
|
import { OrderableList } from "components/Inputs/OrderableList";
|
||||||
import { Select } from "components/Inputs/Select";
|
import { Select } from "components/Inputs/Select";
|
||||||
import { TextInput } from "components/Inputs/TextInput";
|
import { TextInput } from "components/Inputs/TextInput";
|
||||||
import { Popup } from "components/Popup";
|
import { Popup } from "components/Containers/Popup";
|
||||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||||
import { useLocalData } from "contexts/LocalDataContext";
|
import { useLocalData } from "contexts/LocalDataContext";
|
||||||
import { useUserSettings } from "contexts/UserSettingsContext";
|
import { useUserSettings } from "contexts/UserSettingsContext";
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { Chip } from "./Chip";
|
||||||
import { HorizontalLine } from "./HorizontalLine";
|
import { HorizontalLine } from "./HorizontalLine";
|
||||||
import { Markdawn, TableOfContents } from "./Markdown/Markdawn";
|
import { Markdawn, TableOfContents } from "./Markdown/Markdawn";
|
||||||
import { ReturnButton } from "./PanelComponents/ReturnButton";
|
import { ReturnButton } from "./PanelComponents/ReturnButton";
|
||||||
import { ContentPanel } from "./Panels/ContentPanel";
|
import { ContentPanel } from "./Containers/ContentPanel";
|
||||||
import { SubPanel } from "./Panels/SubPanel";
|
import { SubPanel } from "./Containers/SubPanel";
|
||||||
import { RecorderChip } from "./RecorderChip";
|
import { RecorderChip } from "./RecorderChip";
|
||||||
import { ThumbnailHeader } from "./ThumbnailHeader";
|
import { ThumbnailHeader } from "./ThumbnailHeader";
|
||||||
import { ToolTip } from "./ToolTip";
|
import { ToolTip } from "./ToolTip";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useRouter } from "next/router";
|
||||||
import { Chip } from "./Chip";
|
import { Chip } from "./Chip";
|
||||||
import { Ico, Icon } from "./Ico";
|
import { Ico, Icon } from "./Ico";
|
||||||
import { Img } from "./Img";
|
import { Img } from "./Img";
|
||||||
import { Link } from "./Inputs/Link";
|
import { UpPressable } from "./Containers/UpPressable";
|
||||||
import { DatePickerFragment, PricePickerFragment, UploadImageFragment } from "graphql/generated";
|
import { DatePickerFragment, PricePickerFragment, UploadImageFragment } from "graphql/generated";
|
||||||
import { cIf, cJoin } from "helpers/className";
|
import { cIf, cJoin } from "helpers/className";
|
||||||
import { prettyDate, prettyDuration, prettyPrice, prettyShortenNumber } from "helpers/formatters";
|
import { prettyDate, prettyDuration, prettyPrice, prettyShortenNumber } from "helpers/formatters";
|
||||||
|
@ -47,6 +47,7 @@ interface Props {
|
||||||
duration: number;
|
duration: number;
|
||||||
}
|
}
|
||||||
| { __typename: "anotherHoverlayName" };
|
| { __typename: "anotherHoverlayName" };
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||||
|
@ -67,6 +68,7 @@ export const PreviewCard = ({
|
||||||
metadata,
|
metadata,
|
||||||
hoverlay,
|
hoverlay,
|
||||||
infoAppend,
|
infoAppend,
|
||||||
|
disabled = false,
|
||||||
}: Props): JSX.Element => {
|
}: Props): JSX.Element => {
|
||||||
const { currency } = useUserSettings();
|
const { currency } = useUserSettings();
|
||||||
const { currencies } = useLocalData();
|
const { currencies } = useLocalData();
|
||||||
|
@ -110,97 +112,101 @@ export const PreviewCard = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<UpPressable className="grid items-end text-left" href={href} noBackground disabled={disabled}>
|
||||||
href={href}
|
<div className={cJoin("group", cIf(disabled, "pointer-events-none touch-none select-none"))}>
|
||||||
className="group grid cursor-pointer items-end text-left transition-transform
|
{thumbnail ? (
|
||||||
drop-shadow-shade-xl hover:scale-[1.02]">
|
|
||||||
{thumbnail ? (
|
|
||||||
<div
|
|
||||||
className="relative"
|
|
||||||
style={{
|
|
||||||
aspectRatio: thumbnailForceAspectRatio ? thumbnailAspectRatio : "unset",
|
|
||||||
}}>
|
|
||||||
<Img
|
|
||||||
className={cJoin(
|
|
||||||
cIf(
|
|
||||||
thumbnailRounded,
|
|
||||||
cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none")
|
|
||||||
),
|
|
||||||
cIf(thumbnailForceAspectRatio, "h-full w-full object-cover")
|
|
||||||
)}
|
|
||||||
src={thumbnail}
|
|
||||||
quality={ImageQuality.Medium}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{hoverlay && hoverlay.__typename === "Video" && (
|
|
||||||
<>
|
|
||||||
<div
|
|
||||||
className="absolute inset-0 grid place-content-center bg-shade bg-opacity-0
|
|
||||||
text-light transition-colors drop-shadow-shade-lg group-hover:bg-opacity-50">
|
|
||||||
<Ico
|
|
||||||
icon={Icon.PlayCircleOutline}
|
|
||||||
className="!text-6xl opacity-0 transition-opacity group-hover:opacity-100"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="absolute right-2 bottom-2 rounded-full bg-black bg-opacity-60 px-2
|
|
||||||
text-light">
|
|
||||||
{prettyDuration(hoverlay.duration)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{ aspectRatio: thumbnailAspectRatio }}
|
|
||||||
className={cJoin(
|
|
||||||
"relative w-full bg-light",
|
|
||||||
cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none")
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
className={cJoin(
|
|
||||||
"z-20 grid gap-2 p-4 transition-opacity linearbg-obi",
|
|
||||||
cIf(
|
|
||||||
!keepInfoVisible && isHoverable,
|
|
||||||
`-inset-x-0.5 bottom-2 opacity-0 [border-radius:10%_10%_10%_10%_/_1%_1%_3%_3%]
|
|
||||||
group-hover:opacity-100 hoverable:absolute hoverable:drop-shadow-shade-lg
|
|
||||||
notHoverable:rounded-b-md notHoverable:opacity-100`,
|
|
||||||
"[border-radius:0%_0%_10%_10%_/_0%_0%_3%_3%]"
|
|
||||||
)
|
|
||||||
)}>
|
|
||||||
{metadata?.position === "Top" && metadataJSX}
|
|
||||||
{topChips && topChips.length > 0 && (
|
|
||||||
<div className="grid grid-flow-col place-content-start gap-1 overflow-hidden">
|
|
||||||
{topChips.map((text, index) => (
|
|
||||||
<Chip key={index} text={text} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="my-1">
|
|
||||||
{pre_title && <p className="mb-1 leading-none break-words">{pre_title}</p>}
|
|
||||||
{title && (
|
|
||||||
<p className="font-headers text-lg font-bold leading-none break-words">{title}</p>
|
|
||||||
)}
|
|
||||||
{subtitle && <p className="leading-none break-words">{subtitle}</p>}
|
|
||||||
</div>
|
|
||||||
{description && <p>{description}</p>}
|
|
||||||
{bottomChips && bottomChips.length > 0 && (
|
|
||||||
<div
|
<div
|
||||||
className="grid grid-flow-col place-content-start gap-1 overflow-x-scroll
|
className="relative"
|
||||||
[scrollbar-width:none] webkit-scrollbar:h-0">
|
style={{
|
||||||
{bottomChips.map((text, index) => (
|
aspectRatio: thumbnailForceAspectRatio ? thumbnailAspectRatio : "unset",
|
||||||
<Chip key={index} className="text-sm" text={text} />
|
}}>
|
||||||
))}
|
<Img
|
||||||
|
className={cJoin(
|
||||||
|
cIf(
|
||||||
|
thumbnailRounded,
|
||||||
|
cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none")
|
||||||
|
),
|
||||||
|
cIf(thumbnailForceAspectRatio, "h-full w-full object-cover")
|
||||||
|
)}
|
||||||
|
src={thumbnail}
|
||||||
|
quality={ImageQuality.Medium}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{hoverlay && hoverlay.__typename === "Video" && (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="group absolute inset-0 grid place-content-center bg-shade bg-opacity-0
|
||||||
|
text-light transition-colors
|
||||||
|
hover:bg-opacity-50">
|
||||||
|
<Ico
|
||||||
|
icon={Icon.PlayCircleOutline}
|
||||||
|
className="!text-6xl text-black opacity-0 drop-shadow-lg transition-opacity
|
||||||
|
shadow-shade group-hover:opacity-100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="absolute right-2 bottom-2 rounded-full bg-black bg-opacity-60 px-2
|
||||||
|
text-light">
|
||||||
|
{prettyDuration(hoverlay.duration)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
style={{ aspectRatio: thumbnailAspectRatio }}
|
||||||
|
className={cJoin(
|
||||||
|
"relative w-full bg-highlight",
|
||||||
|
cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none")
|
||||||
|
)}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
<div
|
||||||
|
className={cJoin(
|
||||||
|
"z-20 grid gap-2 p-4 transition-opacity linearbg-obi",
|
||||||
|
cIf(
|
||||||
|
!keepInfoVisible && isHoverable,
|
||||||
|
`-inset-x-0.5 bottom-2 opacity-0 shadow-shade
|
||||||
|
[border-radius:10%_10%_10%_10%_/_1%_1%_3%_3%]
|
||||||
|
group-hover:opacity-100 hoverable:absolute hoverable:drop-shadow-lg
|
||||||
|
notHoverable:rounded-b-md notHoverable:opacity-100`,
|
||||||
|
"[border-radius:0%_0%_10%_10%_/_0%_0%_3%_3%]"
|
||||||
|
)
|
||||||
|
)}>
|
||||||
|
{metadata?.position === "Top" && metadataJSX}
|
||||||
|
{topChips && topChips.length > 0 && (
|
||||||
|
<div
|
||||||
|
className="grid grid-flow-col place-content-start gap-1 overflow-x-scroll
|
||||||
|
scrollbar-none">
|
||||||
|
{topChips.map((text, index) => (
|
||||||
|
<Chip key={index} text={text} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="my-1">
|
||||||
|
{pre_title && <p className="mb-1 leading-none break-words">{pre_title}</p>}
|
||||||
|
{title && (
|
||||||
|
<p className="font-headers text-lg font-bold leading-none break-words">{title}</p>
|
||||||
|
)}
|
||||||
|
{subtitle && <p className="leading-none break-words">{subtitle}</p>}
|
||||||
|
</div>
|
||||||
|
{description && <p>{description}</p>}
|
||||||
|
{bottomChips && bottomChips.length > 0 && (
|
||||||
|
<div
|
||||||
|
className="grid grid-flow-col place-content-start gap-1 overflow-x-scroll
|
||||||
|
scrollbar-none">
|
||||||
|
{bottomChips.map((text, index) => (
|
||||||
|
<Chip key={index} className="text-sm" text={text} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{metadata?.position === "Bottom" && metadataJSX}
|
{metadata?.position === "Bottom" && metadataJSX}
|
||||||
|
|
||||||
{infoAppend}
|
{infoAppend}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</UpPressable>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { Chip } from "./Chip";
|
import { Chip } from "./Chip";
|
||||||
import { Img } from "./Img";
|
import { Img } from "./Img";
|
||||||
import { Link } from "./Inputs/Link";
|
import { UpPressable } from "./Containers/UpPressable";
|
||||||
import { UploadImageFragment } from "graphql/generated";
|
import { UploadImageFragment } from "graphql/generated";
|
||||||
import { ImageQuality } from "helpers/img";
|
import { ImageQuality } from "helpers/img";
|
||||||
import { TranslatedProps } from "types/TranslatedProps";
|
import { TranslatedProps } from "types/TranslatedProps";
|
||||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||||
|
import { cIf, cJoin } from "helpers/className";
|
||||||
|
import { isDefined } from "helpers/others";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭─────────────╮
|
* ╭─────────────╮
|
||||||
|
@ -14,60 +16,66 @@ import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
thumbnail?: UploadImageFragment | string | null | undefined;
|
thumbnail?: UploadImageFragment | string | null | undefined;
|
||||||
thumbnailAspectRatio?: string;
|
|
||||||
href: string;
|
href: string;
|
||||||
pre_title?: string | null | undefined;
|
pre_title?: string | null | undefined;
|
||||||
title: string | null | undefined;
|
title: string | null | undefined;
|
||||||
subtitle?: string | null | undefined;
|
subtitle?: string | null | undefined;
|
||||||
topChips?: string[];
|
topChips?: string[];
|
||||||
bottomChips?: string[];
|
bottomChips?: string[];
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||||
|
|
||||||
const PreviewLine = ({
|
export const PreviewLine = ({
|
||||||
href,
|
href,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
pre_title,
|
pre_title,
|
||||||
title,
|
title,
|
||||||
subtitle,
|
subtitle,
|
||||||
topChips,
|
topChips,
|
||||||
|
disabled,
|
||||||
bottomChips,
|
bottomChips,
|
||||||
thumbnailAspectRatio,
|
|
||||||
}: Props): JSX.Element => (
|
}: Props): JSX.Element => (
|
||||||
<Link
|
<UpPressable href={href} disabled={disabled}>
|
||||||
href={href}
|
<div
|
||||||
className="flex h-36 w-full cursor-pointer flex-row place-items-center gap-4 overflow-hidden
|
className={cJoin(
|
||||||
rounded-md bg-light pr-4 transition-transform drop-shadow-shade-xl hover:scale-[1.02]">
|
"grid w-full grid-flow-col place-items-center gap-4",
|
||||||
{thumbnail ? (
|
cIf(disabled, "pointer-events-none touch-none select-none")
|
||||||
<div className="aspect-[3/2] h-full">
|
)}>
|
||||||
<Img className="h-full object-cover" src={thumbnail} quality={ImageQuality.Medium} />
|
{thumbnail && (
|
||||||
</div>
|
<div className="h-full w-full">
|
||||||
) : (
|
<Img className="h-full object-cover" src={thumbnail} quality={ImageQuality.Medium} />
|
||||||
<div style={{ aspectRatio: thumbnailAspectRatio }} />
|
|
||||||
)}
|
|
||||||
<div className="grid gap-2">
|
|
||||||
{topChips && topChips.length > 0 && (
|
|
||||||
<div className="grid grid-flow-col place-content-start gap-1 overflow-hidden">
|
|
||||||
{topChips.map((text, index) => (
|
|
||||||
<Chip key={index} text={text} />
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="my-1 flex flex-col">
|
|
||||||
{pre_title && <p className="mb-1 leading-none">{pre_title}</p>}
|
<div className={cJoin("grid gap-2 py-4", cIf(isDefined(thumbnail), "pr-3", "px-6"))}>
|
||||||
{title && <p className="font-headers text-lg font-bold leading-none">{title}</p>}
|
{topChips && topChips.length > 0 && (
|
||||||
{subtitle && <p className="leading-none">{subtitle}</p>}
|
<div
|
||||||
</div>
|
className="grid grid-flow-col place-content-start gap-1 overflow-scroll
|
||||||
{bottomChips && bottomChips.length > 0 && (
|
scrollbar-none">
|
||||||
<div className="grid grid-flow-col place-content-start gap-1 overflow-hidden">
|
{topChips.map((text, index) => (
|
||||||
{bottomChips.map((text, index) => (
|
<Chip key={index} text={text} />
|
||||||
<Chip key={index} className="text-sm" text={text} />
|
))}
|
||||||
))}
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="my-1 flex flex-col">
|
||||||
|
{pre_title && <p className="mb-1 leading-none">{pre_title}</p>}
|
||||||
|
{title && <p className="font-headers text-lg font-bold leading-none">{title}</p>}
|
||||||
|
{subtitle && <p className="leading-none">{subtitle}</p>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
{bottomChips && bottomChips.length > 0 && (
|
||||||
|
<div
|
||||||
|
className="grid grid-flow-col place-content-start gap-1 overflow-scroll
|
||||||
|
scrollbar-none">
|
||||||
|
{bottomChips.map((text, index) => (
|
||||||
|
<Chip key={index} className="text-sm" text={text} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</UpPressable>
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { useScrollTopOnChange } from "hooks/useScrollTopOnChange";
|
||||||
import { Ids } from "types/ids";
|
import { Ids } from "types/ids";
|
||||||
import { useLocalData } from "contexts/LocalDataContext";
|
import { useLocalData } from "contexts/LocalDataContext";
|
||||||
import { useContainerQueries } from "contexts/ContainerQueriesContext";
|
import { useContainerQueries } from "contexts/ContainerQueriesContext";
|
||||||
|
import { useHotkeys } from "react-hotkeys-hook";
|
||||||
|
|
||||||
interface Group<T> {
|
interface Group<T> {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -163,6 +164,11 @@ export const SmartList = <T,>({
|
||||||
return memo;
|
return memo;
|
||||||
}, [groups, paginationItemPerPage]);
|
}, [groups, paginationItemPerPage]);
|
||||||
|
|
||||||
|
useHotkeys("left", () => setPage((current) => current - 1), { enabled: page > 0 });
|
||||||
|
useHotkeys("right", () => setPage((current) => current + 1), {
|
||||||
|
enabled: page < pages.length - 1,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{pages.length > 1 && paginationSelectorTop && (
|
{pages.length > 1 && paginationSelectorTop && (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Chip } from "components/Chip";
|
import { Chip } from "components/Chip";
|
||||||
import { Img } from "components/Img";
|
import { Img } from "components/Img";
|
||||||
import { InsetBox } from "components/InsetBox";
|
import { InsetBox } from "components/Containers/InsetBox";
|
||||||
import { Markdawn } from "components/Markdown/Markdawn";
|
import { Markdawn } from "components/Markdown/Markdawn";
|
||||||
import { GetContentTextQuery, UploadImageFragment } from "graphql/generated";
|
import { GetContentTextQuery, UploadImageFragment } from "graphql/generated";
|
||||||
import { prettyInlineTitle, prettySlug, slugify } from "helpers/formatters";
|
import { prettyInlineTitle, prettySlug, slugify } from "helpers/formatters";
|
||||||
|
@ -48,7 +48,7 @@ export const ThumbnailHeader = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mb-12 grid place-items-center gap-12">
|
<div className="mb-12 grid place-items-center gap-12">
|
||||||
<div className="drop-shadow-shade-lg">
|
<div className="shadow-shade drop-shadow-lg">
|
||||||
{thumbnail ? (
|
{thumbnail ? (
|
||||||
<Img
|
<Img
|
||||||
className="cursor-pointer rounded-xl"
|
className="cursor-pointer rounded-xl"
|
||||||
|
|
|
@ -2,7 +2,9 @@ export const cIf = (
|
||||||
condition: boolean | string | null | undefined,
|
condition: boolean | string | null | undefined,
|
||||||
ifTrueCss: string,
|
ifTrueCss: string,
|
||||||
ifFalseCss?: string
|
ifFalseCss?: string
|
||||||
): string => (condition ? ifTrueCss : ifFalseCss ?? "");
|
): string => removeWhitespace(condition ? ifTrueCss : ifFalseCss ?? "");
|
||||||
|
|
||||||
export const cJoin = (...args: (string | undefined)[]): string =>
|
export const cJoin = (...args: (string | undefined)[]): string =>
|
||||||
args.filter((elem) => elem).join(" ");
|
removeWhitespace(args.filter((elem) => elem).join(" "));
|
||||||
|
|
||||||
|
const removeWhitespace = (string: string): string => string.replaceAll(/\s+/gu, " ");
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { GetStaticProps } from "next";
|
import { GetStaticProps } from "next";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { getLangui } from "graphql/fetchLocalData";
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
import { Img } from "components/Img";
|
import { Img } from "components/Img";
|
||||||
|
@ -20,7 +20,10 @@ const FourOhFour = ({ openGraph, ...otherProps }: Props): JSX.Element => {
|
||||||
<AppLayout
|
<AppLayout
|
||||||
contentPanel={
|
contentPanel={
|
||||||
<ContentPanel>
|
<ContentPanel>
|
||||||
<Img src={"/gameover_cards.webp"} className="animate-zoom-in drop-shadow-shade-lg" />
|
<Img
|
||||||
|
src={"/gameover_cards.webp"}
|
||||||
|
className="animate-zoom-in drop-shadow-lg shadow-shade"
|
||||||
|
/>
|
||||||
<div className="mt-8 grid place-items-center gap-6">
|
<div className="mt-8 grid place-items-center gap-6">
|
||||||
<h2>{langui.page_not_found}</h2>
|
<h2>{langui.page_not_found}</h2>
|
||||||
<ReturnButton href="/" title="Home" />
|
<ReturnButton href="/" title="Home" />
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { GetStaticProps } from "next";
|
import { GetStaticProps } from "next";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { getLangui } from "graphql/fetchLocalData";
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
import { Img } from "components/Img";
|
import { Img } from "components/Img";
|
||||||
|
@ -20,7 +20,10 @@ const FiveHundred = ({ openGraph, ...otherProps }: Props): JSX.Element => {
|
||||||
<AppLayout
|
<AppLayout
|
||||||
contentPanel={
|
contentPanel={
|
||||||
<ContentPanel>
|
<ContentPanel>
|
||||||
<Img src={"/gameover_cards.webp"} className="animate-zoom-in drop-shadow-shade-lg" />
|
<Img
|
||||||
|
src={"/gameover_cards.webp"}
|
||||||
|
className="animate-zoom-in drop-shadow-lg shadow-shade"
|
||||||
|
/>
|
||||||
<div className="mt-8 grid place-items-center gap-6">
|
<div className="mt-8 grid place-items-center gap-6">
|
||||||
<h2>{langui.page_not_found}</h2>
|
<h2>{langui.page_not_found}</h2>
|
||||||
<ReturnButton href="/" title="Home" />
|
<ReturnButton href="/" title="Home" />
|
||||||
|
|
|
@ -11,8 +11,6 @@ import type { AppProps } from "next/app";
|
||||||
import Script from "next/script";
|
import Script from "next/script";
|
||||||
import { AppContextProvider } from "contexts/AppLayoutContext";
|
import { AppContextProvider } from "contexts/AppLayoutContext";
|
||||||
|
|
||||||
import "styles/animations.css";
|
|
||||||
import "styles/custom-classes.css";
|
|
||||||
import "styles/debug.css";
|
import "styles/debug.css";
|
||||||
import "styles/formatted.css";
|
import "styles/formatted.css";
|
||||||
import "styles/others.css";
|
import "styles/others.css";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { InsetBox } from "components/InsetBox";
|
import { InsetBox } from "components/Containers/InsetBox";
|
||||||
import { PostPage } from "components/PostPage";
|
import { PostPage } from "components/PostPage";
|
||||||
import { getPostStaticProps, PostStaticProps } from "graphql/getPostStaticProps";
|
import { getPostStaticProps, PostStaticProps } from "graphql/getPostStaticProps";
|
||||||
import { cIf, cJoin } from "helpers/className";
|
import { cIf, cJoin } from "helpers/className";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
import { NavOption } from "components/PanelComponents/NavOption";
|
import { NavOption } from "components/PanelComponents/NavOption";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { getLangui } from "graphql/fetchLocalData";
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useMemo } from "react";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { NavOption } from "components/PanelComponents/NavOption";
|
import { NavOption } from "components/PanelComponents/NavOption";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
|
|
|
@ -5,8 +5,8 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Switch } from "components/Inputs/Switch";
|
import { Switch } from "components/Inputs/Switch";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { PreviewCard } from "components/PreviewCard";
|
import { PreviewCard } from "components/PreviewCard";
|
||||||
import { GetVideoChannelQuery } from "graphql/generated";
|
import { GetVideoChannelQuery } from "graphql/generated";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
|
|
|
@ -9,8 +9,8 @@ import { TextInput } from "components/Inputs/TextInput";
|
||||||
import { WithLabel } from "components/Inputs/WithLabel";
|
import { WithLabel } from "components/Inputs/WithLabel";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { PreviewCard } from "components/PreviewCard";
|
import { PreviewCard } from "components/PreviewCard";
|
||||||
import { GetVideosPreviewQuery } from "graphql/generated";
|
import { GetVideosPreviewQuery } from "graphql/generated";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
|
|
|
@ -5,11 +5,11 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { Ico, Icon } from "components/Ico";
|
import { Ico, Icon } from "components/Ico";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { InsetBox } from "components/InsetBox";
|
import { InsetBox } from "components/Containers/InsetBox";
|
||||||
import { NavOption } from "components/PanelComponents/NavOption";
|
import { NavOption } from "components/PanelComponents/NavOption";
|
||||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||||
import { GetVideoQuery } from "graphql/generated";
|
import { GetVideoQuery } from "graphql/generated";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
|
@ -83,7 +83,7 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="grid place-items-center gap-12">
|
<div className="grid place-items-center gap-12">
|
||||||
<div id="video" className="w-full overflow-hidden rounded-xl shadow-lg shadow-shade">
|
<div id="video" className="w-full overflow-hidden rounded-xl shadow-xl shadow-shade/80">
|
||||||
{video.gone ? (
|
{video.gone ? (
|
||||||
<video className="w-full" src={getVideoFile(video.uid)} controls />
|
<video className="w-full" src={getVideoFile(video.uid)} controls />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -5,9 +5,9 @@ import { isDefined, filterHasAttributes } from "helpers/others";
|
||||||
import { ChronicleWithTranslations } from "types/types";
|
import { ChronicleWithTranslations } from "types/types";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||||
import { Markdawn } from "components/Markdown/Markdawn";
|
import { Markdawn } from "components/Markdown/Markdawn";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { ThumbnailHeader } from "components/ThumbnailHeader";
|
import { ThumbnailHeader } from "components/ThumbnailHeader";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { GetChroniclesChaptersQuery } from "graphql/generated";
|
import { GetChroniclesChaptersQuery } from "graphql/generated";
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { GetStaticProps } from "next";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { GetChroniclesChaptersQuery } from "graphql/generated";
|
import { GetChroniclesChaptersQuery } from "graphql/generated";
|
||||||
|
|
|
@ -7,8 +7,8 @@ import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
||||||
import { Markdawn, TableOfContents } from "components/Markdown/Markdawn";
|
import { Markdawn, TableOfContents } from "components/Markdown/Markdawn";
|
||||||
import { TranslatedReturnButton } from "components/PanelComponents/ReturnButton";
|
import { TranslatedReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { PreviewCard } from "components/PreviewCard";
|
import { PreviewCard } from "components/PreviewCard";
|
||||||
import { RecorderChip } from "components/RecorderChip";
|
import { RecorderChip } from "components/RecorderChip";
|
||||||
import { ThumbnailHeader } from "components/ThumbnailHeader";
|
import { ThumbnailHeader } from "components/ThumbnailHeader";
|
||||||
|
@ -315,7 +315,6 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
|
||||||
title: prettySlug(previousContent.attributes.slug),
|
title: prettySlug(previousContent.attributes.slug),
|
||||||
}}
|
}}
|
||||||
thumbnail={previousContent.attributes.thumbnail?.data?.attributes}
|
thumbnail={previousContent.attributes.thumbnail?.data?.attributes}
|
||||||
thumbnailAspectRatio="3/2"
|
|
||||||
topChips={
|
topChips={
|
||||||
isContentPanelAtLeast2xl && previousContent.attributes.type?.data?.attributes
|
isContentPanelAtLeast2xl && previousContent.attributes.type?.data?.attributes
|
||||||
? [
|
? [
|
||||||
|
@ -359,7 +358,6 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
|
||||||
}))}
|
}))}
|
||||||
fallback={{ title: nextContent.attributes.slug }}
|
fallback={{ title: nextContent.attributes.slug }}
|
||||||
thumbnail={nextContent.attributes.thumbnail?.data?.attributes}
|
thumbnail={nextContent.attributes.thumbnail?.data?.attributes}
|
||||||
thumbnailAspectRatio="3/2"
|
|
||||||
topChips={
|
topChips={
|
||||||
isContentPanelAtLeast2xl && nextContent.attributes.type?.data?.attributes
|
isContentPanelAtLeast2xl && nextContent.attributes.type?.data?.attributes
|
||||||
? [
|
? [
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Select } from "components/Inputs/Select";
|
import { Select } from "components/Inputs/Select";
|
||||||
import { Switch } from "components/Inputs/Switch";
|
import { Switch } from "components/Inputs/Switch";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { prettyInlineTitle, prettySlug } from "helpers/formatters";
|
import { prettyInlineTitle, prettySlug } from "helpers/formatters";
|
||||||
import { TextInput } from "components/Inputs/TextInput";
|
import { TextInput } from "components/Inputs/TextInput";
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
|
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
|
||||||
import { useCallback, useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import naturalCompare from "string-natural-compare";
|
import naturalCompare from "string-natural-compare";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { filterHasAttributes } from "helpers/others";
|
import { filterHasAttributes } from "helpers/others";
|
||||||
|
@ -12,17 +12,15 @@ import { prettySlug } from "helpers/formatters";
|
||||||
import { SmartList } from "components/SmartList";
|
import { SmartList } from "components/SmartList";
|
||||||
import { Ico, Icon } from "components/Ico";
|
import { Ico, Icon } from "components/Ico";
|
||||||
import { Button, TranslatedButton } from "components/Inputs/Button";
|
import { Button, TranslatedButton } from "components/Inputs/Button";
|
||||||
import { Link } from "components/Inputs/Link";
|
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { TranslatedProps } from "types/TranslatedProps";
|
|
||||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
|
||||||
import { TranslatedPreviewCard } from "components/PreviewCard";
|
import { TranslatedPreviewCard } from "components/PreviewCard";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { cJoin, cIf } from "helpers/className";
|
import { cJoin, cIf } from "helpers/className";
|
||||||
import { getLangui } from "graphql/fetchLocalData";
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
import { useLocalData } from "contexts/LocalDataContext";
|
import { useLocalData } from "contexts/LocalDataContext";
|
||||||
import { useContainerQueries } from "contexts/ContainerQueriesContext";
|
import { useContainerQueries } from "contexts/ContainerQueriesContext";
|
||||||
|
import { TranslatedPreviewFolder } from "components/Contents/PreviewFolder";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭────────╮
|
* ╭────────╮
|
||||||
|
@ -274,36 +272,6 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
|
||||||
* ───────────────────────────────────╯ PRIVATE COMPONENTS ╰──────────────────────────────────────
|
* ───────────────────────────────────╯ PRIVATE COMPONENTS ╰──────────────────────────────────────
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface PreviewFolderProps {
|
|
||||||
href: string;
|
|
||||||
title: string | null | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PreviewFolder = ({ href, title }: PreviewFolderProps): JSX.Element => (
|
|
||||||
<Link
|
|
||||||
href={href}
|
|
||||||
className="flex w-full cursor-pointer flex-row place-content-center place-items-center gap-4
|
|
||||||
rounded-md bg-light p-6 transition-transform drop-shadow-shade-xl hover:scale-[1.02]">
|
|
||||||
{title && <p className="text-center font-headers text-lg font-bold leading-none">{title}</p>}
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
|
||||||
|
|
||||||
const TranslatedPreviewFolder = ({
|
|
||||||
translations,
|
|
||||||
fallback,
|
|
||||||
...otherProps
|
|
||||||
}: TranslatedProps<PreviewFolderProps, "title">): JSX.Element => {
|
|
||||||
const [selectedTranslation] = useSmartLanguage({
|
|
||||||
items: translations,
|
|
||||||
languageExtractor: useCallback((item: { language: string }): string => item.language, []),
|
|
||||||
});
|
|
||||||
return <PreviewFolder title={selectedTranslation?.title ?? fallback.title} {...otherProps} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
|
||||||
|
|
||||||
const NoContentNorFolderMessage = () => {
|
const NoContentNorFolderMessage = () => {
|
||||||
const { langui } = useLocalData();
|
const { langui } = useLocalData();
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useMemo } from "react";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Chip } from "components/Chip";
|
import { Chip } from "components/Chip";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { ToolTip } from "components/ToolTip";
|
import { ToolTip } from "components/ToolTip";
|
||||||
import { DevGetContentsQuery } from "graphql/generated";
|
import { DevGetContentsQuery } from "graphql/generated";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useMemo } from "react";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Chip } from "components/Chip";
|
import { Chip } from "components/Chip";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { ToolTip } from "components/ToolTip";
|
import { ToolTip } from "components/ToolTip";
|
||||||
import {
|
import {
|
||||||
DevGetLibraryItemsQuery,
|
DevGetLibraryItemsQuery,
|
||||||
|
|
|
@ -4,8 +4,8 @@ import TurndownService from "turndown";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { Markdawn, TableOfContents } from "components/Markdown/Markdawn";
|
import { Markdawn, TableOfContents } from "components/Markdown/Markdawn";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { Popup } from "components/Popup";
|
import { Popup } from "components/Containers/Popup";
|
||||||
import { ToolTip } from "components/ToolTip";
|
import { ToolTip } from "components/ToolTip";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
|
|
|
@ -0,0 +1,966 @@
|
||||||
|
/* eslint-disable id-denylist */
|
||||||
|
import { GetStaticProps } from "next";
|
||||||
|
import { ReactNode, useState } from "react";
|
||||||
|
import Slider from "rc-slider";
|
||||||
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
|
import { Button } from "components/Inputs/Button";
|
||||||
|
import { Icon } from "components/Ico";
|
||||||
|
import { cJoin } from "helpers/className";
|
||||||
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
|
import { Switch } from "components/Inputs/Switch";
|
||||||
|
import { TextInput } from "components/Inputs/TextInput";
|
||||||
|
import { Select } from "components/Inputs/Select";
|
||||||
|
import { WithLabel } from "components/Inputs/WithLabel";
|
||||||
|
import { NavOption } from "components/PanelComponents/NavOption";
|
||||||
|
import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
||||||
|
import { PreviewCard } from "components/PreviewCard";
|
||||||
|
import { PreviewLine } from "components/PreviewLine";
|
||||||
|
import { ChroniclePreview } from "components/Chronicles/ChroniclePreview";
|
||||||
|
import { PreviewFolder } from "components/Contents/PreviewFolder";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ╭────────╮
|
||||||
|
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface Props extends AppLayoutRequired {}
|
||||||
|
|
||||||
|
const DesignSystem = (props: Props): JSX.Element => {
|
||||||
|
const [switchState, setSwitchState] = useState(false);
|
||||||
|
const [selectState, setSelectState] = useState(0);
|
||||||
|
const [sliderState, setSliderState] = useState(5);
|
||||||
|
const [textInputState, setTextInputState] = useState("");
|
||||||
|
const [textAreaState, setTextAreaState] = useState("");
|
||||||
|
const [buttonGroupState, setButtonGroupState] = useState(0);
|
||||||
|
|
||||||
|
const contentPanel = (
|
||||||
|
<ContentPanel
|
||||||
|
className="grid place-items-center text-center"
|
||||||
|
width={ContentPanelWidthSizes.Full}>
|
||||||
|
<h1 className="mb-8 text-4xl">Design System</h1>
|
||||||
|
|
||||||
|
<h2 className="mb-4 text-3xl">Colors</h2>
|
||||||
|
<WhiteSection className="grid grid-cols-[repeat(7,auto)] place-items-center gap-4">
|
||||||
|
<p />
|
||||||
|
<p>Highlight</p>
|
||||||
|
<p>Light</p>
|
||||||
|
<p>Mid</p>
|
||||||
|
<p>Dark</p>
|
||||||
|
<p>Shade</p>
|
||||||
|
<p>Black</p>
|
||||||
|
|
||||||
|
<p>Light theme</p>
|
||||||
|
<ColorSquare className="bg-highlight" />
|
||||||
|
<ColorSquare className="bg-light" />
|
||||||
|
<ColorSquare className="bg-mid" />
|
||||||
|
<ColorSquare className="bg-dark" />
|
||||||
|
<ColorSquare className="bg-shade" />
|
||||||
|
<ColorSquare className="bg-black" />
|
||||||
|
|
||||||
|
<p>Dark theme</p>
|
||||||
|
<ColorSquare className="bg-highlight set-theme-dark" />
|
||||||
|
<ColorSquare className="bg-light set-theme-dark" />
|
||||||
|
<ColorSquare className="bg-mid set-theme-dark" />
|
||||||
|
<ColorSquare className="bg-dark set-theme-dark" />
|
||||||
|
<ColorSquare className="bg-shade set-theme-dark" />
|
||||||
|
<ColorSquare className="bg-black set-theme-dark" />
|
||||||
|
</WhiteSection>
|
||||||
|
|
||||||
|
<h2 className="mb-4 text-3xl">Fonts</h2>
|
||||||
|
<WhiteSection className="grid grid-cols-[repeat(5,auto)] place-items-start gap-y-2 gap-x-12">
|
||||||
|
<p />
|
||||||
|
<p className="font-headers text-xl text-black/50">Vollkorn</p>
|
||||||
|
<p className="font-body text-xl text-black/50">Zen Maru Gothic</p>
|
||||||
|
<p className="font-mono text-xl text-black/50">Share Tech Mono</p>
|
||||||
|
<p className="font-openDyslexic text-xl text-black/50">Open Dyslexic</p>
|
||||||
|
|
||||||
|
<p className="text-3xl text-black/30">3XL</p>
|
||||||
|
<p className="font-headers text-3xl">Header H3XL</p>
|
||||||
|
<p />
|
||||||
|
<p />
|
||||||
|
<p className="font-openDyslexic text-3xl">Dyslexia D3XL</p>
|
||||||
|
|
||||||
|
<p className="text-2xl text-black/30">2XL</p>
|
||||||
|
<p className="font-headers text-2xl">Header H2XL</p>
|
||||||
|
<p />
|
||||||
|
<p />
|
||||||
|
<p className="font-openDyslexic text-2xl">Dyslexia D2XL</p>
|
||||||
|
|
||||||
|
<p className="text-xl text-black/30">XL</p>
|
||||||
|
<p className="font-headers text-xl">Header HXL</p>
|
||||||
|
<p className="font-body text-xl">Body BXL</p>
|
||||||
|
<p className="font-mono text-xl">Mono MXL</p>
|
||||||
|
<p className="font-openDyslexic text-xl">Dyslexia DXL</p>
|
||||||
|
|
||||||
|
<p className="text-lg text-black/30">LG</p>
|
||||||
|
<p className="font-headers text-lg">Header HLG</p>
|
||||||
|
<p className="font-body text-lg">Body BLG</p>
|
||||||
|
<p className="font-mono text-lg">Mono MLG</p>
|
||||||
|
<p className="font-openDyslexic text-lg">Dyslexia DLG</p>
|
||||||
|
|
||||||
|
<p className="text-base text-black/30">B</p>
|
||||||
|
<p />
|
||||||
|
<p className="font-body text-base">Body BB</p>
|
||||||
|
<p className="font-mono text-base">Mono MB</p>
|
||||||
|
<p className="font-openDyslexic text-base">Dyslexia DB</p>
|
||||||
|
|
||||||
|
<p className="text-sm text-black/30">SM</p>
|
||||||
|
<p />
|
||||||
|
<p className="font-body text-sm">Body BSM</p>
|
||||||
|
<p />
|
||||||
|
<p className="font-openDyslexic text-sm">Dyslexia DSM</p>
|
||||||
|
|
||||||
|
<p className="text-xs text-black/30">XS</p>
|
||||||
|
<p />
|
||||||
|
<p />
|
||||||
|
<p />
|
||||||
|
<p className="font-openDyslexic text-xs">Dyslexia DXS</p>
|
||||||
|
</WhiteSection>
|
||||||
|
|
||||||
|
<h2 className="mb-4 text-3xl">Elevations</h2>
|
||||||
|
<TwoThemedSection
|
||||||
|
className="grid grid-cols-[repeat(7,auto)] place-content-center gap-4
|
||||||
|
text-left">
|
||||||
|
<ShadowSquare className="bg-light shadow-inner shadow-shade" text="IN" />
|
||||||
|
<ShadowSquare className="bg-light shadow-inner-sm shadow-shade" text="IN/SM" />
|
||||||
|
<ShadowSquare className="bg-light shadow-sm shadow-shade" text="SM" />
|
||||||
|
<ShadowSquare className="bg-light shadow-md shadow-shade" text="MD" />
|
||||||
|
<ShadowSquare className="bg-light shadow-lg shadow-shade" text="LG" />
|
||||||
|
<ShadowSquare className="bg-light shadow-xl shadow-shade" text="XL" />
|
||||||
|
<ShadowSquare className="bg-light shadow-2xl shadow-shade" text="2XL" />
|
||||||
|
|
||||||
|
<p className="mt-6">Drop shadow</p>
|
||||||
|
<p />
|
||||||
|
<ShadowSquare className="bg-light drop-shadow-sm shadow-shade" text="SM" />
|
||||||
|
<ShadowSquare className="bg-light drop-shadow-md shadow-shade" text="MD" />
|
||||||
|
<ShadowSquare className="bg-light drop-shadow-lg shadow-shade" text="LG" />
|
||||||
|
<ShadowSquare className="bg-light drop-shadow-xl shadow-shade" text="XL" />
|
||||||
|
<ShadowSquare className="bg-light drop-shadow-2xl shadow-shade" text="2XL" />
|
||||||
|
|
||||||
|
<p className="mt-6">Black</p>
|
||||||
|
<p />
|
||||||
|
<ShadowSquare className="bg-black text-light shadow-sm shadow-black" text="SM" />
|
||||||
|
<ShadowSquare className="bg-black text-light shadow-md shadow-black" text="MD" />
|
||||||
|
<ShadowSquare className="bg-black text-light shadow-lg shadow-black" text="LG" />
|
||||||
|
<ShadowSquare className="bg-black text-light shadow-xl shadow-black" text="XL" />
|
||||||
|
<ShadowSquare className="bg-black text-light shadow-2xl shadow-black" text="2XL" />
|
||||||
|
|
||||||
|
<p className="mt-6">
|
||||||
|
Drop shadow
|
||||||
|
<br />
|
||||||
|
black
|
||||||
|
</p>
|
||||||
|
<p />
|
||||||
|
<ShadowSquare className="bg-black text-light drop-shadow-sm shadow-black" text="SM" />
|
||||||
|
<ShadowSquare className="bg-black text-light drop-shadow-md shadow-black" text="MD" />
|
||||||
|
<ShadowSquare className="bg-black text-light drop-shadow-lg shadow-black" text="LG" />
|
||||||
|
<ShadowSquare className="bg-black text-light drop-shadow-xl shadow-black" text="XL" />
|
||||||
|
<ShadowSquare className="bg-black text-light drop-shadow-2xl shadow-black" text="2XL" />
|
||||||
|
</TwoThemedSection>
|
||||||
|
|
||||||
|
<h2 className="mb-4 text-3xl">Buttons</h2>
|
||||||
|
<TwoThemedSection className="grid gap-4">
|
||||||
|
<h3 className="text-xl">Normal sized</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-[repeat(4,auto)] place-content-center gap-4">
|
||||||
|
<p />
|
||||||
|
<p>Icon</p>
|
||||||
|
<p>Text</p>
|
||||||
|
<p>Icon + Text</p>
|
||||||
|
|
||||||
|
<p className="self-center justify-self-start">Normal</p>
|
||||||
|
<Button icon={Icon.Check} />
|
||||||
|
<Button text="Label" />
|
||||||
|
<Button icon={Icon.NavigateBefore} text="Label" />
|
||||||
|
|
||||||
|
<p className="self-center justify-self-start">Active</p>
|
||||||
|
<Button icon={Icon.Camera} active />
|
||||||
|
<Button text="Label" active />
|
||||||
|
<Button icon={Icon.NavigateBefore} text="Label" active />
|
||||||
|
|
||||||
|
<p className="self-center justify-self-start">Disabled</p>
|
||||||
|
<Button icon={Icon.Air} disabled />
|
||||||
|
<Button text="Label" disabled />
|
||||||
|
<Button icon={Icon.NavigateBefore} text="Label" disabled />
|
||||||
|
|
||||||
|
<p className="self-center justify-self-start">Badge</p>
|
||||||
|
<Button icon={Icon.Snooze} badgeNumber={5} />
|
||||||
|
<Button text="Label" badgeNumber={12} />
|
||||||
|
<Button icon={Icon.NavigateBefore} text="Label" badgeNumber={201} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
<h3 className="text-xl">Small sized</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-[repeat(4,auto)] place-content-center gap-4">
|
||||||
|
<p className="self-center justify-self-start">Normal</p>
|
||||||
|
<Button icon={Icon.Check} size={"small"} />
|
||||||
|
<Button text="Label" size={"small"} />
|
||||||
|
<Button icon={Icon.NavigateBefore} text="Label" size={"small"} />
|
||||||
|
|
||||||
|
<p className="self-center justify-self-start">Active</p>
|
||||||
|
<Button icon={Icon.Camera} active size={"small"} />
|
||||||
|
<Button text="Label" active size={"small"} />
|
||||||
|
<Button icon={Icon.NavigateBefore} text="Label" active size={"small"} />
|
||||||
|
|
||||||
|
<p className="self-center justify-self-start">Disabled</p>
|
||||||
|
<Button icon={Icon.Air} disabled size={"small"} />
|
||||||
|
<Button text="Label" disabled size={"small"} />
|
||||||
|
<Button icon={Icon.NavigateBefore} text="Label" disabled size={"small"} />
|
||||||
|
|
||||||
|
<p className="self-center justify-self-start">Badge</p>
|
||||||
|
<Button icon={Icon.Snooze} badgeNumber={5} size={"small"} />
|
||||||
|
<Button text="Label" badgeNumber={12} size={"small"} />
|
||||||
|
<Button icon={Icon.NavigateBefore} text="Label" badgeNumber={201} size={"small"} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
<h3 className="text-xl">Groups</h3>
|
||||||
|
<div className="grid place-items-center gap-4">
|
||||||
|
<ButtonGroup buttonsProps={[{ icon: Icon.CallEnd }, { icon: Icon.ZoomInMap }]} />
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{ icon: Icon.CarCrash },
|
||||||
|
{ icon: Icon.TimeToLeave },
|
||||||
|
{ icon: Icon.LeakAdd },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{ icon: Icon.CarCrash },
|
||||||
|
{ icon: Icon.TimeToLeave, text: "Label", active: true },
|
||||||
|
{ text: "Another Label" },
|
||||||
|
{ icon: Icon.Cable },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{
|
||||||
|
text: "Try me!",
|
||||||
|
active: buttonGroupState === 0,
|
||||||
|
onClick: () => setButtonGroupState(0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Icon.AdUnits,
|
||||||
|
text: "Label",
|
||||||
|
active: buttonGroupState === 1,
|
||||||
|
onClick: () => setButtonGroupState(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Yet another label",
|
||||||
|
active: buttonGroupState === 2,
|
||||||
|
onClick: () => setButtonGroupState(2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Icon.Security,
|
||||||
|
active: buttonGroupState === 3,
|
||||||
|
onClick: () => setButtonGroupState(3),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</TwoThemedSection>
|
||||||
|
|
||||||
|
<h2 className="mb-4 text-3xl">Inputs</h2>
|
||||||
|
<TwoThemedSection className="grid place-content-center gap-4">
|
||||||
|
<h3 className="text-xl">Switches</h3>
|
||||||
|
<WithLabel label="Off">
|
||||||
|
<Switch value={false} onClick={() => null} />
|
||||||
|
</WithLabel>
|
||||||
|
<WithLabel label="On">
|
||||||
|
<Switch value={true} onClick={() => null} />
|
||||||
|
</WithLabel>
|
||||||
|
<WithLabel label="Disabled (Off)">
|
||||||
|
<Switch value={false} onClick={() => null} disabled />
|
||||||
|
</WithLabel>
|
||||||
|
<WithLabel label="Disabled (On)">
|
||||||
|
<Switch value={true} onClick={() => null} disabled />
|
||||||
|
</WithLabel>
|
||||||
|
<WithLabel label={`Try me! (${switchState ? "On" : "Off"})`}>
|
||||||
|
<Switch value={switchState} onClick={() => setSwitchState((current) => !current)} />
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
<h3 className="-mt-6 mb-2 text-xl">Selects</h3>
|
||||||
|
|
||||||
|
<WithLabel label="Empty">
|
||||||
|
<Select
|
||||||
|
value={-1}
|
||||||
|
options={["Option 1", "Option 2", "Option 3", "Option 4"]}
|
||||||
|
onChange={() => null}
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Filled">
|
||||||
|
<Select
|
||||||
|
value={0}
|
||||||
|
options={["Option 1", "Option 2", "Option 3", "Option 4"]}
|
||||||
|
onChange={() => null}
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Filled + allow empty">
|
||||||
|
<Select
|
||||||
|
value={0}
|
||||||
|
options={["Option 1", "Option 2", "Option 3", "Option 4"]}
|
||||||
|
onChange={() => null}
|
||||||
|
allowEmpty
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Disabled">
|
||||||
|
<Select
|
||||||
|
value={0}
|
||||||
|
options={["Option 1", "Option 2", "Option 3", "Option 4"]}
|
||||||
|
onChange={() => null}
|
||||||
|
allowEmpty
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Try me!">
|
||||||
|
<Select
|
||||||
|
value={selectState}
|
||||||
|
options={["Option 1", "Option 2", "Option 3", "Option 4"]}
|
||||||
|
onChange={(index) => setSelectState(index)}
|
||||||
|
allowEmpty
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
<h3 className="-mt-6 mb-2 text-xl">Text inputs</h3>
|
||||||
|
|
||||||
|
<WithLabel label="Empty">
|
||||||
|
<TextInput value="" onChange={() => null} />
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Placeholder">
|
||||||
|
<TextInput value="" placeholder="Placeholder..." onChange={() => null} />
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Filled">
|
||||||
|
<TextInput value="Value" onChange={() => null} />
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Disabled">
|
||||||
|
<TextInput value="Value" onChange={() => null} disabled />
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Try me!">
|
||||||
|
<TextInput
|
||||||
|
value={textInputState}
|
||||||
|
onChange={setTextInputState}
|
||||||
|
placeholder={"Placeholder..."}
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
|
||||||
|
<h3 className="-mt-6 mb-2 text-xl">Text area</h3>
|
||||||
|
|
||||||
|
<WithLabel label="Empty">
|
||||||
|
<textarea value="" name="test" title="aria" />
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Placeholder">
|
||||||
|
<textarea value="" placeholder="Placeholder..." />
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Filled">
|
||||||
|
<textarea
|
||||||
|
value="Eveniet occaecati qui dicta explicabo dolor.
|
||||||
|
Ipsum quam dolorum dolores.
|
||||||
|
Neque dolor nihil neque tempora.
|
||||||
|
Mollitia voluptates iste qui et temporibus eum omnis.
|
||||||
|
Itaque atque architecto maiores qui et optio.
|
||||||
|
Et consequatur dolorem omnis cupiditate."
|
||||||
|
placeholder="Placeholder..."
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Not resizable">
|
||||||
|
<textarea
|
||||||
|
className="resize-none"
|
||||||
|
value="Eveniet occaecati qui dicta explicabo dolor.
|
||||||
|
Ipsum quam dolorum dolores.
|
||||||
|
Neque dolor nihil neque tempora.
|
||||||
|
Mollitia voluptates iste qui et temporibus eum omnis.
|
||||||
|
Itaque atque architecto maiores qui et optio.
|
||||||
|
Et consequatur dolorem omnis cupiditate."
|
||||||
|
placeholder="Placeholder..."
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Disabled">
|
||||||
|
<textarea
|
||||||
|
value="Eveniet occaecati qui dicta explicabo dolor.
|
||||||
|
Ipsum quam dolorum dolores.
|
||||||
|
Neque dolor nihil neque tempora.
|
||||||
|
Mollitia voluptates iste qui et temporibus eum omnis.
|
||||||
|
Itaque atque architecto maiores qui et optio.
|
||||||
|
Et consequatur dolorem omnis cupiditate."
|
||||||
|
placeholder="Placeholder..."
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Try me!">
|
||||||
|
<textarea
|
||||||
|
value={textAreaState}
|
||||||
|
onChange={(event) => setTextAreaState(event.target.value)}
|
||||||
|
placeholder="Placeholder..."
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
|
||||||
|
<h3 className="-mt-6 mb-2 text-xl">Slider</h3>
|
||||||
|
<WithLabel label="Normal">
|
||||||
|
<Slider value={5} />
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Disabled">
|
||||||
|
<Slider value={5} disabled />
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label="Try me!">
|
||||||
|
<Slider
|
||||||
|
value={sliderState}
|
||||||
|
max={100}
|
||||||
|
onChange={(event) => {
|
||||||
|
let value = 0;
|
||||||
|
if (Array.isArray(event)) {
|
||||||
|
value = event[0];
|
||||||
|
} else {
|
||||||
|
value = event;
|
||||||
|
}
|
||||||
|
setSliderState(() => value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
</TwoThemedSection>
|
||||||
|
|
||||||
|
<h2 className="mb-4 text-3xl">Down-Pressables</h2>
|
||||||
|
<TwoThemedSection className="grid gap-4">
|
||||||
|
<h3 className="mb-2 text-xl">Navigation Options</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-[repeat(6,auto)] place-items-center gap-4">
|
||||||
|
<p />
|
||||||
|
<p>Title</p>
|
||||||
|
<p>
|
||||||
|
Title
|
||||||
|
<br />+ Icon
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Title
|
||||||
|
<br />+ Subtitle
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Title
|
||||||
|
<br />+ Subtitle
|
||||||
|
<br />+ Icon
|
||||||
|
</p>
|
||||||
|
<p>Reduced</p>
|
||||||
|
|
||||||
|
<p>Normal</p>
|
||||||
|
<NavOption title="Title" url="#" />
|
||||||
|
<NavOption icon={Icon.Home} title="Title" url="#" />
|
||||||
|
<NavOption title="Title" subtitle="This is a subtitle" url="#" />
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.CalendarMonth}
|
||||||
|
/>
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.AccountBalance}
|
||||||
|
reduced
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p>Border</p>
|
||||||
|
<NavOption title="Title" url="#" border />
|
||||||
|
<NavOption icon={Icon.TravelExplore} title="Title" url="#" border />
|
||||||
|
<NavOption title="Title" subtitle="This is a subtitle" url="#" border />
|
||||||
|
<NavOption title="Title" subtitle="This is a subtitle" url="#" icon={Icon.Help} border />
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.TableRestaurant}
|
||||||
|
border
|
||||||
|
reduced
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p>Active</p>
|
||||||
|
<NavOption title="Title" url="#" active />
|
||||||
|
<NavOption icon={Icon.Hail} title="Title" url="#" active />
|
||||||
|
<NavOption title="Title" subtitle="This is a subtitle" url="#" active />
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.Grading}
|
||||||
|
active
|
||||||
|
/>
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.Timer}
|
||||||
|
active
|
||||||
|
reduced
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Active
|
||||||
|
<br />+ Border
|
||||||
|
</p>
|
||||||
|
<NavOption title="Title" url="#" active />
|
||||||
|
<NavOption icon={Icon.Upcoming} title="Title" url="#" active border />
|
||||||
|
<NavOption title="Title" subtitle="This is a subtitle" url="#" active border />
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.Gamepad}
|
||||||
|
active
|
||||||
|
border
|
||||||
|
/>
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.Scale}
|
||||||
|
active
|
||||||
|
border
|
||||||
|
reduced
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p>Disabled</p>
|
||||||
|
<NavOption title="Title" url="#" disabled />
|
||||||
|
<NavOption icon={Icon.Lan} title="Title" url="#" disabled />
|
||||||
|
<NavOption title="Title" subtitle="This is a subtitle" url="#" disabled />
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.AlignHorizontalRight}
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.YoutubeSearchedFor}
|
||||||
|
reduced
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Disabled
|
||||||
|
<br />+ Border
|
||||||
|
</p>
|
||||||
|
<NavOption title="Title" url="#" border disabled />
|
||||||
|
<NavOption icon={Icon.Sanitizer} title="Title" url="#" border disabled />
|
||||||
|
<NavOption title="Title" subtitle="This is a subtitle" url="#" border disabled />
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.Pages}
|
||||||
|
border
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.Synagogue}
|
||||||
|
border
|
||||||
|
reduced
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Disabled
|
||||||
|
<br />+ Active
|
||||||
|
</p>
|
||||||
|
<NavOption title="Title" url="#" active disabled />
|
||||||
|
<NavOption icon={Icon.Stairs} title="Title" url="#" active disabled />
|
||||||
|
<NavOption title="Title" subtitle="This is a subtitle" url="#" active disabled />
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.Park}
|
||||||
|
active
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<NavOption
|
||||||
|
title="Title"
|
||||||
|
subtitle="This is a subtitle"
|
||||||
|
url="#"
|
||||||
|
icon={Icon.Password}
|
||||||
|
active
|
||||||
|
reduced
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
<h3 className="-mt-6 mb-2 text-xl">Chronology Previews</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-[repeat(5,auto)] place-items-center gap-4">
|
||||||
|
<p />
|
||||||
|
<p>Title</p>
|
||||||
|
<p>Year</p>
|
||||||
|
<p>
|
||||||
|
Year
|
||||||
|
<br />+ Month
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Year
|
||||||
|
<br />+ Month
|
||||||
|
<br />+ Day
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Normal</p>
|
||||||
|
<ChroniclePreview date={{}} title="Title" url="#" />
|
||||||
|
<ChroniclePreview date={{ year: 1970 }} title="Title" url="#" />
|
||||||
|
<ChroniclePreview date={{ year: 1970, month: 1 }} title="Title" url="#" />
|
||||||
|
<ChroniclePreview date={{ year: 1970, month: 1, day: 1 }} title="Title" url="#" />
|
||||||
|
|
||||||
|
<p>Active</p>
|
||||||
|
<ChroniclePreview date={{}} title="Title" url="#" active />
|
||||||
|
<ChroniclePreview date={{ year: 1970 }} title="Title" url="#" active />
|
||||||
|
<ChroniclePreview date={{ year: 1970, month: 1 }} title="Title" url="#" active />
|
||||||
|
<ChroniclePreview date={{ year: 1970, month: 1, day: 1 }} title="Title" url="#" active />
|
||||||
|
|
||||||
|
<p>Disabled</p>
|
||||||
|
<ChroniclePreview date={{}} title="Title" url="#" disabled />
|
||||||
|
<ChroniclePreview date={{ year: 1970 }} title="Title" url="#" disabled />
|
||||||
|
<ChroniclePreview date={{ year: 1970, month: 1 }} title="Title" url="#" disabled />
|
||||||
|
<ChroniclePreview
|
||||||
|
date={{ year: 1970, month: 1, day: 1 }}
|
||||||
|
title="Title"
|
||||||
|
url="#"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Disabled
|
||||||
|
<br />
|
||||||
|
Active
|
||||||
|
</p>
|
||||||
|
<ChroniclePreview date={{}} title="Title" url="#" active disabled />
|
||||||
|
<ChroniclePreview date={{ year: 1970 }} title="Title" url="#" active disabled />
|
||||||
|
<ChroniclePreview date={{ year: 1970, month: 1 }} title="Title" url="#" active disabled />
|
||||||
|
<ChroniclePreview
|
||||||
|
date={{ year: 1970, month: 1, day: 1 }}
|
||||||
|
title="Title"
|
||||||
|
url="#"
|
||||||
|
active
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</TwoThemedSection>
|
||||||
|
|
||||||
|
<h2 className="mb-4 text-3xl">Up-Pressables</h2>
|
||||||
|
<TwoThemedSection className="grid gap-4">
|
||||||
|
<h3 className="-mt-6 mb-2 text-xl">Preview Cards</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-[repeat(2,auto)] place-items-center gap-4">
|
||||||
|
<PreviewCard
|
||||||
|
title="This one only has a title"
|
||||||
|
subtitle="And a subtitle"
|
||||||
|
href="#"
|
||||||
|
keepInfoVisible
|
||||||
|
/>
|
||||||
|
<PreviewCard
|
||||||
|
title="This one only has a title/subtitle"
|
||||||
|
subtitle="And a long description"
|
||||||
|
description="Eveniet occaecati qui dicta explicabo dolor.
|
||||||
|
Ipsum quam dolorum dolores.
|
||||||
|
Neque dolor nihil neque tempora.
|
||||||
|
Mollitia voluptates iste qui et temporibus eum omnis.
|
||||||
|
Itaque atque architecto maiores qui et optio."
|
||||||
|
href="#"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
keepInfoVisible
|
||||||
|
/>
|
||||||
|
<PreviewCard
|
||||||
|
pre_title="Breaking News"
|
||||||
|
title="This one only displays info"
|
||||||
|
subtitle="When it's hovered"
|
||||||
|
href="#"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
/>
|
||||||
|
<PreviewCard
|
||||||
|
title="This one also has metadata at the top"
|
||||||
|
subtitle="And a subtitle"
|
||||||
|
description="Eveniet occaecati qui dicta explicabo dolor.
|
||||||
|
Ipsum quam dolorum dolores.
|
||||||
|
Neque dolor nihil neque tempora.
|
||||||
|
Mollitia voluptates iste qui et temporibus eum omnis.
|
||||||
|
Itaque atque architecto maiores qui et optio."
|
||||||
|
href="#"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
metadata={{
|
||||||
|
price: {
|
||||||
|
amount: 5.23,
|
||||||
|
currency: { data: { attributes: { code: "USD", rate_to_usd: 1, symbol: "$" } } },
|
||||||
|
},
|
||||||
|
releaseDate: { year: 1970, month: 1, day: 1 },
|
||||||
|
views: 550669,
|
||||||
|
position: "Top",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<PreviewCard
|
||||||
|
title="This one also has metadata at the bottom"
|
||||||
|
subtitle="And the thumbnail aspect ratio is forced to be 4:3"
|
||||||
|
href="#"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
keepInfoVisible
|
||||||
|
thumbnailAspectRatio="4/3"
|
||||||
|
thumbnailForceAspectRatio
|
||||||
|
metadata={{
|
||||||
|
price: {
|
||||||
|
amount: 5.23,
|
||||||
|
currency: { data: { attributes: { code: "USD", rate_to_usd: 1, symbol: "$" } } },
|
||||||
|
},
|
||||||
|
releaseDate: { year: 1970, month: 1, day: 1 },
|
||||||
|
views: 550669,
|
||||||
|
position: "Bottom",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<PreviewCard
|
||||||
|
pre_title="Wow, that's a lot"
|
||||||
|
title="This one pretty much has everything"
|
||||||
|
subtitle="No joke, this is a lot of stuff"
|
||||||
|
href="#"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
keepInfoVisible
|
||||||
|
infoAppend={<Button text="Another custom component" />}
|
||||||
|
bottomChips={["Bottom chip 1", "Chip 2", "Chip 3", "Chip 4"]}
|
||||||
|
description="Eveniet occaecati qui dicta explicabo dolor.
|
||||||
|
Ipsum quam dolorum dolores.
|
||||||
|
Neque dolor nihil neque tempora.
|
||||||
|
Mollitia voluptates iste qui et temporibus eum omnis.
|
||||||
|
Itaque atque architecto maiores qui et optio."
|
||||||
|
hoverlay={{ __typename: "Video", duration: 465 }}
|
||||||
|
topChips={[
|
||||||
|
"Top chip 1",
|
||||||
|
"Chip 2",
|
||||||
|
"Chip 3",
|
||||||
|
"Chip 4",
|
||||||
|
"When there are too many, it overflow",
|
||||||
|
]}
|
||||||
|
metadata={{
|
||||||
|
price: {
|
||||||
|
amount: 5.23,
|
||||||
|
currency: { data: { attributes: { code: "USD", rate_to_usd: 1, symbol: "$" } } },
|
||||||
|
},
|
||||||
|
releaseDate: { year: 1970, month: 1, day: 1 },
|
||||||
|
views: 550669,
|
||||||
|
position: "Bottom",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<PreviewCard
|
||||||
|
title="This one is disabled"
|
||||||
|
subtitle="And a subtitle"
|
||||||
|
href="#"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
keepInfoVisible
|
||||||
|
metadata={{
|
||||||
|
price: {
|
||||||
|
amount: 5.23,
|
||||||
|
currency: { data: { attributes: { code: "USD", rate_to_usd: 1, symbol: "$" } } },
|
||||||
|
},
|
||||||
|
releaseDate: { year: 1970, month: 1, day: 1 },
|
||||||
|
views: 550669,
|
||||||
|
position: "Bottom",
|
||||||
|
}}
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<PreviewCard
|
||||||
|
pre_title="Wow, that's a lot"
|
||||||
|
title="This one pretty much has everything"
|
||||||
|
subtitle="And it's disabled"
|
||||||
|
href="#"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
keepInfoVisible
|
||||||
|
infoAppend={<Button text="Another custom component" />}
|
||||||
|
bottomChips={["Bottom chip 1", "Chip 2", "Chip 3", "Chip 4"]}
|
||||||
|
description="Eveniet occaecati qui dicta explicabo dolor.
|
||||||
|
Ipsum quam dolorum dolores.
|
||||||
|
Neque dolor nihil neque tempora.
|
||||||
|
Mollitia voluptates iste qui et temporibus eum omnis.
|
||||||
|
Itaque atque architecto maiores qui et optio."
|
||||||
|
hoverlay={{ __typename: "Video", duration: 465 }}
|
||||||
|
topChips={[
|
||||||
|
"Top chip 1",
|
||||||
|
"Chip 2",
|
||||||
|
"Chip 3",
|
||||||
|
"Chip 4",
|
||||||
|
"When there are too many, it overflow",
|
||||||
|
]}
|
||||||
|
metadata={{
|
||||||
|
price: {
|
||||||
|
amount: 5.23,
|
||||||
|
currency: { data: { attributes: { code: "USD", rate_to_usd: 1, symbol: "$" } } },
|
||||||
|
},
|
||||||
|
releaseDate: { year: 1970, month: 1, day: 1 },
|
||||||
|
views: 550669,
|
||||||
|
position: "Bottom",
|
||||||
|
}}
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
<h3 className="-mt-6 mb-2 text-xl">Preview Line</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-[repeat(2,auto)] place-items-center gap-4">
|
||||||
|
<PreviewLine
|
||||||
|
href="#"
|
||||||
|
pre_title="Breaking News"
|
||||||
|
title="Accord's Library is live"
|
||||||
|
subtitle="I know, big deal, this is subtitle"
|
||||||
|
/>
|
||||||
|
<PreviewLine
|
||||||
|
href="#"
|
||||||
|
pre_title="Breaking News"
|
||||||
|
title="Accord's Library is live"
|
||||||
|
subtitle="I know, big deal, this is subtitle"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
/>
|
||||||
|
<PreviewLine
|
||||||
|
href="#"
|
||||||
|
pre_title="Breaking News"
|
||||||
|
title="Accord's Library is live"
|
||||||
|
subtitle="I know, big deal, this is subtitle"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
topChips={["Top chip 1", "Chip 2", "Chip 3", "Chip 4"]}
|
||||||
|
/>
|
||||||
|
<PreviewLine
|
||||||
|
href="#"
|
||||||
|
pre_title="Breaking News"
|
||||||
|
title="This one has everything"
|
||||||
|
subtitle="I know, big deal, this is subtitle"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
topChips={["Top chip 1", "Chip 2", "Chip 3", "Chip 4"]}
|
||||||
|
bottomChips={["Bottom chip 1", "Chip 2", "Chip 3", "Chip 4"]}
|
||||||
|
/>
|
||||||
|
<PreviewLine
|
||||||
|
href="#"
|
||||||
|
title="Just a title"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
topChips={["Top chip 1", "Chip 2", "Chip 3", "Chip 4"]}
|
||||||
|
bottomChips={["Bottom chip 1", "Chip 2", "Chip 3", "Chip 4"]}
|
||||||
|
/>
|
||||||
|
<PreviewLine
|
||||||
|
href="#"
|
||||||
|
title="Disabled"
|
||||||
|
thumbnail={"/default_og.jpg"}
|
||||||
|
topChips={["Top chip 1", "Chip 2", "Chip 3", "Chip 4"]}
|
||||||
|
bottomChips={["Bottom chip 1", "Chip 2", "Chip 3", "Chip 4"]}
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
<h3 className="-mt-6 mb-2 text-xl">Folder Card</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-[repeat(2,auto)] place-items-center gap-4">
|
||||||
|
<PreviewFolder href="#" title="Title" />
|
||||||
|
<PreviewFolder href="#" title="A longer title, I guess" />
|
||||||
|
<PreviewFolder href="#" title="Disabled" disabled />
|
||||||
|
<PreviewFolder href="#" title="Disabled, with a longer title" disabled />
|
||||||
|
</div>
|
||||||
|
</TwoThemedSection>
|
||||||
|
</ContentPanel>
|
||||||
|
);
|
||||||
|
return <AppLayout {...props} contentPanel={contentPanel} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DesignSystem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ╭──────────────────────╮
|
||||||
|
* ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const getStaticProps: GetStaticProps = (context) => {
|
||||||
|
const langui = getLangui(context.locale);
|
||||||
|
const props: Props = {
|
||||||
|
openGraph: getOpenGraph(langui, "Design System"),
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
props: props,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ╭──────────────────────╮
|
||||||
|
* ───────────────────────────────────╯ PRIVATE COMPONENTS ╰──────────────────────────────────────
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface ThemedSectionProps {
|
||||||
|
className?: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TwoThemedSection = ({ children, className }: ThemedSectionProps) => (
|
||||||
|
<div className="mb-12 grid grid-flow-col drop-shadow-lg shadow-shade">
|
||||||
|
<LightThemeSection className={cJoin("rounded-l-xl text-black", className)}>
|
||||||
|
{children}
|
||||||
|
</LightThemeSection>
|
||||||
|
<DarkThemeSection className={cJoin("rounded-r-xl text-black", className)}>
|
||||||
|
{children}
|
||||||
|
</DarkThemeSection>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const DarkThemeSection = ({ className, children }: ThemedSectionProps) => (
|
||||||
|
<div className={cJoin("bg-light py-10 px-14 set-theme-dark", className)}>{children}</div>
|
||||||
|
);
|
||||||
|
const LightThemeSection = ({ className, children }: ThemedSectionProps) => (
|
||||||
|
<div className={cJoin("bg-light py-10 px-14 set-theme-light", className)}>{children}</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const WhiteSection = ({ className, children }: ThemedSectionProps) => (
|
||||||
|
<div
|
||||||
|
className={cJoin(
|
||||||
|
`mb-12 rounded-xl bg-[white] py-10 px-14 text-black drop-shadow-lg shadow-shade
|
||||||
|
set-theme-light`,
|
||||||
|
className
|
||||||
|
)}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
interface ColorSquareProps {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorSquare = ({ className }: ColorSquareProps) => (
|
||||||
|
<div className={cJoin("h-24 w-24 rounded-lg shadow-inner-sm shadow-shade", className)} />
|
||||||
|
);
|
||||||
|
|
||||||
|
interface ShadowSquareProps {
|
||||||
|
className?: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ShadowSquare = ({ className, text }: ShadowSquareProps) => (
|
||||||
|
<div className={cJoin("mb-12 grid h-20 w-20 place-content-center rounded-lg", className)}>
|
||||||
|
{text}
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -3,7 +3,7 @@ import { useCallback, useMemo, useRef, useState } from "react";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { ToolTip } from "components/ToolTip";
|
import { ToolTip } from "components/ToolTip";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { getLangui } from "graphql/fetchLocalData";
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
|
|
|
@ -7,12 +7,12 @@ import { Chip } from "components/Chip";
|
||||||
import { Img } from "components/Img";
|
import { Img } from "components/Img";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { Switch } from "components/Inputs/Switch";
|
import { Switch } from "components/Inputs/Switch";
|
||||||
import { InsetBox } from "components/InsetBox";
|
import { InsetBox } from "components/Containers/InsetBox";
|
||||||
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
||||||
import { NavOption } from "components/PanelComponents/NavOption";
|
import { NavOption } from "components/PanelComponents/NavOption";
|
||||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { PreviewCard } from "components/PreviewCard";
|
import { PreviewCard } from "components/PreviewCard";
|
||||||
import {
|
import {
|
||||||
Enum_Componentmetadatabooks_Binding_Type,
|
Enum_Componentmetadatabooks_Binding_Type,
|
||||||
|
@ -167,7 +167,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
|
||||||
<div className="grid place-items-center gap-12">
|
<div className="grid place-items-center gap-12">
|
||||||
<div
|
<div
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
"relative h-[50vh] w-full cursor-pointer drop-shadow-shade-xl",
|
"relative h-[50vh] w-full cursor-pointer drop-shadow-xl shadow-shade",
|
||||||
cIf(isContentPanelAtLeast3xl, "mb-16", "h-[60vh]")
|
cIf(isContentPanelAtLeast3xl, "mb-16", "h-[60vh]")
|
||||||
)}>
|
)}>
|
||||||
{item.thumbnail?.data?.attributes ? (
|
{item.thumbnail?.data?.attributes ? (
|
||||||
|
@ -248,7 +248,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
|
||||||
<Fragment key={galleryItem.id}>
|
<Fragment key={galleryItem.id}>
|
||||||
<div
|
<div
|
||||||
className="relative aspect-square cursor-pointer
|
className="relative aspect-square cursor-pointer
|
||||||
transition-transform hover:scale-[1.02]"
|
transition-transform hover:scale-102"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
showLightBox(
|
showLightBox(
|
||||||
filterHasAttributes(item.gallery?.data, ["attributes"] as const).map(
|
filterHasAttributes(item.gallery?.data, ["attributes"] as const).map(
|
||||||
|
@ -258,8 +258,8 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
|
||||||
);
|
);
|
||||||
}}>
|
}}>
|
||||||
<Img
|
<Img
|
||||||
className="h-full w-full rounded-lg
|
className="h-full w-full rounded-lg bg-light object-cover shadow-md
|
||||||
bg-light object-cover drop-shadow-shade-md"
|
shadow-shade/30 transition-shadow hover:shadow-lg hover:shadow-shade/50"
|
||||||
src={galleryItem.attributes}
|
src={galleryItem.attributes}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,12 +20,12 @@ import {
|
||||||
} from "helpers/others";
|
} from "helpers/others";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { getLangui } from "graphql/fetchLocalData";
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { Img } from "components/Img";
|
import { Img } from "components/Img";
|
||||||
import { getAssetFilename, ImageQuality } from "helpers/img";
|
import { getAssetFilename, ImageQuality } from "helpers/img";
|
||||||
import { cIf, cJoin } from "helpers/className";
|
import { cIf, cJoin } from "helpers/className";
|
||||||
import { clamp, isInteger } from "helpers/numbers";
|
import { clamp, isInteger } from "helpers/numbers";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
import { Ids } from "types/ids";
|
import { Ids } from "types/ids";
|
||||||
|
@ -1045,8 +1045,8 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps):
|
||||||
{pages.map((page, index) => (
|
{pages.map((page, index) => (
|
||||||
<div
|
<div
|
||||||
key={page.id}
|
key={page.id}
|
||||||
className="cursor-pointer transition-transform
|
className="cursor-pointer drop-shadow-lg
|
||||||
drop-shadow-shade-lg hover:scale-[1.02]"
|
transition-transform shadow-shade hover:scale-102"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onClickOnImage(index);
|
onClickOnImage(index);
|
||||||
}}>
|
}}>
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Select } from "components/Inputs/Select";
|
import { Select } from "components/Inputs/Select";
|
||||||
import { Switch } from "components/Inputs/Switch";
|
import { Switch } from "components/Inputs/Switch";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { GetLibraryItemsPreviewQuery } from "graphql/generated";
|
import { GetLibraryItemsPreviewQuery } from "graphql/generated";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { prettyInlineTitle, prettyItemSubType } from "helpers/formatters";
|
import { prettyInlineTitle, prettyItemSubType } from "helpers/formatters";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { GetStaticProps } from "next";
|
import { GetStaticProps } from "next";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { getLangui } from "graphql/fetchLocalData";
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { useBoolean } from "usehooks-ts";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Switch } from "components/Inputs/Switch";
|
import { Switch } from "components/Inputs/Switch";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { GetPostsPreviewQuery } from "graphql/generated";
|
import { GetPostsPreviewQuery } from "graphql/generated";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { prettySlug } from "helpers/formatters";
|
import { prettySlug } from "helpers/formatters";
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { Chip } from "components/Chip";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { Img } from "components/Img";
|
import { Img } from "components/Img";
|
||||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import DefinitionCard from "components/Wiki/DefinitionCard";
|
import DefinitionCard from "components/Wiki/DefinitionCard";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { filterHasAttributes, isDefined, isDefinedAndNotEmpty } from "helpers/others";
|
import { filterHasAttributes, isDefined, isDefinedAndNotEmpty } from "helpers/others";
|
||||||
|
|
|
@ -2,10 +2,10 @@ import { GetStaticProps } from "next";
|
||||||
import { Fragment, useCallback, useMemo } from "react";
|
import { Fragment, useCallback, useMemo } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { InsetBox } from "components/InsetBox";
|
import { InsetBox } from "components/Containers/InsetBox";
|
||||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import {
|
import {
|
||||||
Enum_Componenttranslationschronologyitem_Status,
|
Enum_Componenttranslationschronologyitem_Status,
|
||||||
GetChronologyItemsQuery,
|
GetChronologyItemsQuery,
|
||||||
|
|
|
@ -4,11 +4,11 @@ import { useBoolean } from "usehooks-ts";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { NavOption } from "components/PanelComponents/NavOption";
|
import { NavOption } from "components/PanelComponents/NavOption";
|
||||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||||
import { SubPanel } from "components/Panels/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { GetWikiPageQuery, GetWikiPagesPreviewsQuery } from "graphql/generated";
|
import { GetWikiPageQuery, GetWikiPagesPreviewsQuery } from "graphql/generated";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { Switch } from "components/Inputs/Switch";
|
import { Switch } from "components/Inputs/Switch";
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
.animation-carret {
|
|
||||||
animation-name: blink;
|
|
||||||
animation-duration: 1s;
|
|
||||||
animation-timing-function: step-end;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-zoom-in {
|
|
||||||
animation-name: zoom-in;
|
|
||||||
animation-duration: 2s;
|
|
||||||
animation-timing-function: ease-in-out;
|
|
||||||
animation-iteration-count: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes zoom-in {
|
|
||||||
0% {
|
|
||||||
transform: scale(0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes blink {
|
|
||||||
from,
|
|
||||||
to {
|
|
||||||
border-bottom-style: solid;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
border-bottom-style: none;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
.texture-paper-dots {
|
|
||||||
@apply bg-[length:10cm] bg-local [background-image:var(--theme-texture-dots)]
|
|
||||||
[background-blend-mode:var(--theme-texture-dots-blend)];
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
@apply box-border scroll-m-[40vh] scroll-smooth ![-webkit-tap-highlight-color:transparent];
|
@apply box-border scroll-m-[40vh] scroll-smooth scrollbar-thin ![-webkit-tap-highlight-color:transparent];
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
|
@ -32,31 +32,12 @@ mark {
|
||||||
@apply bg-mid px-2;
|
@apply bg-mid px-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SCROLLBARS STYLING */
|
|
||||||
|
|
||||||
* {
|
|
||||||
@apply [scrollbar-color:theme(colors.dark/1)_transparent] [scrollbar-width:thin];
|
|
||||||
}
|
|
||||||
|
|
||||||
*::-webkit-scrollbar {
|
|
||||||
@apply w-3;
|
|
||||||
}
|
|
||||||
|
|
||||||
*::-webkit-scrollbar-track {
|
|
||||||
@apply bg-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
*::-webkit-scrollbar-thumb {
|
|
||||||
@apply rounded-full border-2 border-solid border-light bg-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* INPUT */
|
/* INPUT */
|
||||||
|
|
||||||
input,
|
input,
|
||||||
textarea {
|
textarea {
|
||||||
@apply rounded-full bg-light p-2 text-center text-dark outline outline-1 -outline-offset-1
|
@apply rounded-full bg-[transparent] p-2 text-center text-dark outline outline-1 -outline-offset-1
|
||||||
outline-mid transition-all placeholder:text-dark placeholder:opacity-60 hover:bg-mid
|
outline-mid transition-all placeholder:text-dark placeholder:opacity-60;
|
||||||
hover:outline-transparent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input::placeholder {
|
input::placeholder {
|
||||||
|
@ -65,7 +46,7 @@ input::placeholder {
|
||||||
|
|
||||||
input:focus-visible,
|
input:focus-visible,
|
||||||
textarea:focus-within {
|
textarea:focus-within {
|
||||||
@apply bg-mid shadow-inner-sm shadow-shade outline-none;
|
@apply bg-mid shadow-inner-sm outline-none shadow-shade;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
|
@ -74,7 +55,21 @@ textarea {
|
||||||
|
|
||||||
input[type="submit"] {
|
input[type="submit"] {
|
||||||
@apply grid cursor-pointer place-content-center place-items-center rounded-full border
|
@apply grid cursor-pointer place-content-center place-items-center rounded-full border
|
||||||
border-dark px-4 pt-[0.4rem] pb-[0.5rem] text-dark outline-none transition-all hover:bg-dark
|
border-dark px-4 pt-[0.4rem] pb-[0.5rem] text-dark outline-none transition-all shadow-shade
|
||||||
hover:text-light hover:drop-shadow-shade-lg active:border-black active:bg-black
|
hover:bg-dark hover:text-light hover:drop-shadow-lg active:border-black active:bg-black
|
||||||
active:text-light active:drop-shadow-black-lg;
|
active:text-light active:drop-shadow-lg active:shadow-black;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:enabled,
|
||||||
|
textarea:enabled {
|
||||||
|
@apply hover:bg-mid hover:outline-transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:disabled,
|
||||||
|
textarea:disabled {
|
||||||
|
@apply cursor-not-allowed opacity-50 outline-dark/60 grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
@apply scrollbar-none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
}
|
}
|
||||||
.tippy-box {
|
.tippy-box {
|
||||||
@apply relative rounded-lg bg-light transition-[transform,visibility,opacity]
|
@apply relative rounded-lg bg-light transition-[transform,visibility,opacity]
|
||||||
drop-shadow-shade-xl;
|
shadow-shade shadow-xl;
|
||||||
}
|
}
|
||||||
.tippy-box[data-placement^="top"] > .tippy-arrow {
|
.tippy-box[data-placement^="top"] > .tippy-arrow {
|
||||||
@apply bottom-0;
|
@apply bottom-0;
|
||||||
|
|
|
@ -15,6 +15,7 @@ module.exports = {
|
||||||
dark: "rgb(var(--theme-color-dark) / <alpha-value>)",
|
dark: "rgb(var(--theme-color-dark) / <alpha-value>)",
|
||||||
shade: "rgb(var(--theme-color-shade) / <alpha-value>)",
|
shade: "rgb(var(--theme-color-shade) / <alpha-value>)",
|
||||||
black: "rgb(var(--theme-color-black) / <alpha-value>)",
|
black: "rgb(var(--theme-color-black) / <alpha-value>)",
|
||||||
|
transparent: "transparent",
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
body: "var(--theme-font-body)",
|
body: "var(--theme-font-body)",
|
||||||
|
@ -51,22 +52,147 @@ module.exports = {
|
||||||
1: "0.15rem",
|
1: "0.15rem",
|
||||||
2: "0.17rem",
|
2: "0.17rem",
|
||||||
},
|
},
|
||||||
|
borderRadius: {
|
||||||
|
none: "0",
|
||||||
|
sm: "0.125rem",
|
||||||
|
DEFAULT: "0.25rem",
|
||||||
|
md: "0.375rem",
|
||||||
|
lg: "0.5rem",
|
||||||
|
xl: "0.75rem",
|
||||||
|
"2xl": "1rem",
|
||||||
|
"3xl": "1.25rem",
|
||||||
|
"4xl": "2rem",
|
||||||
|
full: "9999rem",
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
sm: "0 1px 2px 0",
|
||||||
|
DEFAULT: ["0 1px 3px 0", "0 1px 2px -1px"],
|
||||||
|
md: ["0 4px 6px -1px", "0 1px 4px -2px"],
|
||||||
|
lg: ["0 10px 15px -3px", "0 0 6px -4px"],
|
||||||
|
xl: ["0 20px 25px -5px", "0 0 10px -6px"],
|
||||||
|
"2xl": ["0 25px 50px -5px", "0 15px 20px -5px"],
|
||||||
|
inner: "inset 0 2px 4px 0",
|
||||||
|
"inner-sm": "inset 0 1px 4px -2px",
|
||||||
|
none: "0 0 #0000",
|
||||||
|
},
|
||||||
|
dropShadow: {
|
||||||
|
none: "0 0 var(--tw-raw-shadow-color)",
|
||||||
|
sm: "0 2px 1px rgb(var(--tw-raw-shadow-color) / 0.5)",
|
||||||
|
DEFAULT: [
|
||||||
|
"0 1px 2px rgb(var(--tw-raw-shadow-color) / 0.1)",
|
||||||
|
"0 1px 1px rgb(var(--tw-raw-shadow-color) / 0.6)",
|
||||||
|
],
|
||||||
|
md: [
|
||||||
|
"0 4px 3px rgb(var(--tw-raw-shadow-color) / 0.4)",
|
||||||
|
"0 2px 2px rgb(var(--tw-raw-shadow-color) / 0.6)",
|
||||||
|
],
|
||||||
|
lg: [
|
||||||
|
"0 10px 8px rgb(var(--tw-raw-shadow-color) / 0.5)",
|
||||||
|
"0 4px 4px rgb(var(--tw-raw-shadow-color) / 0.7)",
|
||||||
|
],
|
||||||
|
xl: [
|
||||||
|
"0 20px 13px rgb(var(--tw-raw-shadow-color) / 0.4)",
|
||||||
|
"0 8px 8px rgb(var(--tw-raw-shadow-color) / 0.7)",
|
||||||
|
],
|
||||||
|
"2xl": [
|
||||||
|
"0 15px 16px rgb(var(--tw-raw-shadow-color) / 0.7)",
|
||||||
|
"0 10px 8px rgb(var(--tw-raw-shadow-color) / 0.6)",
|
||||||
|
"0 0px 2px rgb(var(--tw-raw-shadow-color) / 0.2)",
|
||||||
|
],
|
||||||
|
},
|
||||||
extend: {
|
extend: {
|
||||||
boxShadow: {
|
|
||||||
"inner-sm": "inset 0 1px 4px -2px",
|
|
||||||
},
|
|
||||||
transitionProperty: {
|
transitionProperty: {
|
||||||
height: "height, max-height, min-height",
|
height: "height, max-height, min-height",
|
||||||
filter: "filter, backdrop-filter",
|
filter: "filter, backdrop-filter",
|
||||||
colors:
|
colors:
|
||||||
"color, background-color, border-color, text-decoration-color, fill, stroke, outline-color",
|
"color, background-color, border-color, text-decoration-color, fill, stroke, outline-color",
|
||||||
},
|
},
|
||||||
outlineColor: {
|
scale: {
|
||||||
transparent: "transparent",
|
102: "1.02",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
/* Add support for coloring drop shadows */
|
||||||
|
plugin(function ({ matchUtilities, theme }) {
|
||||||
|
matchUtilities(
|
||||||
|
{
|
||||||
|
shadow: (value) => ({
|
||||||
|
"--tw-raw-shadow-color": value.slice(4, value.length - 17),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{ values: theme("boxShadowColor") }
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
|
||||||
|
/* Add support for scrollbar styling */
|
||||||
|
plugin(({ addUtilities, theme }) => {
|
||||||
|
addUtilities({
|
||||||
|
".scrollbar-none": {
|
||||||
|
"scrollbar-width": "none",
|
||||||
|
"&::-webkit-scrollbar": {
|
||||||
|
display: "none",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
".scrollbar-thin": {
|
||||||
|
scrollbarWidth: "thin",
|
||||||
|
scrollbarColor: `rgb(var(--theme-color-dark)) transparent`,
|
||||||
|
"&::-webkit-scrollbar": {
|
||||||
|
width: theme("width.3"),
|
||||||
|
height: theme("width.3"),
|
||||||
|
},
|
||||||
|
"&::-webkit-scrollbar-track": {
|
||||||
|
background: "rgb(var(--theme-color-light))",
|
||||||
|
},
|
||||||
|
"&::-webkit-scrollbar-thumb": {
|
||||||
|
background: "rgb(var(--theme-color-dark))",
|
||||||
|
borderRadius: theme("borderRadius.full"),
|
||||||
|
borderWidth: theme("borderWidth.2"),
|
||||||
|
borderColor: "rgb(var(--theme-color-light))",
|
||||||
|
borderStyle: "solid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
/* Add custom animations */
|
||||||
|
plugin(({ addComponents }) => {
|
||||||
|
addComponents({
|
||||||
|
".animate-carret": {
|
||||||
|
animationName: "blink",
|
||||||
|
animationDuration: "1s",
|
||||||
|
animationTimingFunction: "step-end",
|
||||||
|
animationIterationCount: "infinite",
|
||||||
|
},
|
||||||
|
".animate-zoom-in": {
|
||||||
|
animationName: "zoom-in",
|
||||||
|
animationDuration: "2s",
|
||||||
|
animationTimingFunction: "ease-in-out",
|
||||||
|
animationIterationCount: "1",
|
||||||
|
},
|
||||||
|
"@keyframes blink": {
|
||||||
|
from: {
|
||||||
|
borderBottomStyle: "solid",
|
||||||
|
},
|
||||||
|
"50%": {
|
||||||
|
borderBottomStyle: "none",
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
borderBottomStyle: "solid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"@keyframes zoom-in": {
|
||||||
|
from: {
|
||||||
|
transform: "scale(0)",
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
transform: "scale(1)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
/* CSS colors setters */
|
||||||
plugin(({ addUtilities }) => {
|
plugin(({ addUtilities }) => {
|
||||||
addUtilities({
|
addUtilities({
|
||||||
".set-theme-light": {
|
".set-theme-light": {
|
||||||
|
@ -92,6 +218,7 @@ module.exports = {
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/* CSS fonts setters */
|
||||||
plugin(({ addUtilities }) => {
|
plugin(({ addUtilities }) => {
|
||||||
addUtilities({
|
addUtilities({
|
||||||
".set-theme-font-standard": {
|
".set-theme-font-standard": {
|
||||||
|
@ -107,75 +234,38 @@ module.exports = {
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
plugin(({ addVariant, e }) => {
|
/* Linear background colors presets */
|
||||||
addVariant("webkit-scrollbar", ({ modifySelectors, separator }) => {
|
|
||||||
modifySelectors(({ className }) => {
|
|
||||||
return `.${e(`webkit-scrollbar${separator}${className}`)}::-webkit-scrollbar`;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Colored Dropshadow
|
|
||||||
plugin(({ addUtilities }) => {
|
|
||||||
addUtilities({
|
|
||||||
".drop-shadow-shade-md": {
|
|
||||||
filter: `
|
|
||||||
drop-shadow(0 4px 3px rgb(var(--theme-color-shade) / 0.15))
|
|
||||||
drop-shadow(0 2px 2px rgb(var(--theme-color-shade) / 0.2))`,
|
|
||||||
},
|
|
||||||
".drop-shadow-shade-lg": {
|
|
||||||
filter: `
|
|
||||||
drop-shadow(0 10px 8px rgb(var(--theme-color-shade) / 0.2))
|
|
||||||
drop-shadow(0 4px 3px rgb(var(--theme-color-shade) / 0.4))`,
|
|
||||||
},
|
|
||||||
".drop-shadow-shade-xl": {
|
|
||||||
filter: `
|
|
||||||
drop-shadow(0 20px 13px rgb(var(--theme-color-shade) / 0.25))
|
|
||||||
drop-shadow(0 8px 5px rgb(var(--theme-color-shade) / 0.7))`,
|
|
||||||
},
|
|
||||||
".drop-shadow-shade-2xl": {
|
|
||||||
filter: `drop-shadow(0 25px 25px rgb(var(--theme-color-shade) / 0.8))`,
|
|
||||||
},
|
|
||||||
|
|
||||||
".drop-shadow-black-md": {
|
|
||||||
filter: `
|
|
||||||
drop-shadow(0 4px 3px rgb(var(--theme-color-black) / 0.15))
|
|
||||||
drop-shadow(0 2px 2px rgb(var(--theme-color-black) / 0.2))`,
|
|
||||||
},
|
|
||||||
".drop-shadow-black-lg": {
|
|
||||||
filter: `
|
|
||||||
drop-shadow(0 10px 8px rgb(var(--theme-color-black) / 0.2))
|
|
||||||
drop-shadow(0 4px 3px rgb(var(--theme-color-black) / 0.4))`,
|
|
||||||
},
|
|
||||||
".drop-shadow-black-xl": {
|
|
||||||
filter: `
|
|
||||||
drop-shadow(0 20px 13px rgb(var(--theme-color-black) / 0.25))
|
|
||||||
drop-shadow(0 8px 5px rgb(var(--theme-color-black) / 0.7))`,
|
|
||||||
},
|
|
||||||
".drop-shadow-black-2xl": {
|
|
||||||
filter: `drop-shadow(0 25px 25px rgb(var(--theme-color-black) / 0.8))`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
|
|
||||||
plugin(({ addUtilities }) => {
|
plugin(({ addUtilities }) => {
|
||||||
addUtilities({
|
addUtilities({
|
||||||
".linearbg-obi": {
|
".linearbg-obi": {
|
||||||
background: `linear-gradient(
|
background: `linear-gradient(
|
||||||
to right,
|
to right,
|
||||||
rgb(var(--theme-color-mid)),
|
rgb(var(--theme-color-mid)),
|
||||||
rgb(var(--theme-color-light)) 3%,
|
rgb(var(--theme-color-highlight)) 3%,
|
||||||
rgb(var(--theme-color-light)) 97%,
|
rgb(var(--theme-color-highlight)) 97%,
|
||||||
rgb(var(--theme-color-mid))
|
rgb(var(--theme-color-mid))
|
||||||
)`,
|
)`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/* Add support for break-wrods CSS attribute */
|
||||||
plugin(({ addUtilities }) => {
|
plugin(({ addUtilities }) => {
|
||||||
addUtilities({
|
addUtilities({
|
||||||
".break-words": {
|
".break-words": {
|
||||||
"word-break": "break-word",
|
wordBreak: "break-word",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
/* Custom background texture */
|
||||||
|
plugin(({ addUtilities }) => {
|
||||||
|
addUtilities({
|
||||||
|
".texture-paper-dots": {
|
||||||
|
backgroundSize: "10cm",
|
||||||
|
backgroundAttachment: "local",
|
||||||
|
backgroundImage: "var(--theme-texture-dots)",
|
||||||
|
backgroundBlendMode: "var(--theme-texture-dots-blend)",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ESNext",
|
"target": "ES6",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|
Loading…
Reference in New Issue