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!
|
||||
- Autogenerated multi-level table of content and anchor links for the different headers
|
||||
- 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 creating any arbitrary theming mode by swapping CSS variables
|
||||
- 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.
|
||||
- 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)
|
||||
- Persistent app state using LocalStorage
|
||||
- Persistent app state using LocalStorage and SessionStorage
|
||||
- Accessibility
|
||||
- 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)
|
||||
|
@ -54,7 +54,7 @@
|
|||
- Furthermore, the user can temporary select another language then the one that was automatically selected
|
||||
- SSG + ISR (Static Site Generation + Incremental Static Regeneration):
|
||||
- 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
|
||||
- SEO
|
||||
- Good defaults for the metadata and OpenGraph properties
|
||||
|
|
|
@ -8,6 +8,7 @@ const locales = ["en", "es", "fr", "pt-br", "ja"];
|
|||
module.exports = {
|
||||
swcMinify: true,
|
||||
reactStrictMode: true,
|
||||
poweredByHeader: false,
|
||||
i18n: {
|
||||
locales: locales,
|
||||
defaultLocale: "en",
|
||||
|
|
|
@ -168,8 +168,7 @@ export const AppLayout = ({
|
|||
id={Ids.SubPanel}
|
||||
className={cJoin(
|
||||
`texture-paper-dots z-20 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-end border-r-0 [grid-area:content]",
|
||||
|
@ -187,7 +186,7 @@ export const AppLayout = ({
|
|||
<div
|
||||
className={cJoin(
|
||||
`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 && isScreenAtLeastXs, "w-[min(30rem,90%)]"),
|
||||
cIf(!mainPanelOpen && is1ColumnLayout, "-translate-x-full")
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { useCallback } from "react";
|
||||
import { Link } from "components/Inputs/Link";
|
||||
import { DatePickerFragment } from "graphql/generated";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { TranslatedProps } from "types/TranslatedProps";
|
||||
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;
|
||||
title: string;
|
||||
url: string;
|
||||
isActive?: boolean;
|
||||
active?: boolean;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const ChroniclePreview = ({ date, url, title, isActive }: Props): JSX.Element => (
|
||||
<Link
|
||||
export const ChroniclePreview = ({ date, url, title, active, disabled }: Props): JSX.Element => (
|
||||
<DownPressable
|
||||
className="flex w-full gap-4 py-4 px-5"
|
||||
href={url}
|
||||
className={cJoin(
|
||||
`flex w-full cursor-pointer gap-4 rounded-2xl py-4 px-5 text-left align-top outline outline-2
|
||||
-outline-offset-2 outline-mid transition-all hover:bg-mid hover:shadow-inner-sm
|
||||
hover:shadow-shade hover:outline-transparent hover:active:shadow-inner
|
||||
hover:active:shadow-shade`,
|
||||
cIf(isActive, "bg-mid shadow-inner-sm shadow-shade outline-transparent")
|
||||
)}>
|
||||
active={active}
|
||||
border
|
||||
disabled={disabled}>
|
||||
{isDefined(date.year) && (
|
||||
<div className="text-right">
|
||||
<p>{date.year}</p>
|
||||
<p className="text-sm text-dark">{prettyMonthDay(date.month, date.day)}</p>
|
||||
</div>
|
||||
<p className="text-lg leading-tight">{title}</p>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<p
|
||||
className={cJoin(
|
||||
"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) => (
|
||||
<TranslatedChroniclePreview
|
||||
key={index}
|
||||
isActive={chronicle.attributes.slug === currentSlug}
|
||||
active={chronicle.attributes.slug === currentSlug}
|
||||
date={chronicle.attributes.date_start}
|
||||
translations={filterHasAttributes(content.attributes.translations, [
|
||||
"language.data.attributes.code",
|
||||
|
@ -80,7 +80,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element
|
|||
: chronicle.attributes.translations.length > 0 && (
|
||||
<TranslatedChroniclePreview
|
||||
date={chronicle.attributes.date_start}
|
||||
isActive={chronicle.attributes.slug === currentSlug}
|
||||
active={chronicle.attributes.slug === currentSlug}
|
||||
translations={filterHasAttributes(chronicle.attributes.translations, [
|
||||
"language.data.attributes.code",
|
||||
"title",
|
||||
|
|
|
@ -239,8 +239,7 @@ export const Terminal = ({
|
|||
)}>
|
||||
<div
|
||||
ref={terminalWindowRef}
|
||||
className="h-full overflow-scroll scroll-auto p-6
|
||||
[scrollbar-width:none] webkit-scrollbar:w-0">
|
||||
className="h-full overflow-scroll scroll-auto p-6 scrollbar-none">
|
||||
{previousLines.map((previousLine, index) => (
|
||||
<p key={index} className="whitespace-pre-line font-realmono">
|
||||
{previousLine}
|
||||
|
@ -311,7 +310,7 @@ export const Terminal = ({
|
|||
<span
|
||||
className={cJoin(
|
||||
"whitespace-pre font-realmono",
|
||||
cIf(isTextAreaFocused, "animation-carret border-b-2 border-black")
|
||||
cIf(isTextAreaFocused, "animate-carret border-b-2 border-black")
|
||||
)}>
|
||||
{line[carretPosition] ?? " "}
|
||||
</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",
|
||||
}: Props): JSX.Element => (
|
||||
<ConditionalWrapper
|
||||
isWrapping={isDefinedAndNotEmpty(href)}
|
||||
isWrapping={isDefinedAndNotEmpty(href) && !disabled}
|
||||
wrapperProps={{ href: href ?? "", alwaysNewTab }}
|
||||
wrapper={LinkWrapper}>
|
||||
<div className="relative">
|
||||
<div
|
||||
draggable={draggable}
|
||||
id={id}
|
||||
onClick={onClick}
|
||||
onClick={(event) => !disabled && onClick?.(event)}
|
||||
onMouseUp={onMouseUp}
|
||||
onFocus={(event) => event.target.blur()}
|
||||
className={cJoin(
|
||||
`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
|
||||
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(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
|
||||
)}>
|
||||
{isDefined(badgeNumber) && (
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import router from "next/router";
|
||||
import { MouseEventHandler, useState } from "react";
|
||||
import { PointerEventHandler, useState } from "react";
|
||||
import { isDefined } from "helpers/others";
|
||||
|
||||
interface Props {
|
||||
|
@ -8,29 +8,41 @@ interface Props {
|
|||
allowNewTab?: boolean;
|
||||
alwaysNewTab?: boolean;
|
||||
children: React.ReactNode;
|
||||
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||
onClick?: PointerEventHandler<HTMLDivElement>;
|
||||
onFocusChanged?: (isFocused: boolean) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const Link = ({
|
||||
href,
|
||||
allowNewTab = true,
|
||||
alwaysNewTab = false,
|
||||
disabled = false,
|
||||
children,
|
||||
className,
|
||||
onClick,
|
||||
onFocusChanged,
|
||||
}: Props): JSX.Element => {
|
||||
const [isValidClick, setIsValidClick] = useState(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
onMouseLeave={() => setIsValidClick(false)}
|
||||
onContextMenu={(event) => event.preventDefault()}
|
||||
onMouseDown={(event) => {
|
||||
event.preventDefault();
|
||||
setIsValidClick(true);
|
||||
onPointerLeave={() => {
|
||||
setIsValidClick(false);
|
||||
onFocusChanged?.(false);
|
||||
}}
|
||||
onMouseUp={(event) => {
|
||||
onContextMenu={(event) => event.preventDefault()}
|
||||
onPointerDown={(event) => {
|
||||
if (!disabled) {
|
||||
event.preventDefault();
|
||||
onFocusChanged?.(true);
|
||||
setIsValidClick(true);
|
||||
}
|
||||
}}
|
||||
onPointerUp={(event) => {
|
||||
onFocusChanged?.(false);
|
||||
if (!disabled) {
|
||||
if (isDefined(onClick)) {
|
||||
onClick(event);
|
||||
} else if (isValidClick && href) {
|
||||
|
@ -48,6 +60,7 @@ export const Link = ({
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}}>
|
||||
{children}
|
||||
</div>
|
||||
|
|
|
@ -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
|
||||
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>
|
||||
<div className="grid grid-rows-[.8em_.8em] place-items-center">
|
||||
{index > 0 && (
|
||||
|
|
|
@ -15,17 +15,34 @@ interface Props {
|
|||
allowEmpty?: boolean;
|
||||
className?: string;
|
||||
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 tryToggling = useCallback(() => {
|
||||
if (disabled) return;
|
||||
const optionCount = options.length + (value === -1 ? 1 : 0);
|
||||
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);
|
||||
useOnClickOutside(ref, setClosed);
|
||||
|
@ -35,27 +52,29 @@ export const Select = ({ className, value, options, allowEmpty, onChange }: Prop
|
|||
ref={ref}
|
||||
className={cJoin(
|
||||
"relative text-center transition-filter",
|
||||
cIf(isOpened, "z-10 drop-shadow-shade-lg"),
|
||||
cIf(isOpened, "z-10 drop-shadow-lg shadow-shade"),
|
||||
className
|
||||
)}>
|
||||
<div
|
||||
className={cJoin(
|
||||
`grid cursor-pointer grid-flow-col grid-cols-[1fr_auto_auto] place-items-center
|
||||
rounded-[1em] bg-light p-1 outline outline-1 -outline-offset-1 outline-mid
|
||||
transition-all hover:bg-mid hover:outline-transparent`,
|
||||
cIf(isOpened, "rounded-b-none bg-highlight outline-transparent")
|
||||
`grid cursor-pointer select-none grid-flow-col grid-cols-[1fr_auto_auto]
|
||||
place-items-center rounded-3xl p-1 outline outline-1 -outline-offset-1
|
||||
outline-mid`,
|
||||
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]}
|
||||
</p>
|
||||
{value >= 0 && allowEmpty && (
|
||||
<Ico
|
||||
icon={Icon.Close}
|
||||
className="!text-xs"
|
||||
onClick={() => {
|
||||
setClosed();
|
||||
onChange(-1);
|
||||
}}
|
||||
onClick={() => !disabled && onSelectionChanged(-1)}
|
||||
/>
|
||||
)}
|
||||
<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")
|
||||
)}
|
||||
id={option}
|
||||
onClick={() => {
|
||||
setClosed();
|
||||
onChange(index);
|
||||
}}>
|
||||
onClick={() => onSelectionChanged(index)}>
|
||||
{option}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -22,24 +22,21 @@ export const Switch = ({ value, onClick, className, disabled = false }: Props):
|
|||
className={cJoin(
|
||||
`relative grid h-6 w-12 content-center rounded-full border-mid outline
|
||||
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",
|
||||
"bg-light"
|
||||
),
|
||||
cIf(value, "border-none bg-mid shadow-inner-sm shadow-shade outline-transparent"),
|
||||
cIf(disabled, "cursor-not-allowed opacity-50 grayscale", "cursor-pointer"),
|
||||
cIf(disabled, cIf(value, "bg-dark/40 outline-transparent", "outline-dark/60")),
|
||||
className
|
||||
)}
|
||||
onClick={() => {
|
||||
if (!disabled) onClick();
|
||||
}}
|
||||
onPointerDown={() => setIsFocused(true)}
|
||||
onPointerDown={() => !disabled && setIsFocused(true)}
|
||||
onPointerOut={() => setIsFocused(false)}
|
||||
onPointerLeave={() => setIsFocused(false)}
|
||||
onPointerUp={() => setIsFocused(false)}>
|
||||
<div
|
||||
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(isFocused, cIf(value, "translate-x-5", "translate-x-1"))
|
||||
)}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Ico, Icon } from "components/Ico";
|
||||
import { cJoin } from "helpers/className";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { isDefinedAndNotEmpty } from "helpers/others";
|
||||
|
||||
/*
|
||||
|
@ -13,6 +13,7 @@ interface Props {
|
|||
className?: string;
|
||||
name?: string;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
@ -23,6 +24,7 @@ export const TextInput = ({
|
|||
className,
|
||||
name,
|
||||
placeholder,
|
||||
disabled = false,
|
||||
}: Props): JSX.Element => (
|
||||
<div className={cJoin("relative", className)}>
|
||||
<input
|
||||
|
@ -30,6 +32,7 @@ export const TextInput = ({
|
|||
type="text"
|
||||
name={name}
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
placeholder={placeholder}
|
||||
onChange={(event) => {
|
||||
onChange(event.target.value);
|
||||
|
@ -38,11 +41,9 @@ export const TextInput = ({
|
|||
{isDefinedAndNotEmpty(value) && (
|
||||
<div className="absolute right-4 top-0 bottom-0 grid place-items-center">
|
||||
<Ico
|
||||
className="cursor-pointer !text-xs"
|
||||
className={cJoin("!text-xs", cIf(disabled, "opacity-30 grayscale", "cursor-pointer"))}
|
||||
icon={Icon.Close}
|
||||
onClick={() => {
|
||||
onChange("");
|
||||
}}
|
||||
onClick={() => !disabled && onChange("")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -8,18 +8,13 @@ import { isDefinedAndNotEmpty } from "helpers/others";
|
|||
|
||||
interface Props {
|
||||
label: string | null | undefined;
|
||||
disabled?: boolean;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
export const WithLabel = ({ label, children, disabled }: Props): JSX.Element => (
|
||||
<div
|
||||
className={cJoin(
|
||||
"flex flex-row place-content-between place-items-center gap-2",
|
||||
cIf(disabled, "text-dark brightness-150 contrast-75 grayscale")
|
||||
)}>
|
||||
export const WithLabel = ({ label, children }: Props): JSX.Element => (
|
||||
<div className="flex flex-row place-content-between place-items-center gap-2">
|
||||
{isDefinedAndNotEmpty(label) && (
|
||||
<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 { ImageQuality } from "helpers/img";
|
||||
import { isDefined } from "helpers/others";
|
||||
import { useContainerQueries } from "contexts/ContainerQueriesContext";
|
||||
|
||||
interface Props {
|
||||
onCloseRequest: () => void;
|
||||
isVisible: boolean;
|
||||
image?: UploadImageFragment | string;
|
||||
isNextImageAvailable?: boolean;
|
||||
isPreviousImageAvailable?: boolean;
|
||||
onPressNext?: () => void;
|
||||
onPressPrevious?: () => void;
|
||||
isNextImageAvailable: boolean;
|
||||
isPreviousImageAvailable: boolean;
|
||||
onPressNext: () => void;
|
||||
onPressPrevious: () => void;
|
||||
}
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
@ -37,18 +38,15 @@ export const LightBox = ({
|
|||
Ids.LightBox
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
"left",
|
||||
() => onPressPrevious?.(),
|
||||
{ enabled: isVisible && isPreviousImageAvailable },
|
||||
[onPressPrevious]
|
||||
);
|
||||
useHotkeys("left", () => onPressPrevious(), { enabled: isVisible && isPreviousImageAvailable }, [
|
||||
onPressPrevious,
|
||||
]);
|
||||
|
||||
useHotkeys("f", () => requestFullscreen(), { enabled: isVisible && !isFullscreen }, [
|
||||
requestFullscreen,
|
||||
]);
|
||||
|
||||
useHotkeys("right", () => onPressNext?.(), { enabled: isVisible && isNextImageAvailable }, [
|
||||
useHotkeys("right", () => onPressNext(), { enabled: isVisible && isNextImageAvailable }, [
|
||||
onPressNext,
|
||||
]);
|
||||
|
||||
|
@ -69,7 +67,7 @@ export const LightBox = ({
|
|||
/>
|
||||
<div
|
||||
className={cJoin(
|
||||
"absolute inset-8 grid transition-transform",
|
||||
"absolute inset-0 grid transition-transform",
|
||||
cIf(isVisible, "scale-100", "scale-0")
|
||||
)}>
|
||||
<TransformWrapper
|
||||
|
@ -87,46 +85,32 @@ export const LightBox = ({
|
|||
}}>
|
||||
{isDefined(src) && (
|
||||
<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`}
|
||||
src={src}
|
||||
quality={ImageQuality.Large}
|
||||
/>
|
||||
)}
|
||||
</TransformComponent>
|
||||
|
||||
{isPreviousImageAvailable && (
|
||||
<div
|
||||
className={`absolute top-1/2 left-0 grid gap-4 rounded-[2rem] p-4
|
||||
backdrop-blur-lg`}>
|
||||
<Button icon={Icon.NavigateBefore} onClick={onPressPrevious} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isNextImageAvailable && (
|
||||
<div
|
||||
className={`absolute top-1/2 right-0 grid gap-4 rounded-[2rem] p-4
|
||||
backdrop-blur-lg`}>
|
||||
<Button icon={Icon.NavigateNext} onClick={onPressNext} />{" "}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={`absolute top-0 right-0 grid gap-4 rounded-[2rem] p-4
|
||||
backdrop-blur-lg`}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
<ControlButtons
|
||||
isNextImageAvailable={isNextImageAvailable}
|
||||
isPreviousImageAvailable={isPreviousImageAvailable}
|
||||
isFullscreen={isFullscreen}
|
||||
onCloseRequest={() => {
|
||||
resetTransform();
|
||||
exitFullscreen();
|
||||
onCloseRequest();
|
||||
}}
|
||||
icon={Icon.Close}
|
||||
onPressPrevious={() => {
|
||||
resetTransform();
|
||||
onPressPrevious();
|
||||
}}
|
||||
onPressNext={() => {
|
||||
resetTransform();
|
||||
onPressNext();
|
||||
}}
|
||||
toggleFullscreen={toggleFullscreen}
|
||||
/>
|
||||
<Button
|
||||
icon={isFullscreen ? Icon.FullscreenExit : Icon.Fullscreen}
|
||||
onClick={toggleFullscreen}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</TransformWrapper>
|
||||
|
@ -134,3 +118,83 @@ export const LightBox = ({
|
|||
</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 { HorizontalLine } from "components/HorizontalLine";
|
||||
import { Img } from "components/Img";
|
||||
import { InsetBox } from "components/InsetBox";
|
||||
import { InsetBox } from "components/Containers/InsetBox";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { slugify } from "helpers/formatters";
|
||||
import { getAssetURL, ImageQuality } from "helpers/img";
|
||||
|
@ -204,7 +204,7 @@ export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Eleme
|
|||
: compProps.src
|
||||
}
|
||||
quality={ImageQuality.Medium}
|
||||
className="drop-shadow-shade-lg"
|
||||
className="drop-shadow-lg shadow-shade"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
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 { ToolTip } from "components/ToolTip";
|
||||
import { cJoin, cIf } from "helpers/className";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { isDefinedAndNotEmpty } from "helpers/others";
|
||||
import { Link } from "components/Inputs/Link";
|
||||
import { TranslatedProps } from "types/TranslatedProps";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { DownPressable } from "components/Containers/DownPressable";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -21,6 +21,7 @@ interface Props {
|
|||
border?: boolean;
|
||||
reduced?: boolean;
|
||||
active?: boolean;
|
||||
disabled?: boolean;
|
||||
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||
}
|
||||
|
||||
|
@ -34,6 +35,7 @@ export const NavOption = ({
|
|||
border = false,
|
||||
reduced = false,
|
||||
active = false,
|
||||
disabled = false,
|
||||
onClick,
|
||||
}: Props): JSX.Element => {
|
||||
const router = useRouter();
|
||||
|
@ -41,6 +43,7 @@ export const NavOption = ({
|
|||
() => active || router.asPath.startsWith(url),
|
||||
[active, router.asPath, url]
|
||||
);
|
||||
const [isFocused, setFocused] = useState(false);
|
||||
|
||||
return (
|
||||
<ToolTip
|
||||
|
@ -52,27 +55,28 @@ export const NavOption = ({
|
|||
}
|
||||
placement="right"
|
||||
className="text-left"
|
||||
disabled={!reduced}>
|
||||
<Link
|
||||
href={url}
|
||||
onClick={onClick}
|
||||
disabled={!reduced || disabled}>
|
||||
<DownPressable
|
||||
className={cJoin(
|
||||
`relative grid w-full cursor-pointer auto-cols-fr grid-flow-col grid-cols-[auto]
|
||||
justify-center gap-x-5 rounded-2xl p-4 transition-all hover:bg-mid hover:shadow-inner-sm
|
||||
hover:shadow-shade hover:active:shadow-inner hover:active:shadow-shade`,
|
||||
cIf(icon, "text-left", "text-center"),
|
||||
cIf(border, "outline outline-2 -outline-offset-2 outline-mid hover:outline-transparent"),
|
||||
cIf(isActive, "bg-mid shadow-inner-sm shadow-shade")
|
||||
)}>
|
||||
{icon && <Ico icon={icon} className="mt-[-.1em] !text-2xl" isFilled={isActive} />}
|
||||
|
||||
"grid w-full auto-cols-fr grid-flow-col grid-cols-[auto] justify-center gap-x-5",
|
||||
cIf(icon, "text-left", "text-center")
|
||||
)}
|
||||
href={url}
|
||||
border={border}
|
||||
onClick={onClick}
|
||||
active={isActive}
|
||||
disabled={disabled}
|
||||
onFocusChanged={setFocused}>
|
||||
{icon && (
|
||||
<Ico icon={icon} className="mt-[-.1em] !text-2xl" isFilled={isActive || isFocused} />
|
||||
)}
|
||||
{!reduced && (
|
||||
<div>
|
||||
<h3 className="text-2xl">{title}</h3>
|
||||
{isDefinedAndNotEmpty(subtitle) && <p className="col-start-2">{subtitle}</p>}
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
</DownPressable>
|
||||
</ToolTip>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useMemo } from "react";
|
|||
import UAParser from "ua-parser-js";
|
||||
import { useIsClient, useSessionStorage } from "usehooks-ts";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
import { Popup } from "components/Popup";
|
||||
import { Popup } from "components/Containers/Popup";
|
||||
import { sendAnalytics } from "helpers/analytics";
|
||||
|
||||
export const SafariPopup = (): JSX.Element => {
|
||||
|
|
|
@ -6,7 +6,7 @@ import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
|||
import { OrderableList } from "components/Inputs/OrderableList";
|
||||
import { Select } from "components/Inputs/Select";
|
||||
import { TextInput } from "components/Inputs/TextInput";
|
||||
import { Popup } from "components/Popup";
|
||||
import { Popup } from "components/Containers/Popup";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { useLocalData } from "contexts/LocalDataContext";
|
||||
import { useUserSettings } from "contexts/UserSettingsContext";
|
||||
|
|
|
@ -4,8 +4,8 @@ import { Chip } from "./Chip";
|
|||
import { HorizontalLine } from "./HorizontalLine";
|
||||
import { Markdawn, TableOfContents } from "./Markdown/Markdawn";
|
||||
import { ReturnButton } from "./PanelComponents/ReturnButton";
|
||||
import { ContentPanel } from "./Panels/ContentPanel";
|
||||
import { SubPanel } from "./Panels/SubPanel";
|
||||
import { ContentPanel } from "./Containers/ContentPanel";
|
||||
import { SubPanel } from "./Containers/SubPanel";
|
||||
import { RecorderChip } from "./RecorderChip";
|
||||
import { ThumbnailHeader } from "./ThumbnailHeader";
|
||||
import { ToolTip } from "./ToolTip";
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useRouter } from "next/router";
|
|||
import { Chip } from "./Chip";
|
||||
import { Ico, Icon } from "./Ico";
|
||||
import { Img } from "./Img";
|
||||
import { Link } from "./Inputs/Link";
|
||||
import { UpPressable } from "./Containers/UpPressable";
|
||||
import { DatePickerFragment, PricePickerFragment, UploadImageFragment } from "graphql/generated";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { prettyDate, prettyDuration, prettyPrice, prettyShortenNumber } from "helpers/formatters";
|
||||
|
@ -47,6 +47,7 @@ interface Props {
|
|||
duration: number;
|
||||
}
|
||||
| { __typename: "anotherHoverlayName" };
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
@ -67,6 +68,7 @@ export const PreviewCard = ({
|
|||
metadata,
|
||||
hoverlay,
|
||||
infoAppend,
|
||||
disabled = false,
|
||||
}: Props): JSX.Element => {
|
||||
const { currency } = useUserSettings();
|
||||
const { currencies } = useLocalData();
|
||||
|
@ -110,10 +112,8 @@ export const PreviewCard = ({
|
|||
);
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
className="group grid cursor-pointer items-end text-left transition-transform
|
||||
drop-shadow-shade-xl hover:scale-[1.02]">
|
||||
<UpPressable className="grid items-end text-left" href={href} noBackground disabled={disabled}>
|
||||
<div className={cJoin("group", cIf(disabled, "pointer-events-none touch-none select-none"))}>
|
||||
{thumbnail ? (
|
||||
<div
|
||||
className="relative"
|
||||
|
@ -135,11 +135,13 @@ export const PreviewCard = ({
|
|||
{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">
|
||||
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 opacity-0 transition-opacity group-hover:opacity-100"
|
||||
className="!text-6xl text-black opacity-0 drop-shadow-lg transition-opacity
|
||||
shadow-shade group-hover:opacity-100"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
|
@ -154,7 +156,7 @@ export const PreviewCard = ({
|
|||
<div
|
||||
style={{ aspectRatio: thumbnailAspectRatio }}
|
||||
className={cJoin(
|
||||
"relative w-full bg-light",
|
||||
"relative w-full bg-highlight",
|
||||
cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none")
|
||||
)}
|
||||
/>
|
||||
|
@ -164,15 +166,18 @@ export const PreviewCard = ({
|
|||
"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
|
||||
`-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-hidden">
|
||||
<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} />
|
||||
))}
|
||||
|
@ -189,7 +194,7 @@ export const PreviewCard = ({
|
|||
{bottomChips && bottomChips.length > 0 && (
|
||||
<div
|
||||
className="grid grid-flow-col place-content-start gap-1 overflow-x-scroll
|
||||
[scrollbar-width:none] webkit-scrollbar:h-0">
|
||||
scrollbar-none">
|
||||
{bottomChips.map((text, index) => (
|
||||
<Chip key={index} className="text-sm" text={text} />
|
||||
))}
|
||||
|
@ -200,7 +205,8 @@ export const PreviewCard = ({
|
|||
|
||||
{infoAppend}
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</UpPressable>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { useCallback } from "react";
|
||||
import { Chip } from "./Chip";
|
||||
import { Img } from "./Img";
|
||||
import { Link } from "./Inputs/Link";
|
||||
import { UpPressable } from "./Containers/UpPressable";
|
||||
import { UploadImageFragment } from "graphql/generated";
|
||||
import { ImageQuality } from "helpers/img";
|
||||
import { TranslatedProps } from "types/TranslatedProps";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { isDefined } from "helpers/others";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -14,41 +16,44 @@ import { useSmartLanguage } from "hooks/useSmartLanguage";
|
|||
|
||||
interface Props {
|
||||
thumbnail?: UploadImageFragment | string | null | undefined;
|
||||
thumbnailAspectRatio?: string;
|
||||
href: string;
|
||||
pre_title?: string | null | undefined;
|
||||
title: string | null | undefined;
|
||||
subtitle?: string | null | undefined;
|
||||
topChips?: string[];
|
||||
bottomChips?: string[];
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
const PreviewLine = ({
|
||||
export const PreviewLine = ({
|
||||
href,
|
||||
thumbnail,
|
||||
pre_title,
|
||||
title,
|
||||
subtitle,
|
||||
topChips,
|
||||
disabled,
|
||||
bottomChips,
|
||||
thumbnailAspectRatio,
|
||||
}: Props): JSX.Element => (
|
||||
<Link
|
||||
href={href}
|
||||
className="flex h-36 w-full cursor-pointer flex-row place-items-center gap-4 overflow-hidden
|
||||
rounded-md bg-light pr-4 transition-transform drop-shadow-shade-xl hover:scale-[1.02]">
|
||||
{thumbnail ? (
|
||||
<div className="aspect-[3/2] h-full">
|
||||
<UpPressable href={href} disabled={disabled}>
|
||||
<div
|
||||
className={cJoin(
|
||||
"grid w-full grid-flow-col place-items-center gap-4",
|
||||
cIf(disabled, "pointer-events-none touch-none select-none")
|
||||
)}>
|
||||
{thumbnail && (
|
||||
<div className="h-full w-full">
|
||||
<Img className="h-full object-cover" src={thumbnail} quality={ImageQuality.Medium} />
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ aspectRatio: thumbnailAspectRatio }} />
|
||||
)}
|
||||
<div className="grid gap-2">
|
||||
|
||||
<div className={cJoin("grid gap-2 py-4", cIf(isDefined(thumbnail), "pr-3", "px-6"))}>
|
||||
{topChips && topChips.length > 0 && (
|
||||
<div className="grid grid-flow-col place-content-start gap-1 overflow-hidden">
|
||||
<div
|
||||
className="grid grid-flow-col place-content-start gap-1 overflow-scroll
|
||||
scrollbar-none">
|
||||
{topChips.map((text, index) => (
|
||||
<Chip key={index} text={text} />
|
||||
))}
|
||||
|
@ -60,14 +65,17 @@ const PreviewLine = ({
|
|||
{subtitle && <p className="leading-none">{subtitle}</p>}
|
||||
</div>
|
||||
{bottomChips && bottomChips.length > 0 && (
|
||||
<div className="grid grid-flow-col place-content-start gap-1 overflow-hidden">
|
||||
<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>
|
||||
</Link>
|
||||
</div>
|
||||
</UpPressable>
|
||||
);
|
||||
|
||||
/*
|
||||
|
|
|
@ -9,6 +9,7 @@ import { useScrollTopOnChange } from "hooks/useScrollTopOnChange";
|
|||
import { Ids } from "types/ids";
|
||||
import { useLocalData } from "contexts/LocalDataContext";
|
||||
import { useContainerQueries } from "contexts/ContainerQueriesContext";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
|
||||
interface Group<T> {
|
||||
name: string;
|
||||
|
@ -163,6 +164,11 @@ export const SmartList = <T,>({
|
|||
return memo;
|
||||
}, [groups, paginationItemPerPage]);
|
||||
|
||||
useHotkeys("left", () => setPage((current) => current - 1), { enabled: page > 0 });
|
||||
useHotkeys("right", () => setPage((current) => current + 1), {
|
||||
enabled: page < pages.length - 1,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{pages.length > 1 && paginationSelectorTop && (
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Chip } from "components/Chip";
|
||||
import { Img } from "components/Img";
|
||||
import { InsetBox } from "components/InsetBox";
|
||||
import { InsetBox } from "components/Containers/InsetBox";
|
||||
import { Markdawn } from "components/Markdown/Markdawn";
|
||||
import { GetContentTextQuery, UploadImageFragment } from "graphql/generated";
|
||||
import { prettyInlineTitle, prettySlug, slugify } from "helpers/formatters";
|
||||
|
@ -48,7 +48,7 @@ export const ThumbnailHeader = ({
|
|||
return (
|
||||
<>
|
||||
<div className="mb-12 grid place-items-center gap-12">
|
||||
<div className="drop-shadow-shade-lg">
|
||||
<div className="shadow-shade drop-shadow-lg">
|
||||
{thumbnail ? (
|
||||
<Img
|
||||
className="cursor-pointer rounded-xl"
|
||||
|
|
|
@ -2,7 +2,9 @@ export const cIf = (
|
|||
condition: boolean | string | null | undefined,
|
||||
ifTrueCss: string,
|
||||
ifFalseCss?: string
|
||||
): string => (condition ? ifTrueCss : ifFalseCss ?? "");
|
||||
): string => removeWhitespace(condition ? ifTrueCss : ifFalseCss ?? "");
|
||||
|
||||
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 { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
||||
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import { getLangui } from "graphql/fetchLocalData";
|
||||
import { Img } from "components/Img";
|
||||
|
@ -20,7 +20,10 @@ const FourOhFour = ({ openGraph, ...otherProps }: Props): JSX.Element => {
|
|||
<AppLayout
|
||||
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">
|
||||
<h2>{langui.page_not_found}</h2>
|
||||
<ReturnButton href="/" title="Home" />
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
||||
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import { getLangui } from "graphql/fetchLocalData";
|
||||
import { Img } from "components/Img";
|
||||
|
@ -20,7 +20,10 @@ const FiveHundred = ({ openGraph, ...otherProps }: Props): JSX.Element => {
|
|||
<AppLayout
|
||||
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">
|
||||
<h2>{langui.page_not_found}</h2>
|
||||
<ReturnButton href="/" title="Home" />
|
||||
|
|
|
@ -11,8 +11,6 @@ import type { AppProps } from "next/app";
|
|||
import Script from "next/script";
|
||||
import { AppContextProvider } from "contexts/AppLayoutContext";
|
||||
|
||||
import "styles/animations.css";
|
||||
import "styles/custom-classes.css";
|
||||
import "styles/debug.css";
|
||||
import "styles/formatted.css";
|
||||
import "styles/others.css";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { InsetBox } from "components/InsetBox";
|
||||
import { InsetBox } from "components/Containers/InsetBox";
|
||||
import { PostPage } from "components/PostPage";
|
||||
import { getPostStaticProps, PostStaticProps } from "graphql/getPostStaticProps";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
|
|
|
@ -3,7 +3,7 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
|||
import { Icon } from "components/Ico";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { getLangui } from "graphql/fetchLocalData";
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useMemo } from "react";
|
|||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { Icon } from "components/Ico";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
|
|
|
@ -5,8 +5,8 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
|||
import { Switch } from "components/Inputs/Switch";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { PreviewCard } from "components/PreviewCard";
|
||||
import { GetVideoChannelQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
|
|
|
@ -9,8 +9,8 @@ import { TextInput } from "components/Inputs/TextInput";
|
|||
import { WithLabel } from "components/Inputs/WithLabel";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { PreviewCard } from "components/PreviewCard";
|
||||
import { GetVideosPreviewQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
|
|
|
@ -5,11 +5,11 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
|||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { Ico, Icon } from "components/Ico";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
import { InsetBox } from "components/InsetBox";
|
||||
import { InsetBox } from "components/Containers/InsetBox";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { GetVideoQuery } from "graphql/generated";
|
||||
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 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 className="w-full" src={getVideoFile(video.uid)} controls />
|
||||
) : (
|
||||
|
|
|
@ -5,9 +5,9 @@ import { isDefined, filterHasAttributes } from "helpers/others";
|
|||
import { ChronicleWithTranslations } from "types/types";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
||||
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||
import { Markdawn } from "components/Markdown/Markdawn";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { ThumbnailHeader } from "components/ThumbnailHeader";
|
||||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { GetChroniclesChaptersQuery } from "graphql/generated";
|
||||
|
|
|
@ -2,7 +2,7 @@ import { GetStaticProps } from "next";
|
|||
import { useMemo } from "react";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { Icon } from "components/Ico";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetChroniclesChaptersQuery } from "graphql/generated";
|
||||
|
|
|
@ -7,8 +7,8 @@ import { HorizontalLine } from "components/HorizontalLine";
|
|||
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
||||
import { Markdawn, TableOfContents } from "components/Markdown/Markdawn";
|
||||
import { TranslatedReturnButton } from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { PreviewCard } from "components/PreviewCard";
|
||||
import { RecorderChip } from "components/RecorderChip";
|
||||
import { ThumbnailHeader } from "components/ThumbnailHeader";
|
||||
|
@ -315,7 +315,6 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
|
|||
title: prettySlug(previousContent.attributes.slug),
|
||||
}}
|
||||
thumbnail={previousContent.attributes.thumbnail?.data?.attributes}
|
||||
thumbnailAspectRatio="3/2"
|
||||
topChips={
|
||||
isContentPanelAtLeast2xl && previousContent.attributes.type?.data?.attributes
|
||||
? [
|
||||
|
@ -359,7 +358,6 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
|
|||
}))}
|
||||
fallback={{ title: nextContent.attributes.slug }}
|
||||
thumbnail={nextContent.attributes.thumbnail?.data?.attributes}
|
||||
thumbnailAspectRatio="3/2"
|
||||
topChips={
|
||||
isContentPanelAtLeast2xl && nextContent.attributes.type?.data?.attributes
|
||||
? [
|
||||
|
|
|
@ -6,8 +6,8 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
|||
import { Select } from "components/Inputs/Select";
|
||||
import { Switch } from "components/Inputs/Switch";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { prettyInlineTitle, prettySlug } from "helpers/formatters";
|
||||
import { TextInput } from "components/Inputs/TextInput";
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useMemo } from "react";
|
||||
import naturalCompare from "string-natural-compare";
|
||||
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 { getReadySdk } from "graphql/sdk";
|
||||
import { filterHasAttributes } from "helpers/others";
|
||||
|
@ -12,17 +12,15 @@ import { prettySlug } from "helpers/formatters";
|
|||
import { SmartList } from "components/SmartList";
|
||||
import { Ico, Icon } from "components/Ico";
|
||||
import { Button, TranslatedButton } from "components/Inputs/Button";
|
||||
import { Link } from "components/Inputs/Link";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { TranslatedProps } from "types/TranslatedProps";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { TranslatedPreviewCard } from "components/PreviewCard";
|
||||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { cJoin, cIf } from "helpers/className";
|
||||
import { getLangui } from "graphql/fetchLocalData";
|
||||
import { useLocalData } from "contexts/LocalDataContext";
|
||||
import { useContainerQueries } from "contexts/ContainerQueriesContext";
|
||||
import { TranslatedPreviewFolder } from "components/Contents/PreviewFolder";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
|
@ -274,36 +272,6 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
|
|||
* ───────────────────────────────────╯ 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 { langui } = useLocalData();
|
||||
return (
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useMemo } from "react";
|
|||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Chip } from "components/Chip";
|
||||
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 { DevGetContentsQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useMemo } from "react";
|
|||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Chip } from "components/Chip";
|
||||
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 {
|
||||
DevGetLibraryItemsQuery,
|
||||
|
|
|
@ -4,8 +4,8 @@ import TurndownService from "turndown";
|
|||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
import { Markdawn, TableOfContents } from "components/Markdown/Markdawn";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
||||
import { Popup } from "components/Popup";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||
import { Popup } from "components/Containers/Popup";
|
||||
import { ToolTip } from "components/ToolTip";
|
||||
import { Icon } from "components/Ico";
|
||||
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 { Button } from "components/Inputs/Button";
|
||||
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 { getOpenGraph } from "helpers/openGraph";
|
||||
import { getLangui } from "graphql/fetchLocalData";
|
||||
|
|
|
@ -7,12 +7,12 @@ import { Chip } from "components/Chip";
|
|||
import { Img } from "components/Img";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
import { Switch } from "components/Inputs/Switch";
|
||||
import { InsetBox } from "components/InsetBox";
|
||||
import { InsetBox } from "components/Containers/InsetBox";
|
||||
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { PreviewCard } from "components/PreviewCard";
|
||||
import {
|
||||
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={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]")
|
||||
)}>
|
||||
{item.thumbnail?.data?.attributes ? (
|
||||
|
@ -248,7 +248,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
|
|||
<Fragment key={galleryItem.id}>
|
||||
<div
|
||||
className="relative aspect-square cursor-pointer
|
||||
transition-transform hover:scale-[1.02]"
|
||||
transition-transform hover:scale-102"
|
||||
onClick={() => {
|
||||
showLightBox(
|
||||
filterHasAttributes(item.gallery?.data, ["attributes"] as const).map(
|
||||
|
@ -258,8 +258,8 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
|
|||
);
|
||||
}}>
|
||||
<Img
|
||||
className="h-full w-full rounded-lg
|
||||
bg-light object-cover drop-shadow-shade-md"
|
||||
className="h-full w-full rounded-lg bg-light object-cover shadow-md
|
||||
shadow-shade/30 transition-shadow hover:shadow-lg hover:shadow-shade/50"
|
||||
src={galleryItem.attributes}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -20,12 +20,12 @@ import {
|
|||
} from "helpers/others";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
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 { getAssetFilename, ImageQuality } from "helpers/img";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
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 { Icon } from "components/Ico";
|
||||
import { Ids } from "types/ids";
|
||||
|
@ -1045,8 +1045,8 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps):
|
|||
{pages.map((page, index) => (
|
||||
<div
|
||||
key={page.id}
|
||||
className="cursor-pointer transition-transform
|
||||
drop-shadow-shade-lg hover:scale-[1.02]"
|
||||
className="cursor-pointer drop-shadow-lg
|
||||
transition-transform shadow-shade hover:scale-102"
|
||||
onClick={() => {
|
||||
onClickOnImage(index);
|
||||
}}>
|
||||
|
|
|
@ -6,8 +6,8 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
|||
import { Select } from "components/Inputs/Select";
|
||||
import { Switch } from "components/Inputs/Switch";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { GetLibraryItemsPreviewQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { prettyInlineTitle, prettyItemSubType } from "helpers/formatters";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { Icon } from "components/Ico";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import { getLangui } from "graphql/fetchLocalData";
|
||||
|
|
|
@ -4,8 +4,8 @@ import { useBoolean } from "usehooks-ts";
|
|||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Switch } from "components/Inputs/Switch";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { GetPostsPreviewQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { prettySlug } from "helpers/formatters";
|
||||
|
|
|
@ -6,8 +6,8 @@ import { Chip } from "components/Chip";
|
|||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { Img } from "components/Img";
|
||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import DefinitionCard from "components/Wiki/DefinitionCard";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { filterHasAttributes, isDefined, isDefinedAndNotEmpty } from "helpers/others";
|
||||
|
|
|
@ -2,10 +2,10 @@ import { GetStaticProps } from "next";
|
|||
import { Fragment, useCallback, useMemo } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { InsetBox } from "components/InsetBox";
|
||||
import { InsetBox } from "components/Containers/InsetBox";
|
||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ContentPanel } from "components/Containers/ContentPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import {
|
||||
Enum_Componenttranslationschronologyitem_Status,
|
||||
GetChronologyItemsQuery,
|
||||
|
|
|
@ -4,11 +4,11 @@ import { useBoolean } from "usehooks-ts";
|
|||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { SubPanel } from "components/Containers/SubPanel";
|
||||
import { Icon } from "components/Ico";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
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 { Button } from "components/Inputs/Button";
|
||||
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,
|
||||
|
@ -32,31 +32,12 @@ mark {
|
|||
@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,
|
||||
textarea {
|
||||
@apply rounded-full bg-light 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
|
||||
hover:outline-transparent;
|
||||
@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;
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
|
@ -65,7 +46,7 @@ input::placeholder {
|
|||
|
||||
input:focus-visible,
|
||||
textarea:focus-within {
|
||||
@apply bg-mid shadow-inner-sm shadow-shade outline-none;
|
||||
@apply bg-mid shadow-inner-sm outline-none shadow-shade;
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
@ -74,7 +55,21 @@ textarea {
|
|||
|
||||
input[type="submit"] {
|
||||
@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
|
||||
hover:text-light hover:drop-shadow-shade-lg active:border-black active:bg-black
|
||||
active:text-light active:drop-shadow-black-lg;
|
||||
border-dark px-4 pt-[0.4rem] pb-[0.5rem] text-dark outline-none transition-all shadow-shade
|
||||
hover:bg-dark hover:text-light hover:drop-shadow-lg active:border-black active:bg-black
|
||||
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 {
|
||||
@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 {
|
||||
@apply bottom-0;
|
||||
|
|
|
@ -15,6 +15,7 @@ module.exports = {
|
|||
dark: "rgb(var(--theme-color-dark) / <alpha-value>)",
|
||||
shade: "rgb(var(--theme-color-shade) / <alpha-value>)",
|
||||
black: "rgb(var(--theme-color-black) / <alpha-value>)",
|
||||
transparent: "transparent",
|
||||
},
|
||||
fontFamily: {
|
||||
body: "var(--theme-font-body)",
|
||||
|
@ -51,22 +52,147 @@ module.exports = {
|
|||
1: "0.15rem",
|
||||
2: "0.17rem",
|
||||
},
|
||||
extend: {
|
||||
boxShadow: {
|
||||
"inner-sm": "inset 0 1px 4px -2px",
|
||||
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: {
|
||||
transitionProperty: {
|
||||
height: "height, max-height, min-height",
|
||||
filter: "filter, backdrop-filter",
|
||||
colors:
|
||||
"color, background-color, border-color, text-decoration-color, fill, stroke, outline-color",
|
||||
},
|
||||
outlineColor: {
|
||||
transparent: "transparent",
|
||||
scale: {
|
||||
102: "1.02",
|
||||
},
|
||||
},
|
||||
},
|
||||
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 }) => {
|
||||
addUtilities({
|
||||
".set-theme-light": {
|
||||
|
@ -92,6 +218,7 @@ module.exports = {
|
|||
});
|
||||
}),
|
||||
|
||||
/* CSS fonts setters */
|
||||
plugin(({ addUtilities }) => {
|
||||
addUtilities({
|
||||
".set-theme-font-standard": {
|
||||
|
@ -107,75 +234,38 @@ module.exports = {
|
|||
});
|
||||
}),
|
||||
|
||||
plugin(({ addVariant, e }) => {
|
||||
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))`,
|
||||
},
|
||||
});
|
||||
}),
|
||||
|
||||
/* Linear background colors presets */
|
||||
plugin(({ addUtilities }) => {
|
||||
addUtilities({
|
||||
".linearbg-obi": {
|
||||
background: `linear-gradient(
|
||||
to right,
|
||||
rgb(var(--theme-color-mid)),
|
||||
rgb(var(--theme-color-light)) 3%,
|
||||
rgb(var(--theme-color-light)) 97%,
|
||||
rgb(var(--theme-color-highlight)) 3%,
|
||||
rgb(var(--theme-color-highlight)) 97%,
|
||||
rgb(var(--theme-color-mid))
|
||||
)`,
|
||||
},
|
||||
});
|
||||
}),
|
||||
|
||||
/* Add support for break-wrods CSS attribute */
|
||||
plugin(({ addUtilities }) => {
|
||||
addUtilities({
|
||||
".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": {
|
||||
"target": "ESNext",
|
||||
"target": "ES6",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"importHelpers": true,
|
||||
"allowJs": true,
|
||||
|
|
Loading…
Reference in New Issue