Merge pull request #73 from sambecker/component-primitives
Enforce global baseline grid
This commit is contained in:
commit
6fbb9fc1f4
193
src/app/admin/baseline/page.tsx
Normal file
193
src/app/admin/baseline/page.tsx
Normal file
@ -0,0 +1,193 @@
|
||||
'use client';
|
||||
|
||||
import FieldSetWithStatus from '@/components/FieldSetWithStatus';
|
||||
import EntityLink from '@/components/primitives/EntityLink';
|
||||
import LabeledIcon from '@/components/primitives/LabeledIcon';
|
||||
import PhotoFilmSimulationIcon from '@/simulation/PhotoFilmSimulationIcon';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import { useState } from 'react';
|
||||
import { FaCamera, FaHandSparkles, FaUserAltSlash } from 'react-icons/fa';
|
||||
import { IoMdCamera } from 'react-icons/io';
|
||||
import { IoImageSharp } from 'react-icons/io5';
|
||||
|
||||
const DEBUG_LINES = new Array(22).fill(null);
|
||||
|
||||
export default function ComponentsPage() {
|
||||
const [_debugGrid, setDebugGrid] = useState('true');
|
||||
const [_debugComponents, setDebugComponents] = useState('false');
|
||||
|
||||
const debugGrid = _debugGrid === 'true';
|
||||
const debugComponents = _debugComponents === 'true';
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className="flex mb-6">
|
||||
<div className="grow">
|
||||
<span>Baseline Grid: </span>
|
||||
<span className="text-dim">
|
||||
<span className="md:hidden">13px / 18px</span>
|
||||
<span className="hidden md:inline-block">14px / 20px</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className={clsx(
|
||||
'flex gap-1',
|
||||
'[&>*]:inline-flex [&>*]:gap-1 [&_input]:-translate-y-0.5',
|
||||
)}>
|
||||
<FieldSetWithStatus
|
||||
id="grid"
|
||||
label="Grid"
|
||||
type="checkbox"
|
||||
value={_debugGrid}
|
||||
onChange={setDebugGrid}
|
||||
/>
|
||||
<FieldSetWithStatus
|
||||
id="components"
|
||||
label="Components"
|
||||
type="checkbox"
|
||||
value={_debugComponents}
|
||||
onChange={setDebugComponents}
|
||||
/>
|
||||
</div>
|
||||
</h1>
|
||||
<div
|
||||
className={clsx(
|
||||
'flex gap-8',
|
||||
debugGrid && 'bg-baseline-grid'
|
||||
)}
|
||||
>
|
||||
<div className="[&>*]:flex">
|
||||
<div>
|
||||
<LabeledIcon
|
||||
icon={<FaCamera size={12} />}
|
||||
debug={debugComponents}
|
||||
>
|
||||
Camera<br />Line two
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<IoImageSharp />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<EntityLink
|
||||
icon={<FaHandSparkles />}
|
||||
label="Image"
|
||||
debug={debugComponents}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<EntityLink
|
||||
icon={<FaHandSparkles />}
|
||||
label="Image"
|
||||
badged
|
||||
debug={debugComponents}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon
|
||||
icon={<IoMdCamera size={12} />}
|
||||
debug={debugComponents}
|
||||
>
|
||||
Canon Mark III
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<EntityLink
|
||||
icon={<PhotoFilmSimulationIcon simulation="astia" />}
|
||||
label="Astia/Soft"
|
||||
type="icon-last"
|
||||
iconWide
|
||||
badged
|
||||
debug={debugComponents}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<EntityLink
|
||||
icon={<PhotoFilmSimulationIcon simulation="astia" />}
|
||||
label="Astia/Soft"
|
||||
type="icon-last"
|
||||
badged
|
||||
debug={debugComponents}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
|
||||
Image
|
||||
</LabeledIcon>
|
||||
</div>
|
||||
</div>
|
||||
<div className={clsx(
|
||||
debugComponents && '[&>*]:bg-gray-800',
|
||||
'[&>*]:flex',
|
||||
)}>
|
||||
{DEBUG_LINES.map((_, i) =>
|
||||
<div key={i}>
|
||||
Line {(i + 1).toString().padStart(2, '0')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -21,7 +21,7 @@ export default function CameraHeader({
|
||||
const camera = cameraFromPhoto(photos[0], cameraProp);
|
||||
return (
|
||||
<PhotoSetHeader
|
||||
entity={<PhotoCamera {...{ camera }} hideAppleIcon />}
|
||||
entity={<PhotoCamera {...{ camera }} contrast="high" hideAppleIcon />}
|
||||
entityVerb="Photo"
|
||||
entityDescription={
|
||||
descriptionForCameraPhotos(photos, undefined, count, dateRange)}
|
||||
|
||||
@ -2,7 +2,9 @@ import { AiFillApple } from 'react-icons/ai';
|
||||
import { pathForCamera } from '@/site/paths';
|
||||
import { IoMdCamera } from 'react-icons/io';
|
||||
import { Camera, formatCameraText } from '.';
|
||||
import EntityLink, { EntityLinkExternalProps } from '@/components/EntityLink';
|
||||
import EntityLink, {
|
||||
EntityLinkExternalProps,
|
||||
} from '@/components/primitives/EntityLink';
|
||||
|
||||
export default function PhotoCamera({
|
||||
camera,
|
||||
@ -31,7 +33,7 @@ export default function PhotoCamera({
|
||||
/>
|
||||
: <IoMdCamera
|
||||
size={12}
|
||||
className="translate-x-[-1px] translate-y-[3.5px]"
|
||||
className="translate-x-[-1px]"
|
||||
/>}
|
||||
type={showAppleIcon && isCameraApple ? 'icon-first' : type}
|
||||
badged={badged}
|
||||
|
||||
@ -27,8 +27,9 @@ export default function Badge({
|
||||
);
|
||||
case 'small':
|
||||
return clsx(
|
||||
'px-[0.3rem] py-1 rounded-[0.25rem]',
|
||||
'text-[0.7rem] font-medium',
|
||||
'h-max-baseline',
|
||||
'px-[5px] py-[2.75px]',
|
||||
'text-[0.7rem] font-medium rounded-[0.25rem]',
|
||||
highContrast
|
||||
? 'text-invert bg-invert'
|
||||
: 'text-medium bg-gray-300/30 dark:bg-gray-700/50',
|
||||
|
||||
@ -1,97 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
import { ReactNode } from 'react';
|
||||
import Badge from './Badge';
|
||||
import { clsx } from 'clsx/lite';
|
||||
|
||||
export interface EntityLinkExternalProps {
|
||||
type?: 'icon-last' | 'icon-first' | 'icon-only' | 'text-only'
|
||||
badged?: boolean
|
||||
contrast?: 'low' | 'medium' | 'high'
|
||||
}
|
||||
|
||||
export default function EntityLink({
|
||||
label,
|
||||
labelSmall,
|
||||
href,
|
||||
icon,
|
||||
title,
|
||||
type = 'icon-first',
|
||||
badged,
|
||||
contrast = 'high',
|
||||
hoverEntity,
|
||||
}: {
|
||||
label: ReactNode
|
||||
labelSmall?: ReactNode
|
||||
href: string
|
||||
icon?: ReactNode
|
||||
title?: string
|
||||
hoverEntity?: ReactNode
|
||||
} & EntityLinkExternalProps) {
|
||||
const renderLabel = () => <>
|
||||
<span className="xs:hidden">
|
||||
{labelSmall ?? label}
|
||||
</span>
|
||||
<span className="hidden xs:inline-block">
|
||||
{label}
|
||||
</span>
|
||||
</>;
|
||||
|
||||
const classForContrast = () => {
|
||||
switch (contrast) {
|
||||
case 'low':
|
||||
return 'text-dim';
|
||||
case 'high':
|
||||
return 'text-main';
|
||||
default:
|
||||
return 'text-medium';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<span className="group inline-flex items-center gap-2 h-5">
|
||||
<Link
|
||||
href={href}
|
||||
title={title}
|
||||
className={clsx(
|
||||
'inline-flex gap-[0.23rem]',
|
||||
!badged && 'text-main hover:text-gray-900 dark:hover:text-gray-100',
|
||||
classForContrast(),
|
||||
)}
|
||||
>
|
||||
{type !== 'icon-only' && <>
|
||||
{badged
|
||||
? <span className="h-6 inline-flex items-center">
|
||||
<Badge
|
||||
type="small"
|
||||
highContrast={contrast === 'high'}
|
||||
uppercase
|
||||
interactive
|
||||
>
|
||||
{renderLabel()}
|
||||
</Badge>
|
||||
</span>
|
||||
: <span className="uppercase">
|
||||
{renderLabel()}
|
||||
</span>}
|
||||
</>}
|
||||
{icon && type !== 'text-only' &&
|
||||
<span className={clsx(
|
||||
'flex-shrink-0',
|
||||
'inline-flex min-w-[0.9rem]',
|
||||
contrast === 'high'
|
||||
? 'text-icon'
|
||||
: classForContrast(),
|
||||
type === 'icon-first' && 'order-first',
|
||||
badged && 'translate-y-[4px]',
|
||||
hoverEntity !== undefined && 'group-hover:hidden',
|
||||
)}>
|
||||
{icon}
|
||||
</span>}
|
||||
</Link>
|
||||
{hoverEntity !== undefined &&
|
||||
<span className="hidden group-hover:inline">
|
||||
{hoverEntity}
|
||||
</span>}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -110,9 +110,8 @@ export default function OGTile({
|
||||
/>}
|
||||
</div>
|
||||
<div className={clsx(
|
||||
'md:text-lg',
|
||||
'font-sans leading-tight',
|
||||
'flex flex-col gap-1 p-3',
|
||||
'font-sans leading-none',
|
||||
'bg-gray-50 dark:bg-gray-900/50',
|
||||
'group-active:bg-gray-50 group-active:dark:bg-gray-900/50',
|
||||
'group-hover:bg-gray-100 group-hover:dark:bg-gray-900/70',
|
||||
|
||||
@ -24,7 +24,7 @@ export default function ShareModal({
|
||||
<div className="space-y-3 md:space-y-4 w-full">
|
||||
<div className={clsx(
|
||||
'flex items-center gap-x-3',
|
||||
'text-xl md:text-3xl leading-snug',
|
||||
'text-2xl leading-snug',
|
||||
)}>
|
||||
<TbPhotoShare size={22} className="hidden xs:block" />
|
||||
<div className="flex-grow">
|
||||
|
||||
89
src/components/primitives/EntityLink.tsx
Normal file
89
src/components/primitives/EntityLink.tsx
Normal file
@ -0,0 +1,89 @@
|
||||
import { ReactNode } from 'react';
|
||||
import LabeledIcon, { LabeledIconType } from './LabeledIcon';
|
||||
import Badge from '../Badge';
|
||||
import { clsx } from 'clsx/lite';
|
||||
|
||||
export interface EntityLinkExternalProps {
|
||||
type?: LabeledIconType
|
||||
badged?: boolean
|
||||
contrast?: 'low' | 'medium' | 'high'
|
||||
}
|
||||
|
||||
export default function EntityLink({
|
||||
icon,
|
||||
label,
|
||||
labelSmall,
|
||||
iconWide,
|
||||
type,
|
||||
badged,
|
||||
contrast = 'medium',
|
||||
href,
|
||||
prefetch,
|
||||
title,
|
||||
hoverEntity,
|
||||
debug,
|
||||
}: {
|
||||
icon: ReactNode
|
||||
label: ReactNode
|
||||
labelSmall?: ReactNode
|
||||
iconWide?: boolean
|
||||
href?: string
|
||||
prefetch?: boolean
|
||||
title?: string
|
||||
hoverEntity?: ReactNode
|
||||
debug?: boolean
|
||||
} & EntityLinkExternalProps) {
|
||||
const classForContrast = () => {
|
||||
switch (contrast) {
|
||||
case 'low':
|
||||
return 'text-dim';
|
||||
case 'high':
|
||||
return 'text-main';
|
||||
default:
|
||||
return 'text-medium';
|
||||
}
|
||||
};
|
||||
|
||||
const renderLabel = () => <>
|
||||
<span className="xs:hidden">
|
||||
{labelSmall ?? label}
|
||||
</span>
|
||||
<span className="hidden xs:inline-block">
|
||||
{label}
|
||||
</span>
|
||||
</>;
|
||||
|
||||
return (
|
||||
<span className="group inline-flex gap-2">
|
||||
<LabeledIcon {...{
|
||||
icon,
|
||||
iconWide,
|
||||
href,
|
||||
prefetch,
|
||||
title,
|
||||
type,
|
||||
className: clsx(
|
||||
classForContrast(),
|
||||
href && !badged && 'hover:text-gray-900 dark:hover:text-gray-100',
|
||||
),
|
||||
debug,
|
||||
}}>
|
||||
{badged
|
||||
? <Badge
|
||||
type="small"
|
||||
highContrast={contrast === 'high'}
|
||||
className='translate-y-[-0.5px]'
|
||||
uppercase
|
||||
interactive
|
||||
>
|
||||
{renderLabel()}
|
||||
</Badge>
|
||||
: renderLabel()}
|
||||
</LabeledIcon>
|
||||
{hoverEntity !== undefined &&
|
||||
<span className="hidden group-hover:inline">
|
||||
{hoverEntity}
|
||||
</span>}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
35
src/components/primitives/Icon.tsx
Normal file
35
src/components/primitives/Icon.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import Spinner from '../Spinner';
|
||||
|
||||
export default function Icon({
|
||||
children,
|
||||
className,
|
||||
iconClassName,
|
||||
wide,
|
||||
loading,
|
||||
debug,
|
||||
}: {
|
||||
children: ReactNode
|
||||
className?: string
|
||||
iconClassName?: string
|
||||
wide?: boolean
|
||||
loading?: boolean
|
||||
debug?: boolean,
|
||||
}) {
|
||||
return (
|
||||
<span className={clsx(
|
||||
'h-[18px] md:h-[20px]',
|
||||
wide ? 'w-[28px]' : 'w-[14px]',
|
||||
'inline-flex items-center justify-center',
|
||||
debug && 'bg-gray-700',
|
||||
className,
|
||||
)}>
|
||||
{loading
|
||||
? <Spinner />
|
||||
: <span className={iconClassName}>
|
||||
{children}
|
||||
</span>}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
60
src/components/primitives/LabeledIcon.tsx
Normal file
60
src/components/primitives/LabeledIcon.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import { ComponentProps, ReactNode } from 'react';
|
||||
import Icon from './Icon';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import Link from 'next/link';
|
||||
|
||||
export type LabeledIconType =
|
||||
'icon-first' |
|
||||
'icon-last' |
|
||||
'icon-only' |
|
||||
'text-only';
|
||||
|
||||
export default function LabeledIcon({
|
||||
icon,
|
||||
type = 'icon-first',
|
||||
className: classNameProp,
|
||||
children,
|
||||
iconWide,
|
||||
href,
|
||||
prefetch,
|
||||
debug,
|
||||
}: {
|
||||
icon?: ReactNode,
|
||||
type?: LabeledIconType,
|
||||
className?: string,
|
||||
children: ReactNode,
|
||||
iconWide?:boolean,
|
||||
debug?: boolean,
|
||||
} & Partial<ComponentProps<typeof Link>>) {
|
||||
const className = clsx(
|
||||
'inline-flex gap-x-1 md:gap-x-1.5',
|
||||
classNameProp,
|
||||
debug && 'border border-green-500 m-[-1px]',
|
||||
);
|
||||
|
||||
const renderContent = () => <>
|
||||
{icon && type !== 'text-only' &&
|
||||
<Icon {...{
|
||||
className: clsx(type === 'icon-last' && 'order-1'),
|
||||
wide: iconWide,
|
||||
debug,
|
||||
}}>
|
||||
{icon}
|
||||
</Icon>}
|
||||
{children && type !== 'icon-only' &&
|
||||
<span className={clsx(
|
||||
'uppercase',
|
||||
debug && 'bg-gray-700'
|
||||
)}>
|
||||
{children}
|
||||
</span>}
|
||||
</>;
|
||||
|
||||
return href
|
||||
? <Link {...{ href, prefetch, className }}>
|
||||
{renderContent()}
|
||||
</Link>
|
||||
: <div {...{ className }}>
|
||||
{renderContent()}
|
||||
</div>;
|
||||
}
|
||||
@ -65,10 +65,9 @@ export default function PhotoLarge({
|
||||
contentSide={
|
||||
<div className={clsx(
|
||||
'relative',
|
||||
'leading-snug',
|
||||
'sticky top-4 self-start -translate-y-1',
|
||||
'grid grid-cols-2 md:grid-cols-1',
|
||||
'gap-x-0.5 sm:gap-x-1 gap-y-4',
|
||||
'gap-x-0.5 sm:gap-x-1 gap-y-baseline',
|
||||
'pb-6',
|
||||
)}>
|
||||
{/* Meta */}
|
||||
@ -88,7 +87,7 @@ export default function PhotoLarge({
|
||||
</div>
|
||||
</Suspense>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-baseline">
|
||||
{photo.caption &&
|
||||
<div className="uppercase">
|
||||
{photo.caption}
|
||||
@ -106,7 +105,7 @@ export default function PhotoLarge({
|
||||
</div>
|
||||
</div>
|
||||
{/* EXIF Data */}
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-baseline">
|
||||
{showExifContent &&
|
||||
<>
|
||||
<ul className="text-medium">
|
||||
@ -134,8 +133,8 @@ export default function PhotoLarge({
|
||||
/>}
|
||||
</>}
|
||||
<div className={clsx(
|
||||
'flex gap-2',
|
||||
'md:flex-col md:gap-4 md:justify-normal',
|
||||
'flex gap-x-1.5 gap-y-baseline',
|
||||
'md:flex-col md:justify-normal',
|
||||
)}>
|
||||
<div className={clsx(
|
||||
'text-medium uppercase pr-1',
|
||||
|
||||
@ -2,7 +2,9 @@ import { labelForFilmSimulation } from '@/vendors/fujifilm';
|
||||
import PhotoFilmSimulationIcon from './PhotoFilmSimulationIcon';
|
||||
import { pathForFilmSimulation } from '@/site/paths';
|
||||
import { FilmSimulation } from '.';
|
||||
import EntityLink, { EntityLinkExternalProps } from '@/components/EntityLink';
|
||||
import EntityLink, {
|
||||
EntityLinkExternalProps,
|
||||
} from '@/components/primitives/EntityLink';
|
||||
|
||||
export default function PhotoFilmSimulation({
|
||||
simulation,
|
||||
@ -21,15 +23,13 @@ export default function PhotoFilmSimulation({
|
||||
label={medium}
|
||||
labelSmall={small}
|
||||
href={pathForFilmSimulation(simulation)}
|
||||
icon={<PhotoFilmSimulationIcon
|
||||
simulation={simulation}
|
||||
className="translate-y-[-1px]"
|
||||
/>}
|
||||
icon={<PhotoFilmSimulationIcon simulation={simulation} />}
|
||||
title={`Film Simulation: ${large}`}
|
||||
type={type}
|
||||
badged={badged}
|
||||
contrast={contrast}
|
||||
hoverEntity={countOnHover}
|
||||
iconWide
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ export default function FooterClient({
|
||||
'flex items-center',
|
||||
'text-dim min-h-[4rem]',
|
||||
)}>
|
||||
<div className="flex gap-x-4 gap-y-1 flex-grow flex-wrap h-4">
|
||||
<div className="flex gap-x-4 gap-y-0.5 flex-grow flex-wrap">
|
||||
{isPathAdmin(pathname)
|
||||
? <>
|
||||
{userEmail === undefined &&
|
||||
|
||||
@ -57,7 +57,6 @@ export default function NavClient({
|
||||
className={clsx(
|
||||
'flex items-center',
|
||||
'w-full min-h-[4rem]',
|
||||
'leading-none',
|
||||
)}>
|
||||
<div className="flex-grow">
|
||||
<ViewSwitcher
|
||||
|
||||
@ -138,7 +138,7 @@ export default function SiteChecklistClient({
|
||||
</div>;
|
||||
|
||||
return (
|
||||
<div className="text-sm max-w-xl space-y-6 w-full">
|
||||
<div className="max-w-xl space-y-6 w-full">
|
||||
<Checklist
|
||||
title="Storage"
|
||||
icon={<BiData size={16} />}
|
||||
|
||||
@ -116,7 +116,7 @@
|
||||
hover:text-gray-600
|
||||
hover:dark:text-gray-400
|
||||
}
|
||||
/* Common Utilities: Text */
|
||||
/* Utilities: Text */
|
||||
.text-main {
|
||||
@apply
|
||||
text-gray-900 dark:text-gray-100
|
||||
@ -145,7 +145,7 @@
|
||||
@apply
|
||||
text-red-500 dark:text-red-400
|
||||
}
|
||||
/* Common Utilities: Background */
|
||||
/* Utilities: Background */
|
||||
.bg-main {
|
||||
@apply
|
||||
bg-white dark:bg-black
|
||||
@ -159,4 +159,28 @@
|
||||
@apply
|
||||
bg-gray-900 dark:bg-gray-100
|
||||
}
|
||||
/* Utilities: Baseline Grid */
|
||||
.space-y-baseline {
|
||||
@apply
|
||||
space-y-[1.1875rem] md:space-y-[1.25rem]
|
||||
}
|
||||
.gap-y-baseline {
|
||||
@apply
|
||||
gap-y-[1.1875rem] md:gap-y-[1.25rem]
|
||||
}
|
||||
.gap-baseline {
|
||||
@apply
|
||||
gap-[1.1875rem] md:gap-[1.25rem]
|
||||
}
|
||||
.max-h-baseline {
|
||||
@apply
|
||||
max-h-[1.1875rem] md:max-h-[1.25rem]
|
||||
}
|
||||
.bg-baseline-grid {
|
||||
@apply
|
||||
bg-[repeating-linear-gradient(to_bottom,#eee,#eee_1px,transparent_1px,transparent_1.1875rem)]
|
||||
md:bg-[repeating-linear-gradient(to_bottom,#eee,#eee_1px,transparent_1px,transparent_1.25rem)]
|
||||
dark:bg-[repeating-linear-gradient(to_bottom,#222,#222_1px,transparent_1px,transparent_1.1875rem)]
|
||||
dark:md:bg-[repeating-linear-gradient(to_bottom,#222,#222_1px,transparent_1px,transparent_1.25rem)]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { FaStar } from 'react-icons/fa';
|
||||
import EntityLink, { EntityLinkExternalProps } from '@/components/EntityLink';
|
||||
import { TAG_FAVS } from '.';
|
||||
import { pathForTag } from '@/site/paths';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import EntityLink, {
|
||||
EntityLinkExternalProps,
|
||||
} from '@/components/primitives/EntityLink';
|
||||
|
||||
export default function FavsTag({
|
||||
type,
|
||||
@ -30,7 +32,7 @@ export default function FavsTag({
|
||||
size={12}
|
||||
className={clsx(
|
||||
'text-amber-500',
|
||||
'translate-x-[-1px] translate-y-[3.5px]',
|
||||
'translate-x-[-1px] translate-y-[-0.5px]',
|
||||
)}
|
||||
/>}
|
||||
type={type}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import { pathForTag } from '@/site/paths';
|
||||
import { FaTag } from 'react-icons/fa';
|
||||
import { formatTag } from '.';
|
||||
import EntityLink, { EntityLinkExternalProps } from '@/components/EntityLink';
|
||||
import EntityLink, {
|
||||
EntityLinkExternalProps,
|
||||
} from '@/components/primitives/EntityLink';
|
||||
|
||||
export default function PhotoTag({
|
||||
tag,
|
||||
@ -19,7 +21,7 @@ export default function PhotoTag({
|
||||
href={pathForTag(tag)}
|
||||
icon={<FaTag
|
||||
size={11}
|
||||
className="translate-y-[5px]"
|
||||
className="translate-y-[1px]"
|
||||
/>}
|
||||
type={type}
|
||||
badged={badged}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import PhotoTag from '@/tag/PhotoTag';
|
||||
import { isTagFavs } from '.';
|
||||
import FavsTag from './FavsTag';
|
||||
import { EntityLinkExternalProps } from '@/components/EntityLink';
|
||||
import { EntityLinkExternalProps } from '@/components/primitives/EntityLink';
|
||||
|
||||
export default function PhotoTags({
|
||||
tags,
|
||||
@ -10,13 +10,13 @@ export default function PhotoTags({
|
||||
tags: string[]
|
||||
} & EntityLinkExternalProps) {
|
||||
return (
|
||||
<div className="-space-y-0.5">
|
||||
<div className="flex flex-col">
|
||||
{tags.map(tag =>
|
||||
<div key={tag}>
|
||||
<>
|
||||
{isTagFavs(tag)
|
||||
? <FavsTag {...{ contrast }} />
|
||||
: <PhotoTag {...{ tag, contrast }} />}
|
||||
</div>)}
|
||||
? <FavsTag {...{ key:tag, contrast }} />
|
||||
: <PhotoTag {...{ key:tag, tag, contrast }} />}
|
||||
</>)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ export default function TagHeader({
|
||||
<PhotoSetHeader
|
||||
entity={isTagFavs(tag)
|
||||
? <FavsTag />
|
||||
: <PhotoTag tag={tag} />}
|
||||
: <PhotoTag tag={tag} contrast="high" />}
|
||||
entityVerb="Tagged"
|
||||
entityDescription={descriptionForTaggedPhotos(photos, undefined, count)}
|
||||
photos={photos}
|
||||
|
||||
@ -12,13 +12,13 @@ module.exports = {
|
||||
...defaultTheme.screens,
|
||||
},
|
||||
fontSize: {
|
||||
'xs': '0.75rem',
|
||||
'sm': ['0.825rem', '1.15rem'],
|
||||
'base': ['0.875rem', '1.275rem'],
|
||||
'lg': ['0.925rem', '1.05rem'],
|
||||
'xl': '1rem',
|
||||
'2xl': '1.1rem',
|
||||
'3xl': ['1.3rem', '1.7rem'],
|
||||
'xs': ['0.75rem', '1rem'], // 12px on 16px
|
||||
'sm': ['0.84375rem', '1.1875rem'], // 13.5px on 19px [Default: mobile]
|
||||
'base': ['0.875rem', '1.25rem'], // 14px on 20px [Default: desktop]
|
||||
'lg': ['1rem', '1.25rem'], // 16px on 20px
|
||||
'xl': ['1.125rem', '1.25rem'], // 18px on 20px
|
||||
'2xl': ['1.25rem', '1.25rem'], // 20px on 20px
|
||||
'3xl': ['1.5rem', '1.5rem'], // 24px on 24px
|
||||
},
|
||||
extend: {
|
||||
fontFamily: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user