wip: tutorial
This commit is contained in:
58
src/app.tsx
58
src/app.tsx
@@ -14,7 +14,6 @@ import { AppLayout } from '@shared/layouts/app';
|
||||
import { AuthLayout } from '@shared/layouts/auth';
|
||||
import { NewLayout } from '@shared/layouts/new';
|
||||
import { NoteLayout } from '@shared/layouts/note';
|
||||
import { OnboardingLayout } from '@shared/layouts/onboarding';
|
||||
import { SettingsLayout } from '@shared/layouts/settings';
|
||||
|
||||
import './app.css';
|
||||
@@ -197,24 +196,45 @@ export default function App() {
|
||||
},
|
||||
{
|
||||
path: 'onboarding',
|
||||
element: <OnboardingLayout />,
|
||||
errorElement: <ErrorScreen />,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
async lazy() {
|
||||
const { OnboardingScreen } = await import('@app/auth/onboarding');
|
||||
return { Component: OnboardingScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'follow',
|
||||
async lazy() {
|
||||
const { FollowScreen } = await import('@app/auth/follow');
|
||||
return { Component: FollowScreen };
|
||||
},
|
||||
},
|
||||
],
|
||||
async lazy() {
|
||||
const { OnboardingScreen } = await import('@app/auth/onboarding');
|
||||
return { Component: OnboardingScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'follow',
|
||||
async lazy() {
|
||||
const { FollowScreen } = await import('@app/auth/follow');
|
||||
return { Component: FollowScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'finish',
|
||||
async lazy() {
|
||||
const { FinishScreen } = await import('@app/auth/finish');
|
||||
return { Component: FinishScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'tutorials/note',
|
||||
async lazy() {
|
||||
const { TutorialNoteScreen } = await import('@app/auth/tutorials/note');
|
||||
return { Component: TutorialNoteScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'tutorials/widget',
|
||||
async lazy() {
|
||||
const { TutorialWidgetScreen } = await import('@app/auth/tutorials/widget');
|
||||
return { Component: TutorialWidgetScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'tutorials/posting',
|
||||
async lazy() {
|
||||
const { TutorialPostingScreen } = await import('@app/auth/tutorials/posting');
|
||||
return { Component: TutorialPostingScreen };
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
34
src/app/auth/finish.tsx
Normal file
34
src/app/auth/finish.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export function FinishScreen() {
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<div className="mx-auto flex w-full max-w-md flex-col gap-10">
|
||||
<div className="text-center">
|
||||
<img src="/icon.png" alt="Lume's logo" className="mx-auto mb-1 h-auto w-16" />
|
||||
<h1 className="text-2xl font-light">
|
||||
Yo, you're ready to use <span className="font-bold">Lume</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Link
|
||||
to="/auth/tutorials/note"
|
||||
className="inline-flex h-11 w-full items-center justify-center rounded-lg bg-blue-500 font-medium text-white hover:bg-blue-600"
|
||||
>
|
||||
Start tutorial
|
||||
</Link>
|
||||
<Link
|
||||
to="/"
|
||||
className="inline-flex h-11 w-full items-center justify-center rounded-lg bg-neutral-100 font-medium hover:bg-neutral-200 dark:bg-neutral-900 dark:hover:bg-neutral-800"
|
||||
>
|
||||
Skip
|
||||
</Link>
|
||||
<p className="mt-2 text-center text-sm font-medium text-neutral-500 dark:text-neutral-600">
|
||||
You need to restart app to make changes in previous step take effect or you
|
||||
can continue with Lume default settings
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -189,7 +189,7 @@ export function ImportAccountScreen() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={changeAccount}
|
||||
className="h-8 w-20 shrink-0 rounded-lg bg-neutral-200 text-sm font-medium hover:bg-neutral-300 dark:bg-neutral-800 dark:hover:bg-neutral-700"
|
||||
className="h-8 w-max shrink-0 rounded-lg bg-neutral-200 px-2.5 text-sm font-medium hover:bg-neutral-300 dark:bg-neutral-800 dark:hover:bg-neutral-700"
|
||||
>
|
||||
Change
|
||||
</button>
|
||||
|
||||
@@ -18,8 +18,8 @@ export function OnboardingScreen() {
|
||||
});
|
||||
|
||||
const next = () => {
|
||||
if (!db.account.contacts) return navigate('/auth/onboarding/follow');
|
||||
return navigate('/');
|
||||
if (!db.account.contacts) return navigate('/auth/follow');
|
||||
return navigate('/auth/finish');
|
||||
};
|
||||
|
||||
const toggleOutbox = async () => {
|
||||
|
||||
91
src/app/auth/tutorials/note.tsx
Normal file
91
src/app/auth/tutorials/note.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useNDK } from '@libs/ndk/provider';
|
||||
|
||||
import { EditIcon, ReactionIcon, ReplyIcon, RepostIcon, ZapIcon } from '@shared/icons';
|
||||
import { TextNote } from '@shared/notes';
|
||||
|
||||
export function TutorialNoteScreen() {
|
||||
const { ndk } = useNDK();
|
||||
const exampleEvent = new NDKEvent(ndk, {
|
||||
id: 'a3527670dd9b178bf7c2a9ea673b63bc8bfe774942b196691145343623c45821',
|
||||
pubkey: '04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9',
|
||||
created_at: 1701355223,
|
||||
kind: 1,
|
||||
tags: [],
|
||||
content: 'good morning nostr, stay humble and stack sats 🫡',
|
||||
sig: '9e0bd67ec25598744f20bff0fe360fdf190c4240edb9eea260e50f77e07f94ea767ececcc6270819b7f64e5e7ca1fe20b4971f46dc120e6db43114557f3a6dae',
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full select-text items-center justify-center">
|
||||
<div className="mx-auto flex w-full max-w-md flex-col gap-10">
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<div className="inline-flex h-11 w-11 items-center justify-center rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<EditIcon className="h-5 w-5" />
|
||||
</div>
|
||||
<h1 className="text-2xl font-light">
|
||||
What is a <span className="font-bold">Note?</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="px-3">
|
||||
Posts on Nostr based Social Network client are usually called
|
||||
'Notes.' Notes are arranged chronologically on the timeline and are
|
||||
updated in real-time.
|
||||
</p>
|
||||
<p className="px-3 font-semibold">Here is one example:</p>
|
||||
<TextNote event={exampleEvent} className="pointer-events-none my-2" />
|
||||
<p className="px-3 font-semibold">Here are how you can interact with a note:</p>
|
||||
<div className="flex flex-col gap-2 px-3">
|
||||
<div className="inline-flex gap-3">
|
||||
<div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<ReplyIcon className="h-5 w-5 text-blue-500" />
|
||||
</div>
|
||||
<p>
|
||||
Reply - Click on this button to reply to a note. It's also possible
|
||||
to reply to replies, continuing the conversation like a thread.
|
||||
</p>
|
||||
</div>
|
||||
<div className="inline-flex gap-3">
|
||||
<div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<ReactionIcon className="h-5 w-5 text-red-500" />
|
||||
</div>
|
||||
<p>Reaction - You can add reactions to the Note to express your concern.</p>
|
||||
</div>
|
||||
<div className="inline-flex gap-3">
|
||||
<div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<RepostIcon className="h-5 w-5 text-teal-500" />
|
||||
</div>
|
||||
<p>
|
||||
Repost - You can share that note to your own timeline. You can also quote
|
||||
them with your comments.
|
||||
</p>
|
||||
</div>
|
||||
<div className="inline-flex gap-3">
|
||||
<div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<ZapIcon className="h-5 w-5 text-orange-500" />
|
||||
</div>
|
||||
<p>Zap - You can send tip in Bitcoin to that note owner with zero-fees</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 flex gap-2 px-3">
|
||||
<Link
|
||||
to="/auth/finish"
|
||||
className="inline-flex h-9 w-full items-center justify-center rounded-lg bg-neutral-100 font-medium hover:bg-neutral-200 dark:bg-neutral-900 dark:hover:bg-neutral-800"
|
||||
>
|
||||
Back
|
||||
</Link>
|
||||
<Link
|
||||
to="/auth/tutorials/widget"
|
||||
className="inline-flex h-9 w-full items-center justify-center rounded-lg bg-blue-500 font-medium text-white hover:bg-blue-600"
|
||||
>
|
||||
Continue
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
3
src/app/auth/tutorials/posting.tsx
Normal file
3
src/app/auth/tutorials/posting.tsx
Normal file
@@ -0,0 +1,3 @@
|
||||
export function TutorialPostingScreen() {
|
||||
return <div></div>;
|
||||
}
|
||||
64
src/app/auth/tutorials/widget.tsx
Normal file
64
src/app/auth/tutorials/widget.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { BellIcon, HomeIcon, PlusIcon } from '@shared/icons';
|
||||
|
||||
export function TutorialWidgetScreen() {
|
||||
return (
|
||||
<div className="flex h-full w-full select-text items-center justify-center">
|
||||
<div className="mx-auto flex w-full max-w-md flex-col gap-10">
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<div className="inline-flex h-11 w-11 items-center justify-center rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<HomeIcon className="h-5 w-5" />
|
||||
</div>
|
||||
<h1 className="text-2xl font-light">
|
||||
The concept of <span className="font-bold">Widgets</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 px-3">
|
||||
<p>
|
||||
Lume provides multiple widgets based on usage. You always can control what you
|
||||
need to show on your Home.
|
||||
</p>
|
||||
<p className="font-semibold">Default widgets:</p>
|
||||
<div className="inline-flex gap-3">
|
||||
<div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<HomeIcon className="h-5 w-5" />
|
||||
</div>
|
||||
<p>Newsfeed - You can view notes from accounts you follow.</p>
|
||||
</div>
|
||||
<div className="inline-flex gap-3">
|
||||
<div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<BellIcon className="h-5 w-5" />
|
||||
</div>
|
||||
<p>Notification - You can view all notifications related to your account.</p>
|
||||
</div>
|
||||
<p>
|
||||
If you want to add more widget, you can click to this button on Home Screen.
|
||||
</p>
|
||||
<div className="flex h-24 w-full items-center justify-center rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-14 w-14 items-center justify-center rounded-full bg-neutral-200 text-neutral-900 hover:bg-neutral-300 dark:bg-neutral-800 dark:text-neutral-100 dark:hover:bg-neutral-700"
|
||||
>
|
||||
<PlusIcon className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-5 flex gap-2">
|
||||
<Link
|
||||
to="/auth/tutorials/note"
|
||||
className="inline-flex h-9 w-full items-center justify-center rounded-lg bg-neutral-100 font-medium hover:bg-neutral-200 dark:bg-neutral-900 dark:hover:bg-neutral-800"
|
||||
>
|
||||
Back
|
||||
</Link>
|
||||
<Link
|
||||
to="/auth/tutorials/posting"
|
||||
className="inline-flex h-9 w-full items-center justify-center rounded-lg bg-blue-500 font-medium text-white hover:bg-blue-600"
|
||||
>
|
||||
Continue
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -13,13 +13,13 @@ export function WelcomeScreen() {
|
||||
<div className="flex flex-col gap-2 px-8">
|
||||
<Link
|
||||
to="/auth/create"
|
||||
className="inline-flex h-10 w-full items-center justify-center rounded-lg bg-blue-500 font-medium text-white hover:bg-blue-600"
|
||||
className="inline-flex h-11 w-full items-center justify-center rounded-lg bg-blue-500 font-medium text-white hover:bg-blue-600"
|
||||
>
|
||||
Create new account
|
||||
</Link>
|
||||
<Link
|
||||
to="/auth/import"
|
||||
className="inline-flex h-10 w-full items-center justify-center rounded-lg font-medium text-neutral-900 hover:bg-neutral-100 dark:text-neutral-100 dark:hover:bg-neutral-900"
|
||||
className="inline-flex h-11 w-full items-center justify-center rounded-lg font-medium text-neutral-900 hover:bg-neutral-100 dark:text-neutral-100 dark:hover:bg-neutral-900"
|
||||
>
|
||||
Log in
|
||||
</Link>
|
||||
|
||||
@@ -116,17 +116,32 @@ export function ErrorScreen() {
|
||||
</div>
|
||||
<div className="select-text text-lg font-medium text-blue-300">
|
||||
<p>
|
||||
While waiting for Lume's Devs to release the bug fixes, you always can use
|
||||
other Nostr clients with your account:
|
||||
While waiting for Lume's Devs to release the bug fixes, you always
|
||||
can use other Nostr clients with your account:
|
||||
</p>
|
||||
<div className="mt-2 flex flex-col gap-1 text-white">
|
||||
<a href="https://snort.social" className="hover:!underline">
|
||||
<a
|
||||
className="hover:!underline"
|
||||
href="https://snort.social"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
snort.social
|
||||
</a>
|
||||
<a href="https://primal.net" className="hover:!underline">
|
||||
<a
|
||||
className="hover:!underline"
|
||||
href="https://primal.net"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
primal.net
|
||||
</a>
|
||||
<a href="https://nostrudel.ninja" className="hover:!underline">
|
||||
<a
|
||||
className="hover:!underline"
|
||||
href="https://nostrudel.ninja"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
nostrudel.ninja
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -137,7 +137,7 @@ export function NewArticleScreen() {
|
||||
<div className="group flex justify-between gap-2">
|
||||
<input
|
||||
name="title"
|
||||
className="h-9 flex-1 border-none bg-transparent text-2xl font-semibold text-neutral-900 shadow-none outline-none placeholder:text-neutral-400 dark:text-neutral-100 dark:placeholder:text-neutral-600"
|
||||
className="h-9 flex-1 border-none bg-transparent px-0 text-2xl font-semibold text-neutral-900 shadow-none outline-none placeholder:text-neutral-400 focus:border-none focus:outline-none focus:ring-0 dark:text-neutral-100 dark:placeholder:text-neutral-600"
|
||||
placeholder="Untitled"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
export function OnboardingLayout() {
|
||||
return <Outlet />;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
import { memo } from 'react';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
import { ChildNote, NoteActions } from '@shared/notes';
|
||||
import { User } from '@shared/user';
|
||||
@@ -9,7 +10,7 @@ import { useNostr } from '@utils/hooks/useNostr';
|
||||
import { useRichContent } from '@utils/hooks/useRichContent';
|
||||
import { useWidget } from '@utils/hooks/useWidget';
|
||||
|
||||
export function TextNote({ event }: { event: NDKEvent }) {
|
||||
export function TextNote({ event, className }: { event: NDKEvent; className?: string }) {
|
||||
const { parsedContent } = useRichContent(event.content);
|
||||
const { addWidget } = useWidget();
|
||||
const { getEventThread } = useNostr();
|
||||
@@ -17,7 +18,7 @@ export function TextNote({ event }: { event: NDKEvent }) {
|
||||
const thread = getEventThread(event.tags);
|
||||
|
||||
return (
|
||||
<div className="mb-3 h-min w-full px-3">
|
||||
<div className={twMerge('mb-3 h-min w-full px-3', className)}>
|
||||
<div className="relative flex flex-col gap-2 overflow-hidden rounded-xl bg-neutral-50 pt-3 dark:bg-neutral-950">
|
||||
<User pubkey={event.pubkey} time={event.created_at} eventId={event.id} />
|
||||
{thread ? (
|
||||
|
||||
@@ -207,7 +207,7 @@ export const User = memo(function User({
|
||||
{user?.name || user?.display_name || user?.displayName}
|
||||
</h3>
|
||||
<p className="max-w-[10rem] truncate text-sm text-neutral-900 dark:text-neutral-100/70">
|
||||
{user?.username || displayNpub(pubkey, 16)}
|
||||
{user?.nip05 || user?.username || displayNpub(pubkey, 16)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user