update web to dashboard
This commit is contained in:
@@ -1,142 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import "./toolbar.css"
|
||||
|
||||
import { useRef, type PointerEvent as ReactPointerEvent } from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
import type { EditorToolbarAction } from "./types"
|
||||
|
||||
type EditorToolbarProps = {
|
||||
actions: ReadonlyArray<EditorToolbarAction>
|
||||
}
|
||||
|
||||
function isSeparatorAction(
|
||||
action: EditorToolbarAction
|
||||
): action is Extract<EditorToolbarAction, { type: "separator" }> {
|
||||
return "type" in action && action.type === "separator"
|
||||
}
|
||||
|
||||
function isCustomAction(
|
||||
action: EditorToolbarAction
|
||||
): action is Extract<EditorToolbarAction, { type: "custom" }> {
|
||||
return "type" in action && action.type === "custom"
|
||||
}
|
||||
|
||||
export function EditorToolbar({ actions }: EditorToolbarProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const dragStateRef = useRef<{
|
||||
pointerId: number
|
||||
startX: number
|
||||
startScrollLeft: number
|
||||
moved: boolean
|
||||
} | null>(null)
|
||||
|
||||
const handlePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {
|
||||
if (event.pointerType === "mouse" && event.button !== 0) {
|
||||
return
|
||||
}
|
||||
const container = containerRef.current
|
||||
if (!container || container.scrollWidth <= container.clientWidth) {
|
||||
return
|
||||
}
|
||||
dragStateRef.current = {
|
||||
pointerId: event.pointerId,
|
||||
startX: event.clientX,
|
||||
startScrollLeft: container.scrollLeft,
|
||||
moved: false,
|
||||
}
|
||||
container.setPointerCapture(event.pointerId)
|
||||
}
|
||||
|
||||
const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {
|
||||
const container = containerRef.current
|
||||
const dragState = dragStateRef.current
|
||||
if (!container || !dragState || dragState.pointerId !== event.pointerId) {
|
||||
return
|
||||
}
|
||||
const deltaX = event.clientX - dragState.startX
|
||||
if (Math.abs(deltaX) > 3) {
|
||||
dragState.moved = true
|
||||
}
|
||||
container.scrollLeft = dragState.startScrollLeft - deltaX
|
||||
}
|
||||
|
||||
const handlePointerEnd = (event: ReactPointerEvent<HTMLDivElement>) => {
|
||||
const container = containerRef.current
|
||||
const dragState = dragStateRef.current
|
||||
if (!container || !dragState || dragState.pointerId !== event.pointerId) {
|
||||
return
|
||||
}
|
||||
if (container.hasPointerCapture(event.pointerId)) {
|
||||
container.releasePointerCapture(event.pointerId)
|
||||
}
|
||||
window.setTimeout(() => {
|
||||
dragStateRef.current = null
|
||||
}, 0)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="content-editor-toolbar overflow-x-auto overflow-y-hidden border-b border-border px-1 py-1 h-9.25"
|
||||
onPointerDown={handlePointerDown}
|
||||
onPointerMove={handlePointerMove}
|
||||
onPointerUp={handlePointerEnd}
|
||||
onPointerCancel={handlePointerEnd}
|
||||
>
|
||||
<div className="flex min-w-max items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
{actions.map((action) => {
|
||||
if (isSeparatorAction(action)) {
|
||||
return (
|
||||
<span
|
||||
key={action.key}
|
||||
aria-hidden="true"
|
||||
className="relative mx-2 inline-block h-[0.9em] w-px self-center bg-border"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (isCustomAction(action)) {
|
||||
return <div key={action.key}>{action.content}</div>
|
||||
}
|
||||
|
||||
const Icon = action.icon
|
||||
return (
|
||||
<button
|
||||
key={action.key}
|
||||
type="button"
|
||||
aria-label={action.label}
|
||||
title={action.label}
|
||||
disabled={action.disabled}
|
||||
onClick={action.onClick}
|
||||
onClickCapture={(event) => {
|
||||
if (dragStateRef.current?.moved) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
}}
|
||||
data-pressed={action.pressed ? "true" : "false"}
|
||||
className={cn(
|
||||
"mx-[2px] cursor-pointer list-none rounded-[3px] border-none bg-transparent text-[#3f4a54] transition-all duration-300 select-none hover:bg-[#f2f2f2] disabled:cursor-not-allowed disabled:opacity-60 data-[pressed=true]:bg-[#f2f2f2] dark:text-[#999] dark:hover:bg-[#333] dark:data-[pressed=true]:bg-[#333]",
|
||||
action.icon && !action.content
|
||||
? "flex flex-col items-center px-[2px] py-0"
|
||||
: "flex flex-col items-center px-[6px] py-0"
|
||||
)}
|
||||
>
|
||||
{Icon ? <Icon className="box-content size-4 p-1" /> : null}
|
||||
{action.content ? (
|
||||
<span className="text-[12px] leading-none whitespace-nowrap">
|
||||
{action.content}
|
||||
</span>
|
||||
) : null}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user