Skip to content

Commit

Permalink
feat(show/designers): collapse description by default
Browse files Browse the repository at this point in the history
This patch updates the "designers" section of the show page to collapse
the description by default and only show the entire thing if the user
clicks on the "show more" button.

Note that this implementation is WIP and does not have the best a11y,
but it works perfectly for the styles that I want. Eventually, I may
want to try using the `<Collapsible>` from Radix Primitives, but this
works for now.
  • Loading branch information
nicholaschiang committed Jul 24, 2023
1 parent ed19e4f commit 46628d3
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 48 deletions.
36 changes: 21 additions & 15 deletions app/components/avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as React from 'react'

import {
Avatar as AvatarRoot,
AvatarImage,
Expand All @@ -6,18 +8,22 @@ import {

type Source = { name: string; avatar?: string | null }

export function Avatar({ src }: { src?: Source | null }) {
return (
<AvatarRoot>
<AvatarImage src={src?.avatar ?? undefined} alt={src?.name} />
<AvatarFallback>
{src?.name
.split(' ')
.slice(0, 2)
.map((s) => s.substring(0, 1))
.join('')
.toUpperCase()}
</AvatarFallback>
</AvatarRoot>
)
}
const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarRoot>,
React.ComponentPropsWithoutRef<typeof AvatarRoot> & { src?: Source | null }
>(({ src, ...props }, ref) => (
<AvatarRoot ref={ref} {...props}>
<AvatarImage src={src?.avatar ?? undefined} alt={src?.name} />
<AvatarFallback>
{src?.name
.split(' ')
.slice(0, 2)
.map((s) => s.substring(0, 1))
.join('')
.toUpperCase()}
</AvatarFallback>
</AvatarRoot>
))
Avatar.displayName = AvatarRoot.displayName

export { Avatar }
80 changes: 57 additions & 23 deletions app/routes/shows.$showId/designers.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { type User } from '@prisma/client'
import { useLoaderData } from '@remix-run/react'
import { type SerializeFrom } from '@vercel/remix'
import { useState } from 'react'

import { Avatar } from 'components/avatar'
import { Empty } from 'components/empty'
import { ExternalLink } from 'components/external-link'

import { cn } from 'utils/cn'

import { type loader } from './route'
import { Section } from './section'

Expand All @@ -23,32 +28,61 @@ export function Designers() {
{designers.length > 0 && (
<ul className='mt-2 grid gap-2'>
{designers.map((designer) => (
<li key={designer.id}>
<Avatar src={designer} />
<h3 className='flex items-center group gap-1'>
{designer.name}
{designer.url != null && (
<ExternalLink
className='group-hover:opacity-100 opacity-0 transition-opacity text-gray-400 dark:text-gray-600'
href={designer.url}
/>
)}
</h3>
{designer.description != null && (
<article
className='prose prose-sm dark:prose-invert'
dangerouslySetInnerHTML={{ __html: designer.description }}
/>
)}
{designer.description == null && (
<Empty>
No designer description to show yet. Please check back later.
</Empty>
)}
</li>
<DesignerItem key={designer.id} designer={designer} />
))}
</ul>
)}
</Section>
)
}

function DesignerItem({ designer }: { designer: SerializeFrom<User> }) {
const [expanded, setExpanded] = useState(false)
return (
<li className='rounded-md shadow-sm p-4 flex gap-4 border border-gray-200 dark:border-gray-700'>
<Avatar src={designer} className='h-20 w-20' />
<div className={cn(!expanded && 'flex flex-1 flex-col h-0 min-h-full')}>
<h3 className='flex items-center group gap-1 font-medium'>
{designer.url == null && designer.name}
{designer.url != null && (
<ExternalLink
href={designer.url}
className='no-underline [&>svg]:opacity-0 [&>svg]:group-hover:opacity-100 [&>svg]:transition-opacity [&>svg]:text-gray-400 dark:[&>svg]:text-gray-600'
>
{designer.name}
</ExternalLink>
)}
</h3>
{designer.description != null && (
<div
className={cn(
'relative overflow-hidden',
!expanded && 'h-0 flex-1',
)}
>
<article
className='prose prose-sm dark:prose-invert max-w-none'
dangerouslySetInnerHTML={{ __html: designer.description }}
/>
<button
className={cn(
'w-full text-sm mt-2 underline',
!expanded &&
'absolute inset-x-0 bottom-0 pt-10 bg-gradient-to-t from-white dark:from-gray-950 to-transparent',
)}
type='button'
onClick={() => setExpanded(!expanded)}
>
{expanded ? 'Show less' : 'Show more'}
</button>
</div>
)}
{designer.description == null && (
<Empty className='py-2 mt-2'>
No designer description to show yet. Please check back later.
</Empty>
)}
</div>
</li>
)
}
6 changes: 3 additions & 3 deletions scripts/node/save/shows/hermes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ const designer: Prisma.UserCreateInput = {
url: 'https://fr.wikipedia.org/wiki/V%C3%A9ronique_Nichanian',
avatar: 'https://static.nicholas.engineering/designers/veronique-nichanian/avatar.jpg',
description: `
<p>Véronique Nichanian was born on May 3, 1954 in Boulogne-Billancourt.</p>
<p>
In 1976, she graduated from the Ecole de la Chambre Syndicale de la Couture
Parisienne. She started as
Véronique Nichanian was born on May 3, 1954 in Boulogne-Billancourt.In 1976,
she graduated from the Ecole de la Chambre Syndicale de la Couture Parisienne.
She started as
<a
target="_blank"
rel="noopener noreferrer"
Expand Down
11 changes: 4 additions & 7 deletions scripts/node/save/shows/isabel-marant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,10 @@ const designer: Prisma.UserCreateInput = {
description: `
<p>
Isabel Marant (born 12 April 1967) is a French fashion designer, owner of the
eponymous fashion brand.
</p>
<p>
She won the Award de la Mode (1997), the Whirlpool Award for best female
designer (1998), Fashion Designer of the Year at British Glamour's Women of
the Year Awards (2012). She was named Contemporary Designer of the Year at the
Elle Style Awards in 2014.
eponymous fashion brand. She won the Award de la Mode (1997), the Whirlpool
Award for best female designer (1998), Fashion Designer of the Year at British
Glamour's Women of the Year Awards (2012). She was named Contemporary Designer
of the Year at the Elle Style Awards in 2014.
</p>
<p>
Her collaboration with H&M in 2013 was so successful that company's website
Expand Down

0 comments on commit 46628d3

Please sign in to comment.