wip: port more component to new ui

This commit is contained in:
Ren Amamiya 2023-08-02 14:48:51 +07:00
parent a85bcf917b
commit babcd8698e
20 changed files with 410 additions and 559 deletions

View File

@ -102,13 +102,12 @@ export function ResetScreen() {
return (
<div className="flex h-full w-full items-center justify-center">
<div className="mx-auto w-full max-w-md">
<div className="mb-8 text-center">
<h1 className="text-xl font-semibold text-zinc-100">Reset unlock password</h1>
<div className="mb-6 text-center">
<h1 className="text-2xl font-semibold text-white">Reset unlock password</h1>
</div>
<div className="flex flex-col gap-4">
<form onSubmit={handleSubmit(onSubmit)} className="mb-0 flex flex-col gap-3">
<div className="flex flex-col gap-1">
<label htmlFor="privkey" className="font-medium text-zinc-200">
<label htmlFor="privkey" className="font-medium text-white/50">
Private key
</label>
<div className="relative">
@ -116,12 +115,12 @@ export function ResetScreen() {
{...register('privkey', { required: true })}
type="text"
placeholder="nsec..."
className="relative w-full rounded-lg bg-zinc-800 px-3.5 py-3 text-zinc-100 !outline-none placeholder:text-zinc-400"
className="relative h-12 w-full rounded-lg bg-white/10 px-3.5 py-1 text-white !outline-none placeholder:text-white/10"
/>
</div>
</div>
<div className="flex flex-col gap-1">
<label htmlFor="password" className="font-medium text-zinc-200">
<label htmlFor="password" className="font-medium text-white/50">
Set a new password to protect your key
</label>
<div className="relative">
@ -129,25 +128,17 @@ export function ResetScreen() {
{...register('password', { required: true })}
type={passwordInput}
placeholder="min. 4 characters"
className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-zinc-100 !outline-none placeholder:text-zinc-400"
className="relative h-12 w-full rounded-lg bg-white/10 px-3.5 py-1 text-white !outline-none placeholder:text-white/10"
/>
<button
type="button"
onClick={() => showPassword()}
className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded p-1 hover:bg-zinc-700"
className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded p-1 hover:bg-white/10"
>
{passwordInput === 'password' ? (
<EyeOffIcon
width={20}
height={20}
className="text-zinc-500 group-hover:text-zinc-100"
/>
<EyeOffIcon className="h-5 w-5 text-white/50 group-hover:text-white" />
) : (
<EyeOnIcon
width={20}
height={20}
className="text-zinc-500 group-hover:text-zinc-100"
/>
<EyeOnIcon className="h-5 w-5 text-white/50 group-hover:text-white" />
)}
</button>
</div>
@ -159,10 +150,10 @@ export function ResetScreen() {
<button
type="submit"
disabled={!isDirty || !isValid}
className="mt-3 inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50"
className="inline-flex h-12 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-white hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50"
>
{loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" />
<LoaderIcon className="h-4 w-4 animate-spin text-white" />
) : (
'Continue →'
)}
@ -171,6 +162,5 @@ export function ResetScreen() {
</form>
</div>
</div>
</div>
);
}

View File

@ -84,7 +84,7 @@ export function UnlockScreen() {
<div className="mb-6 text-center">
<h1 className="text-2xl font-semibold text-white">Enter password to unlock</h1>
</div>
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-3">
<form onSubmit={handleSubmit(onSubmit)} className="mb-0 flex flex-col gap-3">
<div className="flex flex-col gap-1">
<div className="relative">
<input
@ -98,17 +98,9 @@ export function UnlockScreen() {
className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded p-1 hover:bg-white/10"
>
{passwordInput === 'password' ? (
<EyeOffIcon
width={20}
height={20}
className="text-white/50 group-hover:text-white"
/>
<EyeOffIcon className="h-5 w-5 text-white/50 group-hover:text-white" />
) : (
<EyeOnIcon
width={20}
height={20}
className="text-white/50 group-hover:text-white"
/>
<EyeOnIcon className="h-5 w-5 text-white/50 group-hover:text-white" />
)}
</button>
</div>

View File

@ -1,5 +1,5 @@
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, useState } from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { User } from '@app/auth/components/user';
@ -10,29 +10,22 @@ import { useAccount } from '@utils/hooks/useAccount';
export function NewMessageModal() {
const navigate = useNavigate();
const [isOpen, setIsOpen] = useState(false);
const [open, setOpen] = useState(false);
const { status, account } = useAccount();
const follows = account ? JSON.parse(account.follows as string) : [];
const closeModal = () => {
setIsOpen(false);
};
const openModal = () => {
setIsOpen(true);
};
const openChat = (pubkey: string) => {
closeModal();
setOpen(false);
navigate(`/app/chats/${pubkey}`);
};
return (
<>
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger asChild>
<button
type="button"
onClick={() => openModal()}
className="inline-flex h-9 items-center gap-2.5 rounded-md px-2"
>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
@ -42,69 +35,43 @@ export function NewMessageModal() {
<h5 className="text-white/50">New chat</h5>
</div>
</button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
</Transition.Child>
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-lg border-t border-zinc-800/50 bg-zinc-900">
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-5">
</Dialog.Trigger>
<Dialog.Portal className="relative z-10">
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xl" />
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10">
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title
as="h3"
className="text-lg font-semibold leading-none text-zinc-100"
>
<Dialog.Title className="text-lg font-semibold leading-none text-zinc-100">
New chat
</Dialog.Title>
<button
type="button"
onClick={closeModal}
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-800"
>
<CancelIcon className="h-4 w-4 text-zinc-300" />
</button>
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10">
<CancelIcon className="h-4 w-4 text-white/50" />
</Dialog.Close>
</div>
<Dialog.Description className="text-sm leading-tight text-zinc-400">
<Dialog.Description className="text-sm leading-none text-zinc-400">
All messages will be encrypted, but anyone can see who you chat
</Dialog.Description>
</div>
</div>
<div className="flex h-[500px] flex-col overflow-y-auto overflow-x-hidden pb-5">
<div className="flex h-[500px] flex-col overflow-y-auto overflow-x-hidden pb-2 pt-2">
{status === 'loading' ? (
<div className="inline-flex items-center justify-center px-4 py-3">
<LoaderIcon className="h-5 w-5 animate-spin text-black dark:text-zinc-100" />
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
</div>
) : (
follows.map((follow) => (
<div
key={follow}
className="group flex items-center justify-between px-4 py-3 hover:bg-zinc-800"
className="group flex items-center justify-between px-4 py-2 hover:bg-white/10"
>
<User pubkey={follow} />
<div>
<button
type="button"
onClick={() => openChat(follow)}
className="hidden w-max rounded-md bg-zinc-700 px-3 py-1 text-sm font-medium hover:bg-fuchsia-500 group-hover:inline-flex"
className="hidden w-max rounded bg-white/10 px-3 py-1 text-sm font-medium hover:bg-fuchsia-500 group-hover:inline-flex"
>
Chat
</button>
@ -113,11 +80,9 @@ export function NewMessageModal() {
))
)}
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition>
</>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}

View File

@ -1,103 +1,71 @@
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, useState } from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { User } from '@app/auth/components/user';
import { CancelIcon, StrangersIcon } from '@shared/icons';
import { CancelIcon, PlusIcon } from '@shared/icons';
import { compactNumber } from '@utils/number';
import { Chats } from '@utils/types';
export function UnknownsModal({ data }: { data: Chats[] }) {
const navigate = useNavigate();
const [isOpen, setIsOpen] = useState(false);
const closeModal = () => {
setIsOpen(false);
};
const openModal = () => {
setIsOpen(true);
};
const [open, setOpen] = useState(false);
const openChat = (pubkey: string) => {
closeModal();
setOpen(false);
navigate(`/app/chats/${pubkey}`);
};
return (
<>
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger asChild>
<button
type="button"
onClick={() => openModal()}
className="inline-flex h-9 items-center gap-2.5 rounded-md px-2"
>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<StrangersIcon className="h-3 w-3 text-white" />
<PlusIcon className="h-3 w-3 text-white" />
</div>
<div>
<h5 className="text-white/50">{compactNumber.format(data.length)} unknowns</h5>
<h5 className="text-white/50">
{compactNumber.format(data.length)} unknowns
</h5>
</div>
</button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
</Transition.Child>
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-lg border-t border-zinc-800/50 bg-zinc-900">
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-5">
</Dialog.Trigger>
<Dialog.Portal className="relative z-10">
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xl" />
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10">
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title
as="h3"
className="text-lg font-semibold leading-none text-zinc-100"
>
<Dialog.Title className="text-lg font-semibold leading-none text-zinc-100">
{data.length} unknowns
</Dialog.Title>
<button
type="button"
onClick={closeModal}
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-800"
>
<CancelIcon className="h-4 w-4 text-zinc-300" />
</button>
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10">
<CancelIcon className="h-4 w-4 text-white/50" />
</Dialog.Close>
</div>
<Dialog.Description className="text-sm leading-tight text-zinc-400">
<Dialog.Description className="text-sm leading-none text-zinc-400">
All messages from people you not follow
</Dialog.Description>
</div>
</div>
<div className="flex h-[500px] flex-col overflow-y-auto overflow-x-hidden pb-5">
<div className="flex h-[500px] flex-col overflow-y-auto overflow-x-hidden pb-2 pt-2">
{data.map((user) => (
<div
key={user.sender_pubkey}
className="group flex items-center justify-between px-4 py-3 hover:bg-zinc-800"
className="group flex items-center justify-between px-4 py-2 hover:bg-white/10"
>
<User pubkey={user.sender_pubkey} />
<div>
<button
type="button"
onClick={() => openChat(user.sender_pubkey)}
className="hidden w-max rounded-md bg-zinc-700 px-3 py-1 text-sm font-medium hover:bg-fuchsia-500 group-hover:inline-flex"
className="hidden w-max rounded bg-white/10 px-3 py-1 text-sm font-medium hover:bg-fuchsia-500 group-hover:inline-flex"
>
Chat
</button>
@ -105,11 +73,9 @@ export function UnknownsModal({ data }: { data: Chats[] }) {
</div>
))}
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition>
</>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}

View File

@ -85,7 +85,7 @@ export function SpaceScreen() {
<AddBlock />
</div>
</div>
<div className="w-[350px] shrink-0" />
<div className="w-[250px] shrink-0" />
</div>
);
}

View File

@ -58,21 +58,19 @@ export function Profile({ data }: { data: any }) {
);
return (
<div className="rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-5 py-5">
<div className="rounded-xl bg-white/10 px-5 py-5">
<div className="flex items-center justify-between">
<div className="inline-flex items-center gap-2">
<div className="h-11 w-11 shrink-0">
<Image
src={profile.picture}
fallback={DEFAULT_AVATAR}
className="h-11 w-11 rounded-lg object-cover"
className="h-11 w-11 shrink-0 rounded-lg object-cover"
/>
</div>
<div className="inline-flex flex-col gap-1">
<h3 className="max-w-[15rem] truncate font-semibold leading-none text-zinc-100">
<h3 className="max-w-[15rem] truncate font-semibold leading-none text-white">
{profile.display_name || profile.name}
</h3>
<p className="max-w-[10rem] truncate text-sm leading-none text-zinc-400">
<p className="max-w-[10rem] truncate text-sm leading-none text-white/50">
{profile.nip05 || shortenKey(data.pubkey)}
</p>
</div>
@ -81,15 +79,15 @@ export function Profile({ data }: { data: any }) {
{socialStatus === 'loading' ? (
<button
type="button"
className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-900 hover:bg-fuchsia-500"
className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-white/10 hover:bg-fuchsia-500"
>
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" />
<LoaderIcon className="h-4 w-4 animate-spin text-white" />
</button>
) : followed ? (
<button
type="button"
onClick={() => unfollowUser(data.pubkey)}
className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-800 text-zinc-400 hover:bg-fuchsia-500 hover:text-white"
className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-white/10 text-white hover:bg-fuchsia-500 hover:text-white"
>
<UnfollowIcon className="h-4 w-4" />
</button>
@ -97,7 +95,7 @@ export function Profile({ data }: { data: any }) {
<button
type="button"
onClick={() => followUser(data.pubkey)}
className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-800 text-zinc-400 hover:bg-fuchsia-500 hover:text-white"
className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-white/10 text-white hover:bg-fuchsia-500 hover:text-white"
>
<FollowIcon className="h-4 w-4" />
</button>
@ -105,7 +103,7 @@ export function Profile({ data }: { data: any }) {
</div>
</div>
<div className="mt-2">
<p className="whitespace-pre-line break-words text-zinc-100">
<p className="whitespace-pre-line break-words text-white">
{profile.about || profile.bio}
</p>
</div>
@ -115,26 +113,26 @@ export function Profile({ data }: { data: any }) {
) : (
<div className="flex w-full items-center gap-8">
<div className="inline-flex flex-col gap-1">
<span className="font-semibold leading-none text-zinc-100">
<span className="font-semibold leading-none text-white">
{userStats.stats[data.pubkey].followers_pubkey_count ?? 0}
</span>
<span className="text-sm leading-none text-zinc-400">Followers</span>
<span className="text-sm leading-none text-white/50">Followers</span>
</div>
<div className="inline-flex flex-col gap-1">
<span className="font-semibold leading-none text-zinc-100">
<span className="font-semibold leading-none text-white">
{userStats.stats[data.pubkey].pub_following_pubkey_count ?? 0}
</span>
<span className="text-sm leading-none text-zinc-400">Following</span>
<span className="text-sm leading-none text-white/50">Following</span>
</div>
<div className="inline-flex flex-col gap-1">
<span className="font-semibold leading-none text-zinc-100">
<span className="font-semibold leading-none text-white">
{userStats.stats[data.pubkey].zaps_received
? compactNumber.format(
userStats.stats[data.pubkey].zaps_received.msats / 1000
)
: 0}
</span>
<span className="text-sm leading-none text-zinc-400">Zaps received</span>
<span className="text-sm leading-none text-white/50">Zaps received</span>
</div>
</div>
)}

View File

@ -14,18 +14,18 @@ export function TrendingNotes() {
});
return (
<div className="flex w-[360px] shrink-0 flex-col border-r border-zinc-900">
<div className="scrollbar-hide relative h-full w-[400px] shrink-0 overflow-y-auto bg-white/10 pb-20">
<TitleBar title="Trending Posts" />
<div className="scrollbar-hide flex h-full w-full flex-col justify-between gap-1.5 overflow-y-auto pb-20 pt-1.5">
<div className="h-full">
{error && <p>Failed to fetch</p>}
{status === 'loading' ? (
<div className="px-3 py-1.5">
<div className="shadow-input rounded-md bg-zinc-900 px-3 py-3 shadow-black/20">
<div className="shadow-input rounded-md px-3 py-3">
<NoteSkeleton />
</div>
</div>
) : (
<div className="relative flex w-full flex-col pt-1.5">
<div className="relative flex w-full flex-col">
{data.notes.map((item) => (
<NoteKind_1 key={item.id} event={item.event} skipMetadata={true} />
))}

View File

@ -15,9 +15,9 @@ export function TrendingProfiles() {
});
return (
<div className="flex w-[360px] shrink-0 flex-col border-r border-zinc-900">
<div className="scrollbar-hide relative h-full w-[400px] shrink-0 overflow-y-auto bg-white/10 pb-20">
<TitleBar title="Trending Profiles" />
<div className="scrollbar-hide flex h-full w-full flex-col justify-between gap-1.5 overflow-y-auto pb-20 pt-1.5">
<div className="h-full">
{error && <p>Failed to fetch</p>}
{status === 'loading' ? (
<div className="px-3 py-1.5">
@ -26,7 +26,7 @@ export function TrendingProfiles() {
</div>
</div>
) : (
<div className="relative flex w-full flex-col gap-3 px-3 pt-3">
<div className="relative flex w-full flex-col gap-3 px-3 pt-1.5">
{data.profiles.map((item) => (
<Profile key={item.pubkey} data={item} />
))}

View File

@ -3,7 +3,7 @@ import { TrendingProfiles } from '@app/trending/components/trendingProfiles';
export function TrendingScreen() {
return (
<div className="scrollbar-hide flex h-full w-full flex-nowrap overflow-x-auto overflow-y-hidden">
<div className="scrollbar-hide flex h-full w-full flex-nowrap divide-x divide-white/5 overflow-x-auto overflow-y-hidden">
<TrendingProfiles />
<TrendingNotes />
</div>

View File

@ -19,7 +19,7 @@ button {
}
.ProseMirror p.is-empty::before {
@apply text-zinc-500;
@apply text-white/50;
content: attr(data-placeholder);
float: left;
height: 0;

View File

@ -14,7 +14,6 @@ import { CancelIcon, LoaderIcon, PlusCircleIcon } from '@shared/icons';
import { MentionNote } from '@shared/notes';
import { useComposer } from '@stores/composer';
import { FULL_RELAYS } from '@stores/constants';
import { usePublish } from '@utils/hooks/usePublish';
import { useImageUploader } from '@utils/hooks/useUploader';
@ -45,7 +44,7 @@ export function Composer() {
Image.configure({
HTMLAttributes: {
class:
'rounded-lg w-2/3 h-auto border border-zinc-800 outline outline-2 outline-offset-0 outline-zinc-700 ml-1',
'rounded-lg w-2/3 h-auto border border-white/10 outline outline-2 outline-offset-0 outline-white/20 ml-1',
},
}),
],
@ -54,7 +53,7 @@ export function Composer() {
attributes: {
class: twMerge(
'scrollbar-hide markdown break-all max-h-[500px] overflow-y-auto outline-none pr-2',
`${reply.id ? '!min-h-42' : '!min-h-[100px]'}`
`${reply.id ? '!min-h-42' : '!min-h-[120px]'}`
),
},
},
@ -88,13 +87,13 @@ export function Composer() {
if (reply.id && reply.pubkey) {
if (reply.root && reply.root.length > 1) {
tags = [
['e', reply.root, FULL_RELAYS[0], 'root'],
['e', reply.id, FULL_RELAYS[0], 'reply'],
['e', reply.root, 'wss://relayable.org', 'root'],
['e', reply.id, 'wss://relayable.org', 'reply'],
['p', reply.pubkey],
];
} else {
tags = [
['e', reply.id, FULL_RELAYS[0], 'reply'],
['e', reply.id, 'wss://relayable.org', 'reply'],
['p', reply.pubkey],
];
}
@ -131,7 +130,7 @@ export function Composer() {
<div className="flex h-full flex-col px-4 pb-4">
<div className="flex h-full w-full gap-3">
<div className="flex w-8 shrink-0 items-center justify-center">
<div className="h-full w-[2px] bg-zinc-800" />
<div className="h-full w-[2px] bg-white/10" />
</div>
<div className="w-full">
<EditorContent
@ -147,9 +146,9 @@ export function Composer() {
<button
type="button"
onClick={() => clearReply()}
className="absolute right-3 top-3 inline-flex h-6 w-6 items-center justify-center gap-2 rounded bg-zinc-800 px-2 hover:bg-zinc-700"
className="absolute right-3 top-3 inline-flex h-6 w-6 items-center justify-center rounded bg-white/10 px-2"
>
<CancelIcon className="h-4 w-4 text-zinc-100" />
<CancelIcon className="h-4 w-4 text-white" />
</button>
</div>
)}
@ -159,15 +158,15 @@ export function Composer() {
<button
type="button"
onClick={() => uploadImage()}
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-zinc-800"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-white/10"
>
<PlusCircleIcon className="h-5 w-5 text-zinc-500" />
<PlusCircleIcon className="h-5 w-5 text-white/50" />
</button>
<Button onClick={() => submit()} preset="publish">
{status === 'loading' ? (
<LoaderIcon className="h-4 w-4 animate-spin text-zinc-100" />
<LoaderIcon className="h-4 w-4 animate-spin text-white" />
) : (
'Publish'
'Postr'
)}
</Button>
</div>

View File

@ -1,5 +1,4 @@
import { Dialog, Transition } from '@headlessui/react';
import { Fragment } from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import { useHotkeys } from 'react-hotkeys-hook';
import { Button } from '@shared/button';
@ -27,64 +26,39 @@ export function ComposerModal() {
useHotkeys(COMPOSE_SHORTCUT, () => toggle(true));
return (
<>
<Button onClick={() => toggle(true)} preset="small">
<Dialog.Root open={open}>
<Dialog.Trigger asChild>
<Button preset="small">
<ComposeIcon className="h-4 w-4" />
Postr
</Button>
<Transition appear show={open} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
</Transition.Child>
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative h-min w-full max-w-xl rounded-xl border-t border-zinc-800/50 bg-zinc-900">
</Dialog.Trigger>
<Dialog.Portal className="relative z-10">
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xl" />
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<div className="relative h-min w-full max-w-2xl rounded-xl bg-white/10">
<div className="flex items-center justify-between px-4 py-4">
<div className="flex items-center gap-2">
{account && <ComposerUser pubkey={account.pubkey} />}
<span>
<ChevronRightIcon
width={14}
height={14}
className="text-zinc-500"
/>
<ChevronRightIcon className="h-4 w-4 text-white/50" />
</span>
<div className="inline-flex h-7 w-max items-center justify-center gap-0.5 rounded bg-zinc-800 pl-3 pr-1.5 text-sm font-medium text-zinc-400">
<div className="inline-flex h-7 w-max items-center justify-center gap-0.5 rounded bg-white/10 pl-3 pr-1.5 text-sm font-medium text-white">
New Post
<ChevronDownIcon className="h-4 w-4" />
</div>
</div>
<button
onClick={closeModal}
type="button"
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-800"
<Dialog.Close
onClick={() => closeModal()}
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-zinc-800"
>
<CancelIcon width={16} height={16} className="text-zinc-500" />
</button>
<CancelIcon className="h-5 w-5 text-white/50" />
</Dialog.Close>
</div>
<Composer />
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition>
</>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}

View File

@ -9,15 +9,13 @@ export function ComposerUser({ pubkey }: { pubkey: string }) {
return (
<div className="flex items-center gap-3">
<div className="h-8 w-8 shrink-0 overflow-hidden rounded-md bg-zinc-900">
<Image
src={user?.picture || user?.image}
fallback={DEFAULT_AVATAR}
alt={pubkey}
className="h-8 w-8 object-cover"
className="h-8 w-8 shrink-0 rounded-md object-cover"
/>
</div>
<h5 className="text-base font-semibold leading-none text-zinc-100">
<h5 className="text-base font-semibold leading-none text-white">
{user?.nip05 || user?.name || (
<div className="h-3 w-20 animate-pulse rounded-sm bg-zinc-700" />
)}

View File

@ -1,4 +1,4 @@
import { Dialog, Transition } from '@headlessui/react';
import * as Dialog from '@radix-ui/react-dialog';
import { useQueryClient } from '@tanstack/react-query';
import { relaunch } from '@tauri-apps/plugin-process';
import { Fragment, useState } from 'react';
@ -29,60 +29,34 @@ export function Logout() {
};
return (
<>
<Dialog.Root>
<Dialog.Trigger asChild>
<button
type="button"
onClick={() => openModal()}
aria-label="Logout"
className="inline-flex h-9 w-9 transform items-center justify-center rounded-md bg-white/20 active:translate-y-1"
>
<LogoutIcon className="h-4 w-4 text-white" />
</button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
</Transition.Child>
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative flex h-min w-full max-w-lg flex-col rounded-xl border-t border-zinc-800/50 bg-zinc-900">
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-6">
</Dialog.Trigger>
<Dialog.Portal className="relative z-10">
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xl" />
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10">
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-6">
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<Dialog.Title
as="h3"
className="text-lg font-semibold leading-none text-zinc-100"
>
<Dialog.Title className="text-lg font-semibold leading-none text-white">
Are you sure!
</Dialog.Title>
<button
type="button"
onClick={closeModal}
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-900"
>
<CancelIcon width={20} height={20} className="text-zinc-300" />
</button>
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10">
<CancelIcon className="h-4 w-4 text-white/50" />
</Dialog.Close>
</div>
<Dialog.Description className="text-sm leading-tight text-zinc-400">
<Dialog.Description className="text-sm leading-tight text-white/50">
<p className="mb-2">
When logout, all local data will be wiped, and restart app then
you need to start onboarding process again when you log in.
When logout, all local data will be wiped, and restart app then you
need to start onboarding process again when you log in.
</p>
<p>
In the next version, Lume will support multi account, then you can
@ -96,24 +70,22 @@ export function Logout() {
<button
type="button"
onClick={closeModal}
className="inline-flex h-9 items-center justify-center rounded-md px-3 text-sm font-medium text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100"
className="inline-flex h-9 items-center justify-center rounded-md px-3 text-sm font-medium text-white/50 hover:bg-white/10"
>
Cancel
</button>
<button
type="button"
onClick={() => logout()}
className="inline-flex h-9 items-center justify-center rounded-md bg-red-500 px-3 text-sm font-medium text-zinc-100 hover:bg-red-600"
className="inline-flex h-9 items-center justify-center rounded-md bg-red-500 px-3 text-sm font-medium text-white hover:bg-red-600"
>
Confirm
</button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition>
</>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}

View File

@ -23,6 +23,7 @@ export function Navigation() {
return (
<div className="relative h-full w-[232px] bg-black/80">
<div className="absolute left-0 top-0 h-8 w-full" data-tauri-drag-region />
<div className="scrollbar-hide flex flex-col gap-5 overflow-y-auto pb-20">
<div className="inline-flex h-8 items-center justify-between px-2 pb-4 pt-14">
<ComposerModal />
@ -53,7 +54,7 @@ export function Navigation() {
open ? '' : 'rotate-180'
)}
>
<NavArrowDownIcon width={12} height={12} className="text-white/50" />
<NavArrowDownIcon className="h-3 w-3 text-white/50" />
</div>
<h3 className="text-[11px] font-bold uppercase tracking-widest text-white/50">
Feeds
@ -106,7 +107,7 @@ export function Navigation() {
open ? '' : 'rotate-180'
)}
>
<NavArrowDownIcon width={12} height={12} className="text-white/50" />
<NavArrowDownIcon className="h-3 w-3 text-white/50" />
</div>
<h3 className="text-[11px] font-bold uppercase tracking-widest text-white/50">
Chats

View File

@ -80,7 +80,7 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
<button
type="button"
onClick={() => react('👏')}
className="inline-flex h-8 w-8 items-center justify-center rounded hover:bg-zinc-600"
className="inline-flex h-8 w-8 items-center justify-center rounded hover:bg-white/10"
>
<img
src="https://raw.githubusercontent.com/Tarikul-Islam-Anik/Animated-Fluent-Emojis/master/Emojis/Hand%20gestures/Clapping%20Hands.png"
@ -91,7 +91,7 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
<button
type="button"
onClick={() => react('🤪')}
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-zinc-600"
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-white/10"
>
<img
src="https://raw.githubusercontent.com/Tarikul-Islam-Anik/Animated-Fluent-Emojis/master/Emojis/Smilies/Face%20with%20Tongue.png"
@ -102,7 +102,7 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
<button
type="button"
onClick={() => react('😮')}
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-zinc-600"
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-white/10"
>
<img
src="https://raw.githubusercontent.com/Tarikul-Islam-Anik/Animated-Fluent-Emojis/master/Emojis/Smilies/Face%20with%20Open%20Mouth.png"
@ -113,7 +113,7 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
<button
type="button"
onClick={() => react('😢')}
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-zinc-600"
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-white/10"
>
<img
src="https://raw.githubusercontent.com/Tarikul-Islam-Anik/Animated-Fluent-Emojis/master/Emojis/Smilies/Crying%20Face.png"
@ -124,7 +124,7 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
<button
type="button"
onClick={() => react('🤡')}
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-zinc-600"
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-white/10"
>
<img
src="https://raw.githubusercontent.com/Tarikul-Islam-Anik/Animated-Fluent-Emojis/master/Emojis/Smilies/Clown%20Face.png"

View File

@ -29,7 +29,7 @@ export const MentionNote = memo(function MentionNote({ id }: { id: string }) {
onKeyDown={(e) => openThread(e, id)}
role="button"
tabIndex={0}
className="mb-2 mt-3 cursor-default rounded-lg border-t border-zinc-700/50 bg-zinc-800/50 px-3 py-3"
className="mb-2 mt-3 cursor-default rounded-lg bg-white/10 px-3 py-3"
>
{status === 'loading' ? (
<NoteSkeleton />

View File

@ -27,10 +27,11 @@ export function LinkPreview({ urls }: { urls: string[] }) {
rel="noreferrer"
>
{error ? (
<div className="px-3 py-3">
<p className="line-clamp-3 break-all text-sm text-zinc-400">
<div className="flex flex-col gap-2 px-3 py-3">
<p className="text-sm text-white/50">
Can&apos;t fetch open graph, click to open webpage
</p>
<span className="text-sm leading-none text-white">{domain.hostname}</span>
</div>
) : (
<>

View File

@ -57,10 +57,10 @@ export function NotificationModal({ pubkey }: { pubkey: string }) {
</button>
</Dialog.Trigger>
<Dialog.Portal className="relative z-10">
<Dialog.Overlay className="fixed inset-0 z-[1000px] bg-black bg-opacity-30 backdrop-blur-md data-[state=open]:animate-overlayShow" />
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center data-[state=open]:animate-contentShow">
<Dialog.Content className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-lg border-t border-zinc-800/50 bg-zinc-900">
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-5">
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xl" />
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10">
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title className="text-lg font-semibold leading-none text-zinc-100">
@ -96,8 +96,8 @@ export function NotificationModal({ pubkey }: { pubkey: string }) {
data.map((event) => renderItem(event))
)}
</div>
</Dialog.Content>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);

View File

@ -1,6 +1,6 @@
import { Popover, Transition } from '@headlessui/react';
import { Fragment } from 'react';
import * as Popover from '@radix-ui/react-popover';
import { Link } from 'react-router-dom';
import { twMerge } from 'tailwind-merge';
import { VerticalDotsIcon } from '@shared/icons';
import { Image } from '@shared/image';
@ -9,7 +9,7 @@ import { DEFAULT_AVATAR } from '@stores/constants';
import { formatCreatedAt } from '@utils/createdAt';
import { useProfile } from '@utils/hooks/useProfile';
import { shortenKey } from '@utils/shortenKey';
import { displayNpub, shortenKey } from '@utils/shortenKey';
export function User({
pubkey,
@ -50,58 +50,56 @@ export function User({
}
return (
<Popover
className={`flex ${size === 'small' ? 'items-center gap-2' : 'items-start gap-3'}`}
<Popover.Root>
<div
className={twMerge(
'relative flex',
size === 'small' ? 'items-center gap-2' : 'items-start gap-3'
)}
>
<Popover.Button
className={`${avatarWidth} ${avatarHeight} relative z-10 shrink-0 overflow-hidden bg-zinc-900`}
<Popover.Trigger asChild>
<button
type="button"
className={`${avatarWidth} ${avatarHeight} relative z-40 shrink-0 overflow-hidden`}
>
<Image
src={user?.picture || user?.image}
fallback={DEFAULT_AVATAR}
alt={pubkey}
className={`${
className={twMerge(
`object-cover ${avatarWidth} ${avatarHeight}`,
size === 'small' ? 'rounded' : 'rounded-lg',
isRepost ? 'ring-1 ring-zinc-800' : ''
} ${avatarWidth} ${avatarHeight} ${
size === 'small' ? 'rounded' : 'rounded-lg'
} object-cover`}
)}
/>
</Popover.Button>
</button>
</Popover.Trigger>
<div
className={`${isRepost ? 'mt-4' : ''} flex flex-1 items-baseline justify-between`}
className={twMerge(
'flex flex-1 items-baseline justify-between',
isRepost ? 'mt-4' : ''
)}
>
<h5
className={`truncate font-semibold leading-none text-zinc-100 ${
className={twMerge(
'truncate font-semibold leading-none text-white',
size === 'small' ? 'max-w-[10rem]' : 'max-w-[15rem]'
}`}
)}
>
{user?.nip05?.toLowerCase() ||
user?.name ||
user?.display_name ||
shortenKey(pubkey)}
</h5>
<div className="inline-flex items-center gap-2">
<span className="leading-none text-white/50">{createdAt}</span>
<button
type="button"
className="inline-flex h-5 w-max items-center justify-center rounded px-1 hover:bg-white/20"
>
<VerticalDotsIcon className="h-4 w-4 rotate-90 transform text-white/50" />
</button>
</div>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
<Popover.Portal>
<Popover.Content
className="w-[300px] overflow-hidden rounded-md bg-white/10 backdrop-blur-xl"
sideOffset={5}
>
<Popover.Panel className="absolute top-10 z-50 mt-3">
<div className="w-[250px] overflow-hidden rounded-md border border-zinc-800/50 bg-zinc-900/90 backdrop-blur-lg">
<div className="flex gap-2.5 border-b border-zinc-800 px-3 py-3">
<div className="flex gap-2.5 border-b border-white/5 px-3 py-3">
<Image
src={user?.picture || user?.image}
fallback={DEFAULT_AVATAR}
@ -111,16 +109,14 @@ export function User({
<div className="flex flex-1 flex-col gap-2">
<div className="inline-flex flex-col gap-1">
<h5 className="text-sm font-semibold leading-none">
{user?.displayName || user?.name || (
<div className="h-3 w-20 animate-pulse rounded-sm bg-zinc-700" />
)}
{user?.displayName || user?.name}
</h5>
<span className="max-w-[10rem] truncate text-sm leading-none text-zinc-500">
{user?.nip05 || shortenKey(pubkey)}
<span className="max-w-[10rem] truncate text-sm leading-none text-white/50">
{user?.nip05 || displayNpub(pubkey, 16)}
</span>
</div>
<div>
<p className="line-clamp-3 break-all leading-tight text-zinc-100">
<p className="line-clamp-3 break-all leading-tight text-white">
{user?.about}
</p>
</div>
@ -129,20 +125,19 @@ export function User({
<div className="flex items-center gap-2 px-3 py-3">
<Link
to={`/app/users/${pubkey}`}
className="inline-flex h-10 flex-1 items-center justify-center rounded-md bg-zinc-700 text-sm font-medium hover:bg-fuchsia-500"
className="inline-flex h-10 flex-1 items-center justify-center rounded-md bg-white/10 text-sm font-medium hover:bg-fuchsia-500"
>
View profile
</Link>
<Link
to={`/app/chats/${pubkey}`}
className="inline-flex h-10 flex-1 items-center justify-center rounded-md bg-zinc-700 text-sm font-medium hover:bg-fuchsia-500"
className="inline-flex h-10 flex-1 items-center justify-center rounded-md bg-white/10 text-sm font-medium hover:bg-fuchsia-500"
>
Message
</Link>
</div>
</div>
</Popover.Panel>
</Transition>
</Popover>
</Popover.Content>
</Popover.Portal>
</Popover.Root>
);
}