update design

This commit is contained in:
Ren Amamiya 2023-05-19 08:37:56 +07:00
parent 064700bd5d
commit 4be64f7730
15 changed files with 200 additions and 259 deletions

View File

@ -13,17 +13,11 @@ export function LayoutChannel({ children }: { children: React.ReactNode }) {
<AppHeader /> <AppHeader />
</div> </div>
<div className="relative flex min-h-0 w-full flex-1"> <div className="relative flex min-h-0 w-full flex-1">
<div className="relative w-[68px] shrink-0 border-r border-zinc-900"> <div className="relative flex flex-row flex-wrap shrink-0">
<MultiAccounts /> <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 /> <Navigation />
</div> </div>
<div className="col-span-3 m-3 overflow-hidden xl:col-span-4"> <div className="w-full h-full">{children}</div>
{children}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -13,17 +13,11 @@ export function LayoutChat({ children }: { children: React.ReactNode }) {
<AppHeader /> <AppHeader />
</div> </div>
<div className="relative flex min-h-0 w-full flex-1"> <div className="relative flex min-h-0 w-full flex-1">
<div className="relative w-[68px] shrink-0 border-r border-zinc-900"> <div className="relative flex flex-row flex-wrap shrink-0">
<MultiAccounts /> <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 /> <Navigation />
</div> </div>
<div className="col-span-3 m-3 overflow-hidden xl:col-span-4"> <div className="w-full h-full">{children}</div>
{children}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -191,7 +191,7 @@ export function Page() {
() => { () => {
updateLastLogin(dateToUnix(now.current)); updateLastLogin(dateToUnix(now.current));
timeout = setTimeout(() => { timeout = setTimeout(() => {
navigate("/app/today", { overwriteLastHistoryEntry: true }); navigate("/app/space", { overwriteLastHistoryEntry: true });
}, 5000); }, 5000);
}, },
); );

View File

@ -14,7 +14,10 @@ import useSWRSubscription from "swr/subscription";
export default function NoteMetadata({ export default function NoteMetadata({
id, id,
eventPubkey, eventPubkey,
}: { id: string; eventPubkey: string }) { }: {
id: string;
eventPubkey: string;
}) {
const pool: any = useContext(RelayContext); const pool: any = useContext(RelayContext);
const [replies, setReplies] = useState(0); const [replies, setReplies] = useState(0);
@ -63,20 +66,10 @@ export default function NoteMetadata({
}); });
return ( return (
<div className="mt-4 flex h-12 items-center justify-between border-t border-zinc-800/50"> <div className="mt-4 flex h-12 items-center gap-4 border-t border-zinc-800/50">
<div className="flex items-center gap-16">
<NoteReply id={id} replies={replies} /> <NoteReply id={id} replies={replies} />
<NoteRepost id={id} pubkey={eventPubkey} reposts={reposts} /> <NoteRepost id={id} pubkey={eventPubkey} reposts={reposts} />
<NoteZap zaps={zaps} /> <NoteZap zaps={zaps} />
</div> </div>
<Tooltip message="Save to Space">
<button
type="button"
className="inline-flex w-4 h-4 rounded justify-center items-center gap-1 hover:bg-zinc-800"
>
<PlusIcon className="w-3 h-3 text-zinc-400" />
</button>
</Tooltip>
</div>
); );
} }

View File

@ -13,17 +13,11 @@ export function LayoutNewsfeed({ children }: { children: React.ReactNode }) {
<AppHeader /> <AppHeader />
</div> </div>
<div className="relative flex min-h-0 w-full flex-1"> <div className="relative flex min-h-0 w-full flex-1">
<div className="relative w-[68px] shrink-0 border-r border-zinc-900"> <div className="relative flex flex-row flex-wrap shrink-0">
<MultiAccounts /> <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 /> <Navigation />
</div> </div>
<div className="col-span-3 overflow-hidden xl:col-span-4"> <div className="w-full h-full">{children}</div>
{children}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,4 +1,4 @@
import { CreateViewModal } from "@app/today/components/views/createModal"; import { CreateViewModal } from "@app/space/components/views/createModal";
export function Header() { export function Header() {
return ( return (

View File

@ -13,17 +13,11 @@ export function LayoutNewsfeed({ children }: { children: React.ReactNode }) {
<AppHeader /> <AppHeader />
</div> </div>
<div className="relative flex min-h-0 w-full flex-1"> <div className="relative flex min-h-0 w-full flex-1">
<div className="relative w-[68px] shrink-0 border-r border-zinc-900"> <div className="relative flex flex-row flex-wrap shrink-0">
<MultiAccounts /> <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 /> <Navigation />
</div> </div>
<div className="col-span-3 overflow-hidden xl:col-span-4"> <div className="w-full h-full">{children}</div>
{children}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,7 +1,132 @@
import { NoteBase } from "@app/note/components/base";
import { NoteQuoteRepost } from "@app/note/components/quoteRepost";
import { NoteSkeleton } from "@app/note/components/skeleton";
import { Header } from "@app/space/components/header";
import { getNotes } from "@utils/storage";
import { useInfiniteQuery } from "@tanstack/react-query";
import { useVirtualizer } from "@tanstack/react-virtual";
import { useEffect, useRef } from "react";
const ITEM_PER_PAGE = 10;
const TIME = Math.floor(Date.now() / 1000);
export function Page() { export function Page() {
const {
status,
error,
data,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
}: any = useInfiniteQuery({
queryKey: ["following"],
queryFn: async ({ pageParam = 0 }) => {
return await getNotes(TIME, ITEM_PER_PAGE, pageParam);
},
getNextPageParam: (lastPage) => lastPage.nextCursor,
});
const allRows = data ? data.pages.flatMap((d: { data: any }) => d.data) : [];
const parentRef = useRef();
const rowVirtualizer = useVirtualizer({
count: hasNextPage ? allRows.length + 1 : allRows.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 400,
overscan: 2,
});
const itemsVirtualizer = rowVirtualizer.getVirtualItems();
useEffect(() => {
const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse();
if (!lastItem) {
return;
}
if (
lastItem.index >= allRows.length - 1 &&
hasNextPage &&
!isFetchingNextPage
) {
fetchNextPage();
}
}, [fetchNextPage, allRows.length, rowVirtualizer.getVirtualItems()]);
return ( return (
<div
ref={parentRef}
className="scrollbar-hide flex h-full flex-col justify-between gap-1.5 overflow-y-auto"
style={{ contain: "strict" }}
>
<div className="pt-1.5">
{status === "loading" ? (
<div className="px-3 py-1.5">
<div className="rounded-md border border-zinc-800 bg-zinc-900 px-3 py-3 shadow-input shadow-black/20">
<NoteSkeleton />
</div>
</div>
) : status === "error" ? (
<div>{error.message}</div>
) : (
<div
className="relative w-full"
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
}}
>
<div
className="absolute left-0 top-0 w-full"
style={{
transform: `translateY(${
itemsVirtualizer[0].start -
rowVirtualizer.options.scrollMargin
}px)`,
}}
>
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
const note = allRows[virtualRow.index];
if (note) {
if (note.kind === 1) {
return (
<div
key={virtualRow.index}
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
>
<NoteBase key={note.event_id} event={note} />
</div>
);
} else {
return (
<div
key={virtualRow.index}
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
>
<NoteQuoteRepost key={note.event_id} event={note} />
</div>
);
}
}
})}
</div>
</div>
)}
<div> <div>
<p>Space</p> {isFetching && !isFetchingNextPage ? (
<div className="px-3 py-1.5">
<div className="rounded-md border border-zinc-800 bg-zinc-900 px-3 py-3 shadow-input shadow-black/20">
<NoteSkeleton />
</div>
</div>
) : null}
</div>
</div>
</div> </div>
); );
} }

View File

@ -13,17 +13,11 @@ export function LayoutNewsfeed({ children }: { children: React.ReactNode }) {
<AppHeader /> <AppHeader />
</div> </div>
<div className="relative flex min-h-0 w-full flex-1"> <div className="relative flex min-h-0 w-full flex-1">
<div className="relative w-[68px] shrink-0 border-r border-zinc-900"> <div className="relative flex flex-row flex-wrap shrink-0">
<MultiAccounts /> <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 /> <Navigation />
</div> </div>
<div className="col-span-3 overflow-hidden xl:col-span-4"> <div className="w-full h-full">{children}</div>
{children}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,135 +0,0 @@
import { NoteBase } from "@app/note/components/base";
import { NoteQuoteRepost } from "@app/note/components/quoteRepost";
import { NoteSkeleton } from "@app/note/components/skeleton";
import { Header } from "@app/today/components/header";
import { getNotes } from "@utils/storage";
import { useInfiniteQuery } from "@tanstack/react-query";
import { useVirtualizer } from "@tanstack/react-virtual";
import { useEffect, useRef } from "react";
const ITEM_PER_PAGE = 10;
const TIME = Math.floor(Date.now() / 1000);
export function Page() {
const {
status,
error,
data,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
}: any = useInfiniteQuery({
queryKey: ["following"],
queryFn: async ({ pageParam = 0 }) => {
return await getNotes(TIME, ITEM_PER_PAGE, pageParam);
},
getNextPageParam: (lastPage) => lastPage.nextCursor,
});
const allRows = data ? data.pages.flatMap((d: { data: any }) => d.data) : [];
const parentRef = useRef();
const rowVirtualizer = useVirtualizer({
count: hasNextPage ? allRows.length + 1 : allRows.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 400,
overscan: 2,
});
const itemsVirtualizer = rowVirtualizer.getVirtualItems();
useEffect(() => {
const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse();
if (!lastItem) {
return;
}
if (
lastItem.index >= allRows.length - 1 &&
hasNextPage &&
!isFetchingNextPage
) {
fetchNextPage();
}
}, [fetchNextPage, allRows.length, rowVirtualizer.getVirtualItems()]);
return (
<div
ref={parentRef}
className="scrollbar-hide flex h-full flex-col justify-between gap-1.5 overflow-y-auto"
style={{ contain: "strict" }}
>
<div className="flex h-11 w-full shrink-0 items-center justify-between border-b border-zinc-900 px-3">
<Header />
</div>
<div className="flex-1">
{status === "loading" ? (
<div className="px-3 py-1.5">
<div className="rounded-md border border-zinc-800 bg-zinc-900 px-3 py-3 shadow-input shadow-black/20">
<NoteSkeleton />
</div>
</div>
) : status === "error" ? (
<div>{error.message}</div>
) : (
<div
className="relative w-full"
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
}}
>
<div
className="absolute left-0 top-0 w-full"
style={{
transform: `translateY(${
itemsVirtualizer[0].start -
rowVirtualizer.options.scrollMargin
}px)`,
}}
>
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
const note = allRows[virtualRow.index];
if (note) {
if (note.kind === 1) {
return (
<div
key={virtualRow.index}
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
>
<NoteBase key={note.event_id} event={note} />
</div>
);
} else {
return (
<div
key={virtualRow.index}
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
>
<NoteQuoteRepost key={note.event_id} event={note} />
</div>
);
}
}
})}
</div>
</div>
)}
<div>
{isFetching && !isFetchingNextPage ? (
<div className="px-3 py-1.5">
<div className="rounded-md border border-zinc-800 bg-zinc-900 px-3 py-3 shadow-input shadow-black/20">
<NoteSkeleton />
</div>
</div>
) : null}
</div>
</div>
</div>
);
}

