|
import React, { useEffect, useMemo, useState } from 'react' |
|
import * as Menubar from '@radix-ui/react-menubar' |
|
import { CheckIcon, DotFilledIcon } from '@radix-ui/react-icons' |
|
|
|
import classes from './styles.module.css' |
|
import { BodyEditor } from '../../editor' |
|
import i18n, { IsChina } from '../../i18n' |
|
import { Helper } from '../../environments/online/helper' |
|
import { uploadImage } from '../../utils/transfer' |
|
import { getCurrentTime } from '../../utils/time' |
|
import useForceUpdate from '../../hooks/useFoceUpdate' |
|
import classNames from 'classnames' |
|
import { useLanguageSelect } from '../../hooks' |
|
import { ShowContextMenu } from '../ContextMenu' |
|
import { ShowDialog } from '../Dialog' |
|
import { SetCDNBase } from '../../utils/detect' |
|
|
|
const { |
|
MenubarRoot, |
|
MenubarTrigger, |
|
MenubarContent, |
|
MenubarItem, |
|
MenubarCheckboxItem, |
|
MenubarRadioItem, |
|
MenubarItemIndicator, |
|
MenubarSeparator, |
|
RightSlot, |
|
Blue, |
|
inset, |
|
} = classes |
|
const MenubarDemo: React.FC<{ |
|
editor: BodyEditor |
|
onChangeBackground: (url: string) => void |
|
onScreenShot: (data: Record<string, { src: string; title: string }>) => void |
|
style?: React.CSSProperties |
|
}> = ({ editor, onChangeBackground, onScreenShot, style }) => { |
|
const forceUpdate = useForceUpdate() |
|
const helper = useMemo(() => new Helper(editor), [editor]) |
|
const { current, changeLanguage, languagList } = useLanguageSelect() |
|
|
|
useEffect(() => { |
|
const show = (data: { mouseX: number; mouseY: number }) => { |
|
ShowContextMenu({ ...data, editor, onChangeBackground }) |
|
} |
|
editor?.ContextMenuEventManager.AddEventListener(show) |
|
return () => { |
|
editor?.ContextMenuEventManager.RemoveEventListener(show) |
|
} |
|
}, [editor]) |
|
|
|
return ( |
|
<Menubar.Root className={MenubarRoot} style={style}> |
|
<Menubar.Menu> |
|
<Menubar.Trigger className={MenubarTrigger}> |
|
{i18n.t('File')} |
|
</Menubar.Trigger> |
|
<Menubar.Portal> |
|
<Menubar.Content |
|
className={MenubarContent} |
|
align="start" |
|
sideOffset={5} |
|
alignOffset={-3} |
|
> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => editor.ResetScene()} |
|
> |
|
{i18n.t('Reset Scene')} |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => editor.LoadScene()} |
|
> |
|
{i18n.t('Load Scene')} |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => editor.SaveScene()} |
|
> |
|
{i18n.t('Save Scene')} |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => helper.LoadGesture()} |
|
> |
|
{i18n.t('Load Gesture')} |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => helper.SaveGesture()} |
|
> |
|
{i18n.t('Save Gesture')} |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => { |
|
helper.GenerateSceneURL() |
|
}} |
|
> |
|
{i18n.t('Generate Scene URL')} |
|
</Menubar.Item> |
|
<Menubar.Separator className={MenubarSeparator} /> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => editor.RestoreLastSavedScene()} |
|
> |
|
{i18n.t('Restore Last Scene')} |
|
</Menubar.Item> |
|
<Menubar.Separator className={MenubarSeparator} /> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => |
|
helper.DetectFromImage(onChangeBackground) |
|
} |
|
> |
|
{i18n.t('Detect From Image')} |
|
</Menubar.Item> |
|
{IsChina() ? ( |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => { |
|
SetCDNBase(false) |
|
helper.DetectFromImage(onChangeBackground) |
|
}} |
|
> |
|
{i18n.t('Detect From Image') + ' [中国]'} |
|
</Menubar.Item> |
|
) : undefined} |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => helper.SetRandomPose()} |
|
> |
|
{i18n.t('Set Random Pose')} |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={async () => { |
|
const image = await uploadImage() |
|
if (image) onChangeBackground(image) |
|
}} |
|
> |
|
{i18n.t('Set Background Image')} |
|
</Menubar.Item> |
|
<Menubar.Item className={MenubarItem}> |
|
v{__APP_VERSION__} |
|
</Menubar.Item> |
|
</Menubar.Content> |
|
</Menubar.Portal> |
|
</Menubar.Menu> |
|
|
|
<Menubar.Menu> |
|
<Menubar.Trigger className={MenubarTrigger}> |
|
{i18n.t('Edit')} |
|
</Menubar.Trigger> |
|
<Menubar.Portal> |
|
<Menubar.Content |
|
className={MenubarContent} |
|
align="start" |
|
sideOffset={5} |
|
alignOffset={-3} |
|
> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => editor.Undo()} |
|
> |
|
{i18n.t('Undo')} |
|
<div className={RightSlot}>⌘ Z</div> |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => editor.Redo()} |
|
> |
|
{i18n.t('Redo')} |
|
<div className={RightSlot}>⇧ ⌘ Z</div> |
|
</Menubar.Item> |
|
<Menubar.Separator className={MenubarSeparator} /> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => editor.CopySelectedBody()} |
|
> |
|
{i18n.t('Duplicate Skeleton')} |
|
<div className={RightSlot}>⇧ D</div> |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={MenubarItem} |
|
onSelect={() => editor.RemoveBody()} |
|
> |
|
{i18n.t('Delete Skeleton')} |
|
<div className={RightSlot}>{i18n.t('Del')}</div> |
|
</Menubar.Item> |
|
</Menubar.Content> |
|
</Menubar.Portal> |
|
</Menubar.Menu> |
|
|
|
<Menubar.Menu> |
|
<Menubar.Trigger className={MenubarTrigger}> |
|
{i18n.t('View')} |
|
</Menubar.Trigger> |
|
<Menubar.Portal> |
|
<Menubar.Content |
|
className={MenubarContent} |
|
align="start" |
|
sideOffset={5} |
|
alignOffset={-14} |
|
> |
|
<Menubar.Item |
|
className={classNames(MenubarItem, inset)} |
|
onSelect={() => { |
|
editor.LockView() |
|
}} |
|
> |
|
{i18n.t('Lock View')} |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={classNames(MenubarItem, inset)} |
|
onSelect={() => { |
|
editor.UnlockView() |
|
}} |
|
> |
|
{i18n.t('Unlock View')} |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={classNames(MenubarItem, inset)} |
|
onSelect={() => { |
|
editor.RestoreView() |
|
}} |
|
> |
|
{i18n.t('Restore View')} |
|
</Menubar.Item> |
|
</Menubar.Content> |
|
</Menubar.Portal> |
|
</Menubar.Menu> |
|
|
|
<Menubar.Menu> |
|
<Menubar.Trigger className={MenubarTrigger}> |
|
{i18n.t('Setting')} |
|
</Menubar.Trigger> |
|
<Menubar.Portal> |
|
<Menubar.Content |
|
className={MenubarContent} |
|
align="start" |
|
sideOffset={5} |
|
alignOffset={-14} |
|
> |
|
<Menubar.CheckboxItem |
|
className={classNames(MenubarCheckboxItem, inset)} |
|
checked={editor.MoveMode} |
|
onCheckedChange={() => { |
|
editor.MoveMode = !editor.MoveMode |
|
forceUpdate() |
|
}} |
|
> |
|
<Menubar.ItemIndicator |
|
className={MenubarItemIndicator} |
|
> |
|
<CheckIcon /> |
|
</Menubar.ItemIndicator> |
|
{i18n.t('Move Mode')} |
|
</Menubar.CheckboxItem> |
|
<Menubar.CheckboxItem |
|
className={classNames(MenubarCheckboxItem, inset)} |
|
checked={editor.FreeMode} |
|
onCheckedChange={() => { |
|
editor.FreeMode = !editor.FreeMode |
|
forceUpdate() |
|
}} |
|
> |
|
<Menubar.ItemIndicator |
|
className={MenubarItemIndicator} |
|
> |
|
<CheckIcon /> |
|
</Menubar.ItemIndicator> |
|
{i18n.t('Free Mode')} |
|
</Menubar.CheckboxItem> |
|
<Menubar.CheckboxItem |
|
className={classNames(MenubarCheckboxItem, inset)} |
|
checked={editor.OnlyHand} |
|
onCheckedChange={() => { |
|
editor.OnlyHand = !editor.OnlyHand |
|
forceUpdate() |
|
}} |
|
> |
|
<Menubar.ItemIndicator |
|
className={MenubarItemIndicator} |
|
> |
|
<CheckIcon /> |
|
</Menubar.ItemIndicator> |
|
{i18n.t('Only Hand')} |
|
</Menubar.CheckboxItem> |
|
<Menubar.CheckboxItem |
|
className={classNames(MenubarCheckboxItem, inset)} |
|
checked={editor.enablePreview} |
|
onCheckedChange={() => { |
|
editor.enablePreview = !editor.enablePreview |
|
forceUpdate() |
|
}} |
|
> |
|
<Menubar.ItemIndicator |
|
className={MenubarItemIndicator} |
|
> |
|
<CheckIcon /> |
|
</Menubar.ItemIndicator> |
|
{i18n.t('Show Preview')} |
|
</Menubar.CheckboxItem> |
|
<Menubar.CheckboxItem |
|
className={classNames(MenubarCheckboxItem, inset)} |
|
checked={editor.EnableHelper} |
|
onCheckedChange={() => { |
|
editor.EnableHelper = !editor.EnableHelper |
|
forceUpdate() |
|
}} |
|
> |
|
<Menubar.ItemIndicator |
|
className={MenubarItemIndicator} |
|
> |
|
<CheckIcon /> |
|
</Menubar.ItemIndicator> |
|
{i18n.t('Show Grid')} |
|
</Menubar.CheckboxItem> |
|
</Menubar.Content> |
|
</Menubar.Portal> |
|
</Menubar.Menu> |
|
|
|
<Menubar.Menu> |
|
<Menubar.Trigger className={MenubarTrigger}> |
|
{i18n.t('Feedback')} |
|
</Menubar.Trigger> |
|
<Menubar.Portal> |
|
<Menubar.Content |
|
className={MenubarContent} |
|
align="start" |
|
sideOffset={5} |
|
alignOffset={-14} |
|
> |
|
<Menubar.Item |
|
className={classNames(MenubarItem, inset)} |
|
onSelect={() => { |
|
helper.FeedbackByGithub() |
|
}} |
|
> |
|
Github |
|
</Menubar.Item> |
|
<Menubar.Item |
|
className={classNames(MenubarItem, inset)} |
|
onSelect={() => { |
|
helper.FeedbackByQQ() |
|
}} |
|
> |
|
QQ |
|
</Menubar.Item> |
|
</Menubar.Content> |
|
</Menubar.Portal> |
|
</Menubar.Menu> |
|
<Menubar.Menu> |
|
<Menubar.Trigger className={MenubarTrigger}> |
|
Language |
|
</Menubar.Trigger> |
|
<Menubar.Portal> |
|
<Menubar.Content |
|
className={MenubarContent} |
|
align="start" |
|
sideOffset={5} |
|
alignOffset={-14} |
|
> |
|
<Menubar.RadioGroup |
|
value={current} |
|
onValueChange={(v) => { |
|
changeLanguage(v) |
|
}} |
|
> |
|
{languagList.map((item) => ( |
|
<Menubar.RadioItem |
|
className={classNames( |
|
MenubarRadioItem, |
|
inset |
|
)} |
|
key={item} |
|
value={item} |
|
> |
|
<Menubar.ItemIndicator |
|
className={MenubarItemIndicator} |
|
> |
|
<DotFilledIcon /> |
|
</Menubar.ItemIndicator> |
|
{item} |
|
</Menubar.RadioItem> |
|
))} |
|
</Menubar.RadioGroup> |
|
</Menubar.Content> |
|
</Menubar.Portal> |
|
</Menubar.Menu> |
|
<Menubar.Menu> |
|
<Menubar.Trigger |
|
className={classNames(MenubarTrigger, Blue)} |
|
onClick={async () => { |
|
const image = editor.MakeImages() |
|
const result = Object.fromEntries( |
|
Object.entries(image).map(([name, imgData]) => [ |
|
name, |
|
{ |
|
src: imgData, |
|
title: name + '_' + getCurrentTime(), |
|
}, |
|
]) |
|
) |
|
onScreenShot(result) |
|
}} |
|
> |
|
{i18n.t('Generate')} |
|
</Menubar.Trigger> |
|
</Menubar.Menu> |
|
</Menubar.Root> |
|
) |
|
} |
|
|
|
export default MenubarDemo |
|
|