replaced radix-ui with headless-ui

This commit is contained in:
Ren Amamiya 2023-04-24 16:01:49 +07:00
parent 3e31e7d4dc
commit 188c052a1a
14 changed files with 1094 additions and 1875 deletions

View File

@ -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",

File diff suppressed because it is too large Load Diff

View File

@ -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,147 +83,173 @@ 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">
<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>
<>
<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>
</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">
<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">
Create channel
</h5>
<Dialog.Close asChild>
<div>
<h5 className="text-sm font-medium text-zinc-500 group-hover:text-zinc-400">Add a new channel</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 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">
<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
</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>
<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
</Dialog.Description>
</div>
<p 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>
</div>
</div>
<div className="flex h-full w-full flex-col overflow-y-auto px-5 pb-5 pt-3">
<form onSubmit={handleSubmit(onSubmit)} className="flex h-full w-full flex-col gap-4">
<input
type={'hidden'}
{...register('picture')}
value={image}
className="relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
<div className="flex flex-col gap-1">
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-400">Picture</label>
<div className="relative inline-flex h-36 w-full items-center justify-center overflow-hidden rounded-lg border border-zinc-900 bg-zinc-950">
<img src={image} alt="channel picture" className="relative z-10 h-11 w-11 rounded-md" />
<div className="absolute bottom-3 right-3 z-10">
<AvatarUploader valueState={setImage} />
</div>
</div>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-400">
Channel name *
</label>
<div className="relative 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">
<input
type={'text'}
{...register('name', { required: true, minLength: 4 })}
spellCheck={false}
className="relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
</div>
</div>
<div className="flex flex-col gap-1">
<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')}
spellCheck={false}
className="relative h-20 w-full resize-none rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
</div>
</div>
<div className="flex h-14 items-center justify-between gap-1 rounded-lg bg-zinc-800 px-4 py-2">
<div className="flex flex-col gap-0.5">
<div className="inline-flex items-center gap-1">
<span className="text-sm font-bold leading-none text-zinc-200">Make Private</span>
<div className="inline-flex items-center rounded-md bg-zinc-400/10 px-2 py-0.5 text-xs font-medium ring-1 ring-inset ring-zinc-400/20">
<span className="bg-gradient-to-r from-fuchsia-300 via-orange-100 to-amber-300 bg-clip-text text-transparent">
Coming soon
</span>
<div className="flex h-full w-full flex-col overflow-y-auto px-5 pb-5 pt-3">
<form onSubmit={handleSubmit(onSubmit)} className="flex h-full w-full flex-col gap-4">
<input
type={'hidden'}
{...register('picture')}
value={image}
className="relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
<div className="flex flex-col gap-1">
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-400">Picture</label>
<div className="relative inline-flex h-36 w-full items-center justify-center overflow-hidden rounded-lg border border-zinc-900 bg-zinc-950">
<img src={image} alt="channel picture" className="relative z-10 h-11 w-11 rounded-md" />
<div className="absolute bottom-3 right-3 z-10">
<AvatarUploader valueState={setImage} />
</div>
</div>
<p className="text-sm leading-none text-zinc-400">
Private channels can only be viewed by member
</p>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-400">
Channel name *
</label>
<div className="relative 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">
<input
type={'text'}
{...register('name', { required: true, minLength: 4 })}
spellCheck={false}
className="relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
</div>
</div>
<div className="flex flex-col gap-1">
<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')}
spellCheck={false}
className="relative h-20 w-full resize-none rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
</div>
</div>
<div className="flex h-14 items-center justify-between gap-1 rounded-lg bg-zinc-800 px-4 py-2">
<div className="flex flex-col gap-0.5">
<div className="inline-flex items-center gap-1">
<span className="text-sm font-bold leading-none text-zinc-200">Make Private</span>
<div className="inline-flex items-center rounded-md bg-zinc-400/10 px-2 py-0.5 text-xs font-medium ring-1 ring-inset ring-zinc-400/20">
<span className="bg-gradient-to-r from-fuchsia-300 via-orange-100 to-amber-300 bg-clip-text text-transparent">
Coming soon
</span>
</div>
</div>
<p className="text-sm leading-none text-zinc-400">
Private channels can only be viewed by member
</p>
</div>
<div>
<button
disabled
className="relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent bg-zinc-900 transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-fuchsia-600 focus:ring-offset-2"
role="switch"
aria-checked="false"
>
<span className="pointer-events-none inline-block h-5 w-5 translate-x-0 transform rounded-full bg-zinc-600 shadow ring-0 transition duration-200 ease-in-out"></span>
</button>
</div>
</div>
<div>
<button
disabled
className="relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent bg-zinc-900 transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-fuchsia-600 focus:ring-offset-2"
role="switch"
aria-checked="false"
type="submit"
disabled={!isDirty || !isValid}
className="inline-flex h-11 w-full transform items-center justify-center rounded-lg bg-fuchsia-500 font-medium text-white active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
<span className="pointer-events-none inline-block h-5 w-5 translate-x-0 transform rounded-full bg-zinc-600 shadow ring-0 transition duration-200 ease-in-out"></span>
{loading ? (
<svg
className="h-4 w-4 animate-spin text-black dark:text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
) : (
'Create channel'
)}
</button>
</div>
</div>
<div>
<button
type="submit"
disabled={!isDirty || !isValid}
className="inline-flex h-11 w-full transform items-center justify-center rounded-lg bg-fuchsia-500 font-medium text-white active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
{loading ? (
<svg
className="h-4 w-4 animate-spin text-black dark:text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
) : (
'Create channel'
)}
</button>
</div>
</form>
</div>
</div>
</form>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
</Dialog>
</Transition>
</>
);
};

