refactor(ux): consolidate BMAD skills, update design system, and clean up Prisma generated client

This commit is contained in:
Sepehr Ramezani
2026-04-19 19:21:27 +02:00
parent 5296c4da2c
commit 25529a24b8
2476 changed files with 127934 additions and 101962 deletions

View File

@@ -24,6 +24,7 @@ import { NoteCard } from './note-card';
import { updateFullOrderWithoutRevalidation } from '@/app/actions/notes';
import { useNotebookDrag } from '@/context/notebook-drag-context';
import { useLanguage } from '@/lib/i18n';
import { useCardSizeMode } from '@/hooks/use-card-size-mode';
import dynamic from 'next/dynamic';
import './masonry-grid.css';
@@ -36,6 +37,8 @@ const NoteEditor = dynamic(
interface MasonryGridProps {
notes: Note[];
onEdit?: (note: Note, readOnly?: boolean) => void;
onSizeChange?: (noteId: string, size: 'small' | 'medium' | 'large') => void;
isTrashView?: boolean;
}
// ─────────────────────────────────────────────
@@ -49,6 +52,7 @@ interface SortableNoteProps {
onDragEndNote?: () => void;
isDragging?: boolean;
isOverlay?: boolean;
isTrashView?: boolean;
}
const SortableNoteItem = memo(function SortableNoteItem({
@@ -59,6 +63,7 @@ const SortableNoteItem = memo(function SortableNoteItem({
onDragEndNote,
isDragging,
isOverlay,
isTrashView,
}: SortableNoteProps) {
const {
attributes,
@@ -91,6 +96,7 @@ const SortableNoteItem = memo(function SortableNoteItem({
onDragStart={onDragStartNote}
onDragEnd={onDragEndNote}
isDragging={isDragging}
isTrashView={isTrashView}
onSizeChange={(newSize) => onSizeChange(note.id, newSize)}
/>
</div>
@@ -107,6 +113,7 @@ interface SortableGridSectionProps {
draggedNoteId: string | null;
onDragStartNote: (noteId: string) => void;
onDragEndNote: () => void;
isTrashView?: boolean;
}
const SortableGridSection = memo(function SortableGridSection({
@@ -116,6 +123,7 @@ const SortableGridSection = memo(function SortableGridSection({
draggedNoteId,
onDragStartNote,
onDragEndNote,
isTrashView,
}: SortableGridSectionProps) {
const ids = useMemo(() => notes.map(n => n.id), [notes]);
@@ -131,6 +139,7 @@ const SortableGridSection = memo(function SortableGridSection({
onDragStartNote={onDragStartNote}
onDragEndNote={onDragEndNote}
isDragging={draggedNoteId === note.id}
isTrashView={isTrashView}
/>
))}
</div>
@@ -141,16 +150,28 @@ const SortableGridSection = memo(function SortableGridSection({
// ─────────────────────────────────────────────
// Main MasonryGrid component
// ─────────────────────────────────────────────
export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
export function MasonryGrid({ notes, onEdit, onSizeChange, isTrashView }: MasonryGridProps) {
const { t } = useLanguage();
const [editingNote, setEditingNote] = useState<{ note: Note; readOnly?: boolean } | null>(null);
const { startDrag, endDrag, draggedNoteId } = useNotebookDrag();
const cardSizeMode = useCardSizeMode();
const isUniformMode = cardSizeMode === 'uniform';
// Local notes state for optimistic size/order updates
const [localNotes, setLocalNotes] = useState<Note[]>(notes);
useEffect(() => {
setLocalNotes(notes);
setLocalNotes(prev => {
const prevIds = prev.map(n => n.id).join(',')
const incomingIds = notes.map(n => n.id).join(',')
if (prevIds === incomingIds) {
const localSizeMap = new Map(prev.map(n => [n.id, n.size]))
return notes.map(n => ({ ...n, size: localSizeMap.get(n.id) ?? n.size }))
}
// Notes added/removed: full sync but preserve local sizes
const localSizeMap = new Map(prev.map(n => [n.id, n.size]))
return notes.map(n => ({ ...n, size: localSizeMap.get(n.id) ?? n.size }))
})
}, [notes]);
const pinnedNotes = useMemo(() => localNotes.filter(n => n.isPinned), [localNotes]);
@@ -172,7 +193,8 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
const handleSizeChange = useCallback((noteId: string, newSize: 'small' | 'medium' | 'large') => {
setLocalNotes(prev => prev.map(n => n.id === noteId ? { ...n, size: newSize } : n));
}, []);
onSizeChange?.(noteId, newSize);
}, [onSizeChange]);
// @dnd-kit sensors — pointer (desktop) + touch (mobile)
const sensors = useSensors(
@@ -225,7 +247,7 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
>
<div className="masonry-container">
<div className="masonry-container" data-card-size-mode={cardSizeMode}>
{pinnedNotes.length > 0 && (
<div className="mb-8">
<h2 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3 px-2">
@@ -238,6 +260,7 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
draggedNoteId={draggedNoteId}
onDragStartNote={startDrag}
onDragEndNote={endDrag}
isTrashView={isTrashView}
/>
</div>
)}
@@ -256,6 +279,7 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
draggedNoteId={draggedNoteId}
onDragStartNote={startDrag}
onDragEndNote={endDrag}
isTrashView={isTrashView}
/>
</div>
)}