Lots of misc gui fixes (#516)

Co-authored-by: Louka <marioluigivideo@gmail.com>
This commit is contained in:
Uriel
2023-01-29 13:57:25 -03:00
committed by GitHub
parent 7455c308e8
commit 7e65d02431
17 changed files with 4450 additions and 2070 deletions

View File

@@ -11,14 +11,9 @@
"@tauri-apps/api": "^1.2.0",
"@vitejs/plugin-react": "^3.0.0",
"browserslist": "^4.18.1",
"camelcase": "^6.2.1",
"classnames": "^2.3.1",
"dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0",
"eslint-config-react-app": "^7.0.0",
"file-loader": "^6.2.0",
"flatbuffers": "^22.10.26",
"fs-extra": "^10.0.0",
"identity-obj-proxy": "^3.0.0",
"intl-pluralrules": "^1.3.1",
"ip-num": "^1.4.1",
@@ -32,7 +27,6 @@
"react-hook-form": "^7.29.0",
"react-modal": "3.15.1",
"react-router-dom": "^6.2.2",
"semver": "^7.3.5",
"solarxr-protocol": "file:../solarxr-protocol",
"three": "^0.148.0",
"typescript": "^4.6.3"
@@ -68,7 +62,7 @@
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.0",
"@tauri-apps/cli": "^1.2.2",
"@tauri-apps/cli": "^1.2.3",
"@types/react": "18.0.25",
"@types/react-dom": "^18.0.5",
"@types/react-modal": "3.13.1",

View File

@@ -202,6 +202,14 @@ tracker_selection_menu-unassigned = unassyigned twackaws
tracker_selection_menu-assigned = assyigned twackaws
tracker_selection_menu-dont_assign = do nawt assyign
# This line cares about multilines.
# <b>text</b> means that the text should be bold.
tracker_selection_menu-neck_warning =
<b>wawning:</b> a neck twackew can be deadwy if adjusted too tightwy,
the stwap (collar) couwd cut the ciwcuwation to youw head!
tracker_selection_menu-neck_warning-done = i undewstand the wisks~
tracker_selection_menu-neck_warning-cancel = cancew :o
## Mounting menu
mounting_selection_menu = whewe doo yew want dis twayckaw to be?
mounting_selection_menu-close = cwose
@@ -325,6 +333,13 @@ settings-serial-description =
settings-serial-connection_lost = connyection to shewyaw wost, weconnyecting... >~<
settings-serial-reboot = weboot
settings-serial-factory_reset = fawctowy reset
# This cares about multilines
# <b>text</b> means that the text should be bold
settings-serial-factory_reset-warning =
<b>wawning:</b> this wiww weset the twackew to factowy settings.
which means wi-fi and cawibwation settings <b>wiww aww be wost!</b>
settings-serial-factory_reset-warning-ok = i know what I'm doing :3
settings-serial-factory_reset-warning-cancel = cancew
settings-serial-get_infos = get infows
settings-serial-serial_select = sewect a shewyaw pawt
settings-serial-auto_dropdown_item = awto

View File

@@ -202,6 +202,14 @@ tracker_selection_menu-unassigned = Unassigned Trackers
tracker_selection_menu-assigned = Assigned Trackers
tracker_selection_menu-dont_assign = Do not assign
# This line cares about multilines.
# <b>text</b> means that the text should be bold.
tracker_selection_menu-neck_warning =
<b>Warning:</b> A neck tracker can be deadly if adjusted too tightly,
the strap could cut the circulation to your head!
tracker_selection_menu-neck_warning-done = I understand the risks
tracker_selection_menu-neck_warning-cancel = Cancel
## Mounting menu
mounting_selection_menu = Where do you want this tracker to be?
mounting_selection_menu-close = Close
@@ -325,6 +333,13 @@ settings-serial-description =
settings-serial-connection_lost = Connection to serial lost, Reconnecting...
settings-serial-reboot = Reboot
settings-serial-factory_reset = Factory Reset
# This cares about multilines
# <b>text</b> means that the text should be bold
settings-serial-factory_reset-warning =
<b>Warning:</b> This will reset the tracker to factory settings.
Which means Wi-Fi and calibration settings <b>will all be lost!</b>
settings-serial-factory_reset-warning-ok = I know what I'm doing
settings-serial-factory_reset-warning-cancel = Cancel
settings-serial-get_infos = Get Infos
settings-serial-serial_select = Select a serial port
settings-serial-auto_dropdown_item = Auto

View File

@@ -202,6 +202,14 @@ tracker_selection_menu-unassigned = Capteurs non assignés
tracker_selection_menu-assigned = Capteurs assignés
tracker_selection_menu-dont_assign = Ne pas attribuer
# This line cares about multilines.
# <b>text</b> means that the text should be bold.
tracker_selection_menu-neck_warning =
<b>Attention:</b> Un capteur de cou peut être mortel s'il est ajusté trop serré,
la sangle pourrait couper la circulation à la tête !
tracker_selection_menu-neck_warning-done = Je suis conscient des risques
tracker_selection_menu-neck_warning-cancel = Annuler
## Mounting menu
mounting_selection_menu = Dans quelle direction pointe ce capteur?
mounting_selection_menu-close = Fermer
@@ -325,6 +333,13 @@ settings-serial-description =
settings-serial-connection_lost = Connexion à l'appareil perdue, reconnexion...
settings-serial-reboot = Redémarrer
settings-serial-factory_reset = Remise à zéro
# This cares about multilines
# <b>text</b> means that the text should be bold
settings-serial-factory_reset-warning =
<b>Attention:</b> Cela réinitialisera les paramètres du capteur à zéro.
Ce qui signifie que les paramètres de Wi-Fi et de calibration <b>seront tous perdus!</b>
settings-serial-factory_reset-warning-ok = Je sais ce que je fais
settings-serial-factory_reset-warning-cancel = Annuler
settings-serial-get_infos = Obtenir des informations
settings-serial-serial_select = Sélectionnez un port série
settings-serial-auto_dropdown_item = Automatique

View File

@@ -14,13 +14,19 @@ export function BaseModal({
{...props}
shouldCloseOnOverlayClick
shouldCloseOnEsc
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col justify-center items-center w-full h-full bg-background-90 bg-opacity-60 z-20'
)}
className={classNames(
props.className as string,
'items-center focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none bg-background-60 p-6 rounded-lg text-white'
)}
overlayClassName={
props.overlayClassName ||
classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col justify-center items-center w-full h-full bg-background-90 bg-opacity-60 z-20'
)
}
className={
props.className ||
classNames(
props.className as string,
'items-center focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none bg-background-60 p-6 rounded-lg text-white'
)
}
>
{children}
</ReactModal>

