Skip to content

Commit

Permalink
Merge branch 'master' into hotfix/uws-cork
Browse files Browse the repository at this point in the history
  • Loading branch information
mattkrick authored Dec 4, 2023
2 parents 463e0dc + 619c07c commit 852683c
Show file tree
Hide file tree
Showing 20 changed files with 361 additions and 374 deletions.
138 changes: 104 additions & 34 deletions packages/client/components/ActivityLibrary/ActivityCard.tsx
Original file line number Diff line number Diff line change
@@ -1,68 +1,138 @@
import clsx from 'clsx'
import React, {ComponentPropsWithoutRef, PropsWithChildren} from 'react'
import React, {PropsWithChildren, useEffect, useRef, useState} from 'react'
import {upperFirst} from '../../utils/upperFirst'
import {MeetingTypeEnum} from '../../__generated__/NewMeetingQuery.graphql'
import {ActivityCard_template$key} from '../../__generated__/ActivityCard_template.graphql'
import {backgroundImgMap, CategoryID, MEETING_TYPE_TO_CATEGORY} from './Categories'
import {twMerge} from 'tailwind-merge'
import {Tooltip} from '../../ui/Tooltip/Tooltip'
import {TooltipTrigger} from '../../ui/Tooltip/TooltipTrigger'
import {TooltipContent} from '../../ui/Tooltip/TooltipContent'
import {useFragment} from 'react-relay'
import graphql from 'babel-plugin-relay/macro'
import {ActivityLibraryCardDescription} from './ActivityLibraryCardDescription'

export interface CardTheme {
primary: string
secondary: string
text: string
}

