131 lines
4.2 KiB
TypeScript
131 lines
4.2 KiB
TypeScript
"use client"
|
|
|
|
import { memo, useRef } from "react"
|
|
import type { DocPageLayout } from "@/lib/drive/doc-page-setup"
|
|
import { DOCS_VERTICAL_RULER_WIDTH_PX } from "@/lib/drive/docs-page-layout-constants"
|
|
import { docsPageLengthToScreen } from "@/lib/drive/docs-ruler-scale"
|
|
import { buildVerticalRulerTicks } from "@/lib/drive/docs-ruler-math"
|
|
import type { DocsRulerMarginSide } from "@/lib/drive/docs-ruler-margin-math"
|
|
import {
|
|
DocsRulerDownTriangleMarker,
|
|
DocsRulerDraggableHandle,
|
|
DocsRulerUpTriangleMarker,
|
|
useRulerPointerDrag,
|
|
} from "@/components/drive/richtext/docs-ruler-markers"
|
|
|
|
function DocsVerticalRulerInner({
|
|
pageLayout,
|
|
scale,
|
|
editable,
|
|
onMarginDragStart,
|
|
onMarginDrag,
|
|
onMarginDragEnd,
|
|
}: {
|
|
pageLayout: DocPageLayout
|
|
scale: number
|
|
editable?: boolean
|
|
onMarginDragStart?: (side: DocsRulerMarginSide) => void
|
|
onMarginDrag?: (side: DocsRulerMarginSide, pagePx: number, clientX: number, clientY: number) => void
|
|
onMarginDragEnd?: () => void
|
|
}) {
|
|
const rulerRef = useRef<HTMLDivElement>(null)
|
|
const pageHeight = pageLayout.heightPx
|
|
const margins = pageLayout.marginsPx
|
|
const scaledHeight = docsPageLengthToScreen(pageHeight, scale)
|
|
const ticks = buildVerticalRulerTicks(pageHeight, margins.top, pageLayout.format.id)
|
|
const s = (px: number) => docsPageLengthToScreen(px, scale)
|
|
|
|
const topDrag = useRulerPointerDrag({
|
|
rulerRef,
|
|
axis: "vertical",
|
|
disabled: !editable,
|
|
onDrag: (pagePx, clientX, clientY) => onMarginDrag?.("top", pagePx, clientX, clientY),
|
|
onDragEnd: () => onMarginDragEnd?.(),
|
|
})
|
|
|
|
const bottomDrag = useRulerPointerDrag({
|
|
rulerRef,
|
|
axis: "vertical",
|
|
disabled: !editable,
|
|
onDrag: (pagePx, clientX, clientY) => onMarginDrag?.("bottom", pagePx, clientX, clientY),
|
|
onDragEnd: () => onMarginDragEnd?.(),
|
|
})
|
|
|
|
const wrapMarginDown =
|
|
(side: DocsRulerMarginSide, handler: (e: React.PointerEvent<HTMLDivElement>) => void) =>
|
|
(event: React.PointerEvent<HTMLDivElement>) => {
|
|
onMarginDragStart?.(side)
|
|
handler(event)
|
|
}
|
|
|
|
return (
|
|
<div
|
|
ref={rulerRef}
|
|
data-docs-ruler="vertical"
|
|
data-docs-ruler-scale={scale}
|
|
className="docs-vertical-ruler relative overflow-visible border-r border-[#dadce0] bg-white dark:border-border dark:bg-background"
|
|
style={{
|
|
width: DOCS_VERTICAL_RULER_WIDTH_PX,
|
|
height: scaledHeight,
|
|
}}
|
|
>
|
|
<div
|
|
className="pointer-events-none absolute left-0 right-0 bg-[#f1f3f4] dark:bg-muted/60"
|
|
style={{ top: 0, height: s(margins.top) }}
|
|
/>
|
|
<div
|
|
className="pointer-events-none absolute left-0 right-0 bg-[#f1f3f4] dark:bg-muted/60"
|
|
style={{
|
|
top: s(pageHeight - margins.bottom),
|
|
height: s(margins.bottom),
|
|
}}
|
|
/>
|
|
|
|
{ticks.map((tick, index) => (
|
|
<div
|
|
key={`${tick.pos}-${index}`}
|
|
className="pointer-events-none absolute right-0 h-px bg-[#bdc1c6] dark:bg-muted-foreground/70"
|
|
style={{
|
|
top: s(tick.pos),
|
|
width: tick.major ? 10 : 5,
|
|
}}
|
|
/>
|
|
))}
|
|
|
|
{ticks
|
|
.filter((tick) => tick.major && tick.label != null)
|
|
.map((tick) => (
|
|
<span
|
|
key={`vlabel-${tick.pos}`}
|
|
className="pointer-events-none absolute right-[11px] -translate-y-1/2 text-[9px] leading-none text-[#9aa0a6] dark:text-muted-foreground"
|
|
style={{ top: s(tick.pos) }}
|
|
>
|
|
{tick.label}
|
|
</span>
|
|
))}
|
|
|
|
<DocsRulerDraggableHandle
|
|
style={{ top: s(margins.top) }}
|
|
axis="vertical"
|
|
disabled={!editable}
|
|
ariaLabel="Marge haute"
|
|
onPointerDown={wrapMarginDown("top", topDrag.onPointerDown)}
|
|
>
|
|
<DocsRulerUpTriangleMarker top={0} />
|
|
</DocsRulerDraggableHandle>
|
|
|
|
<DocsRulerDraggableHandle
|
|
style={{ top: s(pageHeight - margins.bottom) }}
|
|
axis="vertical"
|
|
disabled={!editable}
|
|
ariaLabel="Marge basse"
|
|
onPointerDown={wrapMarginDown("bottom", bottomDrag.onPointerDown)}
|
|
>
|
|
<DocsRulerDownTriangleMarker top={0} />
|
|
</DocsRulerDraggableHandle>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const DocsVerticalRuler = memo(DocsVerticalRulerInner)
|