11'use client'
22
3- import { useState } from 'react'
4- import { Check , Copy , LibraryBig } from 'lucide-react'
53import Link from 'next/link'
64import { useParams } from 'next/navigation'
7- import { createLogger } from '@/lib/logs/console/logger'
8-
9- const logger = createLogger ( 'BaseOverviewComponent' )
5+ import { Badge , DocumentAttachment , Tooltip } from '@/components/emcn'
106
117interface BaseOverviewProps {
128 id ?: string
@@ -17,6 +13,9 @@ interface BaseOverviewProps {
1713 updatedAt ?: string
1814}
1915
16+ /**
17+ * Formats a date string to relative time (e.g., "2h ago", "3d ago")
18+ */
2019function formatRelativeTime ( dateString : string ) : string {
2120 const date = new Date ( dateString )
2221 const now = new Date ( )
@@ -49,6 +48,9 @@ function formatRelativeTime(dateString: string): string {
4948 return `${ years } y ago`
5049}
5150
51+ /**
52+ * Formats a date string to absolute format for tooltip display
53+ */
5254function formatAbsoluteDate ( dateString : string ) : string {
5355 const date = new Date ( dateString )
5456 return date . toLocaleDateString ( 'en-US' , {
@@ -60,15 +62,10 @@ function formatAbsoluteDate(dateString: string): string {
6062 } )
6163}
6264
63- export function BaseOverview ( {
64- id,
65- title,
66- docCount,
67- description,
68- createdAt,
69- updatedAt,
70- } : BaseOverviewProps ) {
71- const [ isCopied , setIsCopied ] = useState ( false )
65+ /**
66+ * Knowledge base card component displaying overview information
67+ */
68+ export function BaseOverview ( { id, title, docCount, description, updatedAt } : BaseOverviewProps ) {
7269 const params = useParams ( )
7370 const workspaceId = params ?. workspaceId as string
7471
@@ -77,64 +74,39 @@ export function BaseOverview({
7774 } )
7875 const href = `/workspace/${ workspaceId } /knowledge/${ id || title . toLowerCase ( ) . replace ( / \s + / g, '-' ) } ?${ searchParams . toString ( ) } `
7976
80- const handleCopy = async ( e : React . MouseEvent ) => {
81- e . preventDefault ( )
82- e . stopPropagation ( )
83-
84- if ( id ) {
85- try {
86- await navigator . clipboard . writeText ( id )
87- setIsCopied ( true )
88- setTimeout ( ( ) => setIsCopied ( false ) , 2000 )
89- } catch ( err ) {
90- logger . error ( 'Failed to copy ID:' , err )
91- }
92- }
93- }
77+ const shortId = id ? `kb-${ id . slice ( 0 , 8 ) } ` : ''
9478
9579 return (
96- < Link href = { href } prefetch = { true } >
97- < div className = 'group flex cursor-pointer flex-col gap-3 rounded-md border bg-background p-4 transition-colors hover:bg-accent/50' >
98- < div className = 'flex items-center gap-2' >
99- < LibraryBig className = 'h-4 w-4 flex-shrink-0 text-muted-foreground' />
100- < h3 className = 'truncate font-medium text-sm leading-tight' > { title } </ h3 >
80+ < Link href = { href } prefetch = { true } className = 'h-full' >
81+ < div className = 'group flex h-full cursor-pointer flex-col gap-[12px] rounded-[4px] bg-[var(--surface-elevated)] px-[8px] py-[6px] transition-colors hover:bg-[var(--surface-5)]' >
82+ < div className = 'flex items-center justify-between gap-[8px]' >
83+ < h3 className = 'min-w-0 flex-1 truncate text-[14px] text-[var(--text-primary)]' >
84+ { title }
85+ </ h3 >
86+ { shortId && < Badge className = 'flex-shrink-0 rounded-[4px] text-[12px]' > { shortId } </ Badge > }
10187 </ div >
10288
103- < div className = 'flex flex-col gap-2' >
104- < div className = 'flex items-center gap-2 text-muted-foreground text-xs' >
105- < span >
89+ < div className = 'flex flex-1 flex-col gap-[8px]' >
90+ < div className = 'flex items-center justify-between' >
91+ < span className = 'flex items-center gap-[6px] text-[12px] text-[var(--text-tertiary)]' >
92+ < DocumentAttachment className = 'h-[12px] w-[12px]' />
10693 { docCount } { docCount === 1 ? 'doc' : 'docs' }
10794 </ span >
108- < span > • </ span >
109- < div className = 'flex items-center gap-2' >
110- < span className = 'truncate font-mono' > { id ?. slice ( 0 , 8 ) } </ span >
111- < button
112- onClick = { handleCopy }
113- className = 'flex h-4 w-4 items-center justify-center rounded text-gray-500 hover:bg-gray-100 hover:text-gray-700'
114- >
115- { isCopied ? < Check className = 'h-3 w-3' /> : < Copy className = 'h-3 w-3' /> }
116- </ button >
117- </ div >
95+ { updatedAt && (
96+ < Tooltip . Root >
97+ < Tooltip . Trigger asChild >
98+ < span className = 'cursor-default text-[12px] text-[var(--text-muted)]' >
99+ last updated: { formatRelativeTime ( updatedAt ) }
100+ </ span >
101+ </ Tooltip . Trigger >
102+ < Tooltip . Content > { formatAbsoluteDate ( updatedAt ) } </ Tooltip . Content >
103+ </ Tooltip . Root >
104+ ) }
118105 </ div >
119106
120- { /* Timestamps */ }
121- { ( createdAt || updatedAt ) && (
122- < div className = 'flex items-center gap-2 text-muted-foreground text-xs' >
123- { updatedAt && (
124- < span title = { `Last updated: ${ formatAbsoluteDate ( updatedAt ) } ` } >
125- Updated { formatRelativeTime ( updatedAt ) }
126- </ span >
127- ) }
128- { updatedAt && createdAt && < span > •</ span > }
129- { createdAt && (
130- < span title = { `Created: ${ formatAbsoluteDate ( createdAt ) } ` } >
131- Created { formatRelativeTime ( createdAt ) }
132- </ span >
133- ) }
134- </ div >
135- ) }
107+ < div className = 'h-0 w-full border-[var(--divider)] border-t' />
136108
137- < p className = 'line-clamp-2 overflow-hidden text-muted-foreground text-xs ' >
109+ < p className = 'line-clamp-2 h-[36px] text-[12px] text-[var(--text-tertiary)] leading-[18px] ' >
138110 { description }
139111 </ p >
140112 </ div >
0 commit comments