From 90d5bc32e3a5418f63a9e4efca5f50b046a5fe3d Mon Sep 17 00:00:00 2001
From: Arjun <6592213+arkml@users.noreply.github.com>
Date: Sat, 7 Feb 2026 00:26:07 +0530
Subject: [PATCH] full width
---
.../components/ai-elements/file-path-card.tsx | 159 ++++++++++++------
.../src/components/ai-elements/message.tsx | 2 +-
2 files changed, 107 insertions(+), 54 deletions(-)
diff --git a/apps/x/apps/renderer/src/components/ai-elements/file-path-card.tsx b/apps/x/apps/renderer/src/components/ai-elements/file-path-card.tsx
index e989f278..7175b5ff 100644
--- a/apps/x/apps/renderer/src/components/ai-elements/file-path-card.tsx
+++ b/apps/x/apps/renderer/src/components/ai-elements/file-path-card.tsx
@@ -1,26 +1,70 @@
import { useCallback, useEffect, useRef, useState } from 'react'
-import { BookOpen, ExternalLink, FileIcon, Pause, Play } from 'lucide-react'
+import { BookOpen, FileIcon, FileText, Image, Music, Pause, Play, Video } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { useFileCard } from '@/contexts/file-card-context'
import { wikiLabel } from '@/lib/wiki-links'
const AUDIO_EXTENSIONS = new Set(['.wav', '.mp3', '.m4a', '.ogg', '.flac', '.aac'])
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.ico'])
+const VIDEO_EXTENSIONS = new Set(['.mp4', '.mov', '.avi', '.mkv', '.webm'])
+const DOCUMENT_EXTENSIONS = new Set(['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt', '.rtf', '.csv'])
function getExtension(filePath: string): string {
const dot = filePath.lastIndexOf('.')
return dot >= 0 ? filePath.slice(dot).toLowerCase() : ''
}
-function getFileName(filePath: string): string {
- return filePath.split('/').pop() || filePath
+function getFileNameWithoutExt(filePath: string): string {
+ const name = filePath.split('/').pop() || filePath
+ const dot = name.lastIndexOf('.')
+ return dot > 0 ? name.slice(0, dot) : name
}
-function truncatePath(filePath: string, maxLen = 40): string {
- if (filePath.length <= maxLen) return filePath
- const parts = filePath.split('/')
- if (parts.length <= 2) return filePath
- return `.../${parts.slice(-2).join('/')}`
+function getFileCategory(ext: string): { label: string; icon: typeof FileIcon } {
+ if (AUDIO_EXTENSIONS.has(ext)) return { label: 'Audio', icon: Music }
+ if (IMAGE_EXTENSIONS.has(ext)) return { label: 'Image', icon: Image }
+ if (VIDEO_EXTENSIONS.has(ext)) return { label: 'Video', icon: Video }
+ if (DOCUMENT_EXTENSIONS.has(ext)) return { label: 'Document', icon: FileText }
+ if (ext === '.md') return { label: 'Markdown', icon: FileText }
+ return { label: 'File', icon: FileIcon }
+}
+
+function getExtLabel(ext: string): string {
+ return ext ? ext.slice(1).toUpperCase() : ''
+}
+
+// Shared card shell used by all variants
+function CardShell({
+ icon,
+ title,
+ subtitle,
+ onClick,
+ action,
+}: {
+ icon: React.ReactNode
+ title: string
+ subtitle: string
+ onClick?: () => void
+ action?: React.ReactNode
+}) {
+ return (
+
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onClick() } } : undefined}
+ className="flex items-center gap-3 rounded-xl border border-border bg-card p-3 pr-4 text-left transition-colors hover:bg-accent/50 cursor-pointer w-full my-2"
+ >
+
+ {icon}
+
+
+ {action}
+
+ )
}
// --- Knowledge File Card ---
@@ -28,15 +72,21 @@ function truncatePath(filePath: string, maxLen = 40): string {
function KnowledgeFileCard({ filePath }: { filePath: string }) {
const { onOpenKnowledgeFile } = useFileCard()
const label = wikiLabel(filePath)
+ const ext = getExtension(filePath)
+ const extLabel = getExtLabel(ext)
return (
- }
+ title={label}
+ subtitle={extLabel ? `Knowledge \u00b7 ${extLabel}` : 'Knowledge'}
onClick={() => onOpenKnowledgeFile(filePath)}
- className="flex items-center gap-3 rounded-lg border border-border bg-card p-3 hover:bg-accent max-w-xs text-left transition-colors cursor-pointer w-full"
- >
-
- {label}
-
+ action={
+
+ }
+ />
)
}
@@ -46,8 +96,11 @@ function AudioFileCard({ filePath }: { filePath: string }) {
const [isPlaying, setIsPlaying] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const audioRef = useRef(null)
+ const ext = getExtension(filePath)
+ const extLabel = getExtLabel(ext)
- const handlePlayPause = useCallback(async () => {
+ const handlePlayPause = useCallback(async (e: React.MouseEvent) => {
+ e.stopPropagation()
if (isPlaying && audioRef.current) {
audioRef.current.pause()
setIsPlaying(false)
@@ -88,30 +141,28 @@ function AudioFileCard({ filePath }: { filePath: string }) {
}
return (
-
-
-
-
{getFileName(filePath)}
-
{truncatePath(filePath)}
-
-
-
+
+ {isPlaying
+ ?
+ :
+ }
+
+ }
+ title={getFileNameWithoutExt(filePath)}
+ subtitle={`Audio \u00b7 ${extLabel}`}
+ onClick={handleOpen}
+ action={
+
+ }
+ />
)
}
@@ -121,6 +172,8 @@ function SystemFileCard({ filePath }: { filePath: string }) {
const ext = getExtension(filePath)
const isImage = IMAGE_EXTENSIONS.has(ext)
const [thumbnail, setThumbnail] = useState(null)
+ const { label: categoryLabel, icon: CategoryIcon } = getFileCategory(ext)
+ const extLabel = getExtLabel(ext)
useEffect(() => {
if (!isImage) return
@@ -140,21 +193,21 @@ function SystemFileCard({ filePath }: { filePath: string }) {
}
return (
-
+ :
+ }
+ title={getFileNameWithoutExt(filePath)}
+ subtitle={extLabel ? `${categoryLabel} \u00b7 ${extLabel}` : categoryLabel}
onClick={handleOpen}
- className="flex items-center gap-3 rounded-lg border border-border bg-card p-3 hover:bg-accent max-w-xs text-left transition-colors cursor-pointer w-full"
- >
- {thumbnail ? (
-
- ) : (
-
- )}
-
-
{getFileName(filePath)}
-
{truncatePath(filePath)}
-
-
-
+ action={
+
+ }
+ />
)
}
diff --git a/apps/x/apps/renderer/src/components/ai-elements/message.tsx b/apps/x/apps/renderer/src/components/ai-elements/message.tsx
index 635d455c..ec3acfc1 100644
--- a/apps/x/apps/renderer/src/components/ai-elements/message.tsx
+++ b/apps/x/apps/renderer/src/components/ai-elements/message.tsx
@@ -50,7 +50,7 @@ export const MessageContent = ({
className={cn(
"is-user:dark flex w-fit max-w-full min-w-0 flex-col gap-2 overflow-hidden text-sm",
"group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:bg-secondary group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-foreground",
- "group-[.is-assistant]:text-foreground",
+ "group-[.is-assistant]:w-full group-[.is-assistant]:text-foreground",
className
)}
{...props}