mirror of
https://github.com/lumehq/lume.git
synced 2025-09-29 17:32:31 +02:00
replaced radix-ui with headless-ui
This commit is contained in:
@@ -14,13 +14,7 @@
|
||||
"**/*.{js,ts,jsx,tsx}": "eslint --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-alert-dialog": "^1.0.3",
|
||||
"@radix-ui/react-collapsible": "^1.0.2",
|
||||
"@radix-ui/react-dialog": "^1.0.3",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
||||
"@radix-ui/react-popover": "^1.0.5",
|
||||
"@radix-ui/react-tabs": "^1.0.3",
|
||||
"@radix-ui/react-tooltip": "^1.0.5",
|
||||
"@headlessui/react": "^1.7.14",
|
||||
"@supabase/supabase-js": "^2.21.0",
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"dayjs": "^1.11.7",
|
||||
|
2016
pnpm-lock.yaml
generated
2016
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -8,11 +8,11 @@ import { DEFAULT_AVATAR, MESSAGE_RELAYS } from '@stores/constants';
|
||||
import { dateToUnix } from '@utils/getDate';
|
||||
import { createChannel } from '@utils/storage';
|
||||
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { Dialog, Transition } from '@headlessui/react';
|
||||
import { Cancel, Plus } from 'iconoir-react';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { getEventHash, signEvent } from 'nostr-tools';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { Fragment, useContext, useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { navigate } from 'vite-plugin-ssr/client/router';
|
||||
|
||||
@@ -20,12 +20,20 @@ export const CreateChannelModal = () => {
|
||||
const pool: any = useContext(RelayContext);
|
||||
const activeAccount: any = useContext(AccountContext);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [image, setImage] = useState(DEFAULT_AVATAR);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const setChannel = useSetAtom(defaultChannelsAtom);
|
||||
|
||||
const closeModal = () => {
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const openModal = () => {
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
@@ -64,7 +72,7 @@ export const CreateChannelModal = () => {
|
||||
// insert to database
|
||||
createChannel(event.id, event.content, event.created_at);
|
||||
// close modal
|
||||
setOpen(false);
|
||||
setIsOpen(false);
|
||||
// redirect to channel page
|
||||
navigate(`/channel?id=${event.id}`);
|
||||
}, 2000);
|
||||
@@ -75,42 +83,65 @@ export const CreateChannelModal = () => {
|
||||
}, [setValue, image]);
|
||||
|
||||
return (
|
||||
<Dialog.Root open={open} onOpenChange={setOpen}>
|
||||
<Dialog.Trigger asChild>
|
||||
<div className="group inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-900">
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openModal()}
|
||||
className="group inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-900"
|
||||
>
|
||||
<div className="inline-flex h-5 w-5 shrink items-center justify-center rounded bg-zinc-900 group-hover:bg-zinc-800">
|
||||
<Plus width={12} height={12} className="text-zinc-500" />
|
||||
</div>
|
||||
<div>
|
||||
<h5 className="text-sm font-medium text-zinc-500 group-hover:text-zinc-400">Add a new channel</h5>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md data-[state=open]:animate-overlayShow" />
|
||||
<Dialog.Content className="fixed inset-0 z-50 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center">
|
||||
<div className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-lg border border-zinc-800 bg-zinc-900">
|
||||
</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 data-[state=open]:animate-overlayShow" />
|
||||
</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 border-zinc-800 bg-zinc-900">
|
||||
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-6">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<h5 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-2xl font-semibold leading-none text-transparent">
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-2xl font-semibold leading-none text-transparent"
|
||||
>
|
||||
Create channel
|
||||
</h5>
|
||||
<Dialog.Close asChild>
|
||||
</Dialog.Title>
|
||||
<button
|
||||
type="button"
|
||||
onClick={closeModal}
|
||||
autoFocus={false}
|
||||
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-900"
|
||||
>
|
||||
<Cancel width={20} height={20} className="text-zinc-300" />
|
||||
</button>
|
||||
</Dialog.Close>
|
||||
</div>
|
||||
<p className="leading-tight text-zinc-400">
|
||||
<Dialog.Description className="leading-tight text-zinc-400">
|
||||
Channels are freedom square, everyone can speech freely, no one can stop you or deceive what to
|
||||
speech
|
||||
</p>
|
||||
</Dialog.Description>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex h-full w-full flex-col overflow-y-auto px-5 pb-5 pt-3">
|
||||
@@ -144,7 +175,9 @@ export const CreateChannelModal = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-400">Description</label>
|
||||
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-400">
|
||||
Description
|
||||
</label>
|
||||
<div className="relative h-20 w-full shrink-0 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20">
|
||||
<textarea
|
||||
{...register('about')}
|
||||
@@ -212,10 +245,11 @@ export const CreateChannelModal = () => {
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
</Dialog>
|
||||
</Transition>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { AccountContext } from '@components/accountProvider';
|
||||
import { RelayContext } from '@components/relaysProvider';
|
||||
import Tooltip from '@components/tooltip';
|
||||
|
||||
import { MESSAGE_RELAYS } from '@stores/constants';
|
||||
|
||||
import { dateToUnix } from '@utils/getDate';
|
||||
|
||||
import * as AlertDialog from '@radix-ui/react-alert-dialog';
|
||||
import * as Tooltip from '@radix-ui/react-tooltip';
|
||||
import { EyeClose } from 'iconoir-react';
|
||||
import { getEventHash, signEvent } from 'nostr-tools';
|
||||
import { useCallback, useContext } from 'react';
|
||||
@@ -31,55 +30,13 @@ export const HideMessageButton = ({ id }: { id: string }) => {
|
||||
}, [activeAccount.pubkey, activeAccount.privkey, id, pool]);
|
||||
|
||||
return (
|
||||
<AlertDialog.Root>
|
||||
<Tooltip.Provider>
|
||||
<Tooltip.Root>
|
||||
<AlertDialog.Trigger asChild>
|
||||
<Tooltip.Trigger asChild>
|
||||
<button className="inline-flex h-6 w-6 items-center justify-center rounded hover:bg-zinc-800">
|
||||
<Tooltip message="Hide this message">
|
||||
<button
|
||||
onClick={() => hideMessage()}
|
||||
className="inline-flex h-6 w-6 items-center justify-center rounded hover:bg-zinc-800"
|
||||
>
|
||||
<EyeClose width={16} height={16} className="text-zinc-400" />
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
</AlertDialog.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content
|
||||
className="select-none rounded-md bg-zinc-800 px-4 py-2 text-sm leading-none text-zinc-100 shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] 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"
|
||||
sideOffset={4}
|
||||
>
|
||||
Hide this message
|
||||
<Tooltip.Arrow className="fill-zinc-800" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
</Tooltip.Provider>
|
||||
<AlertDialog.Portal>
|
||||
<AlertDialog.Overlay className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-sm data-[state=open]:animate-overlayShow" />
|
||||
<AlertDialog.Content className="fixed left-[50%] top-[50%] z-50 max-h-[85vh] w-[90vw] max-w-[500px] translate-x-[-50%] translate-y-[-50%] rounded-md bg-zinc-900 p-6 shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] ring-1 ring-zinc-800 focus:outline-none data-[state=open]:animate-contentShow">
|
||||
<AlertDialog.Title className="m-0 font-medium text-zinc-100">Are you absolutely sure?</AlertDialog.Title>
|
||||
<AlertDialog.Description className="mb-5 mt-4 text-zinc-400">
|
||||
This action cannot be undone. This will permanently hide this message and you will never see this again
|
||||
</AlertDialog.Description>
|
||||
<div className="flex justify-end gap-4">
|
||||
<AlertDialog.Cancel asChild>
|
||||
<button
|
||||
autoFocus={false}
|
||||
className="inline-flex h-9 items-center justify-center rounded px-4 font-medium leading-none text-zinc-200 outline-none hover:bg-zinc-900 focus:shadow-[0_0_0_2px]"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</AlertDialog.Cancel>
|
||||
<AlertDialog.Action asChild>
|
||||
<button
|
||||
autoFocus={false}
|
||||
onClick={() => hideMessage()}
|
||||
className="inline-flex h-9 items-center justify-center rounded bg-red-500 px-4 font-medium leading-none text-white outline-none hover:bg-red-600 focus:shadow-[0_0_0_2px] focus:shadow-red-700"
|
||||
>
|
||||
Yes, hide this message
|
||||
</button>
|
||||
</AlertDialog.Action>
|
||||
</div>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Portal>
|
||||
</AlertDialog.Root>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { AccountContext } from '@components/accountProvider';
|
||||
import { RelayContext } from '@components/relaysProvider';
|
||||
import Tooltip from '@components/tooltip';
|
||||
|
||||
import { MESSAGE_RELAYS } from '@stores/constants';
|
||||
|
||||
import { dateToUnix } from '@utils/getDate';
|
||||
|
||||
import * as AlertDialog from '@radix-ui/react-alert-dialog';
|
||||
import * as Tooltip from '@radix-ui/react-tooltip';
|
||||
import { MicMute } from 'iconoir-react';
|
||||
import { getEventHash, signEvent } from 'nostr-tools';
|
||||
import { useContext } from 'react';
|
||||
@@ -31,56 +30,13 @@ export const MuteButton = ({ pubkey }: { pubkey: string }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<AlertDialog.Root>
|
||||
<Tooltip.Provider>
|
||||
<Tooltip.Root>
|
||||
<AlertDialog.Trigger asChild>
|
||||
<Tooltip.Trigger asChild>
|
||||
<button className="inline-flex h-6 w-6 items-center justify-center rounded hover:bg-zinc-800">
|
||||
<Tooltip message="Mute this user">
|
||||
<button
|
||||
onClick={() => muteUser()}
|
||||
className="inline-flex h-6 w-6 items-center justify-center rounded hover:bg-zinc-800"
|
||||
>
|
||||
<MicMute width={16} height={16} className="text-zinc-400" />
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
</AlertDialog.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content
|
||||
className="select-none rounded-md bg-zinc-800 px-4 py-2 text-sm leading-none text-zinc-100 shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] 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"
|
||||
sideOffset={4}
|
||||
>
|
||||
Mute user
|
||||
<Tooltip.Arrow className="fill-zinc-800" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
</Tooltip.Provider>
|
||||
<AlertDialog.Portal>
|
||||
<AlertDialog.Overlay className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-sm data-[state=open]:animate-overlayShow" />
|
||||
<AlertDialog.Content className="fixed left-[50%] top-[50%] z-50 max-h-[85vh] w-[90vw] max-w-[500px] translate-x-[-50%] translate-y-[-50%] rounded-md bg-zinc-900 p-6 shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] ring-1 ring-zinc-800 focus:outline-none data-[state=open]:animate-contentShow">
|
||||
<AlertDialog.Title className="m-0 font-medium text-zinc-100">Are you absolutely sure?</AlertDialog.Title>
|
||||
<AlertDialog.Description className="mb-5 mt-4 text-zinc-400">
|
||||
This action cannot be undone. This will permanently mute this user and you will never receive message from
|
||||
this user
|
||||
</AlertDialog.Description>
|
||||
<div className="flex justify-end gap-4">
|
||||
<AlertDialog.Cancel asChild>
|
||||
<button
|
||||
autoFocus={false}
|
||||
className="inline-flex h-9 items-center justify-center rounded px-4 font-medium leading-none text-zinc-200 outline-none hover:bg-zinc-900 focus:shadow-[0_0_0_2px]"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</AlertDialog.Cancel>
|
||||
<AlertDialog.Action asChild>
|
||||
<button
|
||||
autoFocus={false}
|
||||
onClick={() => muteUser()}
|
||||
className="inline-flex h-9 items-center justify-center rounded bg-red-500 px-4 font-medium leading-none text-white outline-none hover:bg-red-600 focus:shadow-[0_0_0_2px] focus:shadow-red-700"
|
||||
>
|
||||
Yes, mute this user
|
||||
</button>
|
||||
</AlertDialog.Action>
|
||||
</div>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Portal>
|
||||
</AlertDialog.Root>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import Tooltip from '@components/tooltip';
|
||||
|
||||
import { channelReplyAtom } from '@stores/channel';
|
||||
|
||||
import * as Tooltip from '@radix-ui/react-tooltip';
|
||||
import { Reply } from 'iconoir-react';
|
||||
import { useSetAtom } from 'jotai';
|
||||
|
||||
@@ -12,26 +13,13 @@ export const ReplyButton = ({ id, pubkey, content }: { id: string; pubkey: strin
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip.Provider>
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger asChild>
|
||||
<Tooltip message="Reply">
|
||||
<button
|
||||
onClick={() => createReply()}
|
||||
className="inline-flex h-6 w-6 items-center justify-center rounded hover:bg-zinc-800"
|
||||
>
|
||||
<Reply width={16} height={16} className="text-zinc-400" />
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content
|
||||
className="select-none rounded-md bg-zinc-800 px-4 py-2 text-sm leading-none text-zinc-100 shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] 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"
|
||||
sideOffset={4}
|
||||
>
|
||||
Reply
|
||||
<Tooltip.Arrow className="fill-zinc-800" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
</Tooltip.Provider>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
@@ -1,23 +1,7 @@
|
||||
import { ChatModalUser } from '@components/chats/chatModalUser';
|
||||
|
||||
import { getPlebs } from '@utils/storage';
|
||||
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { Cancel, Plus } from 'iconoir-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Plus } from 'iconoir-react';
|
||||
|
||||
export const ChatModal = () => {
|
||||
const [plebs, setPlebs] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
getPlebs()
|
||||
.then((res: any) => setPlebs(res))
|
||||
.catch(console.error);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger asChild>
|
||||
<div className="group inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-900">
|
||||
<div className="group-hover:800 inline-flex h-5 w-5 shrink items-center justify-center rounded bg-zinc-900 group-hover:bg-zinc-800">
|
||||
<Plus width={12} height={12} className="text-zinc-500" />
|
||||
@@ -26,34 +10,5 @@ export const ChatModal = () => {
|
||||
<h5 className="text-sm font-medium text-zinc-500 group-hover:text-zinc-400">Add a new chat</h5>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-sm data-[state=open]:animate-overlayShow" />
|
||||
<Dialog.Content className="fixed inset-0 z-50 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center">
|
||||
<div className="relative flex h-[500px] w-full max-w-2xl flex-col rounded-lg bg-zinc-900 text-zinc-100 ring-1 ring-zinc-800">
|
||||
<div className="sticky left-0 top-0 flex h-12 w-full shrink-0 items-center justify-between rounded-t-lg border-b border-zinc-800 bg-zinc-950 px-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Dialog.Close asChild>
|
||||
<button
|
||||
autoFocus={false}
|
||||
className="inline-flex h-5 w-5 items-center justify-center rounded bg-zinc-900"
|
||||
>
|
||||
<Cancel width={12} height={12} className="text-zinc-300" />
|
||||
</button>
|
||||
</Dialog.Close>
|
||||
<h5 className="font-semibold leading-none text-zinc-500">New chat</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col overflow-y-auto">
|
||||
{plebs.map((pleb) => (
|
||||
<ChatModalUser key={pleb.id} data={pleb} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
);
|
||||
};
|
||||
|
@@ -1,73 +1,11 @@
|
||||
import { DEFAULT_AVATAR } from '@stores/constants';
|
||||
|
||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
||||
import { writeText } from '@tauri-apps/api/clipboard';
|
||||
import { LogOut, ProfileCircle, Settings } from 'iconoir-react';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { navigate } from 'vite-plugin-ssr/client/router';
|
||||
|
||||
export const ActiveAccount = ({ user }: { user: any }) => {
|
||||
const userData = JSON.parse(user.metadata);
|
||||
|
||||
const openProfilePage = () => {
|
||||
navigate(`/user?pubkey=${user.pubkey}`);
|
||||
};
|
||||
|
||||
const copyPublicKey = async () => {
|
||||
await writeText(nip19.npubEncode(user.pubkey));
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<button className="relative h-11 w-11 rounded-lg">
|
||||
<img
|
||||
src={userData.picture || DEFAULT_AVATAR}
|
||||
alt="user's avatar"
|
||||
className="h-11 w-11 rounded-lg object-cover"
|
||||
/>
|
||||
<img src={userData.picture || DEFAULT_AVATAR} alt="user's avatar" className="h-11 w-11 rounded-lg object-cover" />
|
||||
</button>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
className="min-w-[220px] rounded-md bg-zinc-900/80 p-1.5 shadow-input shadow-black/50 ring-1 ring-zinc-800 backdrop-blur-xl will-change-[opacity,transform] data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=top]:animate-slideDownAndFade"
|
||||
side="right"
|
||||
sideOffset={5}
|
||||
align="start"
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
onClick={() => openProfilePage()}
|
||||
className="group relative flex h-7 select-none items-center rounded-sm px-1 pl-7 text-sm leading-none text-zinc-400 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-800 data-[highlighted]:text-fuchsia-500"
|
||||
>
|
||||
<div className="absolute left-0 inline-flex w-6 items-center justify-center">
|
||||
<ProfileCircle />
|
||||
</div>
|
||||
Open profile
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item className="group relative flex h-7 select-none items-center rounded px-1 pl-7 text-sm leading-none text-zinc-400 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-800 data-[highlighted]:text-fuchsia-500">
|
||||
Update profile
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
onClick={() => copyPublicKey()}
|
||||
className="group relative flex h-7 select-none items-center rounded px-1 pl-7 text-sm leading-none text-zinc-400 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-800 data-[highlighted]:text-fuchsia-500"
|
||||
>
|
||||
Copy public key
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator className="m-1 h-px bg-zinc-700/50" />
|
||||
<DropdownMenu.Item className="group relative flex h-7 select-none items-center rounded px-1 pl-7 text-sm leading-none text-zinc-400 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-800 data-[highlighted]:text-fuchsia-500">
|
||||
<div className="absolute left-0 inline-flex w-6 items-center justify-center">
|
||||
<Settings />
|
||||
</div>
|
||||
Settings
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item className="group relative flex h-7 select-none items-center rounded px-1 pl-7 text-sm leading-none text-zinc-400 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-800 data-[highlighted]:text-fuchsia-500">
|
||||
<div className="absolute left-0 inline-flex w-6 items-center justify-center">
|
||||
<LogOut />
|
||||
</div>
|
||||
Logout
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
);
|
||||
};
|
||||
|
@@ -1,17 +1,16 @@
|
||||
import ChannelList from '@components/channels/channelList';
|
||||
|
||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import { Disclosure } from '@headlessui/react';
|
||||
import { NavArrowUp } from 'iconoir-react';
|
||||
import { Suspense, useState } from 'react';
|
||||
import { Suspense } from 'react';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
|
||||
export default function Channels() {
|
||||
const [open, setOpen] = useState(true);
|
||||
|
||||
return (
|
||||
<Collapsible.Root open={open} onOpenChange={setOpen}>
|
||||
<Disclosure>
|
||||
{({ open }) => (
|
||||
<div className="flex flex-col px-2">
|
||||
<Collapsible.Trigger className="flex cursor-pointer items-center gap-1 px-1 py-1">
|
||||
<Disclosure.Button className="flex cursor-pointer items-center gap-1 px-1 py-1">
|
||||
<div
|
||||
className={`inline-flex h-5 w-5 transform items-center justify-center transition-transform duration-150 ease-in-out ${
|
||||
open ? 'rotate-180' : ''
|
||||
@@ -20,13 +19,14 @@ export default function Channels() {
|
||||
<NavArrowUp width={16} height={16} className="text-zinc-700" />
|
||||
</div>
|
||||
<h3 className="text-[11px] font-bold uppercase tracking-widest text-zinc-600">Channels</h3>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
</Disclosure.Button>
|
||||
<Disclosure.Panel>
|
||||
<Suspense fallback={<Skeleton count={2} />}>
|
||||
<ChannelList />
|
||||
</Suspense>
|
||||
</Collapsible.Content>
|
||||
</Disclosure.Panel>
|
||||
</div>
|
||||
</Collapsible.Root>
|
||||
)}
|
||||
</Disclosure>
|
||||
);
|
||||
}
|
||||
|
@@ -1,16 +1,14 @@
|
||||
import ChatList from '@components/chats/chatList';
|
||||
|
||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import { Disclosure } from '@headlessui/react';
|
||||
import { NavArrowUp } from 'iconoir-react';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function Chats() {
|
||||
const [open, setOpen] = useState(true);
|
||||
|
||||
return (
|
||||
<Collapsible.Root open={open} onOpenChange={setOpen}>
|
||||
<Disclosure>
|
||||
{({ open }) => (
|
||||
<div className="flex flex-col px-2">
|
||||
<Collapsible.Trigger className="flex cursor-pointer items-center gap-1 px-1 py-1">
|
||||
<Disclosure.Button className="flex cursor-pointer items-center gap-1 px-1 py-1">
|
||||
<div
|
||||
className={`inline-flex h-5 w-5 transform items-center justify-center transition-transform duration-150 ease-in-out ${
|
||||
open ? 'rotate-180' : ''
|
||||
@@ -19,11 +17,12 @@ export default function Chats() {
|
||||
<NavArrowUp width={16} height={16} className="text-zinc-700" />
|
||||
</div>
|
||||
<h3 className="text-[11px] font-bold uppercase tracking-widest text-zinc-600">Chats</h3>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
</Disclosure.Button>
|
||||
<Disclosure.Panel>
|
||||
<ChatList />
|
||||
</Collapsible.Content>
|
||||
</Disclosure.Panel>
|
||||
</div>
|
||||
</Collapsible.Root>
|
||||
)}
|
||||
</Disclosure>
|
||||
);
|
||||
}
|
||||
|
@@ -1,16 +1,14 @@
|
||||
import { ActiveLink } from '@components/activeLink';
|
||||
|
||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import { Disclosure } from '@headlessui/react';
|
||||
import { Bonfire, NavArrowUp, PeopleTag } from 'iconoir-react';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function Newsfeed() {
|
||||
const [open, setOpen] = useState(true);
|
||||
|
||||
return (
|
||||
<Collapsible.Root open={open} onOpenChange={setOpen}>
|
||||
<Disclosure>
|
||||
{({ open }) => (
|
||||
<div className="flex flex-col px-2">
|
||||
<Collapsible.Trigger className="flex cursor-pointer items-center gap-1 px-1 py-1">
|
||||
<Disclosure.Button className="flex cursor-pointer items-center gap-1 px-1 py-1">
|
||||
<div
|
||||
className={`inline-flex h-5 w-5 transform items-center justify-center transition-transform duration-150 ease-in-out ${
|
||||
open ? 'rotate-180' : ''
|
||||
@@ -19,8 +17,8 @@ export default function Newsfeed() {
|
||||
<NavArrowUp width={16} height={16} className="text-zinc-700" />
|
||||
</div>
|
||||
<h3 className="text-[11px] font-bold uppercase tracking-widest text-zinc-600">Newsfeed</h3>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content className="flex flex-col text-zinc-400">
|
||||
</Disclosure.Button>
|
||||
<Disclosure.Panel className="flex flex-col text-zinc-400">
|
||||
<ActiveLink
|
||||
href="/newsfeed/following"
|
||||
className="flex h-8 items-center gap-2.5 rounded-md px-2.5 text-sm font-medium hover:text-zinc-200"
|
||||
@@ -37,8 +35,9 @@ export default function Newsfeed() {
|
||||
<Bonfire width={16} height={16} className="text-zinc-500" />
|
||||
<span>Circle</span>
|
||||
</ActiveLink>
|
||||
</Collapsible.Content>
|
||||
</Disclosure.Panel>
|
||||
</div>
|
||||
</Collapsible.Root>
|
||||
)}
|
||||
</Disclosure>
|
||||
);
|
||||
}
|
||||
|
@@ -6,10 +6,10 @@ import { DEFAULT_RELAYS } from '@stores/constants';
|
||||
|
||||
import { dateToUnix } from '@utils/getDate';
|
||||
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { Dialog, Transition } from '@headlessui/react';
|
||||
import { ChatLines, OpenNewWindow } from 'iconoir-react';
|
||||
import { getEventHash, signEvent } from 'nostr-tools';
|
||||
import { useContext, useState } from 'react';
|
||||
import { Fragment, useContext, useState } from 'react';
|
||||
import { navigate } from 'vite-plugin-ssr/client/router';
|
||||
|
||||
export const NoteComment = ({
|
||||
@@ -28,11 +28,19 @@ export const NoteComment = ({
|
||||
const pool: any = useContext(RelayContext);
|
||||
const activeAccount: any = useContext(AccountContext);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
const profile = activeAccount ? JSON.parse(activeAccount.metadata) : null;
|
||||
|
||||
const closeModal = () => {
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const openModal = () => {
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const openThread = () => {
|
||||
navigate(`/newsfeed/note?id=${eventID}`);
|
||||
};
|
||||
@@ -49,24 +57,45 @@ export const NoteComment = ({
|
||||
event.sig = signEvent(event, activeAccount.privkey);
|
||||
|
||||
pool.publish(event, DEFAULT_RELAYS);
|
||||
setOpen(false);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog.Root open={open} onOpenChange={setOpen}>
|
||||
<Dialog.Trigger asChild>
|
||||
<button className="group flex w-16 items-center gap-1 text-sm text-zinc-500">
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openModal()}
|
||||
className="group flex w-16 items-center gap-1 text-sm text-zinc-500"
|
||||
>
|
||||
<div className="rounded-md p-1 group-hover:bg-zinc-800">
|
||||
<ChatLines width={20} height={20} className="text-zinc-500" />
|
||||
</div>
|
||||
<span>{count}</span>
|
||||
</button>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-sm data-[state=open]:animate-overlayShow" />
|
||||
<Dialog.Content className="fixed inset-0 z-50 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center">
|
||||
<div className="relative w-full max-w-2xl rounded-lg bg-zinc-900 p-4 text-zinc-100 ring-1 ring-zinc-800">
|
||||
<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 data-[state=open]:animate-overlayShow" />
|
||||
</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 border-zinc-800 bg-zinc-900">
|
||||
{/* root note */}
|
||||
<div className="relative z-10 flex flex-col pb-6">
|
||||
<div className="relative z-10">
|
||||
@@ -121,10 +150,11 @@ export const NoteComment = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
</Dialog>
|
||||
</Transition>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
10
src/components/tooltip.tsx
Normal file
10
src/components/tooltip.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function Tooltip({ message, children }: { message: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="group relative flex">
|
||||
{children}
|
||||
<span className="absolute top-10 scale-0 rounded bg-zinc-800 p-2 text-xs text-zinc-100 transition-all group-hover:scale-100">
|
||||
{message}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,13 +1,7 @@
|
||||
import NewsfeedLayout from '@components/layouts/newsfeed';
|
||||
import ProfileFollowers from '@components/profile/followers';
|
||||
import ProfileFollows from '@components/profile/follows';
|
||||
import ProfileMetadata from '@components/profile/metadata';
|
||||
import ProfileNotes from '@components/profile/notes';
|
||||
|
||||
import { usePageContext } from '@utils/hooks/usePageContext';
|
||||
|
||||
import * as Tabs from '@radix-ui/react-tabs';
|
||||
|
||||
export function Page() {
|
||||
const pageContext = usePageContext();
|
||||
const searchParams: any = pageContext.urlParsed.search;
|
||||
@@ -17,38 +11,7 @@ export function Page() {
|
||||
return (
|
||||
<NewsfeedLayout>
|
||||
<div className="scrollbar-hide h-full w-full overflow-y-auto">
|
||||
<ProfileMetadata id={pubkey} />
|
||||
<Tabs.Root className="flex w-full flex-col" defaultValue="notes">
|
||||
<Tabs.List className="flex border-b border-zinc-800">
|
||||
<Tabs.Trigger
|
||||
className="flex h-10 flex-1 cursor-default select-none items-center justify-center px-5 text-sm font-medium leading-none text-zinc-400 outline-none hover:text-fuchsia-400 data-[state=active]:text-fuchsia-500 data-[state=active]:shadow-[inset_0_-1px_0_0,0_1px_0_0] data-[state=active]:shadow-current"
|
||||
value="notes"
|
||||
>
|
||||
Notes
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger
|
||||
className="flex h-10 flex-1 cursor-default select-none items-center justify-center px-5 text-sm font-medium text-zinc-400 outline-none placeholder:leading-none hover:text-fuchsia-400 data-[state=active]:text-fuchsia-500 data-[state=active]:shadow-[inset_0_-1px_0_0,0_1px_0_0] data-[state=active]:shadow-current"
|
||||
value="followers"
|
||||
>
|
||||
Followers
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger
|
||||
className="flex h-10 flex-1 cursor-default select-none items-center justify-center px-5 text-sm font-medium leading-none text-zinc-400 outline-none hover:text-fuchsia-400 data-[state=active]:text-fuchsia-500 data-[state=active]:shadow-[inset_0_-1px_0_0,0_1px_0_0] data-[state=active]:shadow-current"
|
||||
value="following"
|
||||
>
|
||||
Following
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.Content value="notes">
|
||||
<ProfileNotes id={pubkey} />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="followers">
|
||||
<ProfileFollowers id={pubkey} />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="following">
|
||||
<ProfileFollows id={pubkey} />
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
<p>{pubkey}</p>
|
||||
</div>
|
||||
</NewsfeedLayout>
|
||||
);
|
||||
|
Reference in New Issue
Block a user