feat: add tutorial
This commit is contained in:
BIN
apps/desktop/public/tutorial-1.gif
Normal file
BIN
apps/desktop/public/tutorial-1.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
apps/desktop/public/tutorial-2.gif
Normal file
BIN
apps/desktop/public/tutorial-2.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
apps/desktop/public/tutorial-3.gif
Normal file
BIN
apps/desktop/public/tutorial-3.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 MiB |
@@ -6,13 +6,9 @@ import { Thread } from "@columns/thread";
|
|||||||
import { Timeline } from "@columns/timeline";
|
import { Timeline } from "@columns/timeline";
|
||||||
import { User } from "@columns/user";
|
import { User } from "@columns/user";
|
||||||
import { useColumnContext } from "@lume/ark";
|
import { useColumnContext } from "@lume/ark";
|
||||||
import {
|
import { ArrowLeftIcon, ArrowRightIcon, PlusSquareIcon } from "@lume/icons";
|
||||||
ArrowLeftIcon,
|
|
||||||
ArrowRightIcon,
|
|
||||||
HelpIcon,
|
|
||||||
PlusSquareIcon,
|
|
||||||
} from "@lume/icons";
|
|
||||||
import { IColumn } from "@lume/types";
|
import { IColumn } from "@lume/types";
|
||||||
|
import { TutorialModal } from "@lume/ui/src/tutorial/modal";
|
||||||
import { COL_TYPES } from "@lume/utils";
|
import { COL_TYPES } from "@lume/utils";
|
||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import { VList, VListHandle } from "virtua";
|
import { VList, VListHandle } from "virtua";
|
||||||
@@ -46,6 +42,7 @@ export function HomeScreen() {
|
|||||||
return (
|
return (
|
||||||
<div className="relative w-full h-full">
|
<div className="relative w-full h-full">
|
||||||
<VList
|
<VList
|
||||||
|
id="timeline"
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className="h-full w-full flex-nowrap overflow-x-auto !overflow-y-hidden scrollbar-none focus:outline-none"
|
className="h-full w-full flex-nowrap overflow-x-auto !overflow-y-hidden scrollbar-none focus:outline-none"
|
||||||
itemSize={420}
|
itemSize={420}
|
||||||
@@ -85,7 +82,7 @@ export function HomeScreen() {
|
|||||||
<div className="w-[420px]" />
|
<div className="w-[420px]" />
|
||||||
</VList>
|
</VList>
|
||||||
<div className="absolute bottom-3 right-3">
|
<div className="absolute bottom-3 right-3">
|
||||||
<div className="flex items-center gap-1 p-1 bg-black/50 dark:bg-white/30 backdrop-blur-xl rounded-xl">
|
<div className="flex items-center gap-1 p-1 bg-black/30 dark:bg-white/30 backdrop-blur-xl rounded-xl">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -96,7 +93,7 @@ export function HomeScreen() {
|
|||||||
smooth: true,
|
smooth: true,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
className="inline-flex items-center justify-center rounded-lg text-white/70 hover:text-white hover:bg-black/50 size-10"
|
className="inline-flex items-center justify-center rounded-lg text-white/70 hover:text-white hover:bg-black/30 size-10"
|
||||||
>
|
>
|
||||||
<ArrowLeftIcon className="size-5" />
|
<ArrowLeftIcon className="size-5" />
|
||||||
</button>
|
</button>
|
||||||
@@ -110,7 +107,7 @@ export function HomeScreen() {
|
|||||||
smooth: true,
|
smooth: true,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
className="inline-flex items-center justify-center rounded-lg text-white/70 hover:text-white hover:bg-black/50 size-10"
|
className="inline-flex items-center justify-center rounded-lg text-white/70 hover:text-white hover:bg-black/30 size-10"
|
||||||
>
|
>
|
||||||
<ArrowRightIcon className="size-5" />
|
<ArrowRightIcon className="size-5" />
|
||||||
</button>
|
</button>
|
||||||
@@ -123,17 +120,12 @@ export function HomeScreen() {
|
|||||||
content: "",
|
content: "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
className="inline-flex items-center justify-center rounded-lg text-white/70 hover:text-white hover:bg-black/50 size-10"
|
className="inline-flex items-center justify-center rounded-lg text-white/70 hover:text-white hover:bg-black/30 size-10"
|
||||||
>
|
>
|
||||||
<PlusSquareIcon className="size-5" />
|
<PlusSquareIcon className="size-5" />
|
||||||
</button>
|
</button>
|
||||||
<div className="w-px h-6 bg-white/10" />
|
<div className="w-px h-6 bg-white/10" />
|
||||||
<button
|
<TutorialModal />
|
||||||
type="button"
|
|
||||||
className="inline-flex items-center justify-center rounded-lg text-white/70 hover:text-white hover:bg-black/50 size-10"
|
|
||||||
>
|
|
||||||
<HelpIcon className="size-5" />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"@radix-ui/react-dialog": "^1.0.5",
|
"@radix-ui/react-dialog": "^1.0.5",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||||
"@radix-ui/react-hover-card": "^1.0.7",
|
"@radix-ui/react-hover-card": "^1.0.7",
|
||||||
|
"@radix-ui/react-popover": "^1.0.7",
|
||||||
"@tanstack/react-query": "^5.17.9",
|
"@tanstack/react-query": "^5.17.9",
|
||||||
"@tauri-apps/api": "2.0.0-alpha.13",
|
"@tauri-apps/api": "2.0.0-alpha.13",
|
||||||
"@tauri-apps/plugin-http": "2.0.0-alpha.6",
|
"@tauri-apps/plugin-http": "2.0.0-alpha.6",
|
||||||
|
|||||||
35
packages/ui/src/tutorial/finish.tsx
Normal file
35
packages/ui/src/tutorial/finish.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { tutorialAtom } from "@lume/utils";
|
||||||
|
import { useSetAtom } from "jotai";
|
||||||
|
|
||||||
|
export function TutorialFinishScreen() {
|
||||||
|
const tutorial = useSetAtom(tutorialAtom);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="px-5 h-full flex flex-col justify-between">
|
||||||
|
<div className="h-full min-h-0 flex flex-col gap-2">
|
||||||
|
<p>
|
||||||
|
<span className="font-semibold">Great Job!</span> You have completed
|
||||||
|
this section. Feel free to explore other menus in the interface, such
|
||||||
|
as Activity and Relay Explorer.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you want to see this tutorial again, don't hesitate to press the ?
|
||||||
|
icon in Bottom bar
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you want to seek help from Lume Devs, you can publish a post with{" "}
|
||||||
|
<span className="text-blue-500">#lumesos</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="h-16 w-full shrink-0 flex items-center justify-end">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => tutorial(false)}
|
||||||
|
className="inline-flex items-center justify-center w-20 font-semibold border-t rounded-lg border-neutral-900 dark:border-neutral-800 h-9 bg-neutral-950 text-neutral-50 dark:bg-neutral-900 hover:bg-neutral-900 dark:hover:bg-neutral-800"
|
||||||
|
>
|
||||||
|
Finish
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
packages/ui/src/tutorial/manageColumn.tsx
Normal file
31
packages/ui/src/tutorial/manageColumn.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
export function TutorialManageColumnScreen() {
|
||||||
|
return (
|
||||||
|
<div className="px-5 h-full flex flex-col justify-between">
|
||||||
|
<div className="h-full min-h-0 flex flex-col gap-2">
|
||||||
|
<p>
|
||||||
|
Lume is also provide simple way to customize column after creation.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span className="font-semibold">To customize each column,</span> you
|
||||||
|
can go to header of each column
|
||||||
|
</p>
|
||||||
|
<p>Click to "Three Dots" icon</p>
|
||||||
|
<img
|
||||||
|
src="/tutorial-3.gif"
|
||||||
|
alt="tutorial-3"
|
||||||
|
className="w-full h-auto rounded-lg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="h-16 w-full shrink-0 flex items-center justify-end">
|
||||||
|
<Link
|
||||||
|
to="/finish"
|
||||||
|
className="inline-flex items-center justify-center w-20 font-semibold border-t rounded-lg border-neutral-900 dark:border-neutral-800 h-9 bg-neutral-950 text-neutral-50 dark:bg-neutral-900 hover:bg-neutral-900 dark:hover:bg-neutral-800"
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
38
packages/ui/src/tutorial/modal.tsx
Normal file
38
packages/ui/src/tutorial/modal.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { CancelIcon, HelpIcon } from "@lume/icons";
|
||||||
|
import { tutorialAtom } from "@lume/utils";
|
||||||
|
import * as Popover from "@radix-ui/react-popover";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
import { TutorialRouter } from "./router";
|
||||||
|
|
||||||
|
export function TutorialModal() {
|
||||||
|
const [tutorial, setTutorial] = useAtom(tutorialAtom);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover.Root open={tutorial}>
|
||||||
|
<Popover.Trigger asChild>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setTutorial((state) => !state)}
|
||||||
|
className="inline-flex items-center justify-center rounded-lg text-white/70 hover:text-white hover:bg-black/50 size-10"
|
||||||
|
>
|
||||||
|
<HelpIcon className="size-5" />
|
||||||
|
</button>
|
||||||
|
</Popover.Trigger>
|
||||||
|
<Popover.Portal>
|
||||||
|
<Popover.Content className="relative right-4 bottom-8">
|
||||||
|
<div className="flex flex-col w-full max-w-xs bg-white h-[480px] rounded-xl dark:bg-neutral-950 dark:border dark:border-neutral-900 overflow-hidden shadow-[0_8px_30px_rgb(0,0,0,0.12)]">
|
||||||
|
<div className="pt-5 mb-3 shrink-0 flex px-5 items-center justify-between text-neutral-500 dark:text-neutral-400">
|
||||||
|
<h3 className="text-sm font-medium">Tutorial</h3>
|
||||||
|
<Popover.Close onClick={() => setTutorial(false)}>
|
||||||
|
<CancelIcon className="size-4" />
|
||||||
|
</Popover.Close>
|
||||||
|
</div>
|
||||||
|
<div className="min-h-0 flex-1 h-full">
|
||||||
|
<TutorialRouter />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Portal>
|
||||||
|
</Popover.Root>
|
||||||
|
);
|
||||||
|
}
|
||||||
29
packages/ui/src/tutorial/newColumn.tsx
Normal file
29
packages/ui/src/tutorial/newColumn.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
export function TutorialNewColumnScreen() {
|
||||||
|
return (
|
||||||
|
<div className="px-5 h-full flex flex-col justify-between">
|
||||||
|
<div className="h-full min-h-0 flex flex-col gap-2">
|
||||||
|
<p>Lume is column based, each column is each experience</p>
|
||||||
|
<p>
|
||||||
|
<span className="font-semibold">To create new column,</span> you can
|
||||||
|
look into bottom right part of screen
|
||||||
|
</p>
|
||||||
|
<p>Click to "Plus" icon</p>
|
||||||
|
<img
|
||||||
|
src="/tutorial-2.gif"
|
||||||
|
alt="tutorial-2"
|
||||||
|
className="w-full h-auto rounded-lg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="h-16 w-full shrink-0 flex items-center justify-end">
|
||||||
|
<Link
|
||||||
|
to="/manage-column"
|
||||||
|
className="inline-flex items-center justify-center w-20 font-semibold border-t rounded-lg border-neutral-900 dark:border-neutral-800 h-9 bg-neutral-950 text-neutral-50 dark:bg-neutral-900 hover:bg-neutral-900 dark:hover:bg-neutral-800"
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
packages/ui/src/tutorial/router.tsx
Normal file
31
packages/ui/src/tutorial/router.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { AnimatePresence } from "framer-motion";
|
||||||
|
import {
|
||||||
|
MemoryRouter,
|
||||||
|
Route,
|
||||||
|
Routes,
|
||||||
|
UNSAFE_LocationContext,
|
||||||
|
} from "react-router-dom";
|
||||||
|
import { TutorialFinishScreen } from "./finish";
|
||||||
|
import { TutorialManageColumnScreen } from "./manageColumn";
|
||||||
|
import { TutorialNewColumnScreen } from "./newColumn";
|
||||||
|
import { TutorialWelcomeScreen } from "./welcome";
|
||||||
|
|
||||||
|
export function TutorialRouter() {
|
||||||
|
return (
|
||||||
|
<UNSAFE_LocationContext.Provider value={null}>
|
||||||
|
<MemoryRouter future={{ v7_startTransition: true }}>
|
||||||
|
<AnimatePresence>
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={<TutorialWelcomeScreen />} />
|
||||||
|
<Route path="/new-column" element={<TutorialNewColumnScreen />} />
|
||||||
|
<Route
|
||||||
|
path="/manage-column"
|
||||||
|
element={<TutorialManageColumnScreen />}
|
||||||
|
/>
|
||||||
|
<Route path="/finish" element={<TutorialFinishScreen />} />
|
||||||
|
</Routes>
|
||||||
|
</AnimatePresence>
|
||||||
|
</MemoryRouter>
|
||||||
|
</UNSAFE_LocationContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
30
packages/ui/src/tutorial/welcome.tsx
Normal file
30
packages/ui/src/tutorial/welcome.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
export function TutorialWelcomeScreen() {
|
||||||
|
return (
|
||||||
|
<div className="px-5 h-full flex flex-col justify-between">
|
||||||
|
<div className="h-full min-h-0 flex flex-col gap-2">
|
||||||
|
<p>
|
||||||
|
<span className="font-semibold">Welcome to your Home Screen.</span>{" "}
|
||||||
|
This is your personalized screen, which you can customize to you
|
||||||
|
liking
|
||||||
|
</p>
|
||||||
|
<p>Feel free to make adjustments as needed.</p>
|
||||||
|
<p>Let's take a few minutes to explore the features together.</p>
|
||||||
|
<img
|
||||||
|
src="/tutorial-1.gif"
|
||||||
|
alt="tutorial-1"
|
||||||
|
className="w-full h-auto rounded-lg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="h-16 w-full shrink-0 flex items-center justify-end">
|
||||||
|
<Link
|
||||||
|
to="/new-column"
|
||||||
|
className="inline-flex items-center justify-center w-20 font-semibold border-t rounded-lg border-neutral-900 dark:border-neutral-800 h-9 bg-neutral-950 text-neutral-50 dark:bg-neutral-900 hover:bg-neutral-900 dark:hover:bg-neutral-800"
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -15,3 +15,6 @@ export const onboardingAtom = atom(false);
|
|||||||
// Activity
|
// Activity
|
||||||
export const activityAtom = atom(false);
|
export const activityAtom = atom(false);
|
||||||
export const activityUnreadAtom = atom(0);
|
export const activityUnreadAtom = atom(0);
|
||||||
|
|
||||||
|
// Tutorial
|
||||||
|
export const tutorialAtom = atom(true);
|
||||||
|
|||||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -965,6 +965,9 @@ importers:
|
|||||||
'@radix-ui/react-hover-card':
|
'@radix-ui/react-hover-card':
|
||||||
specifier: ^1.0.7
|
specifier: ^1.0.7
|
||||||
version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.47)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.47)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-popover':
|
||||||
|
specifier: ^1.0.7
|
||||||
|
version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.47)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: ^5.17.9
|
specifier: ^5.17.9
|
||||||
version: 5.17.9(react@18.2.0)
|
version: 5.17.9(react@18.2.0)
|
||||||
|
|||||||
Reference in New Issue
Block a user