Files
supabase/apps/studio/components/ui/SortableSection.tsx
Joshen Lim b648db233b joshen/fe 4113 explorer markdown cells (#48846)
## Context

More groundwork for the Explorer - this PR introduces the Markdown cells
and some basic (non data persisting) editing

Markdown cells will save either on
- Save button click
- Losing focus on the code editor

Hitting esc will cancel the changes

<img width="1387" height="674" alt="image"
src="https://github.com/user-attachments/assets/f0614b37-7a11-404f-9940-8bcd4de25c57"
/>

<img width="1087" height="516" alt="image"
src="https://github.com/user-attachments/assets/0a104168-2001-4ef7-934a-7e864956b3cb"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added editable Markdown cells to notebooks, with save and cancel
controls.
* Added drag-and-drop reordering for notebook cells, including keyboard
support.
* New notebooks now include sample Markdown content to help users get
started.
* **Improvements**
* Improved drag-handle placement and consistency across sortable
sections.
* Updated notebook empty and populated states to reflect the current
cell content.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-11 10:41:59 +07:00

46 lines
1.2 KiB
TypeScript

import { useSortable } from '@dnd-kit/sortable'
import { GripVertical } from 'lucide-react'
import type { CSSProperties, PropsWithChildren } from 'react'
import { cn } from 'ui'
export const SortableSection = ({
id,
children,
gripClassName,
}: PropsWithChildren<{ id: string; gripClassName?: string }>) => {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id,
})
const style: CSSProperties = {
transform: transform
? `translate3d(${Math.round(transform.x)}px, ${Math.round(transform.y)}px, 0)`
: undefined,
transition,
}
return (
<div
ref={setNodeRef}
style={style}
className="relative will-change-transform flex items-start gap-x-2"
>
<button
type="button"
aria-label="Drag to reorder section"
className={cn(
'text-foreground-muted hover:text-foreground cursor-grab active:cursor-grabbing',
'rounded-sm focus-ring',
gripClassName
)}
{...attributes}
{...listeners}
tabIndex={0}
>
<GripVertical size={14} />
</button>
<div className={cn('w-full', isDragging && 'opacity-70')}>{children}</div>
</div>
)
}