Skip to content

Instantly share code, notes, and snippets.

@ZanzyTHEbar
Created January 3, 2024 14:35
Show Gist options
  • Save ZanzyTHEbar/75d7e2f83bcf7193d3238c07dc00fe62 to your computer and use it in GitHub Desktop.
Save ZanzyTHEbar/75d7e2f83bcf7193d3238c07dc00fe62 to your computer and use it in GitHub Desktop.
Solid-DND
import { createDraggable, transformStyle } from '@thisbeyond/solid-dnd'
import { JSXElement, createSignal, type ParentComponent, onMount } from 'solid-js'
import { TabsTrigger } from '@components/ui/tabs'
import { UITab, useAppContextUI } from '@context/ui'
/* Handle Dockable using solid-dnd */
const activeTabClasses = [
'tab-active',
'drop-shadow-2xl',
'shadow-2xl',
'[--tab-bg:var(--fallback-a,oklch(var(--p)/var(--tw-bg-opacity)))]',
'[--tab-border-color:var(--fallback-a,oklch(var(--p)/var(--tw-bg-opacity)))]',
'text-primary',
]
const DockableTab: ParentComponent<{
icon: string | JSXElement
id: string
tab: UITab
}> = (props) => {
const [tabRef, setTabRef] = createSignal<Element | null>(null)
const { setSelectedTab, defaultTab } = useAppContextUI()
const draggable = createDraggable(props.id)
/**
* @description Set the default tab
*/
onMount(() => {
handleActiveTab()
})
/**
* @description Handle the click event
* @param {MouseEvent & { currentTarget: HTMLButtonElement; target: Element }} e - The click event
*/
const handleClick = (
e: MouseEvent & {
currentTarget: HTMLButtonElement
target: Element
},
) => {
setSelectedTab(props.tab)
setTabRef(e.currentTarget)
handleActiveTab()
}
/**
* @description Set the selected tab element
* @returns {void}
*/
const handleActiveTab = () => {
if (!tabRef()) {
setSelectedTab(defaultTab())
const defaultTabElement = document.querySelector(`#${defaultTab().id}`)
setTabRef(defaultTabElement)
defaultTabElement!.classList.add(...activeTabClasses)
}
const tabs = document.querySelectorAll('.tab')
tabs.forEach((tab) => {
if (tab.classList.contains('tab-active')) {
tab.classList.remove(...activeTabClasses)
}
})
tabRef()!.classList.add(...activeTabClasses)
}
return (
<TabsTrigger
style={transformStyle(draggable.transform)}
class="draggable-container tab"
ref={draggable.ref}
id={props.id}
onClick={handleClick}
value={props.id}>
{props.icon}
</TabsTrigger>
)
}
export default DockableTab
import { DragDropProvider, DragDropSensors, createDroppable } from '@thisbeyond/solid-dnd'
import {
type Component,
For,
Show,
createSignal,
JSXElement,
onMount,
createEffect,
} from 'solid-js'
import DockableTab from '@components/DockableTab'
import { CardContent } from '@components/ui/card'
import { Tabs, TabsList, TabsContent } from '@components/ui/tabs'
import { useAppContextUI } from '@src/context/ui'
/* Handle Dockable using solid-dnd */
const TabBar: Component = () => {
let ref: Element
// read in the tab context
const { tabs, defaultTab, selectedTab } = useAppContextUI()
const [id, setID] = createSignal<string>('')
const [content, setContent] = createSignal<JSXElement | null>(null)
const droppable = createDroppable('tab-bar')
onMount(() => {
setID(defaultTab().id)
setContent(defaultTab().content)
})
createEffect(() => {
if (selectedTab() === null) return
setID(selectedTab()!.id)
setContent(selectedTab()!.content)
})
const onDragEnd = ({ draggable, droppable }) => {
if (droppable) {
droppable.node.append(draggable.node)
} else {
ref.append(draggable.node)
}
}
return (
<DragDropProvider onDragEnd={onDragEnd}>
<Tabs defaultValue={defaultTab().id} class="p-2 w-full">
<TabsList>
<DragDropSensors />
<For each={tabs()}>
{(tab) => (
<Show when={tab.visible}>
<div
ref={droppable.ref}
class="droppable"
classList={{
'!droppable-accept': droppable.isActiveDroppable,
}}>
<DockableTab ref={ref} id={tab.id} icon={tab.icon} tab={tab} />
</div>
</Show>
)}
</For>
</TabsList>
<TabsContent class="h-full w-full p-2" value={id()}>
<CardContent class="bg-base-100 rounded-box">{content()}</CardContent>
</TabsContent>
</Tabs>
</DragDropProvider>
)
}
export default TabBar
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment