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") | ||||
|     )}> | ||||
|     <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> | ||||
|     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={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> | ||||
|  | ||||
							
								
								
									
										61
									
								
								src/components/Containers/DownPressable.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/components/Containers/DownPressable.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										42
									
								
								src/components/Containers/UpPressable.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/components/Containers/UpPressable.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										38
									
								
								src/components/Contents/PreviewFolder.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/components/Contents/PreviewFolder.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -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,43 +8,56 @@ 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) => { | ||||
|         if (isDefined(onClick)) { | ||||
|           onClick(event); | ||||
|         } else if (isValidClick && href) { | ||||
|           if (event.button !== MouseButton.Right) { | ||||
|             if (alwaysNewTab) { | ||||
|               window.open(href, "_blank", "noopener"); | ||||
|             } else if (event.button === MouseButton.Left) { | ||||
|               if (href.startsWith("#")) { | ||||
|                 router.replace(href); | ||||
|               } else { | ||||
|                 router.push(href); | ||||
|       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) { | ||||
|             if (event.button !== MouseButton.Right) { | ||||
|               if (alwaysNewTab) { | ||||
|                 window.open(href, "_blank", "noopener"); | ||||
|               } else if (event.button === MouseButton.Left) { | ||||
|                 if (href.startsWith("#")) { | ||||
|                   router.replace(href); | ||||
|                 } else { | ||||
|                   router.push(href); | ||||
|                 } | ||||
|               } else if (allowNewTab) { | ||||
|                 window.open(href, "_blank"); | ||||
|               } | ||||
|             } else if (allowNewTab) { | ||||
|               window.open(href, "_blank"); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
| @ -58,7 +58,7 @@ export const OrderableList = ({ onChange, items, insertLabels }: Props): JSX.Ele | ||||
|             }} | ||||
|             className="grid cursor-grab select-none grid-cols-[auto_1fr] place-content-center gap-2 | ||||
|             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={() => { | ||||
|                     resetTransform(); | ||||
|                     exitFullscreen(); | ||||
|                     onCloseRequest(); | ||||
|                   }} | ||||
|                   icon={Icon.Close} | ||||
|                 /> | ||||
|                 <Button | ||||
|                   icon={isFullscreen ? Icon.FullscreenExit : Icon.Fullscreen} | ||||
|                   onClick={toggleFullscreen} | ||||
|                 /> | ||||
|               </div> | ||||
|               <ControlButtons | ||||
|                 isNextImageAvailable={isNextImageAvailable} | ||||
|                 isPreviousImageAvailable={isPreviousImageAvailable} | ||||
|                 isFullscreen={isFullscreen} | ||||
|                 onCloseRequest={() => { | ||||
|                   resetTransform(); | ||||
|                   exitFullscreen(); | ||||
|                   onCloseRequest(); | ||||
|                 }} | ||||
|                 onPressPrevious={() => { | ||||
|                   resetTransform(); | ||||
|                   onPressPrevious(); | ||||
|                 }} | ||||
|                 onPressNext={() => { | ||||
|                   resetTransform(); | ||||
|                   onPressNext(); | ||||
|                 }} | ||||
|                 toggleFullscreen={toggleFullscreen} | ||||
|               /> | ||||
|             </> | ||||
|           )} | ||||
|         </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,97 +112,101 @@ 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]"> | ||||
|       {thumbnail ? ( | ||||
|         <div | ||||
|           className="relative" | ||||
|           style={{ | ||||
|             aspectRatio: thumbnailForceAspectRatio ? thumbnailAspectRatio : "unset", | ||||
|           }}> | ||||
|           <Img | ||||
|             className={cJoin( | ||||
|               cIf( | ||||
|                 thumbnailRounded, | ||||
|                 cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none") | ||||
|               ), | ||||
|               cIf(thumbnailForceAspectRatio, "h-full w-full object-cover") | ||||
|             )} | ||||
|             src={thumbnail} | ||||
|             quality={ImageQuality.Medium} | ||||
|           /> | ||||
| 
 | ||||
|           {hoverlay && hoverlay.__typename === "Video" && ( | ||||
|             <> | ||||
|               <div | ||||
|                 className="absolute inset-0 grid place-content-center bg-shade bg-opacity-0 | ||||
|                   text-light transition-colors drop-shadow-shade-lg group-hover:bg-opacity-50"> | ||||
|                 <Ico | ||||
|                   icon={Icon.PlayCircleOutline} | ||||
|                   className="!text-6xl opacity-0 transition-opacity group-hover:opacity-100" | ||||
|                 /> | ||||
|               </div> | ||||
|               <div | ||||
|                 className="absolute right-2 bottom-2 rounded-full bg-black bg-opacity-60 px-2 | ||||
|                   text-light"> | ||||
|                 {prettyDuration(hoverlay.duration)} | ||||
|               </div> | ||||
|             </> | ||||
|           )} | ||||
|         </div> | ||||
|       ) : ( | ||||
|         <div | ||||
|           style={{ aspectRatio: thumbnailAspectRatio }} | ||||
|           className={cJoin( | ||||
|             "relative w-full bg-light", | ||||
|             cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none") | ||||
|           )} | ||||
|         /> | ||||
|       )} | ||||
|       <div | ||||
|         className={cJoin( | ||||
|           "z-20 grid gap-2 p-4 transition-opacity linearbg-obi", | ||||
|           cIf( | ||||
|             !keepInfoVisible && isHoverable, | ||||
|             `-inset-x-0.5 bottom-2 opacity-0 [border-radius:10%_10%_10%_10%_/_1%_1%_3%_3%]
 | ||||
|             group-hover:opacity-100 hoverable:absolute hoverable:drop-shadow-shade-lg | ||||
|             notHoverable:rounded-b-md notHoverable:opacity-100`,
 | ||||
|             "[border-radius:0%_0%_10%_10%_/_0%_0%_3%_3%]" | ||||
|           ) | ||||
|         )}> | ||||
|         {metadata?.position === "Top" && metadataJSX} | ||||
|         {topChips && topChips.length > 0 && ( | ||||
|           <div className="grid grid-flow-col place-content-start gap-1 overflow-hidden"> | ||||
|             {topChips.map((text, index) => ( | ||||
|               <Chip key={index} text={text} /> | ||||
|             ))} | ||||
|           </div> | ||||
|         )} | ||||
|         <div className="my-1"> | ||||
|           {pre_title && <p className="mb-1 leading-none break-words">{pre_title}</p>} | ||||
|           {title && ( | ||||
|             <p className="font-headers text-lg font-bold leading-none break-words">{title}</p> | ||||
|           )} | ||||
|           {subtitle && <p className="leading-none break-words">{subtitle}</p>} | ||||
|         </div> | ||||
|         {description && <p>{description}</p>} | ||||
|         {bottomChips && bottomChips.length > 0 && ( | ||||
|     <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="grid grid-flow-col place-content-start gap-1 overflow-x-scroll | ||||
|               [scrollbar-width:none] webkit-scrollbar:h-0"> | ||||
|             {bottomChips.map((text, index) => ( | ||||
|               <Chip key={index} className="text-sm" text={text} /> | ||||
|             ))} | ||||
|             className="relative" | ||||
|             style={{ | ||||
|               aspectRatio: thumbnailForceAspectRatio ? thumbnailAspectRatio : "unset", | ||||
|             }}> | ||||
|             <Img | ||||
|               className={cJoin( | ||||
|                 cIf( | ||||
|                   thumbnailRounded, | ||||
|                   cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none") | ||||
|                 ), | ||||
|                 cIf(thumbnailForceAspectRatio, "h-full w-full object-cover") | ||||
|               )} | ||||
|               src={thumbnail} | ||||
|               quality={ImageQuality.Medium} | ||||
|             /> | ||||
| 
 | ||||
|             {hoverlay && hoverlay.__typename === "Video" && ( | ||||
|               <> | ||||
|                 <div | ||||
|                   className="group absolute inset-0 grid place-content-center bg-shade bg-opacity-0 | ||||
|                   text-light transition-colors | ||||
|                   hover:bg-opacity-50"> | ||||
|                   <Ico | ||||
|                     icon={Icon.PlayCircleOutline} | ||||
|                     className="!text-6xl text-black opacity-0 drop-shadow-lg transition-opacity | ||||
|                   shadow-shade group-hover:opacity-100" | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <div | ||||
|                   className="absolute right-2 bottom-2 rounded-full bg-black bg-opacity-60 px-2 | ||||
|                   text-light"> | ||||
|                   {prettyDuration(hoverlay.duration)} | ||||
|                 </div> | ||||
|               </> | ||||
|             )} | ||||
|           </div> | ||||
|         ) : ( | ||||
|           <div | ||||
|             style={{ aspectRatio: thumbnailAspectRatio }} | ||||
|             className={cJoin( | ||||
|               "relative w-full bg-highlight", | ||||
|               cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none") | ||||
|             )} | ||||
|           /> | ||||
|         )} | ||||
|         <div | ||||
|           className={cJoin( | ||||
|             "z-20 grid gap-2 p-4 transition-opacity linearbg-obi", | ||||
|             cIf( | ||||
|               !keepInfoVisible && isHoverable, | ||||
|               `-inset-x-0.5 bottom-2 opacity-0 shadow-shade
 | ||||
|                [border-radius:10%_10%_10%_10%_/_1%_1%_3%_3%] | ||||
|                group-hover:opacity-100 hoverable:absolute hoverable:drop-shadow-lg | ||||
|                notHoverable:rounded-b-md notHoverable:opacity-100`,
 | ||||
|               "[border-radius:0%_0%_10%_10%_/_0%_0%_3%_3%]" | ||||
|             ) | ||||
|           )}> | ||||
|           {metadata?.position === "Top" && metadataJSX} | ||||
|           {topChips && topChips.length > 0 && ( | ||||
|             <div | ||||
|               className="grid grid-flow-col place-content-start gap-1 overflow-x-scroll | ||||
|             scrollbar-none"> | ||||
|               {topChips.map((text, index) => ( | ||||
|                 <Chip key={index} text={text} /> | ||||
|               ))} | ||||
|             </div> | ||||
|           )} | ||||
|           <div className="my-1"> | ||||
|             {pre_title && <p className="mb-1 leading-none break-words">{pre_title}</p>} | ||||
|             {title && ( | ||||
|               <p className="font-headers text-lg font-bold leading-none break-words">{title}</p> | ||||
|             )} | ||||
|             {subtitle && <p className="leading-none break-words">{subtitle}</p>} | ||||
|           </div> | ||||
|           {description && <p>{description}</p>} | ||||
|           {bottomChips && bottomChips.length > 0 && ( | ||||
|             <div | ||||
|               className="grid grid-flow-col place-content-start gap-1 overflow-x-scroll | ||||
|             scrollbar-none"> | ||||
|               {bottomChips.map((text, index) => ( | ||||
|                 <Chip key={index} className="text-sm" text={text} /> | ||||
|               ))} | ||||
|             </div> | ||||
|           )} | ||||
| 
 | ||||
|         {metadata?.position === "Bottom" && metadataJSX} | ||||
|           {metadata?.position === "Bottom" && metadataJSX} | ||||
| 
 | ||||
|         {infoAppend} | ||||
|           {infoAppend} | ||||
|         </div> | ||||
|       </div> | ||||
|     </Link> | ||||
|     </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,60 +16,66 @@ 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"> | ||||
|         <Img className="h-full object-cover" src={thumbnail} quality={ImageQuality.Medium} /> | ||||
|       </div> | ||||
|     ) : ( | ||||
|       <div style={{ aspectRatio: thumbnailAspectRatio }} /> | ||||
|     )} | ||||
|     <div className="grid gap-2"> | ||||
|       {topChips && topChips.length > 0 && ( | ||||
|         <div className="grid grid-flow-col place-content-start gap-1 overflow-hidden"> | ||||
|           {topChips.map((text, index) => ( | ||||
|             <Chip key={index} text={text} /> | ||||
|           ))} | ||||
|   <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 className="my-1 flex flex-col"> | ||||
|         {pre_title && <p className="mb-1 leading-none">{pre_title}</p>} | ||||
|         {title && <p className="font-headers text-lg font-bold leading-none">{title}</p>} | ||||
|         {subtitle && <p className="leading-none">{subtitle}</p>} | ||||
|       </div> | ||||
|       {bottomChips && bottomChips.length > 0 && ( | ||||
|         <div className="grid grid-flow-col place-content-start gap-1 overflow-hidden"> | ||||
|           {bottomChips.map((text, index) => ( | ||||
|             <Chip key={index} className="text-sm" text={text} /> | ||||
|           ))} | ||||
| 
 | ||||
|       <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-scroll | ||||
|           scrollbar-none"> | ||||
|             {topChips.map((text, index) => ( | ||||
|               <Chip key={index} text={text} /> | ||||
|             ))} | ||||
|           </div> | ||||
|         )} | ||||
|         <div className="my-1 flex flex-col"> | ||||
|           {pre_title && <p className="mb-1 leading-none">{pre_title}</p>} | ||||
|           {title && <p className="font-headers text-lg font-bold leading-none">{title}</p>} | ||||
|           {subtitle && <p className="leading-none">{subtitle}</p>} | ||||
|         </div> | ||||
|       )} | ||||
|         {bottomChips && bottomChips.length > 0 && ( | ||||
|           <div | ||||
|             className="grid grid-flow-col place-content-start gap-1 overflow-scroll | ||||
|           scrollbar-none"> | ||||
|             {bottomChips.map((text, index) => ( | ||||
|               <Chip key={index} className="text-sm" text={text} /> | ||||
|             ))} | ||||
|           </div> | ||||
|         )} | ||||
|       </div> | ||||
|     </div> | ||||
|   </Link> | ||||
|   </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"; | ||||
|  | ||||
							
								
								
									
										966
									
								
								src/pages/dev/showcase/design-system.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										966
									
								
								src/pages/dev/showcase/design-system.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -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", | ||||
|     }, | ||||
|     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: { | ||||
|       boxShadow: { | ||||
|         "inner-sm": "inset 0 1px 4px -2px", | ||||
|       }, | ||||
|       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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint