migrated to vite and vite-plugin-ssr

This commit is contained in:
Ren Amamiya
2023-04-22 17:56:09 +07:00
parent c50e507c14
commit b9bafc851e
67 changed files with 911 additions and 1060 deletions

View File

@@ -1,25 +0,0 @@
'use client';
import Link from 'next/link';
import { useSelectedLayoutSegments } from 'next/navigation';
export const ActiveLink = ({
href,
className,
activeClassName,
children,
}: {
href: string;
className: string;
activeClassName: string;
children: React.ReactNode;
}) => {
const segments = useSelectedLayoutSegments();
const isActive = href.includes(segments[1]);
return (
<Link prefetch={false} href={href} className={`${className}` + ' ' + (isActive ? `${activeClassName}` : '')}>
{children}
</Link>
);
};

View File

@@ -1,24 +1,20 @@
'use client';
import { platform } from '@tauri-apps/api/os';
import { ArrowLeft, ArrowRight, Refresh } from 'iconoir-react';
import { useRouter } from 'next/navigation';
import { useLayoutEffect, useState } from 'react';
export default function AppActions() {
const router = useRouter();
const [os, setOS] = useState('');
const goBack = () => {
router.back();
window.history.back();
};
const goForward = () => {
router.forward();
window.history.forward();
};
const reload = () => {
router.refresh();
window.location.reload();
};
useLayoutEffect(() => {

View File

@@ -1,12 +1,5 @@
import dynamic from 'next/dynamic';
const AppActions = dynamic(() => import('@components/appHeader/actions'), {
ssr: false,
});
const EventCollector = dynamic(() => import('@components/eventCollector'), {
ssr: false,
});
import AppActions from '@components/appHeader/actions';
import EventCollector from '@components/eventCollector';
export default function AppHeader({ collector }: { collector: boolean }) {
return (

View File

@@ -10,19 +10,6 @@ export default function ChannelList() {
return (
<div className="flex flex-col gap-px">
{/*
<Link
href="/explore/channels"
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">
<Globe width={12} height={12} className="text-zinc-500" />
</div>
<div>
<h5 className="text-sm font-medium text-zinc-500 group-hover:text-zinc-400">Browse channels</h5>
</div>
</Link>
*/}
{list.map((item) => (
<ChannelListItem key={item.event_id} data={item} />
))}

View File

@@ -1,31 +1,21 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useChannelMetadata } from '@utils/hooks/useChannelMetadata';
import Link from 'next/link';
export const ChannelListItem = ({ data }: { data: any }) => {
const channel = useChannelMetadata(data.event_id, data.metadata);
return (
<Link
prefetch={false}
href={`/nostr/channel?channel-id=${data.event_id}`}
<a
href={`channel?id=${data.event_id}`}
className="inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-900"
>
<div className="relative h-5 w-5 shrink-0 overflow-hidden rounded">
<ImageWithFallback
src={channel?.picture || DEFAULT_AVATAR}
alt={data.event_id}
fill={true}
className="rounded object-cover"
/>
<div className="relative h-5 w-5 shrink-0 rounded">
<img src={channel?.picture || DEFAULT_AVATAR} alt={data.event_id} className="h-5 w-5 rounded object-cover" />
</div>
<div>
<h5 className="truncate text-sm font-medium text-zinc-400">{channel?.name.toLowerCase()}</h5>
</div>
</Link>
</a>
);
};

View File

@@ -1,13 +1,11 @@
import { ChatListItem } from '@components/chats/chatListItem';
import { ChatModal } from '@components/chats/chatModal';
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { getChats } from '@utils/storage';
import useLocalStorage from '@rehooks/local-storage';
import Link from 'next/link';
import { useEffect, useState } from 'react';
export default function ChatList() {
@@ -33,17 +31,15 @@ export default function ChatList() {
return (
<div className="flex flex-col gap-px">
<Link
prefetch={false}
href={`/nostr/chat?pubkey=${activeAccount.pubkey}`}
<a
href={`/chat?pubkey=${activeAccount.pubkey}`}
className="inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-900"
>
<div className="relative h-5 w-5 shrink overflow-hidden rounded bg-white">
<ImageWithFallback
<div className="relative h-5 w-5 shrink rounded bg-white">
<img
src={profile?.picture || DEFAULT_AVATAR}
alt={activeAccount.pubkey}
fill={true}
className="rounded object-cover"
className="h-5 w-5 rounded object-cover"
/>
</div>
<div>
@@ -51,7 +47,7 @@ export default function ChatList() {
{profile?.display_name || profile?.name} <span className="text-zinc-500">(you)</span>
</h5>
</div>
</Link>
</a>
{list.map((item) => (
<ChatListItem key={item.id} pubkey={item.pubkey} />
))}

View File

@@ -1,34 +1,24 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfileMetadata } from '@utils/hooks/useProfileMetadata';
import { shortenKey } from '@utils/shortenKey';
import Link from 'next/link';
export const ChatListItem = ({ pubkey }: { pubkey: string }) => {
const profile = useProfileMetadata(pubkey);
return (
<Link
prefetch={false}
href={`/nostr/chat?pubkey=${pubkey}`}
<a
href={`/chat?pubkey=${pubkey}`}
className="inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-900"
>
<div className="relative h-5 w-5 shrink overflow-hidden rounded">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}
fill={true}
className="rounded object-cover"
/>
<div className="relative h-5 w-5 shrink rounded">
<img src={profile?.picture || DEFAULT_AVATAR} alt={pubkey} className="h-5 w-5 rounded object-cover" />
</div>
<div>
<h5 className="text-sm font-medium text-zinc-400">
{profile?.display_name || profile?.name || shortenKey(pubkey)}
</h5>
</div>
</Link>
</a>
);
};

View File

@@ -1,28 +1,24 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { shortenKey } from '@utils/shortenKey';
import { useRouter } from 'next/navigation';
import { navigate } from 'vite-plugin-ssr/client/router';
export const ChatModalUser = ({ data }: { data: any }) => {
const router = useRouter();
const profile = JSON.parse(data.metadata);
const openNewChat = () => {
router.push(`/nostr/chat?pubkey=${data.pubkey}`, { forceOptimisticNavigation: true });
navigate(`/chat?pubkey=${data.pubkey}`);
};
return (
<div className="group flex items-center justify-between px-3 py-2 hover:bg-zinc-800">
<div className="flex items-center gap-2">
<div className="relative h-10 w-10 shrink overflow-hidden rounded-md">
<ImageWithFallback
<div className="relative h-10 w-10 shrink-0 rounded-md">
<img
src={profile?.picture || DEFAULT_AVATAR}
alt={data.pubkey}
fill={true}
className="rounded-md object-cover"
className="h-10 w-10 rounded-md object-cover"
/>
</div>
<div className="flex w-full flex-1 flex-col items-start text-start">

View File

@@ -1,5 +1,3 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfileMetadata } from '@utils/hooks/useProfileMetadata';
@@ -15,13 +13,8 @@ export const MessageUser = ({ pubkey, time }: { pubkey: string; time: number })
return (
<div className="group flex items-start gap-3">
<div className="relative h-9 w-9 shrink overflow-hidden rounded-md">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}
fill={true}
className="rounded-md object-cover"
/>
<div className="relative h-9 w-9 shrink rounded-md">
<img src={profile?.picture || DEFAULT_AVATAR} alt={pubkey} className="h-9 w-9 rounded-md object-cover" />
</div>
<div className="flex w-full flex-1 items-start justify-between">
<div className="flex items-baseline gap-2 text-sm">

View File

@@ -1,5 +1,3 @@
'use client';
import { NetworkStatusIndicator } from '@components/networkStatusIndicator';
import { RelayContext } from '@components/relaysProvider';

View File

@@ -1,36 +0,0 @@
import { noteContentAtom } from '@stores/note';
import data from '@emoji-mart/data';
import Picker from '@emoji-mart/react';
import * as Popover from '@radix-ui/react-popover';
import { Emoji } from 'iconoir-react';
import { useAtom } from 'jotai';
export default function EmojiPicker() {
const [value, setValue] = useAtom(noteContentAtom);
return (
<Popover.Root>
<Popover.Trigger asChild>
<button className="inline-flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-zinc-700">
<Emoji width={16} height={16} className="text-zinc-400" />
</button>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content
className="rounded-md 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"
sideOffset={5}
>
<Picker
data={data}
emojiSize={16}
navPosition={'none'}
skinTonePosition={'none'}
onEmojiSelect={(res) => setValue(value + ' ' + res.native)}
/>
<Popover.Arrow className="fill-[#141516]" />
</Popover.Content>
</Popover.Portal>
</Popover.Root>
);
}

View File

@@ -1,26 +0,0 @@
import { DEFAULT_AVATAR } from '@stores/constants';
import Image from 'next/image';
import { memo, useEffect, useState } from 'react';
export const ImageWithFallback = memo(function ImageWithFallback({
src,
alt,
fill,
className,
}: {
src: string;
alt: string;
fill: boolean;
className: string;
}) {
const [error, setError] = useState(null);
useEffect(() => {
setError(null);
}, [src]);
return (
<Image src={error ? DEFAULT_AVATAR : src} alt={alt} fill={fill} className={className} onError={setError} priority />
);
});

View File

@@ -0,0 +1,39 @@
import AppHeader from '@components/appHeader';
import MultiAccounts from '@components/multiAccounts';
import Navigation from '@components/navigation';
export default function NewsfeedLayout({ children }: { children: React.ReactNode }) {
return (
<div className="h-screen w-screen bg-zinc-50 text-zinc-900 dark:bg-black dark:text-white">
<div className="flex h-screen w-full flex-col">
<div
data-tauri-drag-region
className="relative h-11 shrink-0 border-b border-zinc-100 bg-white dark:border-zinc-900 dark:bg-black"
>
<AppHeader collector={true} />
</div>
<div className="relative flex min-h-0 w-full flex-1">
<div className="relative w-[68px] shrink-0 border-r border-zinc-900">
<MultiAccounts />
</div>
<div className="grid w-full grid-cols-4 xl:grid-cols-5">
<div className="scrollbar-hide col-span-1 overflow-y-auto overflow-x-hidden border-r border-zinc-900">
<Navigation />
</div>
<div className="col-span-3 m-3 overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900 shadow-input shadow-black/20 xl:col-span-2 xl:mr-1.5">
<div className="h-full w-full rounded-lg">{children}</div>
</div>
<div className="col-span-3 m-3 hidden overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900 shadow-input shadow-black/20 xl:col-span-2 xl:ml-1.5 xl:flex">
<div className="flex h-full w-full items-center justify-center">
<p className="select-text p-8 text-center text-zinc-400">
This feature hasn&apos;t implemented yet, so resize Lume to the initial size for a better experience.
I&apos;m sorry for this inconvenience, and I swear I will add it soon 😁
</p>
</div>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,17 @@
import AppHeader from '@components/appHeader';
export default function OnboardingLayout({ children }: { children: React.ReactNode }) {
return (
<div className="h-screen w-screen bg-zinc-50 text-zinc-900 dark:bg-black dark:text-white">
<div className="flex h-screen w-full flex-col">
<div
data-tauri-drag-region
className="relative h-11 shrink-0 border-b border-zinc-100 bg-white dark:border-zinc-900 dark:bg-black"
>
<AppHeader collector={false} />
</div>
<div className="relative flex min-h-0 w-full flex-1">{children}</div>
</div>
</div>
);
}

12
src/components/link.tsx Normal file
View File

@@ -0,0 +1,12 @@
import { usePageContext } from '@utils/hooks/usePageContext';
import { AnchorHTMLAttributes, ClassAttributes } from 'react';
export function Link(
props: JSX.IntrinsicAttributes & ClassAttributes<HTMLAnchorElement> & AnchorHTMLAttributes<HTMLAnchorElement>,
activeClass: string
) {
const pageContext = usePageContext();
const className = [props.className, pageContext.urlPathname === props.href && activeClass].filter(Boolean).join(' ');
return <a {...props} className={className} />;
}

View File

@@ -1,20 +1,16 @@
'use client';
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 Image from 'next/image';
import { useRouter } from 'next/navigation';
import { nip19 } from 'nostr-tools';
import { navigate } from 'vite-plugin-ssr/client/router';
export const ActiveAccount = ({ user }: { user: any }) => {
const router = useRouter();
const userData = JSON.parse(user.metadata);
const openProfilePage = () => {
router.push(`/nostr/user?pubkey=${user.pubkey}`, { forceOptimisticNavigation: true });
navigate(`/user?pubkey=${user.pubkey}`);
};
const copyPublicKey = async () => {
@@ -25,12 +21,10 @@ export const ActiveAccount = ({ user }: { user: any }) => {
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<button className="relative h-11 w-11 rounded-lg">
<Image
<img
src={userData.picture || DEFAULT_AVATAR}
alt="user's avatar"
fill={true}
className="rounded-lg object-cover"
priority
className="h-11 w-11 rounded-lg object-cover"
/>
</button>
</DropdownMenu.Trigger>

View File

@@ -1,6 +1,5 @@
import { DEFAULT_AVATAR } from '@stores/constants';
import Image from 'next/image';
import { memo } from 'react';
export const InactiveAccount = memo(function InactiveAccount({ user }: { user: any }) {
@@ -12,13 +11,7 @@ export const InactiveAccount = memo(function InactiveAccount({ user }: { user: a
return (
<button onClick={() => setCurrentUser()} className="relative h-11 w-11 shrink rounded-lg">
<Image
src={userData.picture || DEFAULT_AVATAR}
alt="user's avatar"
fill={true}
className="rounded-lg object-cover"
priority
/>
<img src={userData.picture || DEFAULT_AVATAR} alt="user's avatar" className="h-11 w-11 rounded-lg object-cover" />
</button>
);
});

View File

@@ -1,5 +1,3 @@
'use client';
import { ActiveAccount } from '@components/multiAccounts/activeAccount';
import { InactiveAccount } from '@components/multiAccounts/inactiveAccount';
@@ -11,7 +9,6 @@ import LumeSymbol from '@assets/icons/Lume';
import useLocalStorage from '@rehooks/local-storage';
import { Plus } from 'iconoir-react';
import Link from 'next/link';
import { useCallback, useEffect, useState } from 'react';
export default function MultiAccounts() {
@@ -38,21 +35,19 @@ export default function MultiAccounts() {
return (
<div className="flex h-full flex-col items-center justify-between px-2 pb-4 pt-3">
<div className="flex flex-col gap-4">
<Link
prefetch={false}
<a
href="/explore"
className="group relative flex h-11 w-11 shrink cursor-pointer items-center justify-center rounded-lg bg-zinc-900 hover:bg-zinc-800"
>
<LumeSymbol className="h-6 w-auto text-zinc-400 group-hover:text-zinc-200" />
</Link>
</a>
<div>{users.map((user) => renderAccount(user))}</div>
<Link
prefetch={false}
<a
href="/onboarding"
className="group relative flex h-11 w-11 shrink cursor-pointer items-center justify-center rounded-lg border-2 border-dashed border-zinc-600 hover:border-zinc-400"
>
<Plus width={16} height={16} className="text-zinc-400 group-hover:text-zinc-200" />
</Link>
</a>
</div>
<div className="flex flex-col gap-0.5 text-center">
<span className="animate-moveBg from-fuchsia-300 via-orange-100 to-amber-300 text-sm font-black uppercase leading-tight text-zinc-600 hover:bg-gradient-to-r hover:bg-clip-text hover:text-transparent">

View File

@@ -1,5 +1,3 @@
'use client';
import ChannelList from '@components/channels/channelList';
import * as Collapsible from '@radix-ui/react-collapsible';

View File

@@ -1,5 +1,3 @@
'use client';
import ChatList from '@components/chats/chatList';
import * as Collapsible from '@radix-ui/react-collapsible';

View File

@@ -1,7 +1,3 @@
'use client';
import { ActiveLink } from '@components/activeLink';
import * as Collapsible from '@radix-ui/react-collapsible';
import { Bonfire, NavArrowUp, PeopleTag } from 'iconoir-react';
import { useState } from 'react';
@@ -23,22 +19,22 @@ export default function Newsfeed() {
<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="/nostr/newsfeed/following"
activeClassName="dark:bg-zinc-900 dark:text-zinc-100 hover:dark:bg-zinc-800"
<a
href="/newsfeed/following"
//activeClassName="dark:bg-zinc-900 dark:text-zinc-100 hover:dark:bg-zinc-800"
className="flex h-8 items-center gap-2.5 rounded-md px-2.5 text-sm font-medium hover:text-zinc-200"
>
<PeopleTag width={16} height={16} className="text-zinc-500" />
<span>Following</span>
</ActiveLink>
<ActiveLink
href="/nostr/newsfeed/circle"
activeClassName="dark:bg-zinc-900 dark:text-zinc-100 hover:dark:bg-zinc-800"
</a>
<a
href="/newsfeed/circle"
//activeClassName="dark:bg-zinc-900 dark:text-zinc-100 hover:dark:bg-zinc-800"
className="flex h-8 items-center gap-2.5 rounded-md px-2.5 text-sm font-medium hover:text-zinc-200"
>
<Bonfire width={16} height={16} className="text-zinc-500" />
<span>Circle</span>
</ActiveLink>
</a>
</Collapsible.Content>
</div>
</Collapsible.Root>

View File

@@ -4,11 +4,10 @@ import { UserExtend } from '@components/user/extend';
import { contentParser } from '@utils/parser';
import { useRouter } from 'next/navigation';
import { memo } from 'react';
import { navigate } from 'vite-plugin-ssr/client/router';
export const NoteBase = memo(function NoteBase({ event }: { event: any }) {
const router = useRouter();
const content = contentParser(event.content, event.tags);
const parentNote = () => {
@@ -22,13 +21,13 @@ export const NoteBase = memo(function NoteBase({ event }: { event: any }) {
const openUserPage = (e) => {
e.stopPropagation();
router.push(`/nostr/user?pubkey=${event.pubkey}`, { forceOptimisticNavigation: true });
navigate(`/user?pubkey=${event.pubkey}`);
};
const openThread = (e) => {
const selection = window.getSelection();
if (selection.toString().length === 0) {
router.push(`/nostr/newsfeed/note?id=${event.parent_id}`, { forceOptimisticNavigation: true });
navigate(`/newsfeed/note?id=${event.parent_id}`);
} else {
e.stopPropagation();
}

View File

@@ -1,4 +1,3 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { RelayContext } from '@components/relaysProvider';
import { UserExtend } from '@components/user/extend';
@@ -7,9 +6,9 @@ import { dateToUnix } from '@utils/getDate';
import * as Dialog from '@radix-ui/react-dialog';
import useLocalStorage from '@rehooks/local-storage';
import { ChatLines, OpenNewWindow } from 'iconoir-react';
import { useRouter } from 'next/navigation';
import { getEventHash, signEvent } from 'nostr-tools';
import { useContext, useState } from 'react';
import { navigate } from 'vite-plugin-ssr/client/router';
export const NoteComment = ({
count,
@@ -24,7 +23,6 @@ export const NoteComment = ({
eventTime: number;
eventContent: any;
}) => {
const router = useRouter();
const [pool, relays]: any = useContext(RelayContext);
const [open, setOpen] = useState(false);
@@ -34,7 +32,7 @@ export const NoteComment = ({
const profile = activeAccount.metadata ? JSON.parse(activeAccount.metadata) : null;
const openThread = () => {
router.push(`/nostr/newsfeed/note?id=${eventID}`, { forceOptimisticNavigation: true });
navigate(`/newsfeed/note?id=${eventID}`);
};
const submitEvent = () => {
@@ -84,12 +82,7 @@ export const NoteComment = ({
<div className="flex gap-2">
<div>
<div className="relative h-11 w-11 shrink-0 overflow-hidden rounded-md border border-white/10">
<ImageWithFallback
src={profile?.picture}
alt="user's avatar"
fill={true}
className="rounded-md object-cover"
/>
<img src={profile?.picture} alt="user's avatar" className="h-11 w-11 rounded-md object-cover" />
</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">

View File

@@ -1,18 +1,9 @@
import Image from 'next/image';
import { memo } from 'react';
export const ImagePreview = memo(function ImagePreview({ url, size }: { url: string; size: string }) {
return (
<div className={`relative h-full ${size === 'large' ? 'w-4/5' : 'w-1/2'} mt-2 rounded-lg border border-zinc-800`}>
<Image
src={url}
alt={url}
width="0"
height="0"
sizes="100vw"
className="h-auto w-full rounded-lg object-cover"
priority
/>
<img src={url} alt={url} className="h-auto w-full rounded-lg object-cover" />
</div>
);
});

View File

@@ -1,23 +0,0 @@
import Image from 'next/image';
import Link from 'next/link';
export default function LinkCard({ data }: { data: any }) {
return (
<Link
href={data['url']}
target={'_blank'}
className="relative flex flex-col overflow-hidden rounded-lg border border-zinc-700"
>
<div className="relative aspect-video h-auto w-full">
<Image src={data['image']} alt="image preview" fill={true} className="object-cover" />
</div>
<div className="flex flex-col gap-2 p-4">
<div>
<h5 className="font-semibold leading-tight">{data['title']}</h5>
<p className="text-sm text-zinc-300">{data['description']}</p>
</div>
<span className="text-sm text-zinc-500">{data['url']}</span>
</div>
</Link>
);
}

View File

@@ -4,11 +4,10 @@ import { UserExtend } from '@components/user/extend';
import { contentParser } from '@utils/parser';
import { useRouter } from 'next/navigation';
import { memo, useCallback, useContext, useEffect, useState } from 'react';
import { navigate } from 'vite-plugin-ssr/client/router';
export const RootNote = memo(function RootNote({ event }: { event: any }) {
const router = useRouter();
const [pool, relays]: any = useContext(RelayContext);
const [data, setData] = useState(null);
@@ -16,13 +15,13 @@ export const RootNote = memo(function RootNote({ event }: { event: any }) {
const openUserPage = (e) => {
e.stopPropagation();
router.push(`/nostr/user?pubkey=${event.pubkey}`, { forceOptimisticNavigation: true });
navigate(`/user?pubkey=${event.pubkey}`);
};
const openThread = (e) => {
const selection = window.getSelection();
if (selection.toString().length === 0) {
router.push(`/nostr/newsfeed/note?id=${event.parent_id}`, { forceOptimisticNavigation: true });
navigate(`/newsfeed/note?id=${event.parent_id}`);
} else {
e.stopPropagation();
}

View File

@@ -1,5 +1,3 @@
'use client';
import { RelayContext } from '@components/relaysProvider';
import { UserFollow } from '@components/user/follow';

View File

@@ -1,5 +1,3 @@
'use client';
import { RelayContext } from '@components/relaysProvider';
import { UserFollow } from '@components/user/follow';

View File

@@ -1,6 +1,3 @@
'use client';
import { ImageWithFallback } from '@components/imageWithFallback';
import { RelayContext } from '@components/relaysProvider';
import { DEFAULT_AVATAR } from '@stores/constants';
@@ -8,7 +5,6 @@ import { DEFAULT_AVATAR } from '@stores/constants';
import { shortenKey } from '@utils/shortenKey';
import destr from 'destr';
import Image from 'next/image';
import { Author } from 'nostr-relaypool';
import { useContext, useEffect, useState } from 'react';
@@ -27,21 +23,11 @@ export default function ProfileMetadata({ id }: { id: string }) {
<>
<div className="relative">
<div className="relative h-56 w-full rounded-t-lg bg-zinc-800">
<Image
src={profile?.banner || DEFAULT_BANNER}
alt="user's banner"
fill={true}
className="h-full w-full object-cover"
/>
<img src={profile?.banner || DEFAULT_BANNER} alt="user's banner" className="h-58 w-full object-cover" />
</div>
<div className="relative -top-8 z-10 px-4">
<div className="relative h-16 w-16 rounded-lg bg-zinc-900 ring-2 ring-zinc-900">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={id}
fill={true}
className="rounded-lg object-cover"
/>
<img src={profile?.picture || DEFAULT_AVATAR} alt={id} className="h-16 w-16 rounded-lg object-cover" />
</div>
</div>
</div>

View File

@@ -1,5 +1,3 @@
'use client';
import { NoteBase } from '@components/note/base';
import { RelayContext } from '@components/relaysProvider';

View File

@@ -1,5 +1,3 @@
'use client';
import { DEFAULT_RELAYS } from '@stores/constants';
import { RelayPool } from 'nostr-relaypool';

View File

@@ -1,5 +1,3 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfileMetadata } from '@utils/hooks/useProfileMetadata';
@@ -13,12 +11,7 @@ export const UserBase = memo(function UserBase({ pubkey }: { pubkey: string }) {
return (
<div className="flex items-center gap-2">
<div className="relative h-11 w-11 shrink overflow-hidden rounded-full border border-white/10">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}
fill={true}
className="rounded-full object-cover"
/>
<img src={profile?.picture || DEFAULT_AVATAR} alt={pubkey} className="h-11 w-11 rounded-full object-cover" />
</div>
<div className="flex w-full flex-1 flex-col items-start text-start">
<span className="truncate font-medium leading-tight text-zinc-200">

View File

@@ -1,5 +1,3 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfileMetadata } from '@utils/hooks/useProfileMetadata';
@@ -16,12 +14,7 @@ export const UserExtend = ({ pubkey, time }: { pubkey: string; time: number }) =
return (
<div className="group flex h-11 items-center gap-2">
<div className="relative h-11 w-11 shrink overflow-hidden rounded-md bg-white">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}
fill={true}
className="rounded-md object-cover"
/>
<img src={profile?.picture || DEFAULT_AVATAR} alt={pubkey} className="h-11 w-11 rounded-md object-cover" />
</div>
<div className="flex w-full flex-1 items-start justify-between">
<div className="flex flex-col gap-1">

View File

@@ -1,5 +1,3 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfileMetadata } from '@utils/hooks/useProfileMetadata';
@@ -11,12 +9,7 @@ export const UserFollow = ({ pubkey }: { pubkey: string }) => {
return (
<div className="flex items-center gap-2">
<div className="relative h-11 w-11 shrink overflow-hidden rounded-full border border-white/10">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}
fill={true}
className="rounded-full object-cover"
/>
<img src={profile?.picture || DEFAULT_AVATAR} alt={pubkey} className="h-11 w-11 rounded-full object-cover" />
</div>
<div className="flex w-full flex-1 flex-col items-start text-start">
<span className="truncate font-medium leading-tight text-zinc-200">

View File

@@ -1,5 +1,3 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfileMetadata } from '@utils/hooks/useProfileMetadata';
@@ -17,11 +15,10 @@ export const UserLarge = ({ pubkey, time }: { pubkey: string; time: number }) =>
return (
<div className="flex items-center gap-2">
<div className="relative h-11 w-11 shrink overflow-hidden rounded-md bg-white">
<ImageWithFallback
<img
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}
fill={true}
className="rounded-md border border-white/10 object-cover"
className="h-11 w-11 rounded-md border border-white/10 object-cover"
/>
</div>
<div className="w-full flex-1">

View File

@@ -1,5 +1,3 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfileMetadata } from '@utils/hooks/useProfileMetadata';
@@ -11,12 +9,7 @@ export const UserMini = ({ pubkey }: { pubkey: string }) => {
return (
<div className="group flex items-start gap-1">
<div className="relative h-7 w-7 shrink overflow-hidden rounded border border-white/10">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}
fill={true}
className="rounded object-cover"
/>
<img src={profile?.picture || DEFAULT_AVATAR} alt={pubkey} className="h-7 w-7 rounded object-cover" />
</div>
<span className="text-xs font-medium leading-none text-zinc-500">
Replying to {profile?.name || shortenKey(pubkey)}

View File

@@ -1,5 +1,3 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfileMetadata } from '@utils/hooks/useProfileMetadata';
@@ -16,12 +14,7 @@ export const UserQuoteRepost = ({ pubkey, time }: { pubkey: string; time: number
return (
<div className="group flex items-center gap-2">
<div className="relative h-11 w-11 shrink overflow-hidden rounded-md bg-white">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}
fill={true}
className="rounded-md object-cover"
/>
<img src={profile?.picture || DEFAULT_AVATAR} alt={pubkey} className="h-11 w-11 rounded-md object-cover" />
</div>
<div className="flex items-baseline gap-2 text-sm">
<h5 className="font-semibold leading-tight group-hover:underline">