import { useState, useCallback, useRef, useEffect } from 'react' import type { VaultEntry } from '../types' import type { FrontmatterValue } from './Inspector' import type { ParsedFrontmatter } from '../utils/frontmatter' import { usePropertyPanelState } from '../hooks/usePropertyPanelState' import { getEffectiveDisplayMode, detectPropertyType } from '../utils/propertyTypes' import { SmartPropertyValueCell, DisplayModeSelector } from './PropertyValueCells' import { TypeSelector } from './TypeSelector' import { AddPropertyForm } from './AddPropertyForm' import { countWords } from '../utils/wikilinks' import type { PropertyDisplayMode } from '../utils/propertyTypes' import { PushPin } from '@phosphor-icons/react' // eslint-disable-next-line react-refresh/only-export-components -- utility co-located with component export function containsWikilinks(value: FrontmatterValue): boolean { if (typeof value === 'string') return /^\[\[.*\]\]$/.test(value) if (Array.isArray(value)) return value.some(v => typeof v === 'string' && /^\[\[.*\]\]$/.test(v)) return false } function formatDate(timestamp: number | null): string { if (!timestamp) return '\u2014' const d = new Date(timestamp * 1000) return d.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }) } function formatFileSize(bytes: number): string { if (bytes < 1024) return `${bytes} B` const kb = bytes / 1024 if (kb < 1024) return `${kb.toFixed(1)} KB` const mb = kb / 1024 return `${mb.toFixed(1)} MB` } function PropertyPinMenu({ x, y, isPinned, onPin, onUnpin, onClose }: { x: number; y: number; isPinned: boolean onPin: () => void; onUnpin: () => void; onClose: () => void }) { const ref = useRef(null) useEffect(() => { const handler = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) onClose() } document.addEventListener('mousedown', handler) return () => document.removeEventListener('mousedown', handler) }, [onClose]) return (
) } function PropertyRow({ propKey, value, editingKey, displayMode, autoMode, vaultStatuses, vaultTags, isPinned, onStartEdit, onSave, onSaveList, onUpdate, onDelete, onDisplayModeChange, onPin, onUnpin }: { propKey: string; value: FrontmatterValue; editingKey: string | null displayMode: PropertyDisplayMode; autoMode: PropertyDisplayMode vaultStatuses: string[]; vaultTags: string[] isPinned: boolean onStartEdit: (key: string | null) => void; onSave: (key: string, value: string) => void onSaveList: (key: string, items: string[]) => void onUpdate?: (key: string, value: FrontmatterValue) => void; onDelete?: (key: string) => void onDisplayModeChange: (key: string, mode: PropertyDisplayMode | null) => void onPin?: (key: string) => void; onUnpin?: (key: string) => void }) { const [ctxMenu, setCtxMenu] = useState<{ x: number; y: number } | null>(null) const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && editingKey !== propKey) { e.preventDefault() onStartEdit(propKey) } } const handleContextMenu = useCallback((e: React.MouseEvent) => { if (!onPin && !onUnpin) return e.preventDefault() setCtxMenu({ x: e.clientX, y: e.clientY }) }, [onPin, onUnpin]) return (
{isPinned && } {propKey} {onDelete && ( )}
{ctxMenu && ( onPin?.(propKey)} onUnpin={() => onUnpin?.(propKey)} onClose={() => setCtxMenu(null)} /> )}
) } function InfoRow({ label, value }: { label: string; value: string }) { return (
{label} {value}
) } function AddPropertyButton({ onClick, disabled }: { onClick: () => void; disabled: boolean }) { return ( ) } function NoteInfoSection({ entry, wordCount }: { entry: VaultEntry; wordCount: number }) { return (

Info

) } export function DynamicPropertiesPanel({ entry, content, frontmatter, entries, onUpdateProperty, onDeleteProperty, onAddProperty, onNavigate, isPinned, onPin, onUnpin, }: { entry: VaultEntry content: string | null frontmatter: ParsedFrontmatter entries?: VaultEntry[] onUpdateProperty?: (key: string, value: FrontmatterValue) => void onDeleteProperty?: (key: string) => void onAddProperty?: (key: string, value: FrontmatterValue) => void onNavigate?: (target: string) => void isPinned?: (key: string) => boolean onPin?: (key: string) => void onUnpin?: (key: string) => void }) { const { editingKey, setEditingKey, showAddDialog, setShowAddDialog, displayOverrides, availableTypes, customColorKey, typeColorKeys, typeIconKeys, vaultStatuses, vaultTagsByKey, propertyEntries, handleSaveValue, handleSaveList, handleAdd, handleDisplayModeChange, } = usePropertyPanelState({ entries, entryIsA: entry.isA, frontmatter, onUpdateProperty, onDeleteProperty, onAddProperty }) const wordCount = countWords(content ?? '') return (
{propertyEntries.map(([key, value]) => ( ))}
{showAddDialog ? setShowAddDialog(false)} vaultStatuses={vaultStatuses} /> : setShowAddDialog(true)} disabled={!onAddProperty} /> }
) }