diff --git a/gui/src/App.tsx b/gui/src/App.tsx index 0281f35fa..9559c53f5 100644 --- a/gui/src/App.tsx +++ b/gui/src/App.tsx @@ -80,7 +80,7 @@ function Layout() { + } @@ -88,7 +88,7 @@ function Layout() { + } diff --git a/gui/src/components/MainLayout.scss b/gui/src/components/MainLayout.scss index 7ab819adb..9c0b6816d 100644 --- a/gui/src/components/MainLayout.scss +++ b/gui/src/components/MainLayout.scss @@ -5,11 +5,13 @@ 's c' calc(100% - var(--topbar-h)) / var(--navbar-w) calc(100% - var(--navbar-w)); - &:has(.widgets) { + &.full { grid-template: 't t t' var(--topbar-h) - 's c w' calc(100% - var(--topbar-h)) - / var(--navbar-w) calc(100% - var(--navbar-w) - var(--widget-w)) var(--widget-w); + 's r r' var(--toolbar-h) + 's c l' calc(70% - var(--topbar-h) - var(--toolbar-h)) + 's c p' calc(30%) + / var(--navbar-w) calc(75% - var(--navbar-w)) calc(25%); } @screen mobile { diff --git a/gui/src/components/MainLayout.tsx b/gui/src/components/MainLayout.tsx index 3cd488eaa..87b69de18 100644 --- a/gui/src/components/MainLayout.tsx +++ b/gui/src/components/MainLayout.tsx @@ -9,19 +9,21 @@ import { import { Navbar } from './Navbar'; import { TopBar } from './TopBar'; import { useWebsocketAPI } from '@/hooks/websocket-api'; -import { WidgetsComponent } from './WidgetsComponent'; import './MainLayout.scss'; +import { Toolbar } from './Toolbar'; +import { WidgetsComponent } from './WidgetsComponent'; +import { SkeletonVisualizerWidget } from './widgets/SkeletonVisualizerWidget'; export function MainLayout({ children, background = true, - widgets = true, + full = false, isMobile = undefined, }: { children: ReactNode; background?: boolean; isMobile?: boolean; - widgets?: boolean; + full?: boolean; }) { const { sendRPCPacket } = useWebsocketAPI(); const [ProportionsLastPageOpen, setProportionsLastPageOpen] = useState(true); @@ -58,33 +60,50 @@ export function MainLayout({ }); return ( -
-
-
- -
-
- -
-
- {children} -
- {!isMobile && widgets && ( -
- -
- )} +
+
+
+
+ +
+ +
+ {children} +
+ {!isMobile && full && ( + <> +
+ +
+
+ {/* */} + +
+
+ {/* */} + {/* */} +
+ + )}
); } diff --git a/gui/src/components/Navbar.tsx b/gui/src/components/Navbar.tsx index 4401ead46..66c4ebb27 100644 --- a/gui/src/components/Navbar.tsx +++ b/gui/src/components/Navbar.tsx @@ -2,14 +2,15 @@ import { useLocalization } from '@fluent/react'; import classnames from 'classnames'; import { ReactNode } from 'react'; import { NavLink, useMatch } from 'react-router-dom'; -import { CubeIcon } from './commons/icon/CubeIcon'; import { GearIcon } from './commons/icon/GearIcon'; import { HumanIcon } from './commons/icon/HumanIcon'; import { RulerIcon } from './commons/icon/RulerIcon'; import { SparkleIcon } from './commons/icon/SparkleIcon'; -import { WrenchIcon } from './commons/icon/WrenchIcons'; import { useBreakpoint } from '@/hooks/breakpoint'; import { useConfig } from '@/hooks/config'; +import { Tooltip } from './commons/Tooltip'; +import { HomeIcon } from './commons/icon/HomeIcon'; +import { SkiIcon } from './commons/icon/SkiIcon'; export function NavButton({ to, @@ -24,43 +25,43 @@ export function NavButton({ state?: any; icon: ReactNode; }) { + const { isMobile } = useBreakpoint('mobile'); const doesMatch = useMatch({ path: match || to, }); return ( - -
-
- {icon} -
-
-
- {children} -
-
+
+
+ {icon} +
+
+ + ); } @@ -70,7 +71,7 @@ export function MainLinks() { return ( <> - }> + }> {l10n.getString('navbar-home')} } + icon={} > {l10n.getString('navbar-mounting')} diff --git a/gui/src/components/Toolbar.tsx b/gui/src/components/Toolbar.tsx new file mode 100644 index 000000000..efa59137b --- /dev/null +++ b/gui/src/components/Toolbar.tsx @@ -0,0 +1,13 @@ +import { ResetType } from 'solarxr-protocol'; +import { ResetButton } from './home/ResetButton'; + +export function Toolbar() { + return ( +
+ + + + {/* */} +
+ ); +} diff --git a/gui/src/components/commons/Tooltip.tsx b/gui/src/components/commons/Tooltip.tsx index 102ed304c..ed30d8329 100644 --- a/gui/src/components/commons/Tooltip.tsx +++ b/gui/src/components/commons/Tooltip.tsx @@ -13,11 +13,15 @@ import { createPortal } from 'react-dom'; import { Typography } from './Typography'; import { CloseIcon } from './icon/CloseIcon'; +type Direction = 'top' | 'left' | 'right' | 'bottom'; interface TooltipProps { content: ReactNode; children: ReactElement; - preferedDirection: 'top' | 'left' | 'right' | 'bottom'; + preferedDirection: Direction; + blockedDirections?: Direction[]; mode?: 'corner' | 'center'; + variant?: 'auto' | 'drawer' | 'floating'; + disabled?: boolean; } interface TooltipPos { @@ -76,6 +80,7 @@ const clamp = (v: number, min: number, max: number) => const getFloatingTooltipPosition = ( preferedDirection: TooltipProps['preferedDirection'], + blockedDirections: Direction[], mode: TooltipProps['mode'], childrenRect: DOMRect, tooltipRect: DOMRect @@ -134,9 +139,10 @@ const getFloatingTooltipPosition = ( const pos = getPosition(preferedDirection); if (isNotInside({ ...pos, height: tooltipRect.height }, windowRect)) { const [firstPos] = ['left', 'top', 'right', 'bottom'] + .filter((dir) => !blockedDirections.includes(dir as Direction)) .map((dir) => ({ dir, - area: getPosition(dir as TooltipProps['preferedDirection']), + area: getPosition(dir as Direction), })) .toSorted( (a, b) => @@ -225,12 +231,13 @@ const getFloatingTooltipPosition = ( export function FloatingTooltip({ childRef, preferedDirection, + blockedDirections = [], mode, children, }: { childRef: MutableRefObject; children: ReactNode; -} & Pick) { +} & Pick) { const tooltipRef = useRef(null); const [tooltipStyle, setTooltipStyle] = useState(); @@ -244,6 +251,7 @@ export function FloatingTooltip({ setTooltipStyle( getFloatingTooltipPosition( preferedDirection, + blockedDirections, mode, childrenRect, tooltipRect @@ -372,15 +380,15 @@ export function DrawerTooltip({ if (childRef.current && childRef.current.children[0]) { const elem = childRef.current.children[0] as HTMLElement; - elem.addEventListener('mousedown', touchStart); // for debug on desktop - elem.addEventListener('mouseup', touchEnd); // for debug on desktop - elem.addEventListener('click', touchEnd); + // elem.addEventListener('mousedown', touchStart); // for debug on desktop + // elem.addEventListener('mouseup', touchEnd); // for debug on desktop + // elem.addEventListener('click', touchEnd); elem.addEventListener('touchstart', touchStart); elem.addEventListener('touchend', touchEnd); return () => { - elem.removeEventListener('mousedown', touchStart); // for debug on desktop - elem.removeEventListener('mouseup', touchEnd); // for debug on desktop + // elem.removeEventListener('mousedown', touchStart); // for debug on desktop + // elem.removeEventListener('mouseup', touchEnd); // for debug on desktop elem.removeEventListener('touchstart', touchStart); elem.removeEventListener('touchend', touchEnd); clearTimeout(touchTimeout.current); @@ -435,30 +443,51 @@ export function Tooltip({ content, children, preferedDirection, + blockedDirections = [], mode = 'center', + variant = 'auto', + disabled = false, }: TooltipProps) { const childRef = useRef(null); const { isMobile } = useBreakpoint('mobile'); + let portal = null; + if (variant === 'auto') { + portal = isMobile ? ( + {content} + ) : ( + + {content} + + ); + } + + if (variant === 'drawer') + portal = {content}; + + if (variant === 'floating') + portal = ( + + {content} + + ); + return ( <>
{children}
- {createPortal( - isMobile ? ( - {content} - ) : ( - - {content} - - ), - document.body - )} + {!disabled && createPortal(portal, document.body)} ); } diff --git a/gui/src/components/commons/icon/HomeIcon.tsx b/gui/src/components/commons/icon/HomeIcon.tsx new file mode 100644 index 000000000..18d4f03df --- /dev/null +++ b/gui/src/components/commons/icon/HomeIcon.tsx @@ -0,0 +1,12 @@ +export function HomeIcon() { + return ( + + + + ); +} diff --git a/gui/src/components/commons/icon/SkiIcon.tsx b/gui/src/components/commons/icon/SkiIcon.tsx new file mode 100644 index 000000000..4befe76de --- /dev/null +++ b/gui/src/components/commons/icon/SkiIcon.tsx @@ -0,0 +1,12 @@ +export function SkiIcon() { + return ( + + + + ); +} diff --git a/gui/src/components/onboarding/OnboardingLayout.tsx b/gui/src/components/onboarding/OnboardingLayout.tsx index 671ada5e6..3302ac65d 100644 --- a/gui/src/components/onboarding/OnboardingLayout.tsx +++ b/gui/src/components/onboarding/OnboardingLayout.tsx @@ -34,8 +34,6 @@ export function OnboardingLayout({ children }: { children: ReactNode }) {
) : ( - - {children} - + {children} ); } diff --git a/gui/src/components/widgets/SkeletonVisualizerWidget.tsx b/gui/src/components/widgets/SkeletonVisualizerWidget.tsx index 19725cab0..c8e7a709e 100644 --- a/gui/src/components/widgets/SkeletonVisualizerWidget.tsx +++ b/gui/src/components/widgets/SkeletonVisualizerWidget.tsx @@ -32,7 +32,7 @@ declare module '@react-three/fiber' { } } -const GROUND_COLOR = '#4444aa'; +const GROUND_COLOR = '#2c2c6b'; const FRUSTUM_SIZE = 10; const FACTOR = 2; // Not currently used but nice to have @@ -196,7 +196,7 @@ export function SkeletonVisualizerWidget({ if (!skeleton.current) return <>; return ( -
+
@@ -205,8 +205,8 @@ export function SkeletonVisualizerWidget({ } > diff --git a/gui/src/index.scss b/gui/src/index.scss index 6bbdd8876..ce090e060 100644 --- a/gui/src/index.scss +++ b/gui/src/index.scss @@ -87,13 +87,15 @@ body { // overflow: hidden; -- NEVER EVER BRING THIS BACK <3 background: theme('colors.background.20'); - --navbar-w: 101px; - --widget-w: 274px; + --navbar-w: 66px; --topbar-h: 38px; + --toolbar-h: 65px; + --preview-w: 400px; + --flightlist-w: 272px; @screen mobile { --topbar-h: 44px; - --navbar-h: 90px; + --navbar-h: 60px; } } diff --git a/gui/src/utils/skeletonHelper.ts b/gui/src/utils/skeletonHelper.ts index 0ff8f8e23..9e3d9edd0 100644 --- a/gui/src/utils/skeletonHelper.ts +++ b/gui/src/utils/skeletonHelper.ts @@ -192,7 +192,7 @@ export class BoneKind extends Bone { case BodyPart.NECK: return new Color('silver'); case BodyPart.UPPER_CHEST: - return new Color('blue'); + return new Color('chartreuse'); case BodyPart.CHEST: return new Color('purple'); case BodyPart.WAIST: @@ -201,13 +201,13 @@ export class BoneKind extends Bone { return new Color('orange'); case BodyPart.LEFT_UPPER_LEG: case BodyPart.RIGHT_UPPER_LEG: - return new Color('blue'); + return new Color('chartreuse'); case BodyPart.LEFT_LOWER_LEG: case BodyPart.RIGHT_LOWER_LEG: return new Color('teal'); case BodyPart.LEFT_FOOT: case BodyPart.RIGHT_FOOT: - return new Color('#00ffcc'); + return new Color('gold'); case BodyPart.LEFT_LOWER_ARM: case BodyPart.RIGHT_LOWER_ARM: return new Color('red');