View File

@ -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">
<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 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>
);
};

View File

@ -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">
<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 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>
);
};

View File

@ -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>
<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 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>
);
};

View File

@ -1,59 +1,14 @@
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" />
</div>
<div>
<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>
<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" />
</div>
<div>
<h5 className="text-sm font-medium text-zinc-500 group-hover:text-zinc-400">Add a new chat</h5>
</div>
</div>
);
};

View File

@ -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"
/>
</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>
<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" />
</button>
);
};

View File

@ -1,32 +1,32 @@
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}>
<div className="flex flex-col px-2">
<Collapsible.Trigger 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' : ''
}`}
>
<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>
<Suspense fallback={<Skeleton count={2} />}>
<ChannelList />
</Suspense>
</Collapsible.Content>
</div>
</Collapsible.Root>
<Disclosure>
{({ open }) => (
<div className="flex flex-col px-2">
<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' : ''
}`}
>
<NavArrowUp width={16} height={16} className="text-zinc-700" />
</div>
<h3 className="text-[11px] font-bold uppercase tracking-widest text-zinc-600">Channels</h3>
</Disclosure.Button>
<Disclosure.Panel>
<Suspense fallback={<Skeleton count={2} />}>
<ChannelList />
</Suspense>
</Disclosure.Panel>
</div>
)}
</Disclosure>
);
}

View File

@ -1,29 +1,28 @@
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}>
<div className="flex flex-col px-2">
<Collapsible.Trigger 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' : ''
}`}
>
<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>
<ChatList />
</Collapsible.Content>
</div>
</Collapsible.Root>
<Disclosure>
{({ open }) => (
<div className="flex flex-col px-2">
<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' : ''
}`}
>
<NavArrowUp width={16} height={16} className="text-zinc-700" />
</div>
<h3 className="text-[11px] font-bold uppercase tracking-widest text-zinc-600">Chats</h3>
</Disclosure.Button>
<Disclosure.Panel>
<ChatList />
</Disclosure.Panel>
</div>
)}
</Disclosure>
);
}

View File

@ -1,44 +1,43 @@
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}>
<div className="flex flex-col px-2">
<Collapsible.Trigger 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' : ''
}`}
>
<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">
<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"
activeClassName="dark:bg-zinc-900 dark:text-zinc-100 hover:dark:bg-zinc-800"
>
<PeopleTag width={16} height={16} className="text-zinc-500" />
<span>Following</span>
</ActiveLink>
<ActiveLink
href="/newsfeed/circle"
className="flex h-8 items-center gap-2.5 rounded-md px-2.5 text-sm font-medium hover:text-zinc-200"
activeClassName="dark:bg-zinc-900 dark:text-zinc-100 hover:dark:bg-zinc-800"
>
<Bonfire width={16} height={16} className="text-zinc-500" />
<span>Circle</span>
</ActiveLink>
</Collapsible.Content>
</div>
</Collapsible.Root>
<Disclosure>
{({ open }) => (
<div className="flex flex-col px-2">
<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' : ''
}`}
>
<NavArrowUp width={16} height={16} className="text-zinc-700" />
</div>
<h3 className="text-[11px] font-bold uppercase tracking-widest text-zinc-600">Newsfeed</h3>
</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"
activeClassName="dark:bg-zinc-900 dark:text-zinc-100 hover:dark:bg-zinc-800"
>
<PeopleTag width={16} height={16} className="text-zinc-500" />
<span>Following</span>
</ActiveLink>
<ActiveLink
href="/newsfeed/circle"
className="flex h-8 items-center gap-2.5 rounded-md px-2.5 text-sm font-medium hover:text-zinc-200"
activeClassName="dark:bg-zinc-900 dark:text-zinc-100 hover:dark:bg-zinc-800"
>
<Bonfire width={16} height={16} className="text-zinc-500" />
<span>Circle</span>
</ActiveLink>
</Disclosure.Panel>
</div>
)}
</Disclosure>
);
}

