diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx index 2f64a53..6ffb90a 100644 --- a/src/components/Badge.tsx +++ b/src/components/Badge.tsx @@ -1,6 +1,21 @@ +import { type JSX, useState } from 'react' import { twMerge } from 'tailwind-merge' import type { VariantProps } from 'tailwind-variants' -import { badgeCVA, typeIcons } from '@/components/design' +import { badgeCVA, typeColors, typeIcons } from '@/components/design' + +import { CodePreview } from './BadgePreviews/CodePreview' +import { ImagePreview } from './BadgePreviews/ImagePreview' +import { LinkPreview } from './BadgePreviews/LinkPreview' +import { TextPreview } from './BadgePreviews/TextPreview' +import { TimePreview } from './BadgePreviews/TimePreview' + +const typeTooltips = { + code: CodePreview, + image: ImagePreview, + link: LinkPreview, + text: TextPreview, + time: TimePreview, +} satisfies Partial JSX.Element>> export type BadgeProps = VariantProps & { type: keyof typeof typeIcons @@ -9,17 +24,38 @@ export type BadgeProps = VariantProps & { const Badge = ({ text, type }: BadgeProps) => { const Icon = typeIcons[type] + const [showTooltip, setShowTooltip] = useState(false) + const TooltipComponent = + showTooltip && type in typeTooltips && typeTooltips[type as keyof typeof typeTooltips] return ( - setShowTooltip(true)} + onMouseLeave={() => setShowTooltip(false)} > - {type === 'blank' || } - {text || type} - + + {type === 'blank' || } + {text || type} + + {TooltipComponent && ( +
+ +
+ )} + ) } diff --git a/src/components/BadgePreviews/CodePreview.tsx b/src/components/BadgePreviews/CodePreview.tsx new file mode 100644 index 0000000..5a929a4 --- /dev/null +++ b/src/components/BadgePreviews/CodePreview.tsx @@ -0,0 +1,11 @@ +export function CodePreview() { + return ( + <> + TODO{' '} + + #81 + + : show every codeblock in the draft + + ) +} diff --git a/src/components/BadgePreviews/ImagePreview.tsx b/src/components/BadgePreviews/ImagePreview.tsx new file mode 100644 index 0000000..b4d7ccd --- /dev/null +++ b/src/components/BadgePreviews/ImagePreview.tsx @@ -0,0 +1,11 @@ +export function ImagePreview() { + return ( + <> + TODO{' '} + + #80 + + : show every image in the draft + + ) +} diff --git a/src/components/BadgePreviews/LinkPreview.tsx b/src/components/BadgePreviews/LinkPreview.tsx new file mode 100644 index 0000000..768e97b --- /dev/null +++ b/src/components/BadgePreviews/LinkPreview.tsx @@ -0,0 +1,11 @@ +export function LinkPreview() { + return ( + <> + TODO{' '} + + #79 + + : show text, url, and preview info for every link in the draft + + ) +} diff --git a/src/components/BadgePreviews/TextPreview.tsx b/src/components/BadgePreviews/TextPreview.tsx new file mode 100644 index 0000000..266c4ef --- /dev/null +++ b/src/components/BadgePreviews/TextPreview.tsx @@ -0,0 +1,11 @@ +export function TextPreview() { + return ( + <> + TODO{' '} + + #82 + + : show the syntax-highlighted markdown of the latest draft + + ) +} diff --git a/src/components/BadgePreviews/TimePreview.tsx b/src/components/BadgePreviews/TimePreview.tsx new file mode 100644 index 0000000..1d13c70 --- /dev/null +++ b/src/components/BadgePreviews/TimePreview.tsx @@ -0,0 +1,11 @@ +export function TimePreview() { + return ( + <> + TODO{' '} + + #83 + + : show the revision history of the comment + + ) +} diff --git a/src/components/design.tsx b/src/components/design.tsx index e99ef68..082a570 100644 --- a/src/components/design.tsx +++ b/src/components/design.tsx @@ -13,6 +13,38 @@ import { } from 'lucide-react' import { tv } from 'tailwind-variants' +// Map types to their icons - source of truth for badge types +export const typeIcons = { + blank: Code, + code: Code, + hideTrashed: EyeOff, + image: Image, + link: Link, + open: Monitor, + sent: MailCheck, + settings: Settings, + text: TextSelect, + time: Clock, + trashed: Trash2, + unsent: MessageSquareDashed, +} as const + +// Type colors definition - must be exhaustive with typeIcons +export const typeColors = { + blank: 'bg-transparent text-gray-700', + code: 'bg-pink-50 text-pink-700', + hideTrashed: 'bg-transparent text-gray-700', + image: 'bg-purple-50 text-purple-700', + link: 'bg-blue-50 text-blue-700', + open: 'bg-cyan-50 text-cyan-700', + sent: 'bg-green-50 text-green-700', + settings: 'bg-gray-50 text-gray-700', + text: 'bg-gray-50 text-gray-700', + time: 'bg-gray-50 text-gray-700', + trashed: 'bg-gray-50 text-yellow-700', + unsent: 'bg-amber-100 text-amber-700', +} as const satisfies Record + // TV configuration for stat badges export const badgeCVA = tv({ base: 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs font-normal h-5', @@ -28,35 +60,6 @@ export const badgeCVA = tv({ false: '', true: '!border-solid !border-current', }, - type: { - blank: 'bg-transparent text-gray-700', - code: 'bg-pink-50 text-pink-700', - hideTrashed: 'bg-transparent text-gray-700', - image: 'bg-purple-50 text-purple-700', - link: 'bg-blue-50 text-blue-700', - open: 'bg-cyan-50 text-cyan-700', - sent: 'bg-green-50 text-green-700', - settings: 'bg-gray-50 text-gray-700', - text: 'bg-gray-50 text-gray-700', - time: 'bg-gray-50 text-gray-700', - trashed: 'bg-gray-50 text-yellow-700', - unsent: 'bg-amber-100 text-amber-700', - }, + type: typeColors, }, }) - -// Map types to their icons -export const typeIcons = { - blank: Code, - code: Code, - hideTrashed: EyeOff, - image: Image, - link: Link, - open: Monitor, - sent: MailCheck, - settings: Settings, - text: TextSelect, - time: Clock, - trashed: Trash2, - unsent: MessageSquareDashed, -} as const