Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
b47ebd14d2 | |||
e74bcd0695 | |||
22161ec386 | |||
ada46c4317 | |||
6675fa8d1e |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "untitled-app",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.1",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.9.0",
|
||||
|
@ -6,6 +6,7 @@ use std::io::Read;
|
||||
use anyhow::Result;
|
||||
use oauth2::TokenResponse;
|
||||
use tauri::{InvokeError, Manager};
|
||||
const DEFAULT_HOST: &str = "https://api.kittycad.io";
|
||||
|
||||
/// This command returns the a json string parse from a toml file at the path.
|
||||
#[tauri::command]
|
||||
@ -88,11 +89,34 @@ async fn login(app: tauri::AppHandle, host: &str) -> Result<String, InvokeError>
|
||||
///This command returns the KittyCAD user info given a token.
|
||||
/// The string returned from this method is the user info as a json string.
|
||||
#[tauri::command]
|
||||
async fn get_user(token: Option<String>) -> Result<kittycad::types::User, InvokeError> {
|
||||
async fn get_user(
|
||||
token: Option<String>,
|
||||
hostname: &str,
|
||||
) -> Result<kittycad::types::User, InvokeError> {
|
||||
// Use the host passed in if it's set.
|
||||
// Otherwise, use the default host.
|
||||
let host = if hostname.is_empty() {
|
||||
DEFAULT_HOST.to_string()
|
||||
} else {
|
||||
hostname.to_string()
|
||||
};
|
||||
|
||||
// Change the baseURL to the one we want.
|
||||
let mut baseurl = host.to_string();
|
||||
if !host.starts_with("http://") && !host.starts_with("https://") {
|
||||
baseurl = format!("https://{host}");
|
||||
if host.starts_with("localhost") {
|
||||
baseurl = format!("http://{host}")
|
||||
}
|
||||
}
|
||||
println!("Getting user info...");
|
||||
|
||||
// use kittycad library to fetch the user info from /user/me
|
||||
let client = kittycad::Client::new(token.unwrap());
|
||||
let mut client = kittycad::Client::new(token.unwrap());
|
||||
|
||||
if baseurl != DEFAULT_HOST {
|
||||
client.set_base_url(&baseurl);
|
||||
}
|
||||
|
||||
let user_info: kittycad::types::User = client
|
||||
.users()
|
||||
|
@ -8,7 +8,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "kittycad-modeling",
|
||||
"version": "0.8.0"
|
||||
"version": "0.8.1"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
|
@ -6,9 +6,9 @@ export const Auth = ({ children }: React.PropsWithChildren) => {
|
||||
const {
|
||||
auth: { state },
|
||||
} = useGlobalStateContext()
|
||||
const isLoggedIn = state.matches('checkIfLoggedIn')
|
||||
const isLoggingIn = state.matches('checkIfLoggedIn')
|
||||
|
||||
return isLoggedIn ? (
|
||||
return isLoggingIn ? (
|
||||
<Loading>Loading KittyCAD Modeling App...</Loading>
|
||||
) : (
|
||||
<>{children}</>
|
||||
|
@ -130,6 +130,7 @@ const router = createBrowserRouter(
|
||||
path: paths.INDEX,
|
||||
loader: () =>
|
||||
isTauri() ? redirect(paths.HOME) : redirect(paths.FILE + '/new'),
|
||||
errorElement: <ErrorPage />,
|
||||
},
|
||||
{
|
||||
path: paths.FILE + '/:id',
|
||||
@ -140,7 +141,6 @@ const router = createBrowserRouter(
|
||||
{!isTauri() && import.meta.env.PROD && <DownloadAppBanner />}
|
||||
</Auth>
|
||||
),
|
||||
errorElement: <ErrorPage />,
|
||||
id: paths.FILE,
|
||||
loader: async ({
|
||||
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 = () => {
|
||||
let error = useRouteError()
|
||||
@ -11,7 +19,43 @@ export const ErrorPage = () => {
|
||||
<h1 className="text-4xl mb-8 font-bold">
|
||||
An unexpected error occurred
|
||||
</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>
|
||||
</div>
|
||||
)
|
||||
|
@ -24,7 +24,11 @@ export const MemoryPanel = ({
|
||||
<CollapsiblePanel {...props}>
|
||||
<div className="h-full relative">
|
||||
<div className="absolute inset-0 flex flex-col items-start">
|
||||
<div className=" h-full console-tile w-full">
|
||||
<div
|
||||
className="overflow-y-auto h-full console-tile w-full"
|
||||
style={{ marginBottom: 36 }}
|
||||
>
|
||||
{/* 36px is the height of PanelHeader */}
|
||||
<ReactJson
|
||||
src={ProcessedMemory}
|
||||
collapsed={1}
|
||||
|
@ -5,8 +5,6 @@ import init, {
|
||||
} from '../../wasm-lib/pkg/wasm_lib'
|
||||
import { FromServer, IntoServer } from './codec'
|
||||
|
||||
let server: null | Server
|
||||
|
||||
export default class Server {
|
||||
readonly initOutput: InitOutput
|
||||
readonly #intoServer: IntoServer
|
||||
@ -26,12 +24,8 @@ export default class Server {
|
||||
intoServer: IntoServer,
|
||||
fromServer: FromServer
|
||||
): Promise<Server> {
|
||||
if (null == server) {
|
||||
const initOutput = await init()
|
||||
server = new Server(initOutput, intoServer, fromServer)
|
||||
} else {
|
||||
console.warn('Server already initialized; ignoring')
|
||||
}
|
||||
const initOutput = await init()
|
||||
const server = new Server(initOutput, intoServer, fromServer)
|
||||
return server
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import withBaseURL from '../lib/withBaseURL'
|
||||
import { CommandBarMeta } from '../lib/commands'
|
||||
import { isTauri } from 'lib/isTauri'
|
||||
import { invoke } from '@tauri-apps/api'
|
||||
import { VITE_KC_API_BASE_URL } from 'env'
|
||||
|
||||
const SKIP_AUTH =
|
||||
import.meta.env.VITE_KC_SKIP_AUTH === 'true' && import.meta.env.DEV
|
||||
@ -132,6 +133,7 @@ async function getUser(context: UserContext) {
|
||||
.catch((err) => console.error('error from Browser getUser', err))
|
||||
: invoke<Models['User_type'] | Record<'error_code', unknown>>('get_user', {
|
||||
token: context.token,
|
||||
hostname: VITE_KC_API_BASE_URL,
|
||||
}).catch((err) => console.error('error from Tauri getUser', err))
|
||||
|
||||
const user = await userPromise
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
cameraMouseDragGuards,
|
||||
cameraSystems,
|
||||
} from 'lib/cameraControls'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function Units() {
|
||||
const { buttonDownInStream } = useStore((s) => ({
|
||||
@ -25,7 +24,6 @@ export default function Units() {
|
||||
},
|
||||
},
|
||||
} = useGlobalStateContext()
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -2,7 +2,6 @@ import { faArrowRight, faXmark } from '@fortawesome/free-solid-svg-icons'
|
||||
import { ActionButton } from '../../components/ActionButton'
|
||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||
import { useStore } from '../../useStore'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function CmdK() {
|
||||
const { buttonDownInStream } = useStore((s) => ({
|
||||
@ -10,7 +9,6 @@ export default function CmdK() {
|
||||
}))
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.USER_MENU)
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -3,7 +3,6 @@ import { ActionButton } from '../../components/ActionButton'
|
||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||
import { useStore } from '../../useStore'
|
||||
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function CodeEditor() {
|
||||
const { buttonDownInStream } = useStore((s) => ({
|
||||
@ -11,7 +10,6 @@ export default function CodeEditor() {
|
||||
}))
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -2,7 +2,6 @@ import { faArrowRight, faXmark } from '@fortawesome/free-solid-svg-icons'
|
||||
import { ActionButton } from '../../components/ActionButton'
|
||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||
import { useStore } from '../../useStore'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function Export() {
|
||||
const { buttonDownInStream } = useStore((s) => ({
|
||||
@ -10,7 +9,6 @@ export default function Export() {
|
||||
}))
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.SKETCHING)
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -4,14 +4,12 @@ import { useDismiss } from '.'
|
||||
import { useEffect } from 'react'
|
||||
import { useStore } from 'useStore'
|
||||
import { bracket } from 'lib/exampleKcl'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function FutureWork() {
|
||||
const dismiss = useDismiss()
|
||||
const { deferredSetCode } = useStore((s) => ({
|
||||
deferredSetCode: s.deferredSetCode,
|
||||
}))
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
useEffect(() => {
|
||||
deferredSetCode(bracket)
|
||||
@ -36,7 +34,7 @@ export default function FutureWork() {
|
||||
<div className="flex justify-between mt-6">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
@ -49,7 +47,7 @@ export default function FutureWork() {
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{ icon: faArrowRight }}
|
||||
>
|
||||
Finish
|
||||
|
@ -3,7 +3,6 @@ import { ActionButton } from '../../components/ActionButton'
|
||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||
import { useStore } from '../../useStore'
|
||||
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function InteractiveNumbers() {
|
||||
const { buttonDownInStream } = useStore((s) => ({
|
||||
@ -11,7 +10,6 @@ export default function InteractiveNumbers() {
|
||||
}))
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.COMMAND_K)
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -15,15 +15,13 @@ import { isTauri } from 'lib/isTauri'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { paths } from 'Router'
|
||||
import { useEffect } from 'react'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
function OnboardingWithNewFile() {
|
||||
const navigate = useNavigate()
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.INDEX)
|
||||
const { setCode } = useStore((s) => ({
|
||||
setCode: s.setCode,
|
||||
const { deferredSetCode } = useStore((s) => ({
|
||||
deferredSetCode: s.deferredSetCode,
|
||||
}))
|
||||
const {
|
||||
settings: {
|
||||
@ -53,7 +51,7 @@ function OnboardingWithNewFile() {
|
||||
<div className="flex justify-between mt-6">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash())}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
@ -67,7 +65,7 @@ function OnboardingWithNewFile() {
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => {
|
||||
setCode(bracket)
|
||||
deferredSetCode(bracket)
|
||||
next()
|
||||
}}
|
||||
icon={{ icon: faArrowRight }}
|
||||
@ -91,7 +89,7 @@ function OnboardingWithNewFile() {
|
||||
<div className="flex justify-between mt-6">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash())}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
@ -118,9 +116,9 @@ function OnboardingWithNewFile() {
|
||||
}
|
||||
|
||||
export default function Introduction() {
|
||||
const { setCode, code } = useStore((s) => ({
|
||||
const { deferredSetCode, code } = useStore((s) => ({
|
||||
code: s.code,
|
||||
setCode: s.setCode,
|
||||
deferredSetCode: s.deferredSetCode,
|
||||
}))
|
||||
const {
|
||||
settings: {
|
||||
@ -136,11 +134,10 @@ export default function Introduction() {
|
||||
: ''
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.CAMERA)
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
useEffect(() => {
|
||||
if (code === '') setCode(bracket)
|
||||
}, [code, setCode])
|
||||
if (code === '') deferredSetCode(bracket)
|
||||
}, [code, deferredSetCode])
|
||||
|
||||
return !(code !== '' && code !== bracket) ? (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash())}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -5,7 +5,6 @@ import { useStore } from '../../useStore'
|
||||
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
||||
import { Themes, getSystemTheme } from 'lib/theme'
|
||||
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function ParametricModeling() {
|
||||
const { buttonDownInStream } = useStore((s) => ({
|
||||
@ -23,7 +22,6 @@ export default function ParametricModeling() {
|
||||
: ''
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.INTERACTIVE_NUMBERS)
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -3,7 +3,6 @@ import { ActionButton } from '../../components/ActionButton'
|
||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||
import { useStore } from '../../useStore'
|
||||
import { isTauri } from 'lib/isTauri'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function ProjectMenu() {
|
||||
const { buttonDownInStream } = useStore((s) => ({
|
||||
@ -11,7 +10,6 @@ export default function ProjectMenu() {
|
||||
}))
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.EXPORT)
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -3,7 +3,6 @@ import { ActionButton } from '../../components/ActionButton'
|
||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||
import { useStore } from 'useStore'
|
||||
import { useEffect } from 'react'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function Sketching() {
|
||||
const { deferredSetCode, buttonDownInStream } = useStore((s) => ({
|
||||
@ -16,7 +15,6 @@ export default function Sketching() {
|
||||
useEffect(() => {
|
||||
deferredSetCode('')
|
||||
}, [deferredSetCode])
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -2,7 +2,6 @@ import { faArrowRight, faXmark } from '@fortawesome/free-solid-svg-icons'
|
||||
import { ActionButton } from '../../components/ActionButton'
|
||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||
import { useStore } from '../../useStore'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function Streaming() {
|
||||
const { buttonDownInStream } = useStore((s) => ({
|
||||
@ -10,7 +9,6 @@ export default function Streaming() {
|
||||
}))
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.EDITOR)
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -6,7 +6,6 @@ import { Toggle } from '../../components/Toggle/Toggle'
|
||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
||||
import { UnitSystem } from 'machines/settingsMachine'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function Units() {
|
||||
const dismiss = useDismiss()
|
||||
@ -17,7 +16,6 @@ export default function Units() {
|
||||
context: { unitSystem, baseUnit },
|
||||
},
|
||||
} = useGlobalStateContext()
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -2,7 +2,6 @@ import { faArrowRight, faXmark } from '@fortawesome/free-solid-svg-icons'
|
||||
import { ActionButton } from '../../components/ActionButton'
|
||||
import { onboardingPaths, useDismiss, useNextClick } from '.'
|
||||
import { useStore } from '../../useStore'
|
||||
import { useDotDotSlash } from 'hooks/useDotDotSlash'
|
||||
|
||||
export default function UserMenu() {
|
||||
const { buttonDownInStream } = useStore((s) => ({
|
||||
@ -10,7 +9,6 @@ export default function UserMenu() {
|
||||
}))
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.PROJECT_MENU)
|
||||
const dotDotSlash = useDotDotSlash()
|
||||
|
||||
return (
|
||||
<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">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={() => dismiss(dotDotSlash(2))}
|
||||
onClick={dismiss}
|
||||
icon={{
|
||||
icon: faXmark,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 Camera from './Camera'
|
||||
import Sketching from './Sketching'
|
||||
@ -15,6 +15,7 @@ import UserMenu from './UserMenu'
|
||||
import ProjectMenu from './ProjectMenu'
|
||||
import Export from './Export'
|
||||
import FutureWork from './FutureWork'
|
||||
import { IndexLoaderData, paths } from 'Router'
|
||||
|
||||
export const onboardingPaths = {
|
||||
INDEX: '/',
|
||||
@ -89,42 +90,44 @@ export function useNextClick(newStatus: string) {
|
||||
settings: { send },
|
||||
} = useGlobalStateContext()
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
const lastSlashIndex = location.pathname.lastIndexOf('/')
|
||||
const { project } = useRouteLoaderData(paths.FILE) as IndexLoaderData
|
||||
|
||||
return useCallback(() => {
|
||||
send({
|
||||
type: 'Set Onboarding Status',
|
||||
data: { onboardingStatus: newStatus },
|
||||
})
|
||||
navigate(location.pathname.slice(0, lastSlashIndex) + newStatus)
|
||||
}, [location, lastSlashIndex, newStatus, send, navigate])
|
||||
navigate(
|
||||
paths.FILE +
|
||||
'/' +
|
||||
encodeURIComponent(project?.path || 'new') +
|
||||
paths.ONBOARDING.INDEX.slice(0, -1) +
|
||||
newStatus
|
||||
)
|
||||
}, [project, newStatus, send, navigate])
|
||||
}
|
||||
|
||||
export function useDismiss() {
|
||||
const routeData = useRouteLoaderData(paths.FILE) as IndexLoaderData
|
||||
const {
|
||||
settings: { send },
|
||||
} = useGlobalStateContext()
|
||||
const navigate = useNavigate()
|
||||
|
||||
return useCallback(
|
||||
(path: string) => {
|
||||
send({
|
||||
type: 'Set Onboarding Status',
|
||||
data: { onboardingStatus: 'dismissed' },
|
||||
})
|
||||
console.log('yoyo', window.location.pathname, path)
|
||||
navigate(path)
|
||||
},
|
||||
[send, navigate]
|
||||
)
|
||||
return useCallback(() => {
|
||||
send({
|
||||
type: 'Set Onboarding Status',
|
||||
data: { onboardingStatus: 'dismissed' },
|
||||
})
|
||||
navigate(
|
||||
paths.FILE + '/' + encodeURIComponent(routeData?.project?.path || 'new')
|
||||
)
|
||||
}, [send, navigate, routeData])
|
||||
}
|
||||
|
||||
const Onboarding = () => {
|
||||
const location = useLocation()
|
||||
const dismiss = useDismiss()
|
||||
const lastSlashIndex = location.pathname.lastIndexOf('/')
|
||||
useHotkeys('esc', () => dismiss(location.pathname.slice(0, lastSlashIndex)))
|
||||
useHotkeys('esc', dismiss)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
Reference in New Issue
Block a user