View File

@ -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,82 +57,104 @@ 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">
<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">
{/* root note */}
<div className="relative z-10 flex flex-col pb-6">
<div className="relative z-10">
<UserExtend pubkey={eventPubkey} time={eventTime} />
</div>
<div className="-mt-5 pl-[52px]">
<div className="prose prose-zinc max-w-none break-words leading-tight dark:prose-invert prose-headings:mb-2 prose-headings:mt-3 prose-p:m-0 prose-p:leading-tight prose-a:font-normal prose-a:text-fuchsia-500 prose-a:no-underline prose-ul:mt-2 prose-li:my-1">
{eventContent}
<>
<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>
<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">
<UserExtend pubkey={eventPubkey} time={eventTime} />
</div>
</div>
{/* divider */}
<div className="absolute left-[21px] top-0 h-full w-0.5 bg-gradient-to-t from-zinc-800 to-zinc-600"></div>
</div>
{/* comment form */}
<div className="flex gap-2">
<div>
<div className="relative h-11 w-11 shrink-0 overflow-hidden rounded-md border border-white/10">
<img src={profile?.picture} alt="user's avatar" className="h-11 w-11 rounded-md object-cover" />
<div className="-mt-5 pl-[52px]">
<div className="prose prose-zinc max-w-none break-words leading-tight dark:prose-invert prose-headings:mb-2 prose-headings:mt-3 prose-p:m-0 prose-p:leading-tight prose-a:font-normal prose-a:text-fuchsia-500 prose-a:no-underline prose-ul:mt-2 prose-li:my-1">
{eventContent}
</div>
</div>
{/* divider */}
<div className="absolute left-[21px] top-0 h-full w-0.5 bg-gradient-to-t from-zinc-800 to-zinc-600"></div>
</div>
<div className="relative h-36 w-full flex-1 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-blue-500 before:opacity-0 before:ring-2 before:ring-blue-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-blue-500/100 dark:focus-within:after:shadow-blue-500/20">
{/* comment form */}
<div className="flex gap-2">
<div>
<textarea
name="content"
onChange={(e) => setValue(e.target.value)}
placeholder="Send your comment"
className="relative h-36 w-full resize-none rounded-md border border-black/5 px-3.5 py-3 text-sm shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
spellCheck={false}
/>
<div className="relative h-11 w-11 shrink-0 overflow-hidden rounded-md border border-white/10">
<img src={profile?.picture} alt="user's avatar" className="h-11 w-11 rounded-md object-cover" />
</div>
</div>
<div className="absolute bottom-2 w-full px-2">
<div className="flex w-full items-center justify-between bg-zinc-800">
<div className="flex items-center gap-2 divide-x divide-zinc-700">
<button
onClick={() => openThread()}
className="inline-flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-zinc-700"
>
<OpenNewWindow width={16} height={16} className="text-zinc-400" />
</button>
<div className="flex items-center gap-2 pl-2"></div>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => submitEvent()}
disabled={value.length === 0 ? true : false}
className="inline-flex h-8 w-16 items-center justify-center rounded-md bg-fuchsia-500 px-4 text-sm font-medium shadow-md shadow-fuchsia-900/50 hover:bg-fuchsia-600"
>
<span className="text-white drop-shadow">Send</span>
</button>
<div className="relative h-36 w-full flex-1 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-blue-500 before:opacity-0 before:ring-2 before:ring-blue-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-blue-500/100 dark:focus-within:after:shadow-blue-500/20">
<div>
<textarea
name="content"
onChange={(e) => setValue(e.target.value)}
placeholder="Send your comment"
className="relative h-36 w-full resize-none rounded-md border border-black/5 px-3.5 py-3 text-sm shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
spellCheck={false}
/>
</div>
<div className="absolute bottom-2 w-full px-2">
<div className="flex w-full items-center justify-between bg-zinc-800">
<div className="flex items-center gap-2 divide-x divide-zinc-700">
<button
onClick={() => openThread()}
className="inline-flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-zinc-700"
>
<OpenNewWindow width={16} height={16} className="text-zinc-400" />
</button>
<div className="flex items-center gap-2 pl-2"></div>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => submitEvent()}
disabled={value.length === 0 ? true : false}
className="inline-flex h-8 w-16 items-center justify-center rounded-md bg-fuchsia-500 px-4 text-sm font-medium shadow-md shadow-fuchsia-900/50 hover:bg-fuchsia-600"
>
<span className="text-white drop-shadow">Send</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
</Dialog>
</Transition>
</>
);
};

View 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>
);
}

View File

@ -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>
);