Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
b47ebd14d2 | |||
e74bcd0695 | |||
22161ec386 | |||
ada46c4317 | |||
6675fa8d1e |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.8.0",
|
"version": "0.8.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.9.0",
|
"@codemirror/autocomplete": "^6.9.0",
|
||||||
|
@ -6,6 +6,7 @@ use std::io::Read;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use oauth2::TokenResponse;
|
use oauth2::TokenResponse;
|
||||||
use tauri::{InvokeError, Manager};
|
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.
|
/// This command returns the a json string parse from a toml file at the path.
|
||||||
#[tauri::command]
|
#[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.
|
///This command returns the KittyCAD user info given a token.
|
||||||
/// The string returned from this method is the user info as a json string.
|
/// The string returned from this method is the user info as a json string.
|
||||||
#[tauri::command]
|
#[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...");
|
println!("Getting user info...");
|
||||||
|
|
||||||
// use kittycad library to fetch the user info from /user/me
|
// 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
|
let user_info: kittycad::types::User = client
|
||||||
.users()
|
.users()
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "kittycad-modeling",
|
"productName": "kittycad-modeling",
|
||||||
"version": "0.8.0"
|
"version": "0.8.1"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
@ -6,9 +6,9 @@ export const Auth = ({ children }: React.PropsWithChildren) => {
|
|||||||
const {
|
const {
|
||||||
auth: { state },
|
auth: { state },
|
||||||
} = useGlobalStateContext()
|
} = useGlobalStateContext()
|
||||||
const isLoggedIn = state.matches('checkIfLoggedIn')
|
const isLoggingIn = state.matches('checkIfLoggedIn')
|
||||||
|
|
||||||
return isLoggedIn ? (
|
return isLoggingIn ? (
|
||||||
<Loading>Loading KittyCAD Modeling App...</Loading>
|
<Loading>Loading KittyCAD Modeling App...</Loading>
|
||||||
) : (
|
) : (
|
||||||
<>{children}</>
|
<>{children}</>
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
|
@ -24,7 +24,11 @@ export const MemoryPanel = ({
|
|||||||
<CollapsiblePanel {...props}>
|
<CollapsiblePanel {...props}>
|
||||||
<div className="h-full relative">
|
<div className="h-full relative">
|
||||||
<div className="absolute inset-0 flex flex-col items-start">
|
<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
|
<ReactJson
|
||||||
src={ProcessedMemory}
|
src={ProcessedMemory}
|
||||||
collapsed={1}
|
collapsed={1}
|
||||||
|
@ -5,8 +5,6 @@ import init, {
|
|||||||
} from '../../wasm-lib/pkg/wasm_lib'
|
} from '../../wasm-lib/pkg/wasm_lib'
|
||||||
import { FromServer, IntoServer } from './codec'
|
import { FromServer, IntoServer } from './codec'
|
||||||
|
|
||||||
let server: null | Server
|
|
||||||
|
|
||||||
export default class Server {
|
export default class Server {
|
||||||
readonly initOutput: InitOutput
|
readonly initOutput: InitOutput
|
||||||
readonly #intoServer: IntoServer
|
readonly #intoServer: IntoServer
|
||||||
@ -26,12 +24,8 @@ export default class Server {
|
|||||||
intoServer: IntoServer,
|
intoServer: IntoServer,
|
||||||
fromServer: FromServer
|
fromServer: FromServer
|
||||||
): Promise<Server> {
|
): Promise<Server> {
|
||||||
if (null == server) {
|
const initOutput = await init()
|
||||||
const initOutput = await init()
|
const server = new Server(initOutput, intoServer, fromServer)
|
||||||
server = new Server(initOutput, intoServer, fromServer)
|
|
||||||
} else {
|
|
||||||
console.warn('Server already initialized; ignoring')
|
|
||||||
}
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import withBaseURL from '../lib/withBaseURL'
|
|||||||
import { CommandBarMeta } from '../lib/commands'
|
import { CommandBarMeta } from '../lib/commands'
|
||||||
import { isTauri } from 'lib/isTauri'
|
import { isTauri } from 'lib/isTauri'
|
||||||
import { invoke } from '@tauri-apps/api'
|
import { invoke } from '@tauri-apps/api'
|
||||||
|
import { VITE_KC_API_BASE_URL } from 'env'
|
||||||
|
|
||||||
const SKIP_AUTH =
|
const SKIP_AUTH =
|
||||||
import.meta.env.VITE_KC_SKIP_AUTH === 'true' && import.meta.env.DEV
|
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))
|
.catch((err) => console.error('error from Browser getUser', err))
|
||||||
: invoke<Models['User_type'] | Record<'error_code', unknown>>('get_user', {
|
: invoke<Models['User_type'] | Record<'error_code', unknown>>('get_user', {
|
||||||
token: context.token,
|
token: context.token,
|
||||||
|
hostname: VITE_KC_API_BASE_URL,
|
||||||
}).catch((err) => console.error('error from Tauri getUser', err))
|
}).catch((err) => console.error('error from Tauri getUser', err))
|
||||||
|
|
||||||
const user = await userPromise
|
const user = await userPromise
|
||||||
|
@ -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' },
|
})
|
||||||
})
|
navigate(
|
||||||
console.log('yoyo', window.location.pathname, path)
|
paths.FILE + '/' + encodeURIComponent(routeData?.project?.path || 'new')
|
||||||
navigate(path)
|
)
|
||||||
},
|
}, [send, navigate, routeData])
|
||||||
[send, navigate]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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