UX Papercuts 3: use absolute paths, add error page with buttons to help refresh, etc (#615)
* Fix #593: don't prevent default on link click * Use absolute/explicit path for settings Trying to test fix for #594 * Broken: replace almost all relative URLs with absolute * Clean up to use clean useDismiss with absolute path * Merge branch 'main' into franknoirot/ux-papercuts-3a * Add buttons to home, reload, clear, and bug report on error screen
This commit is contained in:
@ -130,6 +130,7 @@ const router = createBrowserRouter(
|
|||||||
path: paths.INDEX,
|
path: paths.INDEX,
|
||||||
loader: () =>
|
loader: () =>
|
||||||
isTauri() ? redirect(paths.HOME) : redirect(paths.FILE + '/new'),
|
isTauri() ? redirect(paths.HOME) : redirect(paths.FILE + '/new'),
|
||||||
|
errorElement: <ErrorPage />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: paths.FILE + '/:id',
|
path: paths.FILE + '/:id',
|
||||||
@ -140,7 +141,6 @@ const router = createBrowserRouter(
|
|||||||
{!isTauri() && import.meta.env.PROD && <DownloadAppBanner />}
|
{!isTauri() && import.meta.env.PROD && <DownloadAppBanner />}
|
||||||
</Auth>
|
</Auth>
|
||||||
),
|
),
|
||||||
errorElement: <ErrorPage />,
|
|
||||||
id: paths.FILE,
|
id: paths.FILE,
|
||||||
loader: async ({
|
loader: async ({
|
||||||
request,
|
request,
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
import { useRouteError } from 'react-router-dom'
|
import { isTauri } from 'lib/isTauri'
|
||||||
|
import { useRouteError, isRouteErrorResponse } from 'react-router-dom'
|
||||||
|
import { ActionButton } from './ActionButton'
|
||||||
|
import {
|
||||||
|
faBug,
|
||||||
|
faHome,
|
||||||
|
faRefresh,
|
||||||
|
faTrash,
|
||||||
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
export const ErrorPage = () => {
|
export const ErrorPage = () => {
|
||||||
let error = useRouteError()
|
let error = useRouteError()
|
||||||
@ -11,7 +19,43 @@ export const ErrorPage = () => {
|
|||||||
<h1 className="text-4xl mb-8 font-bold">
|
<h1 className="text-4xl mb-8 font-bold">
|
||||||
An unexpected error occurred
|
An unexpected error occurred
|
||||||
</h1>
|
</h1>
|
||||||
<p>{String(error)}</p>
|
{isRouteErrorResponse(error) && (
|
||||||
|
<p className="mb-8">
|
||||||
|
{error.status}: {error.data}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<div className="flex justify-between gap-2 mt-6">
|
||||||
|
{isTauri() && (
|
||||||
|
<ActionButton Element="link" to={'/'} icon={{ icon: faHome }}>
|
||||||
|
Go Home
|
||||||
|
</ActionButton>
|
||||||
|
)}
|
||||||
|
<ActionButton
|
||||||
|
Element="button"
|
||||||
|
icon={{ icon: faRefresh }}
|
||||||
|
onClick={() => window.location.reload()}
|
||||||
|
>
|
||||||
|
Reload
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton
|
||||||
|
Element="button"
|
||||||
|
icon={{ icon: faTrash }}
|
||||||
|
onClick={() => {
|
||||||
|
window.localStorage.clear()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Clear storage
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton
|
||||||
|
Element="link"
|
||||||
|
icon={{ icon: faBug }}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
to="https://discord.com/channels/915388055236509727/1138967922614743060"
|
||||||
|
>
|
||||||
|
Report Bug
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -9,7 +9,6 @@ import {
|
|||||||
cameraMouseDragGuards,
|
cameraMouseDragGuards,
|
||||||
cameraSystems,
|
cameraSystems,
|
||||||
} from 'lib/cameraControls'
|
} from 'lib/cameraControls'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function Units() {
|
export default function Units() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -25,7 +24,6 @@ export default function Units() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
} = useGlobalStateContext()
|
} = useGlobalStateContext()
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-center items-end inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-center items-end inset-0 z-50 pointer-events-none">
|
||||||
@ -74,7 +72,7 @@ export default function Units() {
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -2,7 +2,6 @@ import { faArrowRight, faXmark } from '@fortawesome/free-solid-svg-icons'
|
|||||||
import { ActionButton } from '../../components/ActionButton'
|
import { ActionButton } from '../../components/ActionButton'
|
||||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function CmdK() {
|
export default function CmdK() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -10,7 +9,6 @@ export default function CmdK() {
|
|||||||
}))
|
}))
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.USER_MENU)
|
const next = useNextClick(onboardingPaths.USER_MENU)
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-center items-end inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-center items-end inset-0 z-50 pointer-events-none">
|
||||||
@ -43,7 +41,7 @@ export default function CmdK() {
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -3,7 +3,6 @@ import { ActionButton } from '../../components/ActionButton'
|
|||||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function CodeEditor() {
|
export default function CodeEditor() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -11,7 +10,6 @@ export default function CodeEditor() {
|
|||||||
}))
|
}))
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
|
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
||||||
@ -62,7 +60,7 @@ export default function CodeEditor() {
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -2,7 +2,6 @@ import { faArrowRight, faXmark } from '@fortawesome/free-solid-svg-icons'
|
|||||||
import { ActionButton } from '../../components/ActionButton'
|
import { ActionButton } from '../../components/ActionButton'
|
||||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function Export() {
|
export default function Export() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -10,7 +9,6 @@ export default function Export() {
|
|||||||
}))
|
}))
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.SKETCHING)
|
const next = useNextClick(onboardingPaths.SKETCHING)
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-center items-end inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-center items-end inset-0 z-50 pointer-events-none">
|
||||||
@ -42,7 +40,7 @@ export default function Export() {
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -4,14 +4,12 @@ import { useDismiss } from '.'
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useStore } from 'useStore'
|
import { useStore } from 'useStore'
|
||||||
import { bracket } from 'lib/exampleKcl'
|
import { bracket } from 'lib/exampleKcl'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function FutureWork() {
|
export default function FutureWork() {
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const { deferredSetCode } = useStore((s) => ({
|
const { deferredSetCode } = useStore((s) => ({
|
||||||
deferredSetCode: s.deferredSetCode,
|
deferredSetCode: s.deferredSetCode,
|
||||||
}))
|
}))
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
deferredSetCode(bracket)
|
deferredSetCode(bracket)
|
||||||
@ -36,7 +34,7 @@ export default function FutureWork() {
|
|||||||
<div className="flex justify-between mt-6">
|
<div className="flex justify-between mt-6">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
@ -49,7 +47,7 @@ export default function FutureWork() {
|
|||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{ icon: faArrowRight }}
|
icon={{ icon: faArrowRight }}
|
||||||
>
|
>
|
||||||
Finish
|
Finish
|
||||||
|
@ -3,7 +3,6 @@ import { ActionButton } from '../../components/ActionButton'
|
|||||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function InteractiveNumbers() {
|
export default function InteractiveNumbers() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -11,7 +10,6 @@ export default function InteractiveNumbers() {
|
|||||||
}))
|
}))
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.COMMAND_K)
|
const next = useNextClick(onboardingPaths.COMMAND_K)
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
||||||
@ -102,7 +100,7 @@ export default function InteractiveNumbers() {
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -15,15 +15,13 @@ import { isTauri } from 'lib/isTauri'
|
|||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { paths } from 'Router'
|
import { paths } from 'Router'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
function OnboardingWithNewFile() {
|
function OnboardingWithNewFile() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.INDEX)
|
const next = useNextClick(onboardingPaths.INDEX)
|
||||||
const { setCode } = useStore((s) => ({
|
const { deferredSetCode } = useStore((s) => ({
|
||||||
setCode: s.setCode,
|
deferredSetCode: s.deferredSetCode,
|
||||||
}))
|
}))
|
||||||
const {
|
const {
|
||||||
settings: {
|
settings: {
|
||||||
@ -53,7 +51,7 @@ function OnboardingWithNewFile() {
|
|||||||
<div className="flex justify-between mt-6">
|
<div className="flex justify-between mt-6">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash())}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
@ -67,7 +65,7 @@ function OnboardingWithNewFile() {
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCode(bracket)
|
deferredSetCode(bracket)
|
||||||
next()
|
next()
|
||||||
}}
|
}}
|
||||||
icon={{ icon: faArrowRight }}
|
icon={{ icon: faArrowRight }}
|
||||||
@ -91,7 +89,7 @@ function OnboardingWithNewFile() {
|
|||||||
<div className="flex justify-between mt-6">
|
<div className="flex justify-between mt-6">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash())}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
@ -118,9 +116,9 @@ function OnboardingWithNewFile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Introduction() {
|
export default function Introduction() {
|
||||||
const { setCode, code } = useStore((s) => ({
|
const { deferredSetCode, code } = useStore((s) => ({
|
||||||
code: s.code,
|
code: s.code,
|
||||||
setCode: s.setCode,
|
deferredSetCode: s.deferredSetCode,
|
||||||
}))
|
}))
|
||||||
const {
|
const {
|
||||||
settings: {
|
settings: {
|
||||||
@ -136,11 +134,10 @@ export default function Introduction() {
|
|||||||
: ''
|
: ''
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.CAMERA)
|
const next = useNextClick(onboardingPaths.CAMERA)
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (code === '') setCode(bracket)
|
if (code === '') deferredSetCode(bracket)
|
||||||
}, [code, setCode])
|
}, [code, deferredSetCode])
|
||||||
|
|
||||||
return !(code !== '' && code !== bracket) ? (
|
return !(code !== '' && code !== bracket) ? (
|
||||||
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
||||||
@ -180,7 +177,7 @@ export default function Introduction() {
|
|||||||
<div className="flex justify-between mt-6">
|
<div className="flex justify-between mt-6">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash())}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -5,7 +5,6 @@ import { useStore } from '../../useStore'
|
|||||||
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
||||||
import { Themes, getSystemTheme } from 'lib/theme'
|
import { Themes, getSystemTheme } from 'lib/theme'
|
||||||
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function ParametricModeling() {
|
export default function ParametricModeling() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -23,7 +22,6 @@ export default function ParametricModeling() {
|
|||||||
: ''
|
: ''
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.INTERACTIVE_NUMBERS)
|
const next = useNextClick(onboardingPaths.INTERACTIVE_NUMBERS)
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
||||||
@ -62,7 +60,7 @@ export default function ParametricModeling() {
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -3,7 +3,6 @@ import { ActionButton } from '../../components/ActionButton'
|
|||||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { isTauri } from 'lib/isTauri'
|
import { isTauri } from 'lib/isTauri'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function ProjectMenu() {
|
export default function ProjectMenu() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -11,7 +10,6 @@ export default function ProjectMenu() {
|
|||||||
}))
|
}))
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.EXPORT)
|
const next = useNextClick(onboardingPaths.EXPORT)
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-center items-start inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-center items-start inset-0 z-50 pointer-events-none">
|
||||||
@ -33,7 +31,7 @@ export default function ProjectMenu() {
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -3,7 +3,6 @@ import { ActionButton } from '../../components/ActionButton'
|
|||||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||||
import { useStore } from 'useStore'
|
import { useStore } from 'useStore'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function Sketching() {
|
export default function Sketching() {
|
||||||
const { deferredSetCode, buttonDownInStream } = useStore((s) => ({
|
const { deferredSetCode, buttonDownInStream } = useStore((s) => ({
|
||||||
@ -16,7 +15,6 @@ export default function Sketching() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
deferredSetCode('')
|
deferredSetCode('')
|
||||||
}, [deferredSetCode])
|
}, [deferredSetCode])
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-center items-end inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-center items-end inset-0 z-50 pointer-events-none">
|
||||||
@ -40,7 +38,7 @@ export default function Sketching() {
|
|||||||
<div className="flex justify-between mt-6">
|
<div className="flex justify-between mt-6">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -2,7 +2,6 @@ import { faArrowRight, faXmark } from '@fortawesome/free-solid-svg-icons'
|
|||||||
import { ActionButton } from '../../components/ActionButton'
|
import { ActionButton } from '../../components/ActionButton'
|
||||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function Streaming() {
|
export default function Streaming() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -10,7 +9,6 @@ export default function Streaming() {
|
|||||||
}))
|
}))
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.EDITOR)
|
const next = useNextClick(onboardingPaths.EDITOR)
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-start items-center inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-start items-center inset-0 z-50 pointer-events-none">
|
||||||
@ -43,7 +41,7 @@ export default function Streaming() {
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -6,7 +6,6 @@ import { Toggle } from '../../components/Toggle/Toggle'
|
|||||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||||
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
||||||
import { UnitSystem } from 'machines/settingsMachine'
|
import { UnitSystem } from 'machines/settingsMachine'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function Units() {
|
export default function Units() {
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
@ -17,7 +16,6 @@ export default function Units() {
|
|||||||
context: { unitSystem, baseUnit },
|
context: { unitSystem, baseUnit },
|
||||||
},
|
},
|
||||||
} = useGlobalStateContext()
|
} = useGlobalStateContext()
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
||||||
@ -68,7 +66,7 @@ export default function Units() {
|
|||||||
<div className="flex justify-between mt-6">
|
<div className="flex justify-between mt-6">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -2,7 +2,6 @@ import { faArrowRight, faXmark } from '@fortawesome/free-solid-svg-icons'
|
|||||||
import { ActionButton } from '../../components/ActionButton'
|
import { ActionButton } from '../../components/ActionButton'
|
||||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
|
||||||
|
|
||||||
export default function UserMenu() {
|
export default function UserMenu() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -10,7 +9,6 @@ export default function UserMenu() {
|
|||||||
}))
|
}))
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.PROJECT_MENU)
|
const next = useNextClick(onboardingPaths.PROJECT_MENU)
|
||||||
const dotDotSlash = useDotDotSlash()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-center items-start inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-center items-start inset-0 z-50 pointer-events-none">
|
||||||
@ -30,7 +28,7 @@ export default function UserMenu() {
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => dismiss(dotDotSlash(2))}
|
onClick={dismiss}
|
||||||
icon={{
|
icon={{
|
||||||
icon: faXmark,
|
icon: faXmark,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
|
import { Outlet, useRouteLoaderData, useNavigate } from 'react-router-dom'
|
||||||
import Introduction from './Introduction'
|
import Introduction from './Introduction'
|
||||||
import Camera from './Camera'
|
import Camera from './Camera'
|
||||||
import Sketching from './Sketching'
|
import Sketching from './Sketching'
|
||||||
@ -15,6 +15,7 @@ import UserMenu from './UserMenu'
|
|||||||
import ProjectMenu from './ProjectMenu'
|
import ProjectMenu from './ProjectMenu'
|
||||||
import Export from './Export'
|
import Export from './Export'
|
||||||
import FutureWork from './FutureWork'
|
import FutureWork from './FutureWork'
|
||||||
|
import { IndexLoaderData, paths } from 'Router'
|
||||||
|
|
||||||
export const onboardingPaths = {
|
export const onboardingPaths = {
|
||||||
INDEX: '/',
|
INDEX: '/',
|
||||||
@ -89,42 +90,44 @@ export function useNextClick(newStatus: string) {
|
|||||||
settings: { send },
|
settings: { send },
|
||||||
} = useGlobalStateContext()
|
} = useGlobalStateContext()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const { project } = useRouteLoaderData(paths.FILE) as IndexLoaderData
|
||||||
const lastSlashIndex = location.pathname.lastIndexOf('/')
|
|
||||||
|
|
||||||
return useCallback(() => {
|
return useCallback(() => {
|
||||||
send({
|
send({
|
||||||
type: 'Set Onboarding Status',
|
type: 'Set Onboarding Status',
|
||||||
data: { onboardingStatus: newStatus },
|
data: { onboardingStatus: newStatus },
|
||||||
})
|
})
|
||||||
navigate(location.pathname.slice(0, lastSlashIndex) + newStatus)
|
navigate(
|
||||||
}, [location, lastSlashIndex, newStatus, send, navigate])
|
paths.FILE +
|
||||||
|
'/' +
|
||||||
|
encodeURIComponent(project?.path || 'new') +
|
||||||
|
paths.ONBOARDING.INDEX.slice(0, -1) +
|
||||||
|
newStatus
|
||||||
|
)
|
||||||
|
}, [project, newStatus, send, navigate])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useDismiss() {
|
export function useDismiss() {
|
||||||
|
const routeData = useRouteLoaderData(paths.FILE) as IndexLoaderData
|
||||||
const {
|
const {
|
||||||
settings: { send },
|
settings: { send },
|
||||||
} = useGlobalStateContext()
|
} = useGlobalStateContext()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
return useCallback(
|
return useCallback(() => {
|
||||||
(path: string) => {
|
|
||||||
send({
|
send({
|
||||||
type: 'Set Onboarding Status',
|
type: 'Set Onboarding Status',
|
||||||
data: { onboardingStatus: 'dismissed' },
|
data: { onboardingStatus: 'dismissed' },
|
||||||
})
|
})
|
||||||
console.log('yoyo', window.location.pathname, path)
|
navigate(
|
||||||
navigate(path)
|
paths.FILE + '/' + encodeURIComponent(routeData?.project?.path || 'new')
|
||||||
},
|
|
||||||
[send, navigate]
|
|
||||||
)
|
)
|
||||||
|
}, [send, navigate, routeData])
|
||||||
}
|
}
|
||||||
|
|
||||||
const Onboarding = () => {
|
const Onboarding = () => {
|
||||||
const location = useLocation()
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const lastSlashIndex = location.pathname.lastIndexOf('/')
|
useHotkeys('esc', dismiss)
|
||||||
useHotkeys('esc', () => dismiss(location.pathname.slice(0, lastSlashIndex)))
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
Reference in New Issue
Block a user