Refactor badge text truncation

This commit is contained in:
Sam Becker 2025-01-28 20:06:28 -06:00
parent c692e95693
commit 031c296796
15 changed files with 127 additions and 47 deletions

View File

@ -1,5 +1,6 @@
'use client';
import Badge from '@/components/Badge';
import DivDebugBaselineGrid from '@/components/DivDebugBaselineGrid';
import FieldSetWithStatus from '@/components/FieldSetWithStatus';
import SiteGrid from '@/components/SiteGrid';
@ -8,12 +9,12 @@ import LabeledIcon from '@/components/primitives/LabeledIcon';
import PhotoFilmSimulationIcon from '@/simulation/PhotoFilmSimulationIcon';
import { useAppState } from '@/state/AppState';
import { clsx } from 'clsx/lite';
import { useState } from 'react';
import { useEffect, 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);
const DEBUG_LINES = new Array(30).fill(null);
export default function ComponentsPage() {
const {
@ -23,6 +24,11 @@ export default function ComponentsPage() {
const [debugComponents, setDebugComponents] = useState(false);
useEffect(() => {
setShouldShowBaselineGrid?.(true);
return () => setShouldShowBaselineGrid?.(false);
}, [setShouldShowBaselineGrid]);
return (
<SiteGrid
contentMain={<>
@ -99,21 +105,6 @@ export default function ComponentsPage() {
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 />}
@ -162,6 +153,7 @@ export default function ComponentsPage() {
icon={<PhotoFilmSimulationIcon simulation="astia" />}
label="Astia/Soft"
type="icon-last"
iconWide
badged
debug={debugComponents}
/>
@ -176,9 +168,67 @@ export default function ComponentsPage() {
Image
</LabeledIcon>
</div>
<div>
<EntityLink
icon={<></>}
label="Astia/Soft and another long line here"
type="icon-last"
iconWide
badged
debug={debugComponents}
/>
</div>
<div>
<LabeledIcon icon={<FaUserAltSlash />} debug={debugComponents}>
Image
</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 className="flex items-center h-baseline">
<Badge type="small" uppercase>Optional</Badge>
</div>
<div className="flex items-center h-baseline">
<Badge type="small">Optional</Badge>
</div>
<div className="flex items-center h-baseline">
<Badge type="small" uppercase>Optional</Badge>
</div>
<div className="flex items-center h-baseline">
<Badge type="small">Optional</Badge>
</div>
<div className="flex items-center h-baseline">
<Badge type="small" uppercase>Optional</Badge>
</div>
<div className="flex items-center h-baseline">
<Badge type="small">Optional</Badge>
</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',
debugComponents && '[&>*]:bg-gray-300 [&>*]:dark:bg-gray-700',
'[&>*]:flex',
)}>
{DEBUG_LINES.map((_, i) =>

View File

@ -54,7 +54,7 @@ function AdminChildPage({
<Badge
dimContent={isLoading}
className={clsx(
breadcrumbEllipsis && 'text-ellipsis truncate',
breadcrumbEllipsis && 'truncate',
)}
>
{breadcrumb}

View File

@ -21,14 +21,14 @@ export default function Badge({
switch (type) {
case 'large':
return clsx(
'px-1.5 py-[0.3rem] rounded-md',
'px-1.5 h-[26px]',
'rounded-md',
'bg-gray-100/80 dark:bg-gray-900/80',
'border border-gray-200/60 dark:border-gray-800/75',
);
case 'small':
return clsx(
'h-max-baseline',
'px-[5px] py-[2.75px]',
'px-[5px] h-[17px] md:h-[18px]',
'text-[0.7rem] font-medium rounded-[0.25rem]',
highContrast
? 'text-invert bg-invert'
@ -44,12 +44,16 @@ export default function Badge({
};
return (
<span className={clsx(
'leading-none',
'max-w-full',
'inline-flex items-center',
stylesForType(),
uppercase && 'uppercase tracking-wider',
className,
)}>
<span className={clsx(dimContent && 'opacity-50')}>
<span className={clsx(
'max-w-full truncate',
dimContent && 'opacity-50',
)}>
{children}
</span>
</span>

View File

@ -3,6 +3,7 @@ import { clsx } from 'clsx/lite';
import ExperimentalBadge from './ExperimentalBadge';
import Badge from './Badge';
import ResponsiveText from './primitives/ResponsiveText';
import { parameterize } from '@/utility/string';
export default function Checklist({
title,
@ -19,13 +20,19 @@ export default function Checklist({
experimental?: boolean
children: ReactNode
}) {
const slug = parameterize(title);
return (
<div>
<div className={clsx(
'inline-flex items-center',
'text-gray-600 dark:text-gray-300',
'pl-[18px] mb-3 text-lg',
)}>
<a
id={slug}
href={`#${slug}`}
className={clsx(
'inline-flex items-center',
'text-gray-600 dark:text-gray-300',
'pl-[18px] py-3 text-lg',
)}
>
<span className="w-7 shrink-0">{icon}</span>
<span className="inline-flex flex-wrap items-center gap-y-1 gap-x-1.5">
<ResponsiveText shortText={titleShort}>
@ -38,7 +45,7 @@ export default function Checklist({
{experimental &&
<ExperimentalBadge className="translate-y-[0.5px]" />}
</span>
</div>
</a>
<div className={clsx(
'bg-white dark:bg-black',
'dark:text-gray-400',

View File

@ -222,7 +222,7 @@ export default function ImageInput({
/>
</label>
{showUploadStatus && filesLength > 0 &&
<div className="max-w-full truncate text-ellipsis">
<div className="max-w-full truncate">
{fileUploadName}
</div>}
</div>

View File

@ -48,7 +48,7 @@ export default function CommandKItem({
>
<div className="flex items-center gap-2 sm:gap-3">
{accessory}
<span className="grow text-ellipsis truncate">
<span className="grow truncate">
{label}
</span>
{annotation && !loading &&

View File

@ -22,6 +22,7 @@ export default function EntityLink({
prefetch,
title,
hoverEntity,
className,
debug,
}: {
icon: ReactNode
@ -33,6 +34,7 @@ export default function EntityLink({
title?: string
hoverEntity?: ReactNode
debug?: boolean
className?: string
} & EntityLinkExternalProps) {
const classForContrast = () => {
switch (contrast) {
@ -55,7 +57,10 @@ export default function EntityLink({
</>;
return (
<span className="group inline-flex gap-2">
<span className={clsx(
'group inline-flex gap-2 w-full',
className,
)}>
<LabeledIcon {...{
icon,
iconWide,

View File

@ -22,7 +22,7 @@ export default function Icon({
'h-[18px] md:h-[20px]',
wide ? 'w-[28px]' : 'w-[14px]',
'inline-flex items-center justify-center',
debug && 'bg-gray-700',
debug && 'bg-gray-300 dark:bg-gray-700',
className,
)}>
{loading

View File

@ -27,7 +27,7 @@ export default function LabeledIcon({
debug?: boolean,
} & Partial<ComponentProps<typeof Link>>) {
const className = clsx(
'inline-flex gap-x-1 md:gap-x-1.5',
'inline-flex gap-x-1 md:gap-x-1.5 min-w-0',
classNameProp,
debug && 'border border-green-500 m-[-1px]',
);
@ -43,8 +43,8 @@ export default function LabeledIcon({
</Icon>}
{children && type !== 'icon-only' &&
<span className={clsx(
'uppercase',
debug && 'bg-gray-700',
'uppercase overflow-hidden',
debug && 'bg-gray-300 dark:bg-gray-700',
)}>
{children}
</span>}

View File

@ -81,7 +81,7 @@ export default function PhotoHeader({
selectedPhoto !== undefined &&
<PhotoLink
photo={selectedPhoto}
className="uppercase font-bold text-ellipsis truncate"
className="uppercase font-bold truncate"
>
{titleForPhoto(selectedPhoto, true)}
</PhotoLink>);
@ -112,12 +112,18 @@ export default function PhotoHeader({
? 'col-span-2 sm:col-span-1 lg:col-span-2'
: 'col-span-2 sm:col-span-1'
: isGridHighDensity
? 'col-span-3 sm:col-span-3 lg:col-span-5'
: 'col-span-3 md:col-span-2 lg:col-span-3',
? 'col-span-3 sm:col-span-3 lg:col-span-5 w-[110%] xl:w-full'
: 'col-span-3 md:col-span-2 lg:col-span-3 w-[110%] xl:w-full',
)}>
{headerType === 'photo-detail-with-entity'
? renderContentA()
: <h1>{renderContentA()}</h1>}
// Necessary for title truncation
: <h1 className={clsx(
'w-full truncate',
headerType !== 'photo-detail' && 'sm:pr-2',
)}>
{renderContentA()}
</h1>}
</div>
{/* Content B: Filter Set Meta or Photo Pagination */}
<div className={clsx(

View File

@ -101,7 +101,11 @@ export default function PhotoPrevNext({
'flex items-center',
className,
)}>
<div className="flex items-center gap-2 select-none">
<div className={clsx(
'flex gap-2 select-none',
// Fixes alignment issue when switching from chevrons to text
'items-center sm:items-start',
)}>
<PhotoLink
photo={previousPhoto}
className="select-none h-[1rem]"

View File

@ -206,7 +206,7 @@ export default function SiteChecklistClient({
return (
<div className="max-w-xl w-full">
<div className="space-y-6">
<div className="space-y-3 -mt-3">
<Checklist
title="Storage"
icon={<BiData size={16} />}

View File

@ -190,6 +190,10 @@
@apply
gap-[1.1875rem] md:gap-[1.25rem]
}
.h-baseline {
@apply
h-[1.1875rem] md:h-[1.25rem]
}
.max-h-baseline {
@apply
max-h-[1.1875rem] md:max-h-[1.25rem]

View File

@ -18,11 +18,11 @@ export default function FavsTag({
return (
<EntityLink
label={badged
? <span className="inline-flex gap-1">
? <span className="inline-flex gap-1 items-center">
{TAG_FAVS}
<FaStar
size={10}
className="text-amber-500"
className="text-amber-500 translate-y-[-0.5px]"
/>
</span>
: TAG_FAVS}

View File

@ -17,11 +17,11 @@ export default function HiddenTag({
return (
<EntityLink
label={badged
? <span className="inline-flex gap-1">
? <span className="inline-flex items-center gap-1">
{TAG_HIDDEN}
<AiOutlineEyeInvisible
size={13}
className="translate-y-[-1.5px]"
className="translate-y-[-0.5px]"
/>
</span>
: TAG_HIDDEN}