View File

@@ -1,5 +1,6 @@
import { ReactNode } from 'react';
import { BulbIcon } from './icon/BulbIcon';
import { WarningIcon } from './icon/WarningIcon';
import { Typography } from './Typography';
export function TipBox({ children }: { children: ReactNode }) {
@@ -14,3 +15,21 @@ export function TipBox({ children }: { children: ReactNode }) {
</div>
);
}
/**
* Will respect new lines and spacing given in text
*/
export function WarningBox({ children }: { children: ReactNode }) {
return (
<div className="flex flex-row gap-4 bg-red-900 p-4 rounded-md">
<div className="fill-red-500 flex flex-col justify-center">
<WarningIcon></WarningIcon>
</div>
<div className="flex flex-col">
<Typography color="text-red-300" whitespace="whitespace-pre">
{children}
</Typography>
</div>
</div>
);
}

View File

@@ -5,12 +5,19 @@ export function Typography({
variant = 'standard',
bold = false,
color = 'primary',
whitespace = 'whitespace-normal',
children,
}: {
variant?: 'main-title' | 'section-title' | 'standard' | 'vr-accessible';
bold?: boolean;
block?: boolean;
color?: 'primary' | 'secondary' | string;
whitespace?:
| 'whitespace-normal'
| 'whitespace-nowrap'
| 'whitespace-pre'
| 'whitespace-pre-line'
| 'whitespace-pre-wrap';
children: ReactNode;
}) {
const tag = useMemo(() => {
@@ -36,6 +43,7 @@ export function Typography({
color === 'primary' && 'text-background-10',
color === 'secondary' && 'text-background-30',
typeof color === 'string' && color,
whitespace,
]),
},
children

View File

@@ -0,0 +1,94 @@
import { BodyPart } from 'solarxr-protocol';
import { Button } from '../commons/Button';
import { WarningBox } from '../commons/TipBox';
import { Localized, useLocalization } from '@fluent/react';
import { BaseModal } from '../commons/BaseModal';
import ReactModal from 'react-modal';
export function NeckWarningModal({
isOpen = true,
hasShown = false,
onClose,
setShown,
bodyPart,
...props
}: {
/**
* Is the parent/sibling component opened?
*/
isOpen: boolean;
/**
* Has this warning be shown
* We want the parent/sibling component to tell us this because they also should
* know about the state
*/
hasShown: boolean;
/**
* The current body part chosen
*/
bodyPart: BodyPart | null;
/**
* Function to trigger when the neck warning hasn't been accepted
*/
onClose: () => void;
/**
* Function to change the hasShown value
*/
setShown: (arg0: boolean) => void;
} & ReactModal.Props) {
const { l10n } = useLocalization();
// Skip popup if bodyPart isn't neck or we already showed the warning in this session
if (
isOpen &&
!hasShown &&
(bodyPart !== BodyPart.NECK || sessionStorage.getItem('neckWarning'))
) {
setShown(true);
}
// Reset shown to false when no longer opened
if (!isOpen && hasShown) {
setShown(false);
}
// isOpen is checked by checking if the parent modal is opened + our bodyPart is the
// neck and we havent showed this warning yet
return (
<BaseModal
isOpen={isOpen && bodyPart === BodyPart.NECK && !hasShown}
shouldCloseOnOverlayClick
shouldCloseOnEsc
onRequestClose={onClose}
className={props.className}
overlayClassName={props.overlayClassName}
>
<div className="flex w-full h-full flex-col ">
<div className="flex w-full flex-col flex-grow items-center gap-3">
<Localized
id="tracker_selection_menu-neck_warning"
elems={{ b: <b></b> }}
>
<WarningBox>
<b>Warning:</b> A neck tracker can be deadly if adjusted too
tightly, the strap could cut the circulation to your head!
</WarningBox>
</Localized>
<div className="flex flex-row gap-3 pt-5 place-content-center">
<Button variant="secondary" onClick={onClose}>
{l10n.getString('tracker_selection_menu-neck_warning-cancel')}
</Button>
<Button
variant="primary"
onClick={() => {
setShown(true);
sessionStorage.setItem('neckWarning', 'true');
}}
>
{l10n.getString('tracker_selection_menu-neck_warning-done')}
</Button>
</div>
</div>
</div>
</BaseModal>
);
}

View File

@@ -1,7 +1,7 @@
import { ReactNode } from 'react';
import {
OnboardingContextC,
useProvideOnboarding
useProvideOnboarding,
} from '../../hooks/onboarding';
export function OnboardingContextProvider({

View File

@@ -9,6 +9,8 @@ import { TipBox } from '../../../commons/TipBox';
import { Typography } from '../../../commons/Typography';
import { TrackerCard } from '../../../tracker/TrackerCard';
import { useLocalization } from '@fluent/react';
import { useState } from 'react';
import { NeckWarningModal } from '../../NeckWarningModal';
export function TrackerSelectionMenu({
isOpen = true,
@@ -26,101 +28,116 @@ export function TrackerSelectionMenu({
useLayout<HTMLDivElement>();
const { ref: refOptions, height: optionsHeight } =
useElemSize<HTMLDivElement>();
// This is true when the neck warning has been accepted
// It is used for showing or not showing the actual modal
const [neckVerified, setNeckVerified] = useState(false);
const { useAssignedTrackers, useUnassignedTrackers } = useTrackers();
const unassignedTrackers = useUnassignedTrackers();
const assignedTrackers = useAssignedTrackers();
return (
<ReactModal
isOpen={isOpen}
shouldCloseOnOverlayClick
shouldCloseOnEsc
onRequestClose={onClose}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full bg-black bg-opacity-90 z-20'
)}
className={classNames(
'focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none mt-20 z-10'
)}
>
<div className="flex w-full h-full flex-col ">
<div className="flex w-full flex-col flex-grow items-center gap-3">
<Typography variant="main-title" bold>
{l10n.getString('tracker_selection_menu-' + BodyPart[bodyPart])}
</Typography>
<div className="relative">
<div
className="w-full h-full min-w-[700px] overflow-y-auto p-2 flex flex-col gap-6"
ref={refTrackers}
style={{ height: trackersHeight - optionsHeight }}
>
<div className="flex flex-col gap-3">
{unassignedTrackers.length && (
<div className="flex flex-col gap-3">
<Typography>
{l10n.getString('tracker_selection_menu-unassigned')}
</Typography>
<div className="grid grid-cols-2 gap-3">
{unassignedTrackers.map((fd, index) => (
<TrackerCard
key={index}
tracker={fd.tracker}
device={fd.device}
onClick={() => onTrackerSelected(fd)}
smol
interactable
outlined={
bodyPart ===
(fd.tracker.info?.bodyPart || BodyPart.NONE)
}
></TrackerCard>
))}
<>
<ReactModal
isOpen={isOpen && neckVerified}
shouldCloseOnOverlayClick
shouldCloseOnEsc
onRequestClose={onClose}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full bg-black bg-opacity-90 z-20'
)}
className={classNames(
'focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none mt-20 z-10'
)}
>
<div className="flex w-full h-full flex-col ">
<div className="flex w-full flex-col flex-grow items-center gap-3">
<Typography variant="main-title" bold>
{l10n.getString('tracker_selection_menu-' + BodyPart[bodyPart])}
</Typography>
<div className="relative">
<div
className="w-full h-full min-w-[700px] overflow-y-auto p-2 flex flex-col gap-6"
ref={refTrackers}
style={{ height: trackersHeight - optionsHeight }}
>
<div className="flex flex-col gap-3">
{unassignedTrackers.length && (
<div className="flex flex-col gap-3">
<Typography>
{l10n.getString('tracker_selection_menu-unassigned')}
</Typography>
<div className="grid grid-cols-2 gap-3">
{unassignedTrackers.map((fd, index) => (
<TrackerCard
key={index}
tracker={fd.tracker}
device={fd.device}
onClick={() => onTrackerSelected(fd)}
smol
interactable
outlined={
bodyPart ===
(fd.tracker.info?.bodyPart || BodyPart.NONE)
}
></TrackerCard>
))}
</div>
</div>
)}
<Typography>
{l10n.getString('tracker_selection_menu-assigned')}
</Typography>
<div className=" grid grid-cols-2 gap-3">
{assignedTrackers.map((fd, index) => (
<TrackerCard
key={index}
tracker={fd.tracker}
device={fd.device}
onClick={() => onTrackerSelected(fd)}
smol
interactable
outlined={
bodyPart ===
(fd.tracker.info?.bodyPart || BodyPart.NONE)
}
></TrackerCard>
))}
</div>
)}
<Typography>
{l10n.getString('tracker_selection_menu-assigned')}
</Typography>
<div className=" grid grid-cols-2 gap-3">
{assignedTrackers.map((fd, index) => (
<TrackerCard
key={index}
tracker={fd.tracker}
device={fd.device}
onClick={() => onTrackerSelected(fd)}
smol
interactable
outlined={
bodyPart ===
(fd.tracker.info?.bodyPart || BodyPart.NONE)
}
></TrackerCard>
))}
</div>
</div>
</div>
<div className="absolute px-2 pr-4 bottom-0 h-10 w-full border-b-[1px] border-background-40">
<div className="w-full h-full bg-gradient-to-b from-transparent to-black opacity-50"></div>
<div className="absolute px-2 pr-4 bottom-0 h-10 w-full border-b-[1px] border-background-40">
<div className="w-full h-full bg-gradient-to-b from-transparent to-black opacity-50"></div>
</div>
</div>
</div>
</div>
</div>
<div
className="flex w-full justify-between absolute bottom-0 left-0 p-10 z-0"
onClick={onClose}
ref={refOptions}
>
<div className="w-full max-w-sm">
<TipBox>{l10n.getString('tips-find_tracker')}</TipBox>
<div
className="flex w-full justify-between absolute bottom-0 left-0 p-10 z-0"
onClick={onClose}
ref={refOptions}
>
<div className="w-full max-w-sm">
<TipBox>{l10n.getString('tips-find_tracker')}</TipBox>
</div>
<div className="flex flex-col justify-end pointer-events-auto">
<Button variant="primary" onClick={() => onTrackerSelected(null)}>
{l10n.getString('tracker_selection_menu-dont_assign')}
</Button>
</div>
</div>
<div className="flex flex-col justify-end pointer-events-auto">
<Button variant="primary" onClick={() => onTrackerSelected(null)}>
{l10n.getString('tracker_selection_menu-dont_assign')}
</Button>
</div>
</div>
</ReactModal>
</ReactModal>
{/**
* This one is simple, we simply pass everything directly
* the NeckWarningModal explain how everything works.
*/}
<NeckWarningModal
isOpen={isOpen}
hasShown={neckVerified}
bodyPart={bodyPart}
onClose={onClose}
setShown={(bool) => setNeckVerified(bool)}
></NeckWarningModal>
</>
);
}

View File

@@ -18,7 +18,9 @@ import { useWebsocketAPI } from '../../../hooks/websocket-api';
import { Button } from '../../commons/Button';
import { Dropdown } from '../../commons/Dropdown';
import { Typography } from '../../commons/Typography';
import { useLocalization } from '@fluent/react';
import { Localized, useLocalization } from '@fluent/react';
import { BaseModal } from '../../commons/BaseModal';
import { WarningBox } from '../../commons/TipBox';
export interface SerialForm {
port: string;
@@ -46,6 +48,8 @@ export function Serial() {
Omit<SerialDeviceT, 'pack'>[]
>([]);
const [tryFactoryReset, setTryFactoryReset] = useState(false);
const { control, watch, handleSubmit, reset } = useForm<SerialForm>({
defaultValues: { port: 'Auto' },
});
@@ -143,6 +147,8 @@ export function Serial() {
RpcMessage.SerialTrackerFactoryResetRequest,
new SerialTrackerFactoryResetRequestT()
);
setTryFactoryReset(false);
};
const getInfos = () => {
sendRPCPacket(
@@ -152,67 +158,94 @@ export function Serial() {
};
return (
<div className="flex flex-col bg-background-70 h-full p-5 rounded-md">
<div className="flex flex-col pb-2">
<Typography variant="main-title">
{l10n.getString('settings-serial')}
</Typography>
<>
{l10n
.getString('settings-serial-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
))}
</>
</div>
<div className="bg-background-80 rounded-lg flex flex-col p-2">
<div
ref={consoleRef}
className="overflow-x-auto overflow-y-auto"
style={{
height: layoutHeight - height - 30,
width: layoutWidth - 24,
}}
<>
<BaseModal
isOpen={tryFactoryReset}
onRequestClose={() => setTryFactoryReset(false)}
>
<Localized
id="settings-serial-factory_reset-warning"
elems={{ b: <b></b> }}
>
<div className="flex select-text px-3">
<pre>
{isSerialOpen
? consoleContent
: l10n.getString('settings-serial-connection_lost')}
</pre>
</div>
<WarningBox>
<b>Warning:</b> This will reset the tracker to factory settings.
Which means Wi-Fi and calibration settings <b>will all be lost!</b>
</WarningBox>
</Localized>
<div className="flex flex-row gap-3 pt-5 place-content-center">
<Button variant="secondary" onClick={() => setTryFactoryReset(false)}>
{l10n.getString('settings-serial-factory_reset-warning-cancel')}
</Button>
<Button variant="primary" onClick={factoryReset}>
{l10n.getString('settings-serial-factory_reset-warning-ok')}
</Button>
</div>
<div className="" ref={toolbarRef}>
<div className="border-t-2 pt-2 border-background-60 border-solid m-2 gap-2 flex flex-row">
<div className="flex flex-grow gap-2">
<Button variant="quaternary" onClick={reboot}>
{l10n.getString('settings-serial-reboot')}
</Button>
<Button variant="quaternary" onClick={factoryReset}>
{l10n.getString('settings-serial-factory_reset')}
</Button>
<Button variant="quaternary" onClick={getInfos}>
{l10n.getString('settings-serial-get_infos')}
</Button>
</BaseModal>
<div className="flex flex-col bg-background-70 h-full p-5 rounded-md">
<div className="flex flex-col pb-2">
<Typography variant="main-title">
{l10n.getString('settings-serial')}
</Typography>
<>
{l10n
.getString('settings-serial-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
))}
</>
</div>
<div className="bg-background-80 rounded-lg flex flex-col p-2">
<div
ref={consoleRef}
className="overflow-x-auto overflow-y-auto"
style={{
height: layoutHeight - height - 30,
width: layoutWidth - 24,
}}
>
<div className="flex select-text px-3">
<pre>
{isSerialOpen
? consoleContent
: l10n.getString('settings-serial-connection_lost')}
</pre>
</div>
</div>
<div className="" ref={toolbarRef}>
<div className="border-t-2 pt-2 border-background-60 border-solid m-2 gap-2 flex flex-row">
<div className="flex flex-grow gap-2">
<Button variant="quaternary" onClick={reboot}>
{l10n.getString('settings-serial-reboot')}
</Button>
<Button
variant="quaternary"
onClick={() => setTryFactoryReset(true)}
>
{l10n.getString('settings-serial-factory_reset')}
</Button>
<Button variant="quaternary" onClick={getInfos}>
{l10n.getString('settings-serial-get_infos')}
</Button>
</div>
<div className="flex justify-end">
<Dropdown
control={control}
name="port"
placeholder={l10n.getString('settings-serial-serial_select')}
items={serialDevices.map((device) => ({
label: device.name?.toString() || 'error',
value: device.port?.toString() || 'error',
}))}
></Dropdown>
<div className="flex justify-end">
<Dropdown
control={control}
name="port"
placeholder={l10n.getString('settings-serial-serial_select')}
items={serialDevices.map((device) => ({
label: device.name?.toString() || 'error',
value: device.port?.toString() || 'error',
}))}
></Dropdown>
</div>
</div>
</div>
</div>
</div>
</div>
</>
);
}

View File

@@ -7,6 +7,8 @@ import { CheckBox } from '../commons/Checkbox';
import { Typography } from '../commons/Typography';
import { BodyAssignment } from '../onboarding/BodyAssignment';
import { useLocalization } from '@fluent/react';
import { useState } from 'react';
import { NeckWarningModal } from '../onboarding/NeckWarningModal';
export function SingleTrackerBodyAssignmentMenu({
isOpen = true,
@@ -21,67 +23,104 @@ export function SingleTrackerBodyAssignmentMenu({
const { control, watch } = useForm<{ advanced: boolean }>({
defaultValues: { advanced: false },
});
const [bodyPart, setBodyPart] = useState<null | BodyPart>(null);
const [neckVerified, setNeckVerified] = useState(true);
const { advanced } = watch();
return (
<ReactModal
isOpen={isOpen}
shouldCloseOnOverlayClick
shouldCloseOnEsc
onRequestClose={onClose}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full justify-center bg-black bg-opacity-90 z-20'
)}
className={classNames(
'focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none mt-20 z-10'
)}
>
<div className="flex w-full h-full flex-col gap-10 px-3">
<div className="flex flex-col w-full h-full justify-center items-center">
<div className="flex gap-8">
<div className="flex flex-col max-w-sm gap-3">
<Typography variant="main-title" bold>
{l10n.getString('body_assignment_menu')}
</Typography>
<Typography color="secondary">
{l10n.getString('body_assignment_menu-description')}
</Typography>
<CheckBox
control={control}
label={l10n.getString(
'body_assignment_menu-show_advanced_locations'
)}
name="advanced"
variant="toggle"
></CheckBox>
<div className="flex">
<Button
variant="secondary"
to="/onboarding/trackers-assign"
state={{ alonePage: true }}
>
{l10n.getString('body_assignment_menu-manage_trackers')}
</Button>
<>
<ReactModal
isOpen={isOpen && neckVerified}
shouldCloseOnOverlayClick
shouldCloseOnEsc
onRequestClose={onClose}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full justify-center bg-black bg-opacity-90 z-20'
)}
className={classNames(
'focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none mt-20 z-10'
)}
>
<div className="flex w-full h-full flex-col gap-10 px-3">
<div className="flex flex-col w-full h-full justify-center items-center">
<div className="flex gap-8">
<div className="flex flex-col max-w-sm gap-3">
<Typography variant="main-title" bold>
{l10n.getString('body_assignment_menu')}
</Typography>
<Typography color="secondary">
{l10n.getString('body_assignment_menu-description')}
</Typography>
<CheckBox
control={control}
label={l10n.getString(
'body_assignment_menu-show_advanced_locations'
)}
name="advanced"
variant="toggle"
></CheckBox>
<div className="flex">
<Button
variant="secondary"
to="/onboarding/trackers-assign"
state={{ alonePage: true }}
>
{l10n.getString('body_assignment_menu-manage_trackers')}
</Button>
</div>
</div>
</div>
<div className="flex flex-col flex-grow gap-3 rounded-xl fill-background-50">
<BodyAssignment
onlyAssigned={false}
advanced={advanced}
onRoleSelected={onRoleSelected}
></BodyAssignment>
<div className="flex justify-center">
<Button
variant="secondary"
onClick={() => onRoleSelected(BodyPart.NONE)}
>
{l10n.getString('body_assignment_menu-unassign_tracker')}
</Button>
<div className="flex flex-col flex-grow gap-3 rounded-xl fill-background-50">
<BodyAssignment
onlyAssigned={false}
advanced={advanced}
onRoleSelected={(b) => {
setBodyPart(b);
setNeckVerified(false);
}}
></BodyAssignment>
<div className="flex justify-center">
<Button
variant="secondary"
onClick={() => onRoleSelected(BodyPart.NONE)}
>
{l10n.getString('body_assignment_menu-unassign_tracker')}
</Button>
</div>
</div>
</div>
</div>
</div>
</div>
</ReactModal>
</ReactModal>
{/**
* This is a nightmare so, we pass the overlay class to respect styling of the
* other modal.
* `onClose`: we want to update the `bodyPart` to null because we need to know if the
* `bodyPart` is no longer being chosen in the `NeckWarningModal`, if we don't do this
* then the state of `bodyPart` (and use `BodyPart.NONE` instead), this will later
* propagate to `setShown` and unassign the tracker.
* `setShown`: is more simple than what I just explained above, we only want to know
* when the `NeckWarningModal` wants to set to true `neckVerified`. We don't want it to
* reset to false in any circumstance because then the main modal won't show because we
* check for `neckVerified`.
*/}
<NeckWarningModal
isOpen={isOpen}
hasShown={neckVerified}
bodyPart={bodyPart}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full justify-center bg-black bg-opacity-90 z-20'
)}
onClose={() => {
setBodyPart(null);
setNeckVerified(true);
}}
setShown={(bool) => {
if (bool && bodyPart !== null) {
onRoleSelected(bodyPart);
setNeckVerified(true);
}
}}
></NeckWarningModal>
</>
);
}

