Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fission/bun.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "synthesis-fission",
Expand Down
4 changes: 3 additions & 1 deletion fission/src/Synthesis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { SnackbarProvider } from "notistack"
import Slide from "@mui/material/Slide"
import { useCallback, useEffect, useRef, useState } from "react"
import { globalAddToast } from "@/components/GlobalUIControls.ts"
import MainHUD from "@/components/MainHUD"
import MainHUD, { EVENT_KEY_OPEN_MAIN_HUD } from "@/components/MainHUD"
import MultiplayerHUD from "@/components/MultiplayerHUD.tsx"
import Scene from "@/components/Scene.tsx"
import MultiplayerStartModal from "@/modals/MultiplayerStartModal.tsx"
Expand Down Expand Up @@ -40,6 +40,8 @@ function Synthesis() {
World.updateWorld()
}

document.dispatchEvent(new Event(EVENT_KEY_OPEN_MAIN_HUD))

mainLoop()
}
useEffect(() => {
Expand Down
71 changes: 71 additions & 0 deletions fission/src/ui/components/HelpPopover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Button, List, ListItemButton, ListItemIcon, ListItemText, Popover } from "@mui/material"
import { IoHelpCircle } from "react-icons/io5"
import { useCallback, useState } from "react"
import { type HelpOption, HelpOptionType } from "@/util/HelpOption"
import { FaDiscord, FaYoutube } from "react-icons/fa6"
import { MdArticle } from "react-icons/md"

function helpOptionIcon(type: HelpOptionType) {
switch (type) {
case HelpOptionType.YouTube:
return <FaYoutube />
case HelpOptionType.Codelab:
return <MdArticle />
case HelpOptionType.Discord:
return <FaDiscord />
case HelpOptionType.Website:
return <IoHelpCircle />
default:
return <IoHelpCircle />
}
}

const HelpPopover: React.FC<{ id: string; helpOptions?: HelpOption[] }> = ({ id, helpOptions }) => {
const [helpPopoverAnchor, setHelpPopoverAnchor] = useState<HTMLButtonElement | null>(null)

const handleHelpButton = useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
setHelpPopoverAnchor(event.currentTarget)
}, [])

const handleCloseHelpPopover = useCallback(() => {
setHelpPopoverAnchor(null)
}, [])

const helpPopoverOpen = Boolean(helpPopoverAnchor)
const helpPopoverId = helpPopoverOpen ? id : undefined

return (
helpOptions && (
<>
<Button variant="outlined" startIcon={<IoHelpCircle />} onClick={handleHelpButton}>
Help
</Button>
<Popover
id={helpPopoverId}
open={helpPopoverOpen}
anchorEl={helpPopoverAnchor}
onClose={handleCloseHelpPopover}
anchorOrigin={{
vertical: "bottom",
horizontal: "center",
}}
>
<List
sx={{ width: "100%", maxWidth: 360, bgcolor: "background.paper" }}
component="nav"
aria-labelledby="nested-list-subheader"
>
{helpOptions.map(x => (
<ListItemButton onClick={() => window.open(x.link, "_blank", "noopener, noreferrer")}>
<ListItemIcon>{helpOptionIcon(x.type)}</ListItemIcon>
<ListItemText primary={x.text} />
</ListItemButton>
))}
</List>
</Popover>
</>
)
)
}

export { HelpPopover }
31 changes: 30 additions & 1 deletion fission/src/ui/components/MainHUD.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, ButtonGroup, ButtonProps, Stack } from "@mui/material"
import { Box, ButtonGroup, type ButtonProps, Stack } from "@mui/material"
import { motion } from "framer-motion"
import type React from "react"
import { useEffect, useState } from "react"
Expand All @@ -22,6 +22,23 @@ import { setAddToast, setOpenModal, setOpenPanel } from "./GlobalUIControls"
import { Button, IconButton, SynthesisIcons } from "./StyledComponents"
import { TouchControlsEvent, TouchControlsEventKeys } from "./TouchControls"
import UserIcon from "./UserIcon"
import { HelpPopover } from "./HelpPopover"
import {
HELP_OPTION_ALL_TUTORIALS,
HELP_OPTION_DISCORD,
HELP_OPTION_EXPORT_CODELAB,
HELP_OPTION_SPAWN_ASSET_YOUTUBE,
type HelpOption,
} from "@/util/HelpOption"

const HELP_OPTIONS: HelpOption[] = [
HELP_OPTION_SPAWN_ASSET_YOUTUBE,
HELP_OPTION_EXPORT_CODELAB,
HELP_OPTION_ALL_TUTORIALS,
HELP_OPTION_DISCORD,
]

export const EVENT_KEY_OPEN_MAIN_HUD = "openMainHud"

