mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-25 00:16:29 +02:00
inline-expand knowledge folders via hover chevron
This commit is contained in:
parent
acc655172d
commit
5aedec2db9
2 changed files with 55 additions and 5 deletions
|
|
@ -3390,9 +3390,9 @@ function App() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Top-level knowledge folders (except Notes) open as a bases view with folder filter
|
// Top-level knowledge folders open as a bases view with folder filter
|
||||||
const parts = path.split('/')
|
const parts = path.split('/')
|
||||||
if (parts.length === 2 && parts[0] === 'knowledge' && parts[1] !== 'Notes') {
|
if (parts.length === 2 && parts[0] === 'knowledge') {
|
||||||
const folderName = parts[1]
|
const folderName = parts[1]
|
||||||
const folderCfg = FOLDER_BASE_CONFIGS[folderName]
|
const folderCfg = FOLDER_BASE_CONFIGS[folderName]
|
||||||
setBaseConfigByPath((prev) => ({
|
setBaseConfigByPath((prev) => ({
|
||||||
|
|
@ -4141,6 +4141,14 @@ function App() {
|
||||||
selectedPath={selectedPath}
|
selectedPath={selectedPath}
|
||||||
expandedPaths={expandedPaths}
|
expandedPaths={expandedPaths}
|
||||||
onSelectFile={toggleExpand}
|
onSelectFile={toggleExpand}
|
||||||
|
onToggleFolder={(path) => {
|
||||||
|
setExpandedPaths((prev) => {
|
||||||
|
const next = new Set(prev)
|
||||||
|
if (next.has(path)) next.delete(path)
|
||||||
|
else next.add(path)
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}}
|
||||||
knowledgeActions={knowledgeActions}
|
knowledgeActions={knowledgeActions}
|
||||||
onVoiceNoteCreated={handleVoiceNoteCreated}
|
onVoiceNoteCreated={handleVoiceNoteCreated}
|
||||||
runs={runs}
|
runs={runs}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ import {
|
||||||
SidebarGroupContent,
|
SidebarGroupContent,
|
||||||
SidebarHeader,
|
SidebarHeader,
|
||||||
SidebarMenu,
|
SidebarMenu,
|
||||||
|
SidebarMenuAction,
|
||||||
SidebarMenuButton,
|
SidebarMenuButton,
|
||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
SidebarMenuSub,
|
SidebarMenuSub,
|
||||||
|
|
@ -170,6 +171,7 @@ type SidebarContentPanelProps = {
|
||||||
selectedPath: string | null
|
selectedPath: string | null
|
||||||
expandedPaths: Set<string>
|
expandedPaths: Set<string>
|
||||||
onSelectFile: (path: string, kind: "file" | "dir") => void
|
onSelectFile: (path: string, kind: "file" | "dir") => void
|
||||||
|
onToggleFolder?: (path: string) => void
|
||||||
knowledgeActions: KnowledgeActions
|
knowledgeActions: KnowledgeActions
|
||||||
onVoiceNoteCreated?: (path: string) => void
|
onVoiceNoteCreated?: (path: string) => void
|
||||||
runs?: RunListItem[]
|
runs?: RunListItem[]
|
||||||
|
|
@ -403,6 +405,7 @@ export function SidebarContentPanel({
|
||||||
selectedPath,
|
selectedPath,
|
||||||
expandedPaths,
|
expandedPaths,
|
||||||
onSelectFile,
|
onSelectFile,
|
||||||
|
onToggleFolder,
|
||||||
knowledgeActions,
|
knowledgeActions,
|
||||||
onVoiceNoteCreated,
|
onVoiceNoteCreated,
|
||||||
runs = [],
|
runs = [],
|
||||||
|
|
@ -605,6 +608,7 @@ export function SidebarContentPanel({
|
||||||
selectedPath={selectedPath}
|
selectedPath={selectedPath}
|
||||||
expandedPaths={expandedPaths}
|
expandedPaths={expandedPaths}
|
||||||
onSelectFile={onSelectFile}
|
onSelectFile={onSelectFile}
|
||||||
|
onToggleFolder={onToggleFolder}
|
||||||
actions={knowledgeActions}
|
actions={knowledgeActions}
|
||||||
onVoiceNoteCreated={onVoiceNoteCreated}
|
onVoiceNoteCreated={onVoiceNoteCreated}
|
||||||
/>
|
/>
|
||||||
|
|
@ -993,6 +997,7 @@ function KnowledgeSection({
|
||||||
selectedPath,
|
selectedPath,
|
||||||
expandedPaths,
|
expandedPaths,
|
||||||
onSelectFile,
|
onSelectFile,
|
||||||
|
onToggleFolder,
|
||||||
actions,
|
actions,
|
||||||
onVoiceNoteCreated,
|
onVoiceNoteCreated,
|
||||||
}: {
|
}: {
|
||||||
|
|
@ -1000,6 +1005,7 @@ function KnowledgeSection({
|
||||||
selectedPath: string | null
|
selectedPath: string | null
|
||||||
expandedPaths: Set<string>
|
expandedPaths: Set<string>
|
||||||
onSelectFile: (path: string, kind: "file" | "dir") => void
|
onSelectFile: (path: string, kind: "file" | "dir") => void
|
||||||
|
onToggleFolder?: (path: string) => void
|
||||||
actions: KnowledgeActions
|
actions: KnowledgeActions
|
||||||
onVoiceNoteCreated?: (path: string) => void
|
onVoiceNoteCreated?: (path: string) => void
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -1089,6 +1095,7 @@ function KnowledgeSection({
|
||||||
selectedPath={selectedPath}
|
selectedPath={selectedPath}
|
||||||
expandedPaths={expandedPaths}
|
expandedPaths={expandedPaths}
|
||||||
onSelect={onSelectFile}
|
onSelect={onSelectFile}
|
||||||
|
onToggleFolder={onToggleFolder}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
@ -1125,12 +1132,14 @@ function Tree({
|
||||||
selectedPath,
|
selectedPath,
|
||||||
expandedPaths,
|
expandedPaths,
|
||||||
onSelect,
|
onSelect,
|
||||||
|
onToggleFolder,
|
||||||
actions,
|
actions,
|
||||||
}: {
|
}: {
|
||||||
item: TreeNode
|
item: TreeNode
|
||||||
selectedPath: string | null
|
selectedPath: string | null
|
||||||
expandedPaths: Set<string>
|
expandedPaths: Set<string>
|
||||||
onSelect: (path: string, kind: "file" | "dir") => void
|
onSelect: (path: string, kind: "file" | "dir") => void
|
||||||
|
onToggleFolder?: (path: string) => void
|
||||||
actions: KnowledgeActions
|
actions: KnowledgeActions
|
||||||
}) {
|
}) {
|
||||||
const isDir = item.kind === 'dir'
|
const isDir = item.kind === 'dir'
|
||||||
|
|
@ -1267,15 +1276,15 @@ function Tree({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Top-level knowledge folders (except Notes) open bases view — render as flat items
|
// Top-level knowledge folders open bases view — render as flat items
|
||||||
const parts = item.path.split('/')
|
const parts = item.path.split('/')
|
||||||
const isBasesFolder = isDir && parts.length === 2 && parts[0] === 'knowledge' && parts[1] !== 'Notes'
|
const isBasesFolder = isDir && parts.length === 2 && parts[0] === 'knowledge'
|
||||||
|
|
||||||
if (isBasesFolder) {
|
if (isBasesFolder) {
|
||||||
return (
|
return (
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<ContextMenuTrigger asChild>
|
<ContextMenuTrigger asChild>
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem className="group/file-item">
|
||||||
<SidebarMenuButton onClick={() => onSelect(item.path, item.kind)}>
|
<SidebarMenuButton onClick={() => onSelect(item.path, item.kind)}>
|
||||||
<Folder className="size-4 shrink-0" />
|
<Folder className="size-4 shrink-0" />
|
||||||
<div className="flex w-full items-center gap-1 min-w-0">
|
<div className="flex w-full items-center gap-1 min-w-0">
|
||||||
|
|
@ -1283,6 +1292,38 @@ function Tree({
|
||||||
<span className="text-xs text-sidebar-foreground/50 tabular-nums shrink-0">{countFiles(item)}</span>
|
<span className="text-xs text-sidebar-foreground/50 tabular-nums shrink-0">{countFiles(item)}</span>
|
||||||
</div>
|
</div>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
|
{onToggleFolder && (item.children?.length ?? 0) > 0 && (
|
||||||
|
<SidebarMenuAction
|
||||||
|
showOnHover
|
||||||
|
aria-label={isExpanded ? "Collapse folder" : "Expand folder"}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
onToggleFolder(item.path)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ChevronRight
|
||||||
|
className={cn(
|
||||||
|
"transition-transform",
|
||||||
|
isExpanded && "rotate-90",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SidebarMenuAction>
|
||||||
|
)}
|
||||||
|
{isExpanded && (
|
||||||
|
<SidebarMenuSub>
|
||||||
|
{(item.children ?? []).map((subItem, index) => (
|
||||||
|
<Tree
|
||||||
|
key={index}
|
||||||
|
item={subItem}
|
||||||
|
selectedPath={selectedPath}
|
||||||
|
expandedPaths={expandedPaths}
|
||||||
|
onSelect={onSelect}
|
||||||
|
onToggleFolder={onToggleFolder}
|
||||||
|
actions={actions}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</SidebarMenuSub>
|
||||||
|
)}
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
{contextMenuContent}
|
{contextMenuContent}
|
||||||
|
|
@ -1347,6 +1388,7 @@ function Tree({
|
||||||
selectedPath={selectedPath}
|
selectedPath={selectedPath}
|
||||||
expandedPaths={expandedPaths}
|
expandedPaths={expandedPaths}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
|
onToggleFolder={onToggleFolder}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue