Files
tolaria/src/utils/viewOrdering.ts
2026-04-28 20:41:07 +02:00

63 lines
2.3 KiB
TypeScript

import type { ViewDefinition, ViewFile } from '../types'
export type ViewMoveDirection = 'up' | 'down'
export type ViewMoveHandler = (filename: string, direction: ViewMoveDirection) => Promise<void> | void
export type ViewReorderHandler = (orderedFilenames: string[]) => Promise<void> | void
export interface ViewOrderUpdate {
filename: string
definition: ViewDefinition
}
function orderedViewIndex(views: ViewFile[], filename: string): number {
return views.findIndex((view) => view.filename === filename)
}
function destinationIndex(index: number, direction: ViewMoveDirection): number {
return direction === 'up' ? index - 1 : index + 1
}
export function canMoveView(views: ViewFile[], filename: string, direction: ViewMoveDirection): boolean {
const index = orderedViewIndex(views, filename)
if (index === -1) return false
const nextIndex = destinationIndex(index, direction)
return nextIndex >= 0 && nextIndex < views.length
}
export function moveView(views: ViewFile[], filename: string, direction: ViewMoveDirection): ViewFile[] | null {
if (!canMoveView(views, filename, direction)) return null
const index = orderedViewIndex(views, filename)
const nextIndex = destinationIndex(index, direction)
const reordered = [...views]
const [view] = reordered.splice(index, 1)
reordered.splice(nextIndex, 0, view)
return reordered
}
export function orderViewsByFilename(views: ViewFile[], orderedFilenames: string[]): ViewFile[] | null {
if (views.length !== orderedFilenames.length) return null
if (new Set(orderedFilenames).size !== orderedFilenames.length) return null
const viewByFilename = new Map(views.map((view) => [view.filename, view]))
const ordered = orderedFilenames.map((filename) => viewByFilename.get(filename))
if (ordered.some((view) => view === undefined)) return null
return ordered as ViewFile[]
}
export function buildViewOrderUpdates(views: ViewFile[]): ViewOrderUpdate[] {
return views.map((view, order) => ({
filename: view.filename,
definition: { ...view.definition, order },
}))
}
export function nextViewOrder(views: ViewFile[]): number {
const explicitOrders = views
.map((view) => view.definition.order)
.filter((order): order is number => typeof order === 'number' && Number.isFinite(order))
return explicitOrders.length > 0 ? Math.max(...explicitOrders) + 1 : views.length
}