View File

@ -2,7 +2,16 @@ import ArrowLeftIcon from "@icons/arrowLeft";
import ArrowRightIcon from "@icons/arrowRight"; import ArrowRightIcon from "@icons/arrowRight";
import RefreshIcon from "@icons/refresh"; import RefreshIcon from "@icons/refresh";
import useSWR from "swr";
const fetcher = async () => {
const { platform } = await import("@tauri-apps/api/os");
return await platform();
};
export default function AppHeader() { export default function AppHeader() {
const { data: platform } = useSWR("platform", fetcher);
const goBack = () => { const goBack = () => {
window.history.back(); window.history.back();
}; };
@ -21,10 +30,10 @@ export default function AppHeader() {
className="flex h-full w-full flex-1 items-center px-2" className="flex h-full w-full flex-1 items-center px-2"
> >
<div <div
data-tauri-drag-region className={`flex h-full items-center gap-2 ${
className="flex w-full items-center justify-center gap-2" platform === "darwin" ? "pl-[68px]" : ""
}`}
> >
<div className="flex h-full items-center gap-2">
<button <button
type="button" type="button"
onClick={() => goBack()} onClick={() => goBack()}
@ -47,16 +56,6 @@ export default function AppHeader() {
className="text-zinc-500 group-hover:text-zinc-300" className="text-zinc-500 group-hover:text-zinc-300"
/> />
</button> </button>
</div>
<div>
<input
autoCapitalize="none"
autoCorrect="off"
placeholder="Search..."
className="h-6 w-[453px] rounded border border-zinc-800 bg-zinc-900 px-2.5 text-center text-[11px] text-sm leading-5 text-zinc-500 placeholder:leading-5 placeholder:text-zinc-600 focus:outline-none"
/>
</div>
<div className="flex h-full items-center gap-2">
<button <button
type="button" type="button"
onClick={() => reload()} onClick={() => reload()}
@ -70,6 +69,5 @@ export default function AppHeader() {
</button> </button>
</div> </div>
</div> </div>
</div>
); );
} }

View File

@ -18,7 +18,7 @@ export default function MultiAccounts() {
const { data: activeAccount }: any = useSWR("activeAccount", fetcher); const { data: activeAccount }: any = useSWR("activeAccount", fetcher);
return ( return (
<div className="flex h-full flex-col items-center justify-between pb-4 pt-3"> <div className="flex shrink-0 w-[68px] h-full flex-col items-center justify-between border-r border-zinc-900 pb-4 pt-3">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<> <>

View File

@ -14,7 +14,7 @@ import { Disclosure } from "@headlessui/react";
export default function Navigation() { export default function Navigation() {
return ( return (
<div className="relative flex h-full flex-col gap-3 pt-1.5"> <div className="flex w-[232px] h-full flex-col gap-3 pt-1.5">
<div className="flex h-11 items-center justify-between px-3.5"> <div className="flex h-11 items-center justify-between px-3.5">
<ComposerModal /> <ComposerModal />
<EventCollector /> <EventCollector />
@ -28,14 +28,14 @@ export default function Navigation() {
</div> </div>
<div className="flex flex-col text-zinc-400"> <div className="flex flex-col text-zinc-400">
<ActiveLink <ActiveLink
href="/app/today" href="/app/space"
className="flex h-8 items-center gap-2.5 rounded-md px-2.5 text-[13px] font-semibold hover:text-zinc-200" className="flex h-8 items-center gap-2.5 rounded-md px-2.5 text-[13px] font-semibold hover:text-zinc-200"
activeClassName="bg-zinc-900/50 hover:bg-zinc-900" activeClassName="bg-zinc-900/50 hover:bg-zinc-900"
> >
<span className="inline-flex h-5 w-5 items-center justify-center rounded bg-zinc-900"> <span className="inline-flex h-5 w-5 items-center justify-center rounded bg-zinc-900">
<WorldIcon width={12} height={12} className="text-zinc-200" /> <WorldIcon width={12} height={12} className="text-zinc-200" />
</span> </span>
<span>Today</span> <span>Space</span>
</ActiveLink> </ActiveLink>
<ActiveLink <ActiveLink
href="/app/threads" href="/app/threads"
@ -47,16 +47,6 @@ export default function Navigation() {
</span> </span>
<span>Threads</span> <span>Threads</span>
</ActiveLink> </ActiveLink>
<ActiveLink
href="/app/space"
className="flex h-8 items-center gap-2.5 rounded-md px-2.5 text-[13px] font-semibold hover:text-zinc-200"
activeClassName=""
>
<span className="inline-flex h-5 w-5 items-center justify-center rounded bg-zinc-900">
<MyspaceIcon width={12} height={12} className="text-zinc-200" />
</span>
<span>Space</span>
</ActiveLink>
</div> </div>
</div> </div>
{/* Channels */} {/* Channels */}