export const ActivityCardImage = (
props: PropsWithChildren<React.ImgHTMLAttributes<HTMLImageElement>>
) => {
const {className, src} = props

return (
<div
className={clsx(
'my-1 flex flex-1 items-center justify-center overflow-hidden px-4',
className
)}
>
<img className={'h-full w-full object-contain'} src={src} />
</div>
)
type ActivityCardImageProps = {
className?: string
src: string
category: CategoryID
}

const ActivityCardTitle = (props: ComponentPropsWithoutRef<'div'>) => {
const {children, className, ...rest} = props
export const ActivityCardImage = (props: PropsWithChildren<ActivityCardImageProps>) => {
const {className, src, category} = props
const backgroundSrc = backgroundImgMap[category]

return (
<div
className={clsx(
'px-2 py-1 text-sm font-semibold leading-5 text-slate-800 sm:text-base',
className={twMerge(
'relative flex h-full w-full items-center justify-center overflow-hidden',
className
)}
{...rest}
style={{backgroundImage: `url(${backgroundSrc})`, backgroundSize: 'cover'}}
>
{children}
<img
className='absolute top-0 left-0 z-10 h-full w-full object-contain p-10'
src={src}
alt='Card Illustration'
/>
</div>
)
}

export interface ActivityCardProps {
className?: string
theme: CardTheme
titleAs?: React.ElementType
title?: string
badge?: React.ReactNode
children?: React.ReactNode
type?: MeetingTypeEnum
templateRef?: ActivityCard_template$key
}

export const ActivityCard = (props: ActivityCardProps) => {
const {className, theme, title, titleAs, badge, children} = props
const Title = titleAs ?? ActivityCardTitle
const {className, theme, title, children, type, badge, templateRef} = props
const category = type && MEETING_TYPE_TO_CATEGORY[type]
const [showTooltip, setShowTooltip] = useState(false)
const hoverTimeout = useRef<NodeJS.Timeout | null>(null)

const template = useFragment(
graphql`
fragment ActivityCard_template on MeetingTemplate {
...ActivityLibraryCardDescription_template
}
`,
templateRef ?? null
)

const handleMouseEnter = () => {
hoverTimeout.current = setTimeout(() => {
setShowTooltip(true)
}, 500)
}

const handleMouseLeave = () => {
if (hoverTimeout.current) {
clearTimeout(hoverTimeout.current)
}
setShowTooltip(false)
}

useEffect(() => {
return () => {
if (hoverTimeout.current) {
clearTimeout(hoverTimeout.current)
}
}
}, [])

return (
<div className={clsx('flex flex-col overflow-hidden rounded-lg', theme.secondary, className)}>
<div className='flex flex-shrink-0'>
<Title>{title}</Title>
<div className={clsx('ml-auto h-8 w-8 flex-shrink-0 rounded-bl-full', theme.primary)} />
</div>
{children}
<div className='flex flex-shrink-0 group-hover/card:hidden'>
<div className={clsx('mt-auto h-8 w-8 flex-shrink-0 rounded-tr-full', theme.primary)} />
<div className='ml-auto'>{badge}</div>
<div
className='flex w-full flex-col'
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div
className={twMerge(
'relative flex h-full min-w-0 flex-col overflow-hidden rounded-lg',
`bg-${theme.secondary}`,
className
)}
>
<div className='flex-1'>
{children}
<div className='absolute bottom-0 right-0'>{badge}</div>
</div>
{template && (
<Tooltip open={showTooltip}>
<TooltipTrigger asChild>
<div className='h-50 w-50 text-sky-500 hover:text-sky-700' />
</TooltipTrigger>
<TooltipContent
side='bottom'
align='center'
sideOffset={20}
className='max-w-md whitespace-normal rounded-lg bg-white p-4 text-left text-slate-700 shadow-lg hover:cursor-pointer sm:max-w-sm'
>
<div className='mb-2 text-left text-lg font-semibold'>{title}</div>
<ActivityLibraryCardDescription templateRef={template} />
</TooltipContent>
</Tooltip>
)}
</div>
{title && category && (
<div className='mt-2 px-2 pb-2'>
<div className='truncate pb-1 text-lg leading-5 text-slate-800'>{title}</div>
<div className={clsx('font-semibold italic', `text-${theme.primary}`)}>
{upperFirst(category)}
</div>
</div>
)}
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const ActivityDetails = (props: Props) => {
})
}, [])

const {category, illustrationUrl, viewerLowestScope} = activity
const {category, illustrationUrl, viewerLowestScope, type} = activity
const prevCategory = history.location.state?.prevCategory
const categoryLink = `/activity-library/category/${
prevCategory ?? category ?? QUICK_START_CATEGORY_ID
Expand Down Expand Up @@ -112,11 +112,12 @@ const ActivityDetails = (props: Props) => {
)}
>
<ActivityCard
className='ml-14 mb-8 h-[200px] w-80 xl:ml-0 xl:mb-0'
className='ml-14 mb-8 max-h-[200px] w-80 xl:ml-0 xl:mb-0'
theme={CATEGORY_THEMES[category as CategoryID]}
badge={null}
type={type}
>
<ActivityCardImage src={illustrationUrl} />
<ActivityCardImage src={illustrationUrl} category={category as CategoryID} />
</ActivityCard>
<div className='pb-20'>
<div className='mb-10 space-y-2 pl-14'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const ActivityDetailsCategoryBadge = (props: Props) => {
<DropdownMenu.Trigger asChild disabled={!isEditing}>
<PlainButton className={clsx(!isEditing && 'cursor-default', 'flex')} disabled={false}>
<ActivityDetailsBadge
className={clsx(CATEGORY_THEMES[category].primary, 'select-none text-white')}
className={clsx(`bg-${CATEGORY_THEMES[category].primary}`, 'select-none text-white')}
>
{CATEGORY_ID_TO_NAME[category]}
</ActivityDetailsBadge>
Expand All @@ -59,7 +59,10 @@ const ActivityDetailsCategoryBadge = (props: Props) => {
value={categoryId}
>
<span
className={clsx(CATEGORY_THEMES[categoryId].primary, 'h-5 w-5 rounded-full')}
className={clsx(
`bg-${CATEGORY_THEMES[categoryId].primary}`,
'h-5 w-5 rounded-full'
)}
></span>
<span className='pl-5 pr-10 text-xs font-semibold'>
{CATEGORY_ID_TO_NAME[categoryId]}
Expand Down
13 changes: 6 additions & 7 deletions packages/client/components/ActivityLibrary/ActivityLibrary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import IconLabel from '../IconLabel'
import {ActivityBadge} from './ActivityBadge'
import {ActivityCardImage} from './ActivityCard'
import {ActivityLibraryCard} from './ActivityLibraryCard'
import {ActivityLibraryCardDescription} from './ActivityLibraryCardDescription'
import {
CategoryID,
CATEGORY_ID_TO_NAME,
Expand Down Expand Up @@ -70,6 +69,7 @@ graphql`
isRecommended
isFree
...ActivityLibrary_templateSearchDocument @relay(mask: false)
...ActivityCard_template
...ActivityLibraryCardDescription_template
}
`
Expand Down Expand Up @@ -125,7 +125,7 @@ const getTemplateDocumentValue = (
.join('-')

const CategoryIDToColorClass = {
[QUICK_START_CATEGORY_ID]: 'bg-grape-700',
[QUICK_START_CATEGORY_ID]: 'grape-700',
...Object.fromEntries(
Object.entries(CATEGORY_THEMES).map(([key, value]) => {
return [key, value.primary]
Expand Down Expand Up @@ -167,6 +167,8 @@ const ActivityGrid = ({templates, selectedCategory}: ActivityGridProps) => {
key={template.id}
theme={CATEGORY_THEMES[template.category as CategoryID]}
title={template.name}
type={template.type}
templateRef={template}
badge={
!template.isFree ? (
<ActivityBadge className='m-2 bg-gold-300 text-grape-700'>Premium</ActivityBadge>
Expand All @@ -176,10 +178,7 @@ const ActivityGrid = ({templates, selectedCategory}: ActivityGridProps) => {
<ActivityCardImage
className='group-hover/card:hidden'
src={template.illustrationUrl}
/>
<ActivityLibraryCardDescription
className='hidden group-hover/card:flex'
templateRef={template}
category={template.category as CategoryID}
/>
</ActivityLibraryCard>
</Link>
Expand Down Expand Up @@ -337,7 +336,7 @@ export const ActivityLibrary = (props: Props) => {
'flex-shrink-0 cursor-pointer rounded-full py-2 px-4 text-sm text-slate-800',
category === selectedCategory && searchQuery.length === 0
? [
CategoryIDToColorClass[category],
`bg-${CategoryIDToColorClass[category]}`,
'font-semibold text-white focus:text-white'
]
: 'border border-slate-300 bg-white'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ export const ActivityLibraryCard = (props: ActivityCardProps) => {

return (
<ActivityCard
className={clsx(
'group/card transition-shadow focus-within:ring-2 focus-within:ring-primary hover:shadow-md motion-reduce:transition-none',
className
)}
className={clsx('focus-within:ring-2 focus-within:ring-primary hover:shadow-md', className)}
{...rest}
/>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@ interface RetroDescriptionProps {
prompts: ActivityLibraryCardDescription_template$data['prompts']
}

const RetroDescription = (props: RetroDescriptionProps) => {
export const RetroDescription = (props: RetroDescriptionProps) => {
const {prompts} = props

return (
<>
{prompts!.map((prompt, index) => (
<div key={index} className='flex items-center gap-x-2'>
{prompts!.map((prompt) => (
<div key={prompt.id} className='mb-1 flex flex-col items-start py-1 sm:flex-row'>
<div
className='mt-1 h-3 w-3 shrink-0 self-start rounded-full'
className='mt-1 mr-4 h-3 w-3 shrink-0 self-start rounded-full'
style={{backgroundColor: prompt.groupColor}}
/>
<div className='text-sm font-medium'>{prompt.question}</div>
<div className='flex min-w-0 flex-grow flex-col'>
<div className='text-sm font-semibold'>{prompt.question}</div>
<div className='text-sm font-normal'>{prompt.description}</div>
</div>
</div>
))}
</>
Expand All @@ -38,16 +40,16 @@ interface PokerDescriptionProps {

const PokerDescription = (props: PokerDescriptionProps) => {
const {dimensions} = props

return (
<>
{dimensions!.map((dimension, index) => (
<div key={index} className='flex items-center gap-x-2'>
<div className='mt-1 shrink-0 self-start'>
{dimensions!.map((dimension) => (
<div key={dimension.id} className='mb-1 flex items-center py-1 sm:flex-row'>
<div className='mr-4 shrink-0 self-start'>
<LinearScale className='h-4 w-4' />
</div>
<div className='text-sm font-medium'>
{dimension.name}: <span className='font-semibold'>{dimension.selectedScale.name}</span>
<div className='flex min-w-0 flex-grow flex-col'>
<div className='text-sm font-semibold'>{dimension.name}</div>
<div className='text-sm font-normal'>{dimension.selectedScale.name}</div>
</div>
</div>
))}
Expand All @@ -70,9 +72,11 @@ const ActionDescription = () => {
return (
<>
{items.map((item, index) => (
<div key={index} className='flex items-center gap-x-2'>
<div className='mt-1 shrink-0 self-start'>{item.icon}</div>
<div className='text-sm font-medium'>{item.description}</div>
<div key={index} className='mb-1 flex items-start py-1 sm:flex-row'>
<div className='mr-4 flex shrink-0 items-center self-start'>{item.icon}</div>
<div className='flex min-w-0 flex-grow flex-col'>
<div className='text-sm font-normal'>{item.description}</div>
</div>
</div>
))}
</>
Expand All @@ -90,9 +94,11 @@ const TeamPromptDescription = () => {
return (
<>
{items.map((item, index) => (
<div key={index} className='flex items-center gap-x-2'>
<div className='mt-1 shrink-0 self-start'>{item.icon}</div>
<div className='text-sm font-medium'>{item.description}</div>
<div key={index} className='mb-1 flex items-start py-1 sm:flex-row'>
<div className='mr-4 flex shrink-0 items-center self-start'>{item.icon}</div>
<div className='flex min-w-0 flex-grow flex-col'>
<div className='text-sm font-normal'>{item.description}</div>
</div>
</div>
))}
</>
Expand All @@ -113,6 +119,7 @@ export const ActivityLibraryCardDescription = (props: Props) => {
type
... on PokerTemplate {
dimensions {
id
name
description
selectedScale {
Expand All @@ -122,8 +129,10 @@ export const ActivityLibraryCardDescription = (props: Props) => {
}
... on ReflectTemplate {
prompts {
id
question
groupColor
description
}
}
}
Expand Down
Loading

0 comments on commit 852683c

Please sign in to comment.