Make Lume Faster (#208)
* chore: fix some lint issues * feat: refactor contact list * feat: refactor relay hint * feat: add missing commands * feat: use new cache layer for react query * feat: refactor column * feat: improve relay hint * fix: replace break with continue in parser * refactor: publish function * feat: add reply command * feat: improve editor * fix: quote * chore: update deps * refactor: note component * feat: improve repost * feat: improve cache * fix: backup screen * refactor: column manager
This commit is contained in:
@@ -2,17 +2,18 @@ import { Conversation } from "@/components/conversation";
|
||||
import { Quote } from "@/components/quote";
|
||||
import { RepostNote } from "@/components/repost";
|
||||
import { TextNote } from "@/components/text";
|
||||
import { ArrowRightCircleIcon, ArrowRightIcon } from "@lume/icons";
|
||||
import { ArrowRightCircleIcon } from "@lume/icons";
|
||||
import { NostrQuery } from "@lume/system";
|
||||
import {
|
||||
type ColumnRouteSearch,
|
||||
type NostrEvent,
|
||||
type Topic,
|
||||
Kind,
|
||||
Topic,
|
||||
} from "@lume/types";
|
||||
import { Spinner } from "@lume/ui";
|
||||
import { useInfiniteQuery } from "@tanstack/react-query";
|
||||
import { Link, createFileRoute, redirect } from "@tanstack/react-router";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
import { useCallback } from "react";
|
||||
import { Virtualizer } from "virtua";
|
||||
|
||||
export const Route = createFileRoute("/topic")({
|
||||
@@ -26,7 +27,6 @@ export const Route = createFileRoute("/topic")({
|
||||
beforeLoad: async ({ search }) => {
|
||||
const key = `lume_topic_${search.label}`;
|
||||
const topics = (await NostrQuery.getNstore(key)) as unknown as Topic[];
|
||||
const settings = await NostrQuery.getSettings();
|
||||
|
||||
if (!topics?.length) {
|
||||
throw redirect({
|
||||
@@ -38,16 +38,13 @@ export const Route = createFileRoute("/topic")({
|
||||
});
|
||||
}
|
||||
|
||||
let hashtags: string[] = [];
|
||||
const hashtags: string[] = [];
|
||||
|
||||
for (const topic of topics) {
|
||||
hashtags.push(...topic.content);
|
||||
}
|
||||
|
||||
return {
|
||||
hashtags,
|
||||
settings,
|
||||
};
|
||||
return { hashtags };
|
||||
},
|
||||
component: Screen,
|
||||
});
|
||||
@@ -74,34 +71,39 @@ export function Screen() {
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
const renderItem = (event: NostrEvent) => {
|
||||
if (!event) return;
|
||||
switch (event.kind) {
|
||||
case Kind.Repost:
|
||||
return <RepostNote key={event.id} event={event} />;
|
||||
default: {
|
||||
const isConversation =
|
||||
event.tags.filter((tag) => tag[0] === "e" && tag[3] !== "mention")
|
||||
.length > 0;
|
||||
const isQuote = event.tags.filter((tag) => tag[0] === "q").length > 0;
|
||||
const renderItem = useCallback(
|
||||
(event: NostrEvent) => {
|
||||
if (!event) return;
|
||||
switch (event.kind) {
|
||||
case Kind.Repost:
|
||||
return <RepostNote key={event.id} event={event} />;
|
||||
default: {
|
||||
const isConversation =
|
||||
event.tags.filter((tag) => tag[0] === "e" && tag[3] !== "mention")
|
||||
.length > 0;
|
||||
const isQuote = event.tags.filter((tag) => tag[0] === "q").length > 0;
|
||||
|
||||
if (isConversation) {
|
||||
return <Conversation key={event.id} event={event} className="mb-3" />;
|
||||
if (isConversation) {
|
||||
return (
|
||||
<Conversation key={event.id} event={event} className="mb-3" />
|
||||
);
|
||||
}
|
||||
|
||||
if (isQuote) {
|
||||
return <Quote key={event.id} event={event} className="mb-3" />;
|
||||
}
|
||||
|
||||
return <TextNote key={event.id} event={event} className="mb-3" />;
|
||||
}
|
||||
|
||||
if (isQuote) {
|
||||
return <Quote key={event.id} event={event} className="mb-3" />;
|
||||
}
|
||||
|
||||
return <TextNote key={event.id} event={event} className="mb-3" />;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
[data],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="p-2 w-full h-full overflow-y-auto scrollbar-none">
|
||||
<div className="w-full h-full p-2 overflow-y-auto scrollbar-none">
|
||||
{isFetching && !isLoading && !isFetchingNextPage ? (
|
||||
<div className="mb-3 w-full h-11 flex items-center justify-center bg-black/10 dark:bg-white/10 backdrop-blur-lg rounded-xl shadow-primary dark:ring-1 ring-neutral-800/50">
|
||||
<div className="flex items-center justify-center w-full mb-3 h-11 bg-black/10 dark:bg-white/10 backdrop-blur-lg rounded-xl shadow-primary dark:ring-1 ring-neutral-800/50">
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<Spinner className="size-5" />
|
||||
<span className="text-sm font-medium">Fetching new notes...</span>
|
||||
@@ -109,7 +111,7 @@ export function Screen() {
|
||||
</div>
|
||||
) : null}
|
||||
{isLoading ? (
|
||||
<div className="flex h-16 w-full items-center justify-center gap-2">
|
||||
<div className="flex items-center justify-center w-full h-16 gap-2">
|
||||
<Spinner className="size-5" />
|
||||
<span className="text-sm font-medium">Loading...</span>
|
||||
</div>
|
||||
@@ -126,7 +128,7 @@ export function Screen() {
|
||||
type="button"
|
||||
onClick={() => fetchNextPage()}
|
||||
disabled={isFetchingNextPage || isLoading}
|
||||
className="inline-flex h-12 w-full items-center justify-center gap-2 rounded-xl bg-neutral-100 px-3 font-medium hover:bg-neutral-50 focus:outline-none dark:bg-white/10 dark:hover:bg-white/20"
|
||||
className="inline-flex items-center justify-center w-full h-12 gap-2 px-3 font-medium rounded-xl bg-neutral-100 hover:bg-neutral-50 focus:outline-none dark:bg-white/10 dark:hover:bg-white/20"
|
||||
>
|
||||
{isFetchingNextPage ? (
|
||||
<Spinner className="size-5" />
|
||||
@@ -145,31 +147,12 @@ export function Screen() {
|
||||
|
||||
function Empty() {
|
||||
return (
|
||||
<div className="flex flex-col py-10 gap-10">
|
||||
<div className="text-center flex flex-col items-center justify-center">
|
||||
<div className="size-24 bg-blue-100 flex flex-col items-center justify-end overflow-hidden dark:bg-blue-900 rounded-full mb-8">
|
||||
<div className="w-12 h-16 bg-gradient-to-b from-blue-500 dark:from-blue-200 to-blue-50 dark:to-blue-900 rounded-t-lg" />
|
||||
<div className="flex flex-col gap-10 py-10">
|
||||
<div className="flex flex-col items-center justify-center text-center">
|
||||
<div className="flex flex-col items-center justify-end mb-8 overflow-hidden bg-blue-100 rounded-full size-24 dark:bg-blue-900">
|
||||
<div className="w-12 h-16 rounded-t-lg bg-gradient-to-b from-blue-500 dark:from-blue-200 to-blue-50 dark:to-blue-900" />
|
||||
</div>
|
||||
<p className="text-lg font-medium">Your newsfeed is empty</p>
|
||||
<p className="leading-tight text-neutral-700 dark:text-neutral-300">
|
||||
Here are few suggestions to get started.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col px-3 gap-2">
|
||||
<Link
|
||||
to="/trending/notes"
|
||||
className="h-11 w-full flex items-center hover:bg-neutral-200 text-sm font-medium dark:hover:bg-neutral-800 gap-2 bg-neutral-100 rounded-lg dark:bg-neutral-900 px-3"
|
||||
>
|
||||
<ArrowRightIcon className="size-5" />
|
||||
Show trending notes
|
||||
</Link>
|
||||
<Link
|
||||
to="/trending/users"
|
||||
className="h-11 w-full flex items-center hover:bg-neutral-200 text-sm font-medium dark:hover:bg-neutral-800 gap-2 bg-neutral-100 rounded-lg dark:bg-neutral-900 px-3"
|
||||
>
|
||||
<ArrowRightIcon className="size-5" />
|
||||
Discover trending users
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user