const MainHUDButton: React.FC<ButtonProps> = ({ startIcon, endIcon, children, ...props }) => {
return (
Expand Down Expand Up @@ -61,6 +78,17 @@ const MainHUD: React.FC = () => {
const [userInfo, setUserInfo] = useState(APS.userInfo)
const [matchModeRunning, setMatchModeRunning] = useState(MatchMode.getInstance().isMatchEnabled())

useEffect(() => {
const handler = (event: Event) => {
if (event.type === EVENT_KEY_OPEN_MAIN_HUD) setIsOpen(true)
}

document.addEventListener(EVENT_KEY_OPEN_MAIN_HUD, handler)
return () => {
document.removeEventListener(EVENT_KEY_OPEN_MAIN_HUD, handler)
}
}, [])

useEffect(() => {
document.addEventListener(APS_USER_INFO_UPDATE_EVENT, () => {
setUserInfo(APS.userInfo)
Expand Down Expand Up @@ -267,6 +295,7 @@ const MainHUD: React.FC = () => {
Abort Match Mode
</MainHUDButton>
)}
<HelpPopover id="main-hud-help" helpOptions={HELP_OPTIONS} />
</Box>
</>
)
Expand Down
16 changes: 13 additions & 3 deletions fission/src/ui/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Card, CardActions, CardContent, CardHeader, Modal as MUIModal } from "@mui/material"
import React, { type ReactElement } from "react"
import { Box, Card, CardActions, CardContent, CardHeader, Modal as MUIModal, Typography } from "@mui/material"
import React, { useMemo, type ReactElement } from "react"
import type { Modal as ModalType, Panel as PanelType } from "../helpers/UIProviderHelpers"
import { CloseType, useUIContext } from "../helpers/UIProviderHelpers"
import { Button } from "./StyledComponents"
import { HelpPopover } from "./HelpPopover"

export type ModalImplProps<T, P> = Partial<{
modal: ModalType<T, P>
Expand All @@ -22,6 +23,15 @@ export const Modal = <T, P>({ children, modal, parent }: ModalElementProps<T, P>

const props = modal.props

const header = useMemo(() => {
return (
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
<Typography>{props.title}</Typography>
<HelpPopover id={`model-help-${modal.id}`} helpOptions={modal.props.helpOptions} />
</Box>
)
}, [props.title])

return (
<MUIModal
open={modal !== undefined}
Expand All @@ -47,7 +57,7 @@ export const Modal = <T, P>({ children, modal, parent }: ModalElementProps<T, P>
>
{props.title && (
<CardHeader
title={props.title}
title={header}
className="select-none"
titleTypographyProps={{ variant: "h5" }}
sx={{
Expand Down
24 changes: 21 additions & 3 deletions fission/src/ui/components/Panel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Card, CardActions, CardContent, CardHeader } from "@mui/material"
import React, { type ReactElement, useRef } from "react"
import { Box, Card, CardActions, CardContent, CardHeader, Typography } from "@mui/material"
import React, { type ReactElement, useMemo, useRef } from "react"
import Draggable from "react-draggable"
import {
CloseType,
Expand All @@ -9,6 +9,7 @@ import {
useUIContext,
} from "../helpers/UIProviderHelpers"
import { Button } from "./StyledComponents"
import { HelpPopover } from "./HelpPopover"

// biome-ignore-start lint/suspicious/noExplicitAny: need to be able to extend
export type PanelImplProps<T, P> = Partial<{
Expand Down Expand Up @@ -59,6 +60,23 @@ export const Panel = <T, P>({ children, panel, parent }: PanelElementProps<T, P>
const props = panel.props
const nodeRef = useRef<HTMLDivElement | null>(null)

const header = useMemo(() => {
return (
<Box
sx={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
gap: "1rem",
}}
>
<Typography variant="h5">{props.title}</Typography>
<HelpPopover id={`panel-help-${panel.id}`} helpOptions={panel.props.helpOptions} />
</Box>
)
}, [props.title])

// FIXME: sliders show up as <span> so want to cancel drag on those
// however still can drag on dropdown but menu elements are left behind
return (
Expand All @@ -84,7 +102,7 @@ export const Panel = <T, P>({ children, panel, parent }: PanelElementProps<T, P>
>
{props.title && (
<CardHeader
title={props.title}
title={header}
className="panel-drag-handle select-none hover:cursor-grab active:cursor-grabbing"
sx={{
cursor: "move",
Expand Down
2 changes: 2 additions & 0 deletions fission/src/ui/helpers/UIProviderHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createContext, type FunctionComponent, type ReactNode, useContext } fro
import type { ModalImplProps } from "../components/Modal"
import type { PanelImplProps } from "../components/Panel"
import type { UICallback } from "../UICallbacks"
import type { HelpOption } from "@/util/HelpOption"

export enum CloseType {
Accept = 0,
Expand All @@ -28,6 +29,7 @@ export interface UIScreenProps<P> {
disableAccept?: boolean
cancelText?: string
acceptText?: string
helpOptions?: HelpOption[]
custom: P
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { Tab, Tabs } from "@mui/material"
import { SoundPlayer } from "@/systems/sound/SoundPlayer"
import CommandRegistry, { type CommandDefinition, type CommandProvider } from "@/ui/components/CommandRegistry"
import { globalOpenPanel } from "@/ui/components/GlobalUIControls"
import { HELP_OPTION_CONFIGURE_YOUTUBE } from "@/util/HelpOption"

// Register command: Configure Assets (module-scope side effect)
CommandRegistry.get().registerCommands([
Expand Down Expand Up @@ -314,7 +315,12 @@ const ConfigurePanel: React.FC<PanelImplProps<void, ConfigurePanelCustomProps>>

configureScreen(
panel!,
{ title: "Configure Assets", acceptText: "Save", cancelText: "Cancel" },
{
title: "Configure Assets",
acceptText: "Save",
cancelText: "Cancel",
helpOptions: [HELP_OPTION_CONFIGURE_YOUTUBE],
},
{ onBeforeAccept, onCancel }
)
}, [selectedAssembly, pendingDeletes])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { useUIContext } from "@/ui/helpers/UIProviderHelpers"
import NewInputSchemeModal from "@/ui/modals/configuring/inputs/NewInputSchemeModal"
import ConfigurePanel from "../assembly-config/ConfigurePanel"
import InputSchemeSelection from "./InputSchemeSelection"
import { HELP_OPTION_SPAWN_ASSET_YOUTUBE } from "@/util/HelpOption"

const InitialConfigPanel: React.FC<PanelImplProps<void, void>> = ({ panel }) => {
// TODO: can we pass these as custom props?
Expand Down Expand Up @@ -76,7 +77,12 @@ const InitialConfigPanel: React.FC<PanelImplProps<void, void>> = ({ panel }) =>

configureScreen(
panel!,
{ title: "Assembly Setup", acceptText: "Finish", cancelText: "Remove" },
{
title: "Assembly Setup",
acceptText: "Finish",
cancelText: "Remove",
helpOptions: [HELP_OPTION_SPAWN_ASSET_YOUTUBE],
},
{
onBeforeAccept: () => {
closeFinish()
Expand Down
12 changes: 11 additions & 1 deletion fission/src/ui/panels/mirabuf/ImportMirabufPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
import InitialConfigPanel from "../configuring/initial-config/InitialConfigPanel"
import CommandRegistry from "@/ui/components/CommandRegistry"
import type { CustomOrbitControls } from "@/systems/scene/CameraControls"
import { HELP_OPTION_SPAWN_ASSET_YOUTUBE } from "@/util/HelpOption"

// Register commands: Open import panel scoped to robots/fields (module-scope side effect)
CommandRegistry.get().registerCommands([
Expand Down Expand Up @@ -192,7 +193,16 @@ const ImportMirabufPanel: React.FC<PanelImplProps<void, ImportMirabufPanelCustom
const [files, setFiles] = useState<Data[] | undefined>(undefined)

useEffect(() => {
configureScreen(panel!, { title: "Spawn Asset", hideAccept: true, cancelText: "Back" }, {})
configureScreen(
panel!,
{
title: "Spawn Asset",
hideAccept: true,
cancelText: "Back",
helpOptions: [HELP_OPTION_SPAWN_ASSET_YOUTUBE],
},
{}
)
}, [])

useEffect(() => {
Expand Down
42 changes: 42 additions & 0 deletions fission/src/util/HelpOption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export enum HelpOptionType {
YouTube = "YouTube",
Codelab = "Codelab",
Website = "Website",
Discord = "Discord",
}

export type HelpOption = {
text: string
link: string
type: HelpOptionType
}

export const HELP_OPTION_SPAWN_ASSET_YOUTUBE: HelpOption = {
text: "How to Spawn a Robot/Field",
link: "https://youtu.be/u608dgHAc2s?si=25tbYWZpHNxGdVzU",
type: HelpOptionType.YouTube,
}

export const HELP_OPTION_CONFIGURE_YOUTUBE: HelpOption = {
text: "How to Configure a Robot/Field",
link: "https://youtu.be/hHf-7Ojl-fE?si=6xpjRkiFwjrosDyd",
type: HelpOptionType.YouTube,
}

export const HELP_OPTION_DISCORD: HelpOption = {
text: "Synthesis Community",
link: "https://discord.gg/AnGhEyAn",
type: HelpOptionType.Discord,
}

export const HELP_OPTION_EXPORT_CODELAB: HelpOption = {
text: "Exporter Guide",
link: "https://synthesis.autodesk.com/codelab/FusionExporterCodelab/#0",
type: HelpOptionType.Codelab,
}

export const HELP_OPTION_ALL_TUTORIALS: HelpOption = {
text: "All Tutorials",
link: "https://synthesis.autodesk.com/tutorials.html",
type: HelpOptionType.Website,
}
Loading