Add a "back" button to the onboarding buttons, move the dismiss button to a little corner x
button (#5296)
* Add previous button to OnboardingButtons, move dismiss to popover corner * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * Clean up diagnostics I am thoroughly enjoying nvim now * Amend "click through" test to also click back * fmt * Set this test back to fixme, that work should be its own PR --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
@ -27,7 +27,7 @@ test.describe('Onboarding tests', () => {
|
|||||||
},
|
},
|
||||||
cleanProjectDir: true,
|
cleanProjectDir: true,
|
||||||
},
|
},
|
||||||
async ({ context, page, homePage }) => {
|
async ({ page, homePage }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
@ -68,7 +68,7 @@ test.describe('Onboarding tests', () => {
|
|||||||
},
|
},
|
||||||
cleanProjectDir: true,
|
cleanProjectDir: true,
|
||||||
},
|
},
|
||||||
async ({ page, homePage }, testInfo) => {
|
async ({ page }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
const viewportSize = { width: 1200, height: 500 }
|
const viewportSize = { width: 1200, height: 500 }
|
||||||
@ -154,7 +154,7 @@ test.describe('Onboarding tests', () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'Click through each onboarding step',
|
'Click through each onboarding step and back',
|
||||||
{
|
{
|
||||||
appSettings: {
|
appSettings: {
|
||||||
app: {
|
app: {
|
||||||
@ -187,15 +187,21 @@ test.describe('Onboarding tests', () => {
|
|||||||
).toBeVisible()
|
).toBeVisible()
|
||||||
|
|
||||||
const nextButton = page.getByTestId('onboarding-next')
|
const nextButton = page.getByTestId('onboarding-next')
|
||||||
|
const prevButton = page.getByTestId('onboarding-prev')
|
||||||
|
|
||||||
while ((await nextButton.innerText()) !== 'Finish') {
|
while ((await nextButton.innerText()) !== 'Finish') {
|
||||||
await nextButton.hover()
|
await nextButton.hover()
|
||||||
await nextButton.click()
|
await nextButton.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish the onboarding
|
while ((await prevButton.innerText()) !== 'Dismiss') {
|
||||||
await nextButton.hover()
|
await prevButton.hover()
|
||||||
await nextButton.click()
|
await prevButton.click()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dismiss the onboarding
|
||||||
|
await prevButton.hover()
|
||||||
|
await prevButton.click()
|
||||||
|
|
||||||
// Test that the onboarding pane is gone
|
// Test that the onboarding pane is gone
|
||||||
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
|
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
|
||||||
@ -269,7 +275,7 @@ test.describe('Onboarding tests', () => {
|
|||||||
cleanProjectDir: true,
|
cleanProjectDir: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
async ({ context, page, homePage }) => {
|
async ({ page, homePage }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
const badCode = `// This is bad code we shouldn't see`
|
const badCode = `// This is bad code we shouldn't see`
|
||||||
|
|
||||||
@ -336,10 +342,10 @@ test.describe('Onboarding tests', () => {
|
|||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
|
|
||||||
// Test that the text in this step is correct
|
// Test that the text in this step is correct
|
||||||
const avatarLocator = await page
|
const avatarLocator = page
|
||||||
.getByTestId('user-sidebar-toggle')
|
.getByTestId('user-sidebar-toggle')
|
||||||
.locator('img')
|
.locator('img')
|
||||||
const onboardingOverlayLocator = await page
|
const onboardingOverlayLocator = page
|
||||||
.getByTestId('onboarding-content')
|
.getByTestId('onboarding-content')
|
||||||
.locator('div')
|
.locator('div')
|
||||||
.nth(1)
|
.nth(1)
|
||||||
@ -447,7 +453,7 @@ test.fixme(
|
|||||||
},
|
},
|
||||||
cleanProjectDir: true,
|
cleanProjectDir: true,
|
||||||
},
|
},
|
||||||
async ({ context, page, homePage }, testInfo) => {
|
async ({ context, page }) => {
|
||||||
await context.folderSetupFn(async (dir) => {
|
await context.folderSetupFn(async (dir) => {
|
||||||
const routerTemplateDir = join(dir, 'router-template-slate')
|
const routerTemplateDir = join(dir, 'router-template-slate')
|
||||||
await fsp.mkdir(routerTemplateDir, { recursive: true })
|
await fsp.mkdir(routerTemplateDir, { recursive: true })
|
||||||
@ -486,10 +492,6 @@ test.fixme(
|
|||||||
})
|
})
|
||||||
|
|
||||||
await test.step('Navigate into project', async () => {
|
await test.step('Navigate into project', async () => {
|
||||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
page.on('console', console.log)
|
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('heading', { name: 'Your Projects' })
|
page.getByRole('heading', { name: 'Your Projects' })
|
||||||
).toBeVisible()
|
).toBeVisible()
|
||||||
|
@ -26,7 +26,7 @@ export default function Units() {
|
|||||||
<div className="fixed inset-0 z-50 grid items-end justify-start px-4 pointer-events-none">
|
<div className="fixed inset-0 z-50 grid items-end justify-start px-4 pointer-events-none">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SettingsSection
|
<SettingsSection
|
||||||
@ -72,9 +72,7 @@ export default function Units() {
|
|||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
<OnboardingButtons
|
<OnboardingButtons
|
||||||
currentSlug={onboardingPaths.CAMERA}
|
currentSlug={onboardingPaths.CAMERA}
|
||||||
dismiss={dismiss}
|
dismissClassName="right-auto left-full"
|
||||||
next={next}
|
|
||||||
nextText="Next: Streaming"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
import usePlatform from 'hooks/usePlatform'
|
import usePlatform from 'hooks/usePlatform'
|
||||||
import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, kbdClasses } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { hotkeyDisplay } from 'lib/hotkeyWrapper'
|
import { hotkeyDisplay } from 'lib/hotkeyWrapper'
|
||||||
import { COMMAND_PALETTE_HOTKEY } from 'components/CommandBar/CommandBar'
|
import { COMMAND_PALETTE_HOTKEY } from 'components/CommandBar/CommandBar'
|
||||||
|
|
||||||
export default function CmdK() {
|
export default function CmdK() {
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.USER_MENU)
|
|
||||||
const platformName = usePlatform()
|
const platformName = usePlatform()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 grid items-end justify-center pointer-events-none">
|
<div className="fixed inset-0 z-50 grid items-end justify-center pointer-events-none">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto max-w-full xl:max-w-4xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto max-w-full xl:max-w-4xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<h2 className="text-2xl font-bold">Command Bar</h2>
|
<h2 className="text-2xl font-bold">Command Bar</h2>
|
||||||
@ -38,12 +36,7 @@ export default function CmdK() {
|
|||||||
. You can control settings, authentication, and file management from
|
. You can control settings, authentication, and file management from
|
||||||
the command bar, as well as a growing number of modeling commands.
|
the command bar, as well as a growing number of modeling commands.
|
||||||
</p>
|
</p>
|
||||||
<OnboardingButtons
|
<OnboardingButtons currentSlug={onboardingPaths.COMMAND_K} />
|
||||||
currentSlug={onboardingPaths.COMMAND_K}
|
|
||||||
dismiss={dismiss}
|
|
||||||
next={next}
|
|
||||||
nextText="Next: User Menu"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,22 +1,14 @@
|
|||||||
import {
|
import { kbdClasses, OnboardingButtons, useDemoCode } from '.'
|
||||||
kbdClasses,
|
|
||||||
OnboardingButtons,
|
|
||||||
useDemoCode,
|
|
||||||
useDismiss,
|
|
||||||
useNextClick,
|
|
||||||
} from '.'
|
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
|
|
||||||
export default function OnboardingCodeEditor() {
|
export default function OnboardingCodeEditor() {
|
||||||
useDemoCode()
|
useDemoCode()
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
|
|
||||||
|
|
||||||
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">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1 overflow-y-auto">
|
<section className="flex-1 overflow-y-auto">
|
||||||
@ -73,12 +65,7 @@ export default function OnboardingCodeEditor() {
|
|||||||
pressing <kbd className={kbdClasses}>Shift + C</kbd>.
|
pressing <kbd className={kbdClasses}>Shift + C</kbd>.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<OnboardingButtons
|
<OnboardingButtons currentSlug={onboardingPaths.EDITOR} />
|
||||||
currentSlug={onboardingPaths.EDITOR}
|
|
||||||
dismiss={dismiss}
|
|
||||||
next={next}
|
|
||||||
nextText="Next: Parametric Modeling"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
import { APP_NAME } from 'lib/constants'
|
import { APP_NAME } from 'lib/constants'
|
||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
|
|
||||||
export default function Export() {
|
export default function Export() {
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.SKETCHING)
|
|
||||||
|
|
||||||
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">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1">
|
<section className="flex-1">
|
||||||
@ -52,12 +49,7 @@ export default function Export() {
|
|||||||
!
|
!
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<OnboardingButtons
|
<OnboardingButtons currentSlug={onboardingPaths.EXPORT} />
|
||||||
currentSlug={onboardingPaths.EXPORT}
|
|
||||||
next={next}
|
|
||||||
dismiss={dismiss}
|
|
||||||
nextText="Next: Sketching"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { OnboardingButtons, useDemoCode, useDismiss } from '.'
|
import { OnboardingButtons, useDemoCode } from '.'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useModelingContext } from 'hooks/useModelingContext'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
import { APP_NAME } from 'lib/constants'
|
import { APP_NAME } from 'lib/constants'
|
||||||
@ -7,7 +7,6 @@ import { sceneInfra } from 'lib/singletons'
|
|||||||
|
|
||||||
export default function FutureWork() {
|
export default function FutureWork() {
|
||||||
const { send } = useModelingContext()
|
const { send } = useModelingContext()
|
||||||
const dismiss = useDismiss()
|
|
||||||
|
|
||||||
// Reset the code, the camera, and the modeling state
|
// Reset the code, the camera, and the modeling state
|
||||||
useDemoCode()
|
useDemoCode()
|
||||||
@ -19,7 +18,7 @@ export default function FutureWork() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-center items-center inset-0 bg-chalkboard-100/50 z-50">
|
<div className="fixed grid justify-center items-center inset-0 bg-chalkboard-100/50 z-50">
|
||||||
<div className="max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded">
|
<div className="relative max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded">
|
||||||
<h1 className="text-2xl font-bold">Future Work</h1>
|
<h1 className="text-2xl font-bold">Future Work</h1>
|
||||||
<p className="my-4">
|
<p className="my-4">
|
||||||
We have curves, cuts, multi-profile sketch mode, and many more CAD
|
We have curves, cuts, multi-profile sketch mode, and many more CAD
|
||||||
@ -59,9 +58,6 @@ export default function FutureWork() {
|
|||||||
<OnboardingButtons
|
<OnboardingButtons
|
||||||
currentSlug={onboardingPaths.FUTURE_WORK}
|
currentSlug={onboardingPaths.FUTURE_WORK}
|
||||||
className="mt-6"
|
className="mt-6"
|
||||||
dismiss={dismiss}
|
|
||||||
next={dismiss}
|
|
||||||
nextText="Finish"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
import {
|
import { OnboardingButtons, kbdClasses, useDemoCode } from '.'
|
||||||
OnboardingButtons,
|
|
||||||
kbdClasses,
|
|
||||||
useDemoCode,
|
|
||||||
useDismiss,
|
|
||||||
useNextClick,
|
|
||||||
} from '.'
|
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { bracketWidthConstantLine } from 'lib/exampleKcl'
|
import { bracketWidthConstantLine } from 'lib/exampleKcl'
|
||||||
|
|
||||||
export default function OnboardingInteractiveNumbers() {
|
export default function OnboardingInteractiveNumbers() {
|
||||||
useDemoCode()
|
useDemoCode()
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.COMMAND_K)
|
|
||||||
|
|
||||||
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">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1 overflow-y-auto mb-6">
|
<section className="flex-1 overflow-y-auto mb-6">
|
||||||
@ -88,12 +80,7 @@ export default function OnboardingInteractiveNumbers() {
|
|||||||
your ideas for how to make it better.
|
your ideas for how to make it better.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<OnboardingButtons
|
<OnboardingButtons currentSlug={onboardingPaths.INTERACTIVE_NUMBERS} />
|
||||||
currentSlug={onboardingPaths.INTERACTIVE_NUMBERS}
|
|
||||||
dismiss={dismiss}
|
|
||||||
next={next}
|
|
||||||
nextText="Next: Command Bar"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDemoCode } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
import { Themes, getSystemTheme } from 'lib/theme'
|
import { Themes, getSystemTheme } from 'lib/theme'
|
||||||
@ -8,13 +8,12 @@ import { isDesktop } from 'lib/isDesktop'
|
|||||||
import { useNavigate, useRouteLoaderData } from 'react-router-dom'
|
import { useNavigate, useRouteLoaderData } from 'react-router-dom'
|
||||||
import { codeManager, kclManager } from 'lib/singletons'
|
import { codeManager, kclManager } from 'lib/singletons'
|
||||||
import { APP_NAME } from 'lib/constants'
|
import { APP_NAME } from 'lib/constants'
|
||||||
import { useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { IndexLoaderData } from 'lib/types'
|
import { IndexLoaderData } from 'lib/types'
|
||||||
import { PATHS } from 'lib/paths'
|
import { PATHS } from 'lib/paths'
|
||||||
import { useFileContext } from 'hooks/useFileContext'
|
import { useFileContext } from 'hooks/useFileContext'
|
||||||
import { useLspContext } from 'components/LspProvider'
|
import { useLspContext } from 'components/LspProvider'
|
||||||
import { reportRejection } from 'lib/trap'
|
import { reportRejection } from 'lib/trap'
|
||||||
import { toSync } from 'lib/utils'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show either a welcome screen or a warning screen
|
* Show either a welcome screen or a warning screen
|
||||||
@ -39,7 +38,7 @@ interface OnboardingResetWarningProps {
|
|||||||
function OnboardingResetWarning(props: OnboardingResetWarningProps) {
|
function OnboardingResetWarning(props: OnboardingResetWarningProps) {
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 grid place-content-center bg-chalkboard-110/50">
|
<div className="fixed inset-0 z-50 grid place-content-center bg-chalkboard-110/50">
|
||||||
<div className="max-w-3xl p-8 rounded bg-chalkboard-10 dark:bg-chalkboard-90">
|
<div className="relative max-w-3xl p-8 rounded bg-chalkboard-10 dark:bg-chalkboard-90">
|
||||||
{!isDesktop() ? (
|
{!isDesktop() ? (
|
||||||
<OnboardingWarningWeb {...props} />
|
<OnboardingWarningWeb {...props} />
|
||||||
) : (
|
) : (
|
||||||
@ -52,7 +51,6 @@ function OnboardingResetWarning(props: OnboardingResetWarningProps) {
|
|||||||
|
|
||||||
function OnboardingWarningDesktop(props: OnboardingResetWarningProps) {
|
function OnboardingWarningDesktop(props: OnboardingResetWarningProps) {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const dismiss = useDismiss()
|
|
||||||
const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
|
const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
|
||||||
const { context: fileContext } = useFileContext()
|
const { context: fileContext } = useFileContext()
|
||||||
const { onProjectClose, onProjectOpen } = useLspContext()
|
const { onProjectClose, onProjectOpen } = useLspContext()
|
||||||
@ -81,17 +79,28 @@ function OnboardingWarningDesktop(props: OnboardingResetWarningProps) {
|
|||||||
</section>
|
</section>
|
||||||
<OnboardingButtons
|
<OnboardingButtons
|
||||||
className="mt-6"
|
className="mt-6"
|
||||||
dismiss={dismiss}
|
onNextOverride={() => {
|
||||||
next={toSync(onAccept, reportRejection)}
|
onAccept().catch(reportRejection)
|
||||||
nextText="Make a new project"
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function OnboardingWarningWeb(props: OnboardingResetWarningProps) {
|
function OnboardingWarningWeb(props: OnboardingResetWarningProps) {
|
||||||
const dismiss = useDismiss()
|
useEffect(() => {
|
||||||
|
async function beforeNavigate() {
|
||||||
|
// We do want to update both the state and editor here.
|
||||||
|
codeManager.updateCodeStateEditor(bracket)
|
||||||
|
await codeManager.writeToFile()
|
||||||
|
|
||||||
|
await kclManager.executeCode(true)
|
||||||
|
props.setShouldShowWarning(false)
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
beforeNavigate().catch(reportRejection)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1 className="text-3xl font-bold text-warn-80 dark:text-warn-10">
|
<h1 className="text-3xl font-bold text-warn-80 dark:text-warn-10">
|
||||||
@ -101,19 +110,7 @@ function OnboardingWarningWeb(props: OnboardingResetWarningProps) {
|
|||||||
We see you have some of your own code written in this project. Please
|
We see you have some of your own code written in this project. Please
|
||||||
save it somewhere else before continuing the onboarding.
|
save it somewhere else before continuing the onboarding.
|
||||||
</p>
|
</p>
|
||||||
<OnboardingButtons
|
<OnboardingButtons className="mt-6" />
|
||||||
className="mt-6"
|
|
||||||
dismiss={dismiss}
|
|
||||||
next={toSync(async () => {
|
|
||||||
// We do want to update both the state and editor here.
|
|
||||||
codeManager.updateCodeStateEditor(bracket)
|
|
||||||
await codeManager.writeToFile()
|
|
||||||
|
|
||||||
await kclManager.executeCode(true)
|
|
||||||
props.setShouldShowWarning(false)
|
|
||||||
}, reportRejection)}
|
|
||||||
nextText="Overwrite code and continue"
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -136,12 +133,10 @@ function OnboardingIntroductionInner() {
|
|||||||
(theme.current === Themes.System && getSystemTheme() === Themes.Light)
|
(theme.current === Themes.System && getSystemTheme() === Themes.Light)
|
||||||
? '-dark'
|
? '-dark'
|
||||||
: ''
|
: ''
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.CAMERA)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 grid place-content-center bg-chalkboard-110/50">
|
<div className="fixed inset-0 z-50 grid place-content-center bg-chalkboard-110/50">
|
||||||
<div className="max-w-3xl p-8 rounded bg-chalkboard-10 dark:bg-chalkboard-90">
|
<div className="relative max-w-3xl p-8 rounded bg-chalkboard-10 dark:bg-chalkboard-90">
|
||||||
<h1 className="flex flex-wrap items-center gap-4 text-3xl font-bold">
|
<h1 className="flex flex-wrap items-center gap-4 text-3xl font-bold">
|
||||||
<img
|
<img
|
||||||
src={`${isDesktop() ? '.' : ''}/zma-logomark${getLogoTheme()}.svg`}
|
src={`${isDesktop() ? '.' : ''}/zma-logomark${getLogoTheme()}.svg`}
|
||||||
@ -192,9 +187,6 @@ function OnboardingIntroductionInner() {
|
|||||||
<OnboardingButtons
|
<OnboardingButtons
|
||||||
currentSlug={onboardingPaths.INDEX}
|
currentSlug={onboardingPaths.INDEX}
|
||||||
className="mt-6"
|
className="mt-6"
|
||||||
dismiss={dismiss}
|
|
||||||
next={next}
|
|
||||||
nextText="Mouse Controls"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDemoCode } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { Themes, getSystemTheme } from 'lib/theme'
|
import { Themes, getSystemTheme } from 'lib/theme'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
@ -21,14 +21,12 @@ export default function OnboardingParametricModeling() {
|
|||||||
(theme === Themes.System && getSystemTheme() === Themes.Light)
|
(theme === Themes.System && getSystemTheme() === Themes.Light)
|
||||||
? '-dark'
|
? '-dark'
|
||||||
: ''
|
: ''
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.INTERACTIVE_NUMBERS)
|
|
||||||
|
|
||||||
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">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1 overflow-y-auto mb-6">
|
<section className="flex-1 overflow-y-auto mb-6">
|
||||||
@ -77,12 +75,7 @@ export default function OnboardingParametricModeling() {
|
|||||||
</figcaption>
|
</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
</section>
|
</section>
|
||||||
<OnboardingButtons
|
<OnboardingButtons currentSlug={onboardingPaths.PARAMETRIC_MODELING} />
|
||||||
currentSlug={onboardingPaths.PARAMETRIC_MODELING}
|
|
||||||
dismiss={dismiss}
|
|
||||||
next={next}
|
|
||||||
nextText="Next: Interactive Numbers"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { isDesktop } from 'lib/isDesktop'
|
import { isDesktop } from 'lib/isDesktop'
|
||||||
|
|
||||||
export default function ProjectMenu() {
|
export default function ProjectMenu() {
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.EXPORT)
|
|
||||||
const onDesktop = isDesktop()
|
const onDesktop = isDesktop()
|
||||||
|
|
||||||
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">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1">
|
<section className="flex-1">
|
||||||
@ -57,12 +55,7 @@ export default function ProjectMenu() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
<OnboardingButtons
|
<OnboardingButtons currentSlug={onboardingPaths.PROJECT_MENU} />
|
||||||
currentSlug={onboardingPaths.PROJECT_MENU}
|
|
||||||
next={next}
|
|
||||||
dismiss={dismiss}
|
|
||||||
nextText="Next: Export"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { codeManager, kclManager } from 'lib/singletons'
|
import { codeManager, kclManager } from 'lib/singletons'
|
||||||
|
|
||||||
export default function Sketching() {
|
export default function Sketching() {
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.FUTURE_WORK)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function clearEditor() {
|
async function clearEditor() {
|
||||||
// We do want to update both the state and editor here.
|
// We do want to update both the state and editor here.
|
||||||
@ -22,7 +19,7 @@ export default function Sketching() {
|
|||||||
<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">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<h1 className="text-2xl font-bold">Sketching</h1>
|
<h1 className="text-2xl font-bold">Sketching</h1>
|
||||||
@ -45,9 +42,6 @@ export default function Sketching() {
|
|||||||
<OnboardingButtons
|
<OnboardingButtons
|
||||||
currentSlug={onboardingPaths.SKETCHING}
|
currentSlug={onboardingPaths.SKETCHING}
|
||||||
className="mt-6"
|
className="mt-6"
|
||||||
next={next}
|
|
||||||
dismiss={dismiss}
|
|
||||||
nextText="Next: Future Work"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
|
|
||||||
export default function Streaming() {
|
export default function Streaming() {
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.EDITOR)
|
|
||||||
|
|
||||||
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">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1 overflow-y-auto">
|
<section className="flex-1 overflow-y-auto">
|
||||||
@ -44,9 +41,7 @@ export default function Streaming() {
|
|||||||
</section>
|
</section>
|
||||||
<OnboardingButtons
|
<OnboardingButtons
|
||||||
currentSlug={onboardingPaths.STREAMING}
|
currentSlug={onboardingPaths.STREAMING}
|
||||||
dismiss={dismiss}
|
dismissClassName="right-auto left-full"
|
||||||
next={next}
|
|
||||||
nextText="Next: Code Editor"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useUser } from 'machines/appMachine'
|
import { useUser } from 'machines/appMachine'
|
||||||
|
|
||||||
export default function UserMenu() {
|
export default function UserMenu() {
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const dismiss = useDismiss()
|
|
||||||
const next = useNextClick(onboardingPaths.PROJECT_MENU)
|
|
||||||
const [avatarErrored, setAvatarErrored] = useState(false)
|
const [avatarErrored, setAvatarErrored] = useState(false)
|
||||||
|
|
||||||
const errorOrNoImage = !user?.image || avatarErrored
|
const errorOrNoImage = !user?.image || avatarErrored
|
||||||
@ -32,7 +30,7 @@ export default function UserMenu() {
|
|||||||
<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">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pointer-events-auto max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
'relative pointer-events-auto max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1">
|
<section className="flex-1">
|
||||||
@ -48,12 +46,7 @@ export default function UserMenu() {
|
|||||||
only apply to the current project.
|
only apply to the current project.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<OnboardingButtons
|
<OnboardingButtons currentSlug={onboardingPaths.USER_MENU} />
|
||||||
currentSlug={onboardingPaths.USER_MENU}
|
|
||||||
dismiss={dismiss}
|
|
||||||
next={next}
|
|
||||||
nextText="Next: Project Menu"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -26,6 +26,9 @@ import { reportRejection } from 'lib/trap'
|
|||||||
import { useNetworkContext } from 'hooks/useNetworkContext'
|
import { useNetworkContext } from 'hooks/useNetworkContext'
|
||||||
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
||||||
import { EngineConnectionStateType } from 'lang/std/engineConnection'
|
import { EngineConnectionStateType } from 'lang/std/engineConnection'
|
||||||
|
import { CustomIcon } from 'components/CustomIcon'
|
||||||
|
import Tooltip from 'components/Tooltip'
|
||||||
|
import { commandBarActor } from 'machines/commandBarMachine'
|
||||||
|
|
||||||
export const kbdClasses =
|
export const kbdClasses =
|
||||||
'py-0.5 px-1 text-sm rounded bg-chalkboard-10 dark:bg-chalkboard-100 border border-chalkboard-50 border-b-2'
|
'py-0.5 px-1 text-sm rounded bg-chalkboard-10 dark:bg-chalkboard-100 border border-chalkboard-50 border-b-2'
|
||||||
@ -163,58 +166,99 @@ export function useStepNumber(
|
|||||||
: onboardingRoutes.findIndex(
|
: onboardingRoutes.findIndex(
|
||||||
(r) => r.path === makeUrlPathRelative(slug)
|
(r) => r.path === makeUrlPathRelative(slug)
|
||||||
) + 1
|
) + 1
|
||||||
: undefined
|
: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OnboardingButtons({
|
export function OnboardingButtons({
|
||||||
next,
|
|
||||||
nextText,
|
|
||||||
dismiss,
|
|
||||||
currentSlug,
|
currentSlug,
|
||||||
className,
|
className,
|
||||||
|
dismissClassName,
|
||||||
|
onNextOverride,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
next: () => void
|
|
||||||
nextText?: string
|
|
||||||
dismiss: () => void
|
|
||||||
currentSlug?: (typeof onboardingPaths)[keyof typeof onboardingPaths]
|
currentSlug?: (typeof onboardingPaths)[keyof typeof onboardingPaths]
|
||||||
className?: string
|
className?: string
|
||||||
|
dismissClassName?: string
|
||||||
|
onNextOverride?: () => void
|
||||||
} & React.HTMLAttributes<HTMLDivElement>) {
|
} & React.HTMLAttributes<HTMLDivElement>) {
|
||||||
|
const dismiss = useDismiss()
|
||||||
const stepNumber = useStepNumber(currentSlug)
|
const stepNumber = useStepNumber(currentSlug)
|
||||||
|
const previousStep =
|
||||||
|
!stepNumber || stepNumber === 0 ? null : onboardingRoutes[stepNumber - 2]
|
||||||
|
const goToPrevious = useNextClick(
|
||||||
|
onboardingPaths.INDEX + (previousStep?.path ?? '')
|
||||||
|
)
|
||||||
|
const nextStep =
|
||||||
|
!stepNumber || stepNumber === onboardingRoutes.length
|
||||||
|
? null
|
||||||
|
: onboardingRoutes[stepNumber]
|
||||||
|
const goToNext = useNextClick(onboardingPaths.INDEX + (nextStep?.path ?? ''))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
className={'flex items-center justify-between ' + (className ?? '')}
|
<button
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<ActionButton
|
|
||||||
Element="button"
|
|
||||||
onClick={dismiss}
|
onClick={dismiss}
|
||||||
iconStart={{
|
className={
|
||||||
icon: 'close',
|
'group block !absolute left-auto right-full top-[-3px] m-2.5 p-0 border-none bg-transparent hover:bg-transparent ' +
|
||||||
className: 'text-chalkboard-10',
|
dismissClassName
|
||||||
bgClassName: 'bg-destroy-80 group-hover:bg-destroy-80',
|
}
|
||||||
}}
|
data-testid="onboarding-dismiss"
|
||||||
className="hover:border-destroy-40 hover:bg-destroy-10/50 dark:hover:bg-destroy-80/50"
|
|
||||||
>
|
>
|
||||||
Dismiss
|
<CustomIcon
|
||||||
</ActionButton>
|
name="close"
|
||||||
{stepNumber !== undefined && (
|
className="w-5 h-5 rounded-sm bg-destroy-10 text-destroy-80 dark:bg-destroy-80 dark:text-destroy-10 group-hover:brightness-110"
|
||||||
<p className="font-mono text-xs text-center m-0">
|
/>
|
||||||
{stepNumber} / {onboardingRoutes.length}
|
<Tooltip position="bottom" delay={500}>
|
||||||
</p>
|
Dismiss <kbd className="hotkey ml-4 dark:!bg-chalkboard-80">esc</kbd>
|
||||||
)}
|
</Tooltip>
|
||||||
<ActionButton
|
</button>
|
||||||
autoFocus
|
<div
|
||||||
Element="button"
|
className={'flex items-center justify-between ' + (className ?? '')}
|
||||||
onClick={next}
|
{...props}
|
||||||
iconStart={{ icon: 'arrowRight', bgClassName: 'dark:bg-chalkboard-80' }}
|
|
||||||
className="dark:hover:bg-chalkboard-80/50"
|
|
||||||
data-testid="onboarding-next"
|
|
||||||
>
|
>
|
||||||
{nextText ?? 'Next'}
|
<ActionButton
|
||||||
</ActionButton>
|
Element="button"
|
||||||
</div>
|
onClick={() =>
|
||||||
|
previousStep?.path || previousStep?.index
|
||||||
|
? goToPrevious()
|
||||||
|
: dismiss()
|
||||||
|
}
|
||||||
|
iconStart={{
|
||||||
|
icon: previousStep ? 'arrowLeft' : 'close',
|
||||||
|
className: 'text-chalkboard-10',
|
||||||
|
bgClassName: 'bg-destroy-80 group-hover:bg-destroy-80',
|
||||||
|
}}
|
||||||
|
className="hover:border-destroy-40 hover:bg-destroy-10/50 dark:hover:bg-destroy-80/50"
|
||||||
|
data-testid="onboarding-prev"
|
||||||
|
>
|
||||||
|
{previousStep ? `Back` : 'Dismiss'}
|
||||||
|
</ActionButton>
|
||||||
|
{stepNumber !== undefined && (
|
||||||
|
<p className="font-mono text-xs text-center m-0">
|
||||||
|
{stepNumber} / {onboardingRoutes.length}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<ActionButton
|
||||||
|
autoFocus
|
||||||
|
Element="button"
|
||||||
|
onClick={() => {
|
||||||
|
if (nextStep?.path) {
|
||||||
|
onNextOverride ? onNextOverride() : goToNext()
|
||||||
|
} else {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
iconStart={{
|
||||||
|
icon: nextStep ? 'arrowRight' : 'checkmark',
|
||||||
|
bgClassName: 'dark:bg-chalkboard-80',
|
||||||
|
}}
|
||||||
|
className="dark:hover:bg-chalkboard-80/50"
|
||||||
|
data-testid="onboarding-next"
|
||||||
|
>
|
||||||
|
{nextStep ? `Next` : 'Finish'}
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user