Settings Manager (#211)

* refactor: landing screen

* fix: code debt

* feat: add settings screen

* chore: clean up

* feat: settings

* feat: small updates
This commit is contained in:
雨宮蓮
2024-06-19 14:00:58 +07:00
committed by GitHub
parent 0061ecea78
commit 18c133d096
50 changed files with 937 additions and 1167 deletions
+21 -39
View File
@@ -3,19 +3,18 @@ import { Quote } from "@/components/quote";
import { RepostNote } from "@/components/repost";
import { TextNote } from "@/components/text";
import { ArrowRightCircleIcon } from "@lume/icons";
import { NostrQuery } from "@lume/system";
import {
type ColumnRouteSearch,
type NostrEvent,
type Topic,
Kind,
} from "@lume/types";
import { type LumeEvent, NostrQuery } from "@lume/system";
import { type ColumnRouteSearch, Kind } from "@lume/types";
import { Spinner } from "@lume/ui";
import { useInfiniteQuery } from "@tanstack/react-query";
import { createFileRoute, redirect } from "@tanstack/react-router";
import { useCallback } from "react";
import { Virtualizer } from "virtua";
type Topic = {
content: string[];
};
export const Route = createFileRoute("/topic")({
validateSearch: (search: Record<string, string>): ColumnRouteSearch => {
return {
@@ -25,8 +24,9 @@ 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 key = `lume:topic:${search.label}`;
const topics: Topic[] = await NostrQuery.getNstore(key);
const settings = await NostrQuery.getUserSettings();
if (!topics?.length) {
throw redirect({
@@ -44,7 +44,7 @@ export const Route = createFileRoute("/topic")({
hashtags.push(...topic.content);
}
return { hashtags };
return { settings, hashtags };
},
component: Screen,
});
@@ -67,32 +67,25 @@ export function Screen() {
return events;
},
getNextPageParam: (lastPage) => lastPage?.at(-1)?.created_at - 1,
select: (data) => data?.pages.flatMap((page) => page),
select: (data) => data?.pages.flat(),
refetchOnWindowFocus: false,
});
const renderItem = useCallback(
(event: NostrEvent) => {
(event: LumeEvent) => {
if (!event) return;
switch (event.kind) {
case Kind.Repost:
return <RepostNote key={event.id} event={event} />;
return <RepostNote key={event.id} event={event} className="mb-3" />;
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) {
if (event.isConversation) {
return (
<Conversation key={event.id} event={event} className="mb-3" />
<Conversation key={event.id} className="mb-3" event={event} />
);
}
if (isQuote) {
if (event.isQuote) {
return <Quote key={event.id} event={event} className="mb-3" />;
}
return <TextNote key={event.id} event={event} className="mb-3" />;
}
}
@@ -101,7 +94,7 @@ export function Screen() {
);
return (
<div className="w-full h-full p-2 overflow-y-auto scrollbar-none">
<div className="w-full h-full p-3 overflow-y-auto scrollbar-none">
{isFetching && !isLoading && !isFetchingNextPage ? (
<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">
@@ -116,7 +109,9 @@ export function Screen() {
<span className="text-sm font-medium">Loading...</span>
</div>
) : !data.length ? (
<Empty />
<div className="flex items-center justify-center">
Yo. You're catching up on all the things happening around you.
</div>
) : (
<Virtualizer overscan={3}>
{data.map((item) => renderItem(item))}
@@ -128,7 +123,7 @@ export function Screen() {
type="button"
onClick={() => fetchNextPage()}
disabled={isFetchingNextPage || isLoading}
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"
className="inline-flex items-center justify-center w-full gap-2 px-3 font-medium h-9 rounded-xl bg-black/5 hover:bg-black/10 focus:outline-none dark:bg-white/10 dark:hover:bg-white/20"
>
{isFetchingNextPage ? (
<Spinner className="size-5" />
@@ -144,16 +139,3 @@ export function Screen() {
</div>
);
}
function Empty() {
return (
<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>
</div>
</div>
);
}