View File

@@ -352,7 +352,7 @@ export function TrackersTable({
tracker.position && (
<Typography color={fontColor}>
<span className="whitespace-nowrap">
{formatVector3(tracker.position, 1)}
{formatVector3(tracker.position, 2)}
</span>
</Typography>
),

View File

@@ -1,7 +1,6 @@
import { BodyPart } from 'solarxr-protocol';
export const bodypartToString = (id: BodyPart) =>
BodyPart[id].replace(/_/g, ' ');
export const bodypartToString = (id: BodyPart) => BodyPart[id].replace(/_/g, ' ');
type Vector3 = { x: number; y: number; z: number };
export const formatVector3 = ({ x, y, z }: Vector3, precision = 0) =>

View File

@@ -4,7 +4,7 @@
body {
font-variant-numeric: tabular-nums;
font-family: "Twemoji Country Flags", 'poppins', sans-serif;
font-family: 'poppins', sans-serif, emoji, "Twemoji Country Flags";
height: 100vh;
width: 100vw;
user-select: none;

View File

@@ -2,18 +2,12 @@ import react from '@vitejs/plugin-react';
import { defineConfig, PluginOption } from 'vite';
import { execSync } from 'child_process';
const commitHash = execSync('git rev-parse --verify --short HEAD')
.toString()
.trim();
const versionTag = execSync('git --no-pager tag --points-at HEAD')
.toString()
.trim();
const commitHash = execSync('git rev-parse --verify --short HEAD').toString().trim();
const versionTag = execSync('git --no-pager tag --points-at HEAD').toString().trim();
// If not empty then it's not clean
const gitClean = execSync('git status --porcelain').toString() ? false : true;
console.log(
`version is ${versionTag || commitHash}${gitClean ? '' : '-dirty'}`
);
console.log(`version is ${versionTag || commitHash}${gitClean ? '' : '-dirty'}`);
// Detect fluent file changes
export function i18nHotReload(): PluginOption {

5834
package-lock.json generated

File diff suppressed because it is too large Load Diff