119 lines
3.0 KiB
TypeScript
119 lines
3.0 KiB
TypeScript
import { t } from '@/i18n'
|
|
import type { ArticleCapability, CoverageEntry } from '@/lib/articleTypes'
|
|
import { holds } from '@/lib/editorCapabilities'
|
|
import { unpublishLabel } from '@/lib/editorLabels'
|
|
|
|
export interface OverflowItem {
|
|
key: 'unpublish' | 'editSlug' | 'move' | 'deleteVersion' | 'deleteArticle'
|
|
label: string
|
|
icon: string
|
|
danger: boolean
|
|
disabled: boolean
|
|
reason: string
|
|
onSelect: () => void
|
|
}
|
|
|
|
export interface OverflowContext {
|
|
capabilities: ArticleCapability[]
|
|
siblings: CoverageEntry[]
|
|
language: string | null
|
|
unpublishInMenu: boolean
|
|
handlers: Partial<Record<OverflowItem['key'], () => void>>
|
|
}
|
|
|
|
function ignore() {
|
|
return undefined
|
|
}
|
|
|
|
function unavailable(key: OverflowItem['key'], context: OverflowContext): Partial<OverflowItem> {
|
|
return context.handlers[key] ? {} : { disabled: true, reason: t('Not available yet.') }
|
|
}
|
|
|
|
function item(
|
|
key: OverflowItem['key'],
|
|
label: string,
|
|
icon: string,
|
|
context: OverflowContext,
|
|
extra: Partial<OverflowItem> = {},
|
|
): OverflowItem {
|
|
return {
|
|
key,
|
|
label,
|
|
icon,
|
|
danger: false,
|
|
disabled: false,
|
|
reason: '',
|
|
onSelect: context.handlers[key] ?? ignore,
|
|
...unavailable(key, context),
|
|
...extra,
|
|
}
|
|
}
|
|
|
|
function deleteVersionLabel(language: string | null) {
|
|
return language ? t('Delete {0} version', [language]) : t('Delete article')
|
|
}
|
|
|
|
function blocksWholeArticle(context: OverflowContext) {
|
|
return context.siblings.some((sibling) => !holds(sibling.capabilities, 'delete'))
|
|
}
|
|
|
|
function blockedExtra(blocked: boolean, reason: string): Partial<OverflowItem> {
|
|
return blocked ? { disabled: true, reason } : {}
|
|
}
|
|
|
|
function editItems(context: OverflowContext): OverflowItem[] {
|
|
const blocked = blocksWholeArticle(context)
|
|
return [
|
|
item('editSlug', t('Edit slug'), 'i-lucide-link', context),
|
|
item(
|
|
'move',
|
|
t('Move article'),
|
|
'i-lucide-arrow-right-left',
|
|
context,
|
|
blockedExtra(blocked, t("You can't delete this article.")),
|
|
),
|
|
]
|
|
}
|
|
|
|
function deleteItems(context: OverflowContext): OverflowItem[] {
|
|
if (context.language && context.siblings.length === 0) {
|
|
return [
|
|
item('deleteArticle', t('Delete article'), 'i-lucide-trash-2', context, {
|
|
danger: true,
|
|
}),
|
|
]
|
|
}
|
|
const versionItem = item(
|
|
'deleteVersion',
|
|
deleteVersionLabel(context.language),
|
|
'i-lucide-trash-2',
|
|
context,
|
|
{ danger: true },
|
|
)
|
|
if (!context.language) {
|
|
return [versionItem]
|
|
}
|
|
const blocked = blocksWholeArticle(context)
|
|
return [
|
|
versionItem,
|
|
item('deleteArticle', t('Delete article'), 'i-lucide-trash-2', context, {
|
|
danger: !blocked,
|
|
...blockedExtra(blocked, t("You can't delete this article.")),
|
|
}),
|
|
]
|
|
}
|
|
|
|
export function overflowItems(context: OverflowContext): OverflowItem[] {
|
|
const items: OverflowItem[] = []
|
|
if (context.unpublishInMenu) {
|
|
items.push(item('unpublish', unpublishLabel(context.language), 'i-lucide-eye-off', context))
|
|
}
|
|
if (holds(context.capabilities, 'edit')) {
|
|
items.push(...editItems(context))
|
|
}
|
|
if (holds(context.capabilities, 'delete')) {
|
|
items.push(...deleteItems(context))
|
|
}
|
|
return items
|
|
}
|