feat: new flow (#235)
* feat: redesign initial screen * feat: improve login process
This commit is contained in:
@@ -20,7 +20,7 @@ export function NoteOpenThread() {
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
||||
Open
|
||||
View thread
|
||||
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
|
||||
@@ -15,6 +15,9 @@ export function UserAvatar({ className }: { className?: string }) {
|
||||
|
||||
const picture = useMemo(() => {
|
||||
if (service?.length && user.profile?.picture?.length) {
|
||||
if (user.profile?.picture.includes("_next/")) {
|
||||
return user.profile?.picture;
|
||||
}
|
||||
return `${service}?url=${user.profile?.picture}&w=100&h=100&n=-1&default=${user.profile?.picture}`;
|
||||
} else {
|
||||
return user.profile?.picture;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { commands } from "@/commands.gen";
|
||||
import { appSettings, displayNpub } from "@/commons";
|
||||
import { Frame, Spinner, User } from "@/components";
|
||||
import { ArrowRight, DotsThree, GearSix, Plus } from "@phosphor-icons/react";
|
||||
import { Link, createLazyFileRoute } from "@tanstack/react-router";
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import { Menu, MenuItem } from "@tauri-apps/api/menu";
|
||||
import { message } from "@tauri-apps/plugin-dialog";
|
||||
import {
|
||||
@@ -37,6 +37,32 @@ function Screen() {
|
||||
const [password, setPassword] = useState("");
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
const showContextMenu = useCallback(
|
||||
async (e: React.MouseEvent, account: string) => {
|
||||
e.stopPropagation();
|
||||
|
||||
const menuItems = await Promise.all([
|
||||
MenuItem.new({
|
||||
text: "Reset password",
|
||||
enabled: !account.includes("_nostrconnect"),
|
||||
// @ts-ignore, this is tanstack router bug
|
||||
action: () => navigate({ to: "/reset", search: { account } }),
|
||||
}),
|
||||
MenuItem.new({
|
||||
text: "Delete account",
|
||||
action: async () => await deleteAccount(account),
|
||||
}),
|
||||
]);
|
||||
|
||||
const menu = await Menu.new({
|
||||
items: menuItems,
|
||||
});
|
||||
|
||||
await menu.popup().catch((e) => console.error(e));
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const deleteAccount = async (account: string) => {
|
||||
const res = await commands.deleteAccount(account);
|
||||
|
||||
@@ -69,12 +95,14 @@ function Screen() {
|
||||
if (status) {
|
||||
navigate({
|
||||
to: "/$account/home",
|
||||
// @ts-ignore, this is tanstack router bug
|
||||
params: { account: res.data },
|
||||
replace: true,
|
||||
});
|
||||
} else {
|
||||
navigate({
|
||||
to: "/loading",
|
||||
// @ts-ignore, this is tanstack router bug
|
||||
search: { account: res.data },
|
||||
replace: true,
|
||||
});
|
||||
@@ -86,31 +114,6 @@ function Screen() {
|
||||
});
|
||||
};
|
||||
|
||||
const showContextMenu = useCallback(
|
||||
async (e: React.MouseEvent, account: string) => {
|
||||
e.stopPropagation();
|
||||
|
||||
const menuItems = await Promise.all([
|
||||
MenuItem.new({
|
||||
text: "Reset password",
|
||||
enabled: !account.includes("_nostrconnect"),
|
||||
action: () => navigate({ to: "/reset", search: { account } }),
|
||||
}),
|
||||
MenuItem.new({
|
||||
text: "Delete account",
|
||||
action: async () => await deleteAccount(account),
|
||||
}),
|
||||
]);
|
||||
|
||||
const menu = await Menu.new({
|
||||
items: menuItems,
|
||||
});
|
||||
|
||||
await menu.popup().catch((e) => console.error(e));
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (autoLogin) {
|
||||
loginWith();
|
||||
@@ -204,8 +207,8 @@ function Screen() {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<Link
|
||||
to="/new"
|
||||
<a
|
||||
href="/new"
|
||||
className="flex items-center justify-between hover:bg-black/5 dark:hover:bg-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-2.5 p-3">
|
||||
@@ -216,17 +219,17 @@ function Screen() {
|
||||
New account
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
</a>
|
||||
</Frame>
|
||||
</div>
|
||||
<div className="absolute bottom-2 right-2">
|
||||
<Link
|
||||
to="/bootstrap-relays"
|
||||
<a
|
||||
href="/bootstrap-relays"
|
||||
className="h-8 w-max text-xs px-3 inline-flex items-center justify-center gap-1.5 bg-black/5 hover:bg-black/10 dark:bg-white/5 dark:hover:bg-white/10 rounded-full"
|
||||
>
|
||||
<GearSix className="size-4" />
|
||||
Manage Relays
|
||||
</Link>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Spinner } from "@/components";
|
||||
import { Frame, Spinner } from "@/components";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { useEffect } from "react";
|
||||
@@ -24,6 +24,7 @@ function Screen() {
|
||||
const unlisten = listen("synchronized", () => {
|
||||
navigate({
|
||||
to: "/$account/home",
|
||||
// @ts-ignore, this is tanstack router bug
|
||||
params: { account: search.account },
|
||||
replace: true,
|
||||
});
|
||||
@@ -36,12 +37,15 @@ function Screen() {
|
||||
|
||||
return (
|
||||
<div className="size-full flex items-center justify-center">
|
||||
<div className="flex flex-col gap-2 items-center justify-center text-center">
|
||||
<Frame
|
||||
className="p-6 h-36 flex flex-col gap-2 items-center justify-center text-center rounded-xl overflow-hidden"
|
||||
shadow
|
||||
>
|
||||
<Spinner />
|
||||
<p className="text-sm">
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-40">
|
||||
Fetching necessary data for the first time login...
|
||||
</p>
|
||||
</div>
|
||||
</Frame>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { GoBack } from "@/components";
|
||||
import { ArrowLeft } from "@phosphor-icons/react";
|
||||
import { Link, createLazyFileRoute } from "@tanstack/react-router";
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createLazyFileRoute("/new")({
|
||||
component: Screen,
|
||||
@@ -10,42 +8,79 @@ function Screen() {
|
||||
return (
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className="relative size-full flex items-center justify-center"
|
||||
className="bg-white/50 dark:bg-black/50 relative size-full flex items-center justify-center"
|
||||
>
|
||||
<div className="w-[320px] flex flex-col gap-8">
|
||||
<div className="w-[350px] flex flex-col gap-8">
|
||||
<div className="flex flex-col gap-1 text-center">
|
||||
<h1 className="leading-tight text-xl font-semibold">
|
||||
Welcome to Nostr.
|
||||
<h1 className="leading-tight text-lg font-semibold">
|
||||
How would you like to use Lume?
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Link
|
||||
to="/auth/new"
|
||||
className="w-full h-10 bg-blue-500 font-medium hover:bg-blue-600 text-white rounded-lg inline-flex items-center justify-center shadow"
|
||||
<a
|
||||
href="/auth/connect"
|
||||
className="w-full p-4 rounded-xl hover:shadow-lg hover:ring-0 hover:bg-white dark:hover:bg-neutral-900 ring-1 ring-black/5 dark:ring-white/5"
|
||||
>
|
||||
Create a new identity
|
||||
</Link>
|
||||
<div className="w-full h-px bg-black/5 dark:bg-white/5" />
|
||||
<h3 className="mb-1.5 font-medium">Continue with Nostr Connect</h3>
|
||||
<div className="text-sm">
|
||||
<p className="text-neutral-500 dark:text-neutral-600">
|
||||
Your account will be handled by a remote signer. Lume will not
|
||||
store your account keys.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="/auth/import"
|
||||
className="w-full p-4 rounded-xl hover:shadow-lg hover:ring-0 hover:bg-white dark:hover:bg-neutral-900 ring-1 ring-black/5 dark:ring-white/5"
|
||||
>
|
||||
<h3 className="mb-1.5 font-medium">Continue with Secret Key</h3>
|
||||
<div className="text-sm">
|
||||
<p className="text-neutral-500 dark:text-neutral-600">
|
||||
Lume will store your keys in secure storage. You can provide a
|
||||
password to add extra security.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex-1 h-px bg-black/5 dark:bg-white/5" />
|
||||
<div className="shrink-0 text-sm text-neutral-500 dark:text-neutral-400">
|
||||
Do you not have a Nostr account yet?
|
||||
</div>
|
||||
<div className="flex-1 h-px bg-black/5 dark:bg-white/5" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Link
|
||||
to="/auth/connect"
|
||||
className="w-full h-10 bg-white hover:bg-neutral-100 dark:hover:bg-neutral-100 dark:text-black rounded-lg inline-flex items-center justify-center"
|
||||
<a
|
||||
href="https://nsec.app"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-sm bg-black/5 dark:bg-white/5 hover:bg-black/10 dark:hover:bg-white/10 rounded-lg flex items-center gap-1.5 h-9 px-1"
|
||||
>
|
||||
Login with Nostr Connect
|
||||
</Link>
|
||||
<Link
|
||||
to="/auth/import"
|
||||
className="w-full h-10 bg-white hover:bg-neutral-100 dark:hover:bg-neutral-100 dark:text-black rounded-lg inline-flex items-center justify-center"
|
||||
<div className="size-7 rounded-md bg-black inline-flex items-center justify-center">
|
||||
<img src="/nsec_app.svg" alt="nsec.app" className="size-5" />
|
||||
</div>
|
||||
Create one with nsec.app
|
||||
</a>
|
||||
<a
|
||||
href="https://nosta.me"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-sm bg-black/5 dark:bg-white/5 hover:bg-black/10 dark:hover:bg-white/10 rounded-lg flex items-center gap-1.5 h-9 px-1"
|
||||
>
|
||||
Login with Private Key
|
||||
</Link>
|
||||
<div className="size-7 rounded-md bg-black overflow-hidden">
|
||||
<img
|
||||
src="/nosta.jpg"
|
||||
alt="nosta"
|
||||
className="size-7 object-cover"
|
||||
/>
|
||||
</div>
|
||||
Create one with nosta.me
|
||||
</a>
|
||||
<p className="text-xs text-neutral-400 dark:text-neutral-600">
|
||||
Or you can create account from other Nostr clients.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<GoBack className="fixed top-11 left-2 flex items-center gap-1.5 text-sm font-medium">
|
||||
<ArrowLeft className="size-5" />
|
||||
Back
|
||||
</GoBack>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user