Files
UHD_Media_Tool/apps/web/app/components/slots/slot-mounts.tsx
T
rootandClaude Opus 5.5 62119a9b30 feat(web): 前端插槽设施,作品页与整理记录行挂「补字幕」
- lib/slots.ts 按位置注册(侧栏入口、作品页操作区 / 面板区、整理记录行操作、设置分区),默认直接显示;
  components/slots 挂载点:面板类直接渲染,动作类渲染成按钮 / 菜单项、对话框在菜单外渲染
- 作品页操作区与面板区、整理记录行菜单接入插槽;补字幕改由 features/subtitles.tsx 注册,
  作品页按钮行为不变,整理记录行菜单新增「补字幕」(成功 / 部分成功的入库类整理)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
2026-10-06 19:27:14 +08:00

58 lines
1.8 KiB
TypeScript

import { type ComponentType, type ReactNode, useState } from "react";
import "~/features/index.ts";
import {
type ActionPosition,
type ActionSlot,
type PanelPosition,
type PanelSlot,
type SlotProps,
type SlotRegistry,
slots,
visibleActions,
} from "~/lib/slots.ts";
// 插槽挂载点(ADR-006)。功能在 app/features/*.tsx 里注册,这里只负责在页面上渲染;没有注册时什么都不渲染。
/** 面板类插槽:按顺序渲染所有注册的组件 */
export function SlotPanels<P extends PanelPosition>({
position,
props,
registry = slots,
}: {
position: P;
props: SlotProps[P];
registry?: SlotRegistry;
}) {
const entries = registry.entries(position) as PanelSlot<P>[];
if (entries.length === 0) return null;
return (
<>
{entries.map(({ id, Component }) => (
<Component key={id} {...props} />
))}
</>
);
}
/**
* 动作类插槽:返回可见的项(页面按自己的样式渲染成按钮或菜单项)和当前打开的对话框。
* 对话框由页面渲染在菜单外面(菜单关了对话框也不会跟着卸载)。
*/
export function useSlotActions<P extends ActionPosition>(
position: P,
registry: SlotRegistry = slots,
): {
items: (props: SlotProps[P]) => ActionSlot<P>[];
open: (entry: ActionSlot<P>, props: SlotProps[P]) => void;
dialog: ReactNode;
} {
const [active, setActive] = useState<{ entry: ActionSlot<P>; props: SlotProps[P] } | null>(null);
// 泛型位置的 props 与 IntrinsicAttributes 交不出来,这里按具体对象渲染
const Dialog = active?.entry.Dialog as ComponentType<{ onClose: () => void }> | undefined;
return {
items: (props) => visibleActions(registry, position, props),
open: (entry, props) => setActive({ entry, props }),
dialog: Dialog && active ? <Dialog {...(active.props as object)} onClose={() => setActive(null)} /> : null,
};
}