Files
Genarrative/src/components/image-editor/ImageCanvasEditorPrimitives.tsx
T
menghao 03a4410272
Project CI / Native shell tests (push) Failing after 11m56s
Project CI / Repository checks (push) Successful in 1m5s
Project CI / Frontend tests (push) Successful in 3m20s
Project CI / Backend tests (push) Successful in 4m1s
game agent无限画布开发 (#136)
主要工作是共享同一套“画布内核与通用 UI 源码”,网站和 Tauri 只分别实现宿主适配层。

---------

Co-authored-by: 段舒康 <kdletters@qq.com>
Co-authored-by: kdletters <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/136
Co-authored-by: menghao <mh18530625731@163.com>
Co-committed-by: menghao <mh18530625731@163.com>
2026-08-12 10:54:16 +08:00

178 lines
4.0 KiB
TypeScript

import { CanvasChromeButton } from '@genarrative/image-canvas-react';
import type {
ComponentType,
DragEventHandler,
MouseEventHandler,
PointerEventHandler,
ReactNode,
} from 'react';
import {
PlatformIconButton,
type PlatformIconButtonVariant,
} from '../common/PlatformIconButton';
import { PlatformMediaFrame } from '../common/PlatformMediaFrame';
type IconComponent = ComponentType<{ className?: string }>;
export type EditorIconButtonProps = {
label: string;
title?: string;
icon: IconComponent;
className?: string;
type?: 'button' | 'submit';
disabled?: boolean;
pressed?: boolean;
expanded?: boolean;
variant?: PlatformIconButtonVariant;
onClick?: () => void;
};
export function EditorIconButton({
label,
title = label,
icon: Icon,
className,
type = 'button',
disabled,
pressed,
expanded,
variant,
onClick,
}: EditorIconButtonProps) {
const iconNode = <Icon className="h-4 w-4" />;
if (variant === undefined || variant === 'platformIcon') {
return (
<CanvasChromeButton
type={type}
className={className}
label={label}
title={title}
disabled={disabled}
pressed={pressed}
expanded={expanded}
onClick={onClick}
icon={iconNode}
/>
);
}
return (
<PlatformIconButton
variant={variant}
type={type}
className={className}
label={label}
title={title}
disabled={disabled}
aria-pressed={pressed}
aria-expanded={expanded}
onClick={onClick}
icon={iconNode}
/>
);
}
export type SidebarMediaItemProps = {
title: string;
detail: string;
imageSrc: string;
objectKey?: string | null;
imageAlt: string;
selected?: boolean;
primaryLabel: string;
primaryDisabled?: boolean;
onPrimaryClick: MouseEventHandler<HTMLButtonElement>;
thumbnailClassName: string;
metaClassName: string;
rowClassName: string;
primaryClassName?: string;
actions?: ReactNode;
titleNode?: ReactNode;
previewNode?: ReactNode;
previewOverlay?: ReactNode;
footerNode?: ReactNode;
draggable?: boolean;
onDragStart?: DragEventHandler<HTMLElement>;
onDragEnd?: DragEventHandler<HTMLElement>;
onDragOver?: DragEventHandler<HTMLDivElement>;
onDrop?: DragEventHandler<HTMLDivElement>;
onPointerDown?: PointerEventHandler<HTMLDivElement>;
onPointerEnter?: PointerEventHandler<HTMLDivElement>;
onContextMenu?: MouseEventHandler<HTMLDivElement>;
};
export function SidebarMediaItem({
title,
detail,
imageSrc,
objectKey,
imageAlt,
selected = false,
primaryLabel,
primaryDisabled = false,
onPrimaryClick,
thumbnailClassName,
metaClassName,
rowClassName,
primaryClassName,
actions,
titleNode,
previewNode,
previewOverlay,
footerNode,
draggable,
onDragStart,
onDragEnd,
onDragOver,
onDrop,
onPointerDown,
onPointerEnter,
onContextMenu,
}: SidebarMediaItemProps) {
return (
<div
className={`${rowClassName} ${selected ? `${rowClassName}--selected` : ''}`}
draggable={draggable}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
onDragOver={onDragOver}
onDrop={onDrop}
onPointerDown={onPointerDown}
onPointerEnter={onPointerEnter}
onContextMenu={onContextMenu}
>
<button
type="button"
className={primaryClassName}
onClick={onPrimaryClick}
aria-label={primaryLabel}
disabled={primaryDisabled}
draggable={draggable}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
>
{previewNode ?? (
<PlatformMediaFrame
src={imageSrc}
objectKey={objectKey}
alt={imageAlt}
fallbackLabel={title}
aspect="square"
surface="none"
className={thumbnailClassName}
previewOverlay={previewOverlay}
/>
)}
</button>
<div className={metaClassName}>
{titleNode ?? <span>{title}</span>}
<span>{detail}</span>
{footerNode}
</div>
{actions}
</div>
);
}