wip
This commit is contained in:
@@ -9,6 +9,12 @@
|
||||
|
||||
html {
|
||||
font-size: 14px;
|
||||
/* Smoothing */
|
||||
text-rendering: optimizeLegibility;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-smoothing: antialiased;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-shadow: rgba(0, 0, 0, .01) 0 0 1px;
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
@@ -79,7 +79,7 @@ export function RelayScreen() {
|
||||
<a
|
||||
href={`mailto:${resolvedRelay.contact}`}
|
||||
target="_blank"
|
||||
className="underline after:content-['_↗'] hover:text-blue-500"
|
||||
className="underline after:content-['_↗'] hover:text-blue-600"
|
||||
rel="noreferrer"
|
||||
>
|
||||
mailto:{resolvedRelay.contact}
|
||||
@@ -92,7 +92,7 @@ export function RelayScreen() {
|
||||
href={resolvedRelay.software}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="underline after:content-['_↗'] hover:text-blue-500"
|
||||
className="underline after:content-['_↗'] hover:text-blue-600"
|
||||
>
|
||||
{getSoftwareName(resolvedRelay.software) +
|
||||
' - ' +
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { VList } from 'virtua';
|
||||
import { VList, WVList } from 'virtua';
|
||||
|
||||
import { ToggleWidgetList } from '@app/space/components/toggle';
|
||||
import { WidgetList } from '@app/space/components/widgetList';
|
||||
@@ -85,17 +85,15 @@ export function SpaceScreen() {
|
||||
}, [fetchWidgets]);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full">
|
||||
<VList className="h-full w-full scrollbar-none" horizontal>
|
||||
{!widgets ? (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center">
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-neutral-900 dark:text-neutral-100" />
|
||||
</div>
|
||||
) : (
|
||||
widgets.map((widget) => renderItem(widget))
|
||||
)}
|
||||
<ToggleWidgetList />
|
||||
</VList>
|
||||
</div>
|
||||
<VList className="h-screen w-full scrollbar-none" horizontal>
|
||||
{!widgets ? (
|
||||
<div className="flex h-full w-[420px] flex-col items-center justify-center">
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-neutral-900 dark:text-neutral-100" />
|
||||
</div>
|
||||
) : (
|
||||
widgets.map((widget) => renderItem(widget))
|
||||
)}
|
||||
<ToggleWidgetList />
|
||||
</VList>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export function ActiveAccount() {
|
||||
alt={db.account.npub}
|
||||
className="aspect-square h-full w-full rounded-md"
|
||||
/>
|
||||
<span className="absolute bottom-0 right-0 block h-2 w-2 rounded-full bg-green-400 ring-2 ring-neutral-50 dark:ring-neutral-950" />
|
||||
<span className="absolute bottom-0 right-0 block h-2 w-2 rounded-full bg-emerald-500 ring-2 ring-neutral-100 dark:ring-neutral-900" />
|
||||
</Link>
|
||||
<div className="inline-flex items-center justify-center rounded-md">
|
||||
<HorizontalDotsIcon className="h-4 w-4" />
|
||||
|
||||
@@ -11,11 +11,16 @@ export function FocusIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElemen
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="M8.25 3.75h-3.5a1 1 0 00-1 1v3.5m12-4.5h3.5a1 1 0 011 1v3.5m0 7.5v3.5a1 1 0 01-1 1h-3.5m-7.5 0h-3.5a1 1 0 01-1-1v-3.5"
|
||||
fill="currentColor"
|
||||
d="M9 13a3 3 0 013 3v3a3 3 0 01-3 3H5a3 3 0 01-3-3v-3a3 3 0 013-3h4z"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M20 6a1 1 0 00-1-1H6a1 1 0 00-1 1v4a1 1 0 11-2 0V6a3 3 0 013-3h13a3 3 0 013 3v7a3 3 0 01-3 3h-4a1 1 0 110-2h4a1 1 0 001-1V6z"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M17 7a1 1 0 011 1v3a1 1 0 11-2 0v-.586l-1.293 1.293a1 1 0 01-1.414-1.414L14.586 9H14a1 1 0 110-2h3z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -12,17 +12,13 @@ export function HorizontalDotsIcon(
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12 13a1 1 0 100-2 1 1 0 000 2zM20.25 13a1 1 0 100-2 1 1 0 000 2zM3.75 13a1 1 0 100-2 1 1 0 000 2z"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="M12 13a1 1 0 100-2 1 1 0 000 2zM20.25 13a1 1 0 100-2 1 1 0 000 2zM3.75 13a1 1 0 100-2 1 1 0 000 2z"
|
||||
/>
|
||||
strokeWidth="2"
|
||||
d="M12 13a1 1 0 100-2 1 1 0 000 2zM20 13a1 1 0 100-2 1 1 0 000 2zM4 13a1 1 0 100-2 1 1 0 000 2z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,24 +12,12 @@ export function ReactionIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGEle
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M19 1a.75.75 0 01.75.75v2.5h2.5a.75.75 0 110 1.5h-2.5v2.5a.75.75 0 11-1.5 0v-2.5h-2.5a.75.75 0 110-1.5h2.5v-2.5A.75.75 0 0119 1z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M10.5 9.5c0 .828-.56 1.5-1.25 1.5S8 10.328 8 9.5 8.56 8 9.25 8s1.25.672 1.25 1.5zM16 9.5c0 .828-.56 1.5-1.25 1.5s-1.25-.672-1.25-1.5.56-1.5 1.25-1.5S16 8.672 16 9.5z"
|
||||
d="M10.499 9.5c0 .828-.56 1.5-1.25 1.5s-1.25-.672-1.25-1.5.56-1.5 1.25-1.5 1.25.672 1.25 1.5zM15.999 9.5c0 .828-.56 1.5-1.25 1.5s-1.25-.672-1.25-1.5.56-1.5 1.25-1.5 1.25.672 1.25 1.5z"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M8.642 14.298a.75.75 0 011.06 0 3.25 3.25 0 004.597 0 .75.75 0 011.06 1.06 4.75 4.75 0 01-6.717 0 .75.75 0 010-1.06z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M12 3.5a8.5 8.5 0 108.5 8.5.75.75 0 011.5 0c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2a.75.75 0 010 1.5z"
|
||||
d="M18.999 1a1 1 0 011 1v2h2a1 1 0 110 2h-2v2a1 1 0 11-2 0V6h-2a1 1 0 010-2h2V2a1 1 0 011-1zm-7.006 1.945a1 1 0 01-.884 1.104 8.001 8.001 0 108.842 8.841 1 1 0 011.988.22C21.386 18.11 17.148 22 12 22 6.477 22 2 17.523 2 12c0-5.147 3.888-9.385 8.889-9.939a1 1 0 011.104.884zm-3.53 11.176a1 1 0 011.415 0 3 3 0 004.242 0 1 1 0 011.415 1.415 5 5 0 01-7.072 0 1 1 0 010-1.415z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
|
||||
@@ -2,14 +2,28 @@ import { SVGProps } from 'react';
|
||||
|
||||
export function ReplyIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M12 21.25C17.1086 21.25 21.25 17.1086 21.25 12C21.25 6.89137 17.1086 2.75 12 2.75C6.89137 2.75 2.75 6.89137 2.75 12C2.75 13.529 3.12096 14.9713 3.77778 16.2418L2.75 21.25L7.88889 20.2885C9.12732 20.9039 10.5232 21.25 12 21.25Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
strokeWidth="2"
|
||||
d="M12 21a9 9 0 10-9-9c0 1.354.3 2.639.835 3.791.102.219.133.465.076.7l-.778 3.191a1 1 0 001.191 1.213l3.33-.752c.224-.05.458-.02.667.073A8.969 8.969 0 0012 21z"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="square"
|
||||
strokeWidth="0.75"
|
||||
d="M6.625 12a.875.875 0 101.75 0 .875.875 0 00-1.75 0zm4.5 0a.875.875 0 101.75 0 .875.875 0 00-1.75 0zm4.5 0a.875.875 0 101.75 0 .875.875 0 00-1.75 0z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,10 +11,8 @@ export function RepostIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGEleme
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="M12 21.25c4.28 0 7.75-3.75 7.75-8.25 0-5.167-4.613-8.829-6.471-10.094-.426-.29-.988-.165-1.285.257L9.582 6.59a1.002 1.002 0 01-1.525.131c-.39-.387-1.026-.391-1.376.033C5.06 8.718 4.25 11.16 4.25 13c0 4.5 3.47 8.25 7.75 8.25zm0 0c1.657 0 3-1.533 3-3.424 0-2.084-1.663-3.601-2.513-4.24a.802.802 0 00-.974 0c-.85.639-2.513 2.156-2.513 4.24 0 1.89 1.343 3.424 3 3.424z"
|
||||
fill="currentColor"
|
||||
d="M17.957 2.293a1 1 0 10-1.414 1.414L17.836 5H6a3 3 0 00-3 3v3a1 1 0 102 0V8a1 1 0 011-1h11.836l-1.293 1.293a1 1 0 001.414 1.414l2.47-2.47a1.75 1.75 0 000-2.474l-2.47-2.47zM20 12a1 1 0 011 1v3a3 3 0 01-3 3H6.164l1.293 1.293a1 1 0 11-1.414 1.414l-2.47-2.47a1.75 1.75 0 010-2.474l2.47-2.47a1 1 0 011.414 1.414L6.164 17H18a1 1 0 001-1v-3a1 1 0 011-1z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@ export function ThreadIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGEleme
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12 19.25V20a.75.75 0 00.75-.75H12zm8.5-9a.75.75 0 001.5 0h-1.5zm-.75 3.5a.75.75 0 00-1.5 0h1.5zm-1.5 6.5a.75.75 0 001.5 0h-1.5zm-2.5-4a.75.75 0 000 1.5v-1.5zm6.5 1.5a.75.75 0 000-1.5v1.5zm-18.75.5V5.75H2v12.5h1.5zm8.5.25H3.75V20H12v-1.5zm8.5-12.75v4.5H22v-4.5h-1.5zM3.75 5.5H12V4H3.75v1.5zm8.25 0h8.25V4H12v1.5zm.75 13.75V4.75h-1.5v14.5h1.5zm5.5-5.5V17h1.5v-3.25h-1.5zm0 3.25v3.25h1.5V17h-1.5zm-2.5.75H19v-1.5h-3.25v1.5zm3.25 0h3.25v-1.5H19v1.5zm3-12A1.75 1.75 0 0020.25 4v1.5a.25.25 0 01.25.25H22zm-18.5 0a.25.25 0 01.25-.25V4A1.75 1.75 0 002 5.75h1.5zM2 18.25c0 .966.784 1.75 1.75 1.75v-1.5a.25.25 0 01-.25-.25H2z"
|
||||
d="M12 19v1a1 1 0 001-1h-1zm8-9a1 1 0 102 0h-2zm0 4a1 1 0 10-2 0h2zm-2 6a1 1 0 102 0h-2zm-2-4a1 1 0 100 2v-2zm6 2a1 1 0 100-2v2zM4 17V7H2v10h2zm8 1H5v2h7v-2zm8-11v3h2V7h-2zM5 6h7V4H5v2zm7 0h7V4h-7v2zm1 13V5h-2v14h2zm5-5v3h2v-3h-2zm0 3v3h2v-3h-2zm-2 1h3v-2h-3v2zm3 0h3v-2h-3v2zm3-11a3 3 0 00-3-3v2a1 1 0 011 1h2zM4 7a1 1 0 011-1V4a3 3 0 00-3 3h2zM2 17a3 3 0 003 3v-2a1 1 0 01-1-1H2z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -3,20 +3,20 @@ import { SVGProps } from 'react';
|
||||
export function ZapIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M3.75 12.75L8.75 2.75H18L15.25 8.25H21.25L6.75 21.25L8.89706 12.75H3.75Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
strokeWidth="2"
|
||||
d="M4.116 12.276l4.5-9A.5.5 0 019.063 3h8.058a.5.5 0 01.429.757l-2.091 3.486a.5.5 0 00.428.757h4.804a.5.5 0 01.332.873L7.381 21.023c-.38.34-.965-.042-.808-.527l2.219-6.842A.5.5 0 008.316 13H4.563a.5.5 0 01-.447-.724z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,33 +28,16 @@ export function NoteActions({
|
||||
|
||||
return (
|
||||
<Tooltip.Provider>
|
||||
<div className="-ml-1 mt-3 inline-flex w-full items-center">
|
||||
<div className="inline-flex items-center gap-2">
|
||||
<div className="-ml-1 mt-4 inline-flex w-full items-center">
|
||||
<div className="inline-flex items-center gap-8">
|
||||
<NoteReply id={id} pubkey={pubkey} root={root} />
|
||||
<NoteReaction id={id} pubkey={pubkey} />
|
||||
<NoteRepost id={id} pubkey={pubkey} />
|
||||
<NoteZap id={id} pubkey={pubkey} />
|
||||
</div>
|
||||
{extraButtons && (
|
||||
<>
|
||||
<div className="mx-2 block h-4 w-px bg-white/10 backdrop-blur-xl" />
|
||||
<div className="inline-flex items-center gap-2">
|
||||
<Tooltip.Root delayDuration={150}>
|
||||
<Tooltip.Trigger asChild>
|
||||
<Link
|
||||
to={`/notes/text/${id}`}
|
||||
className="group inline-flex h-7 w-7 items-center justify-center"
|
||||
>
|
||||
<FocusIcon className="h-5 w-5 text-white/80 group-hover:text-blue-400" />
|
||||
</Link>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white 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">
|
||||
Focus
|
||||
<Tooltip.Arrow className="fill-black" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
<div className="ml-auto">
|
||||
<div className="inline-flex items-center gap-3">
|
||||
<Tooltip.Root delayDuration={150}>
|
||||
<Tooltip.Trigger asChild>
|
||||
<button
|
||||
@@ -66,22 +49,22 @@ export function NoteActions({
|
||||
content: id,
|
||||
})
|
||||
}
|
||||
className="group inline-flex h-7 w-7 items-center justify-center"
|
||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
|
||||
>
|
||||
<ThreadIcon className="h-5 w-5 text-white/80 group-hover:text-blue-400" />
|
||||
<ThreadIcon className="h-5 w-5 group-hover:text-blue-500" />
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white 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">
|
||||
<Tooltip.Content className="-left-10 inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-200 px-3.5 text-sm text-neutral-900 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 dark:bg-neutral-800 dark:text-neutral-100">
|
||||
Open thread
|
||||
<Tooltip.Arrow className="fill-black" />
|
||||
<Tooltip.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
<MoreActions id={id} pubkey={pubkey} />
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
<MoreActions id={id} pubkey={pubkey} />
|
||||
</div>
|
||||
</Tooltip.Provider>
|
||||
);
|
||||
|
||||
@@ -30,26 +30,35 @@ export function MoreActions({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="group ml-auto inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
|
||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
|
||||
>
|
||||
<HorizontalDotsIcon className="h-5 w-5 group-hover:text-blue-500" />
|
||||
</button>
|
||||
</DropdownMenu.Trigger>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white 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">
|
||||
<Tooltip.Content className="-left-10 inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-200 px-3.5 text-sm text-neutral-900 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 dark:bg-neutral-800 dark:text-neutral-100">
|
||||
More
|
||||
<Tooltip.Arrow className="fill-black" />
|
||||
<Tooltip.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content className="flex w-[200px] flex-col overflow-hidden rounded-xl border border-white/10 bg-white/20 p-2 backdrop-blur-3xl focus:outline-none">
|
||||
<DropdownMenu.Content className="flex w-[200px] flex-col overflow-hidden rounded-xl border border-neutral-300 bg-neutral-200 focus:outline-none dark:border-neutral-700 dark:bg-neutral-800">
|
||||
<DropdownMenu.Item asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyLink()}
|
||||
className="inline-flex h-10 items-center rounded-md px-2 text-sm font-medium text-white hover:bg-white/10 focus:outline-none"
|
||||
className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-300 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-700"
|
||||
>
|
||||
Focus
|
||||
</button>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyLink()}
|
||||
className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-300 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-700"
|
||||
>
|
||||
Copy shareable link
|
||||
</button>
|
||||
@@ -58,7 +67,7 @@ export function MoreActions({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyID()}
|
||||
className="inline-flex h-10 items-center rounded-md px-2 text-sm font-medium text-white hover:bg-white/10 focus:outline-none"
|
||||
className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-300 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-700"
|
||||
>
|
||||
Copy ID
|
||||
</button>
|
||||
@@ -66,7 +75,7 @@ export function MoreActions({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
<DropdownMenu.Item asChild>
|
||||
<Link
|
||||
to={`/users/${pubkey}`}
|
||||
className="inline-flex h-10 items-center rounded-md px-2 text-sm font-medium text-white hover:bg-white/10 focus:outline-none"
|
||||
className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-300 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-700"
|
||||
>
|
||||
View profile
|
||||
</Link>
|
||||
|
||||
@@ -65,15 +65,15 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
|
||||
>
|
||||
{reaction ? (
|
||||
<img src={getReactionImage(reaction)} alt={reaction} className="h-6 w-6" />
|
||||
<img src={getReactionImage(reaction)} alt={reaction} className="h-5 w-5" />
|
||||
) : (
|
||||
<ReactionIcon className="h-5 w-5 group-hover:text-red-400" />
|
||||
<ReactionIcon className="h-5 w-5 group-hover:text-blue-500" />
|
||||
)}
|
||||
</button>
|
||||
</Popover.Trigger>
|
||||
<Popover.Portal>
|
||||
<Popover.Content
|
||||
className="select-none rounded-md bg-black px-1 py-1 text-sm will-change-[transform,opacity] data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=top]:animate-slideDownAndFade"
|
||||
className="select-none rounded-md bg-neutral-200 px-1 py-1 text-sm will-change-[transform,opacity] data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=top]:animate-slideDownAndFade dark:bg-neutral-800"
|
||||
sideOffset={0}
|
||||
side="top"
|
||||
>
|
||||
@@ -122,7 +122,7 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
<img src="/clown_face.png" alt="Clown Face" className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
<Popover.Arrow className="fill-black" />
|
||||
<Popover.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
|
||||
</Popover.Content>
|
||||
</Popover.Portal>
|
||||
</Popover.Root>
|
||||
|
||||
@@ -23,13 +23,13 @@ export function NoteReply({
|
||||
onClick={() => setReply(id, pubkey, root)}
|
||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
|
||||
>
|
||||
<ReplyIcon className="h-5 w-5 group-hover:text-green-500" />
|
||||
<ReplyIcon className="h-5 w-5 group-hover:text-blue-500" />
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white 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">
|
||||
<Tooltip.Content className="-left-10 inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-200 px-3.5 text-sm text-neutral-900 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 dark:bg-neutral-800 dark:text-neutral-100">
|
||||
Quick reply
|
||||
<Tooltip.Arrow className="fill-black" />
|
||||
<Tooltip.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
|
||||
@@ -48,7 +48,7 @@ export function NoteRepost({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
>
|
||||
<RepostIcon
|
||||
className={twMerge(
|
||||
'h-5 w-5 group-hover:text-blue-500',
|
||||
'h-5 w-5 group-hover:text-blue-600',
|
||||
isRepost ? 'text-blue-500' : ''
|
||||
)}
|
||||
/>
|
||||
@@ -56,9 +56,9 @@ export function NoteRepost({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
</AlertDialog.Trigger>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white 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">
|
||||
<Tooltip.Content className="-left-10 inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-200 px-3.5 text-sm text-neutral-900 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 dark:bg-neutral-800 dark:text-neutral-100">
|
||||
Repost
|
||||
<Tooltip.Arrow className="fill-black" />
|
||||
<Tooltip.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
|
||||
@@ -95,7 +95,7 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
type="button"
|
||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
|
||||
>
|
||||
<ZapIcon className="h-5 w-5 group-hover:text-orange-400" />
|
||||
<ZapIcon className="h-5 w-5 group-hover:text-blue-500" />
|
||||
</button>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
|
||||
@@ -56,7 +56,7 @@ export function ChildNote({ id, root }: { id: string; root?: string }) {
|
||||
Lume <span className="text-green-500">(System)</span>
|
||||
</h5>
|
||||
</div>
|
||||
<div className="-mt-5 flex items-start gap-3">
|
||||
<div className="-mt-3 flex items-start gap-3">
|
||||
<div className="w-10 shrink-0" />
|
||||
<div>
|
||||
<div className="relative z-20 mt-1 flex-1 select-text">
|
||||
@@ -81,7 +81,7 @@ export function ChildNote({ id, root }: { id: string; root?: string }) {
|
||||
<div className="absolute bottom-0 left-[18px] h-[calc(100%-3.6rem)] w-0.5 bg-gradient-to-t from-black/20 to-black/10 dark:from-white/20 dark:to-white/10" />
|
||||
<div className="mb-6 flex flex-col">
|
||||
<User pubkey={data.pubkey} time={data.created_at} />
|
||||
<div className="-mt-4 flex items-start gap-3">
|
||||
<div className="-mt-3 flex items-start gap-3">
|
||||
<div className="w-10 shrink-0" />
|
||||
<div className="relative z-20 flex-1">
|
||||
{renderKind(data)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
import { useMemo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Image } from '@shared/image';
|
||||
@@ -54,3 +54,5 @@ export function ArticleNote(props: { event?: NDKEvent }) {
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
export const MemoizedArticleNote = memo(ArticleNote);
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
DefaultVideoLayout,
|
||||
defaultLayoutIcons,
|
||||
} from '@vidstack/react/player/layouts/default';
|
||||
import { memo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Image } from '@shared/image';
|
||||
@@ -34,13 +35,19 @@ export function FileNote(props: { event?: NDKEvent }) {
|
||||
key={url}
|
||||
src={url}
|
||||
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
||||
load="visible"
|
||||
load="idle"
|
||||
aspectRatio="16/9"
|
||||
muted={true}
|
||||
crossorigin=""
|
||||
className="player"
|
||||
>
|
||||
<MediaProvider />
|
||||
<MediaProvider>
|
||||
<Poster
|
||||
className="vds-poster"
|
||||
src={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
||||
alt="poster"
|
||||
/>
|
||||
</MediaProvider>
|
||||
<DefaultAudioLayout
|
||||
icons={defaultLayoutIcons}
|
||||
smallLayoutWhen="(width < 500) or (height < 380)"
|
||||
@@ -61,10 +68,12 @@ export function FileNote(props: { event?: NDKEvent }) {
|
||||
<Link
|
||||
to={url}
|
||||
target="_blank"
|
||||
className="break-all font-normal text-blue-500 hover:text-blue-500"
|
||||
className="break-all font-normal text-blue-500 hover:text-blue-600"
|
||||
>
|
||||
{url}
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const MemoizedFileNote = memo(FileNote);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { useCallback } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
@@ -71,7 +71,7 @@ export function Repost({
|
||||
<User pubkey={event.pubkey} time={event.created_at} variant="repost" />
|
||||
<div className="relative flex flex-col">
|
||||
<User pubkey={embedEvent.pubkey} time={embedEvent.created_at} />
|
||||
<div className="-mt-4 flex items-start gap-3">
|
||||
<div className="-mt-3 flex items-start gap-3">
|
||||
<div className="w-10 shrink-0" />
|
||||
<div className="relative z-20 flex-1">
|
||||
{renderKind(embedEvent)}
|
||||
@@ -116,7 +116,7 @@ export function Repost({
|
||||
Lume <span className="text-green-500">(System)</span>
|
||||
</h5>
|
||||
</div>
|
||||
<div className="-mt-4 flex items-start gap-3">
|
||||
<div className="-mt-3 flex items-start gap-3">
|
||||
<div className="w-11 shrink-0" />
|
||||
<div>
|
||||
<div className="relative z-20 mt-1 flex-1 select-text">
|
||||
@@ -148,7 +148,7 @@ export function Repost({
|
||||
<User pubkey={event.pubkey} time={event.created_at} variant="repost" />
|
||||
<div className="relative flex flex-col">
|
||||
<User pubkey={data.pubkey} time={data.created_at} />
|
||||
<div className="-mt-4 flex items-start gap-3">
|
||||
<div className="-mt-3 flex items-start gap-3">
|
||||
<div className="w-10 shrink-0" />
|
||||
<div className="relative z-20 flex-1">
|
||||
{renderKind(data)}
|
||||
@@ -160,3 +160,5 @@ export function Repost({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const MemoizedRepost = memo(Repost);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { memo } from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import { Link } from 'react-router-dom';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
@@ -82,3 +83,5 @@ export function TextNote(props: { content?: string }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const MemoizedTextNote = memo(TextNote);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
|
||||
export function UnknownNote(props: { event?: NDKEvent }) {
|
||||
return (
|
||||
<div className="mt-2 flex w-full flex-col gap-2">
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<div className="inline-flex flex-col rounded-md bg-neutral-200 px-2 py-2 dark:bg-neutral-800">
|
||||
<span className="text-sm font-medium text-neutral-500 dark:text-neutral-400">
|
||||
Kind: {props.event.kind}
|
||||
@@ -11,7 +11,7 @@ export function UnknownNote(props: { event?: NDKEvent }) {
|
||||
Unsupport kind on newsfeed
|
||||
</p>
|
||||
</div>
|
||||
<div className="select-text whitespace-pre-line break-all text-neutral-800 dark:text-neutral-200">
|
||||
<div className="select-text whitespace-pre-line break-words text-neutral-800 dark:text-neutral-200">
|
||||
<p>{props.event.content.toString()}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export function Boost({ boost }: { boost: string }) {
|
||||
return <span className="break-words text-blue-400 hover:text-blue-500">{boost}</span>;
|
||||
return <span className="break-words text-blue-400 hover:text-blue-600">{boost}</span>;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export function Hashtag({ tag }: { tag: string }) {
|
||||
content: tag.replace('#', ''),
|
||||
})
|
||||
}
|
||||
className="break-all text-blue-500 hover:text-blue-500"
|
||||
className="cursor-default break-all text-blue-500 hover:text-blue-600"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { QRCodeSVG } from 'qrcode.react';
|
||||
import { memo } from 'react';
|
||||
|
||||
export function Invoice({ invoice }: { invoice: string }) {
|
||||
export const Invoice = memo(function Invoice({ invoice }: { invoice: string }) {
|
||||
return (
|
||||
<div className="mt-2 flex items-center rounded-lg bg-neutral-200 p-2 dark:bg-neutral-800">
|
||||
<span className="mt-2 flex items-center rounded-lg bg-neutral-200 p-2 dark:bg-neutral-800">
|
||||
<QRCodeSVG value={invoice} includeMargin={true} className="rounded-lg" />
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -30,7 +30,7 @@ export const MentionUser = memo(function MentionUser({ pubkey }: { pubkey: strin
|
||||
content: pubkey,
|
||||
})
|
||||
}
|
||||
className="break-words text-blue-500 hover:text-blue-500"
|
||||
className="break-words text-blue-500 hover:text-blue-600"
|
||||
>
|
||||
{'@' +
|
||||
(user?.name ||
|
||||
|
||||
@@ -11,30 +11,25 @@ export function ImagePreview({ urls, truncate }: { urls: string[]; truncate?: bo
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-3 overflow-hidden">
|
||||
<div className="flex flex-col gap-2">
|
||||
{urls.map((url) => (
|
||||
<div key={url} className="group relative min-w-0 shrink-0 grow-0 basis-full">
|
||||
<img
|
||||
src={url}
|
||||
alt="image"
|
||||
className={`${
|
||||
truncate ? 'h-auto max-h-[300px]' : 'h-auto'
|
||||
} w-full rounded-lg border border-white/10 object-cover`}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
style={{ contentVisibility: 'auto' }}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => downloadImage(url)}
|
||||
className="absolute right-2 top-2 hidden h-8 w-8 items-center justify-center rounded-md bg-black/50 backdrop-blur-md hover:bg-black/40 group-hover:inline-flex"
|
||||
>
|
||||
<DownloadIcon className="h-5 w-5 text-white" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
{urls.map((url) => (
|
||||
<div key={url} className="group relative min-w-0 shrink-0 grow-0 basis-full">
|
||||
<img
|
||||
src={url}
|
||||
alt="image"
|
||||
className={`${
|
||||
truncate ? 'h-auto max-h-[300px]' : 'h-auto'
|
||||
} w-full rounded-lg border border-white/10 object-cover`}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => downloadImage(url)}
|
||||
className="absolute right-2 top-2 hidden h-8 w-8 items-center justify-center rounded-md bg-black/50 backdrop-blur-md group-hover:inline-flex hover:bg-black/40"
|
||||
>
|
||||
<DownloadIcon className="h-5 w-5 text-white" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export function LinkPreview({ urls }: { urls: string[] }) {
|
||||
const domain = new URL(urls[0]);
|
||||
|
||||
return (
|
||||
<div className="mt-3 overflow-hidden rounded-lg bg-white/10 backdrop-blur-xl">
|
||||
<div className="rounded-lg bg-neutral-200 dark:bg-neutral-800">
|
||||
{status === 'loading' ? (
|
||||
<div className="flex flex-col">
|
||||
<div className="h-44 w-full animate-pulse bg-white/10 backdrop-blur-xl" />
|
||||
|
||||
@@ -4,21 +4,29 @@ import {
|
||||
DefaultVideoLayout,
|
||||
defaultLayoutIcons,
|
||||
} from '@vidstack/react/player/layouts/default';
|
||||
import { memo } from 'react';
|
||||
|
||||
export function VideoPreview({ urls }: { urls: string[] }) {
|
||||
export const VideoPreview = memo(function VideoPreview({ urls }: { urls: string[] }) {
|
||||
return (
|
||||
<div className="relative mt-3 flex w-full flex-col gap-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
{urls.map((url) => (
|
||||
<MediaPlayer
|
||||
key={url}
|
||||
src={url}
|
||||
load="visible"
|
||||
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
||||
load="idle"
|
||||
aspectRatio="16/9"
|
||||
crossorigin=""
|
||||
muted={true}
|
||||
className="player"
|
||||
>
|
||||
<MediaProvider />
|
||||
<MediaProvider>
|
||||
<Poster
|
||||
className="vds-poster"
|
||||
src={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
||||
alt="poster"
|
||||
/>
|
||||
</MediaProvider>
|
||||
<DefaultAudioLayout
|
||||
icons={defaultLayoutIcons}
|
||||
smallLayoutWhen="(width < 500) or (height < 380)"
|
||||
@@ -33,4 +41,4 @@ export function VideoPreview({ urls }: { urls: string[] }) {
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ export function NoteWrapper({
|
||||
<div className="relative">{reply && <ChildNote id={reply} root={root} />}</div>
|
||||
<div className="relative flex flex-col">
|
||||
<User pubkey={event.pubkey} time={event.created_at} />
|
||||
<div className="-mt-4 flex items-start gap-3">
|
||||
<div className="-mt-3 flex items-start gap-3">
|
||||
<div className="w-10 shrink-0" />
|
||||
<div className="relative z-20 flex-1">
|
||||
{cloneElement(
|
||||
|
||||
@@ -229,7 +229,7 @@ export const User = memo(function User({
|
||||
return (
|
||||
<div className="flex gap-3">
|
||||
<div className="inline-flex h-10 w-10 items-center justify-center">
|
||||
<RepostIcon className="h-6 w-6 text-blue-500" />
|
||||
<RepostIcon className="h-5 w-5 text-blue-500" />
|
||||
</div>
|
||||
<div className="inline-flex items-center gap-2">
|
||||
<Avatar.Root className="shrink-0">
|
||||
@@ -308,7 +308,7 @@ export const User = memo(function User({
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
style={{ contentVisibility: 'auto' }}
|
||||
className="h-10 w-10 rounded-lg border border-white/5 object-cover"
|
||||
className="h-10 w-10 rounded-lg object-cover"
|
||||
/>
|
||||
<Avatar.Fallback delayMs={300}>
|
||||
<img
|
||||
@@ -320,14 +320,15 @@ export const User = memo(function User({
|
||||
</Avatar.Root>
|
||||
</HoverCard.Trigger>
|
||||
<div className="flex flex-1 items-center gap-2">
|
||||
<h5 className="max-w-[15rem] truncate font-semibold text-neutral-900 dark:text-neutral-100">
|
||||
<div className="max-w-[15rem] truncate font-semibold text-neutral-950 dark:text-neutral-50">
|
||||
{user?.name ||
|
||||
user?.display_name ||
|
||||
user?.displayName ||
|
||||
displayNpub(pubkey, 16)}
|
||||
</h5>
|
||||
<span className="text-neutral-500 dark:text-neutral-300">·</span>
|
||||
<span className="text-neutral-500 dark:text-neutral-300">{createdAt}</span>
|
||||
</div>
|
||||
<div className="ml-auto text-neutral-500 dark:text-neutral-400">
|
||||
{createdAt}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<HoverCard.Portal>
|
||||
|
||||
@@ -7,11 +7,11 @@ import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons';
|
||||
import {
|
||||
ArticleNote,
|
||||
FileNote,
|
||||
MemoizedArticleNote,
|
||||
MemoizedFileNote,
|
||||
MemoizedRepost,
|
||||
MemoizedTextNote,
|
||||
NoteWrapper,
|
||||
Repost,
|
||||
TextNote,
|
||||
UnknownNote,
|
||||
} from '@shared/notes';
|
||||
import { TitleBar } from '@shared/titleBar';
|
||||
@@ -48,21 +48,21 @@ export function LocalFollowsWidget({ params }: { params: Widget }) {
|
||||
root={dbEvent.root_id}
|
||||
reply={dbEvent.reply_id}
|
||||
>
|
||||
<TextNote />
|
||||
<MemoizedTextNote />
|
||||
</NoteWrapper>
|
||||
);
|
||||
case NDKKind.Repost:
|
||||
return <Repost key={dbEvent.id} event={event} />;
|
||||
return <MemoizedRepost key={dbEvent.id} event={event} />;
|
||||
case 1063:
|
||||
return (
|
||||
<NoteWrapper key={dbEvent.id} event={event}>
|
||||
<FileNote />
|
||||
<MemoizedFileNote />
|
||||
</NoteWrapper>
|
||||
);
|
||||
case NDKKind.Article:
|
||||
return (
|
||||
<NoteWrapper key={dbEvent.id} event={event}>
|
||||
<ArticleNote />
|
||||
<MemoizedArticleNote />
|
||||
</NoteWrapper>
|
||||
);
|
||||
default:
|
||||
|
||||
@@ -7,11 +7,11 @@ import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons';
|
||||
import {
|
||||
ArticleNote,
|
||||
FileNote,
|
||||
MemoizedArticleNote,
|
||||
MemoizedFileNote,
|
||||
MemoizedRepost,
|
||||
MemoizedTextNote,
|
||||
NoteWrapper,
|
||||
Repost,
|
||||
TextNote,
|
||||
UnknownNote,
|
||||
} from '@shared/notes';
|
||||
import { NoteSkeleton } from '@shared/notes/skeleton';
|
||||
@@ -55,21 +55,21 @@ export function LocalNetworkWidget() {
|
||||
root={dbEvent.root_id}
|
||||
reply={dbEvent.reply_id}
|
||||
>
|
||||
<TextNote />
|
||||
<MemoizedTextNote />
|
||||
</NoteWrapper>
|
||||
);
|
||||
case NDKKind.Repost:
|
||||
return <Repost key={dbEvent.id} event={event} />;
|
||||
return <MemoizedRepost key={dbEvent.id} event={event} />;
|
||||
case 1063:
|
||||
return (
|
||||
<NoteWrapper key={dbEvent.id} event={event}>
|
||||
<FileNote />
|
||||
<MemoizedFileNote />
|
||||
</NoteWrapper>
|
||||
);
|
||||
case NDKKind.Article:
|
||||
return (
|
||||
<NoteWrapper key={dbEvent.id} event={event}>
|
||||
<ArticleNote />
|
||||
<MemoizedArticleNote />
|
||||
</NoteWrapper>
|
||||
);
|
||||
default:
|
||||
|
||||
@@ -4,12 +4,12 @@ import { useCallback } from 'react';
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import {
|
||||
ArticleNote,
|
||||
FileNote,
|
||||
MemoizedArticleNote,
|
||||
MemoizedFileNote,
|
||||
MemoizedTextNote,
|
||||
NoteActions,
|
||||
NoteReplyForm,
|
||||
NoteStats,
|
||||
TextNote,
|
||||
UnknownNote,
|
||||
} from '@shared/notes';
|
||||
import { RepliesList } from '@shared/notes/replies/list';
|
||||
@@ -29,11 +29,11 @@ export function LocalThreadWidget({ params }: { params: Widget }) {
|
||||
(event: NDKEvent) => {
|
||||
switch (event.kind) {
|
||||
case NDKKind.Text:
|
||||
return <TextNote content={event.content} />;
|
||||
return <MemoizedTextNote content={event.content} />;
|
||||
case NDKKind.Article:
|
||||
return <ArticleNote event={event} />;
|
||||
return <MemoizedArticleNote event={event} />;
|
||||
case 1063:
|
||||
return <FileNote event={event} />;
|
||||
return <MemoizedFileNote event={event} />;
|
||||
default:
|
||||
return <UnknownNote event={event} />;
|
||||
}
|
||||
|
||||
@@ -13,15 +13,15 @@ export function WidgetWrapper({
|
||||
|
||||
return (
|
||||
<Resizable
|
||||
size={{ width: width, height: '100vh' }}
|
||||
size={{ width: width, height: '100%' }}
|
||||
onResizeStart={(e) => e.preventDefault()}
|
||||
onResizeStop={(_e, _direction, _ref, d) => {
|
||||
setWidth((prevWidth) => prevWidth + d.width);
|
||||
}}
|
||||
minWidth={420}
|
||||
minHeight={'100vh'}
|
||||
maxWidth={600}
|
||||
className={twMerge(
|
||||
'h-full border-r border-neutral-100 pb-10 dark:border-neutral-900',
|
||||
'flex flex-col border-r border-neutral-100 dark:border-neutral-900',
|
||||
className
|
||||
)}
|
||||
enable={{ right: true }}
|
||||
|
||||
Reference in New Issue
Block a user