feat: improve official columns

This commit is contained in:
reya 2024-04-18 07:50:46 +07:00
parent f3c52237fa
commit cd31b99559
10 changed files with 59 additions and 77 deletions

View File

@ -1,6 +1,6 @@
import { CheckCircleIcon } from "@lume/icons";
import { ColumnRouteSearch } from "@lume/types";
import { Column, User } from "@lume/ui";
import { Column, Spinner, User } from "@lume/ui";
import { createFileRoute, useRouter } from "@tanstack/react-router";
import { useState } from "react";
import { toast } from "sonner";
@ -30,6 +30,7 @@ function Screen() {
const [title, setTitle] = useState<string>("Just a new group");
const [users, setUsers] = useState<Array<string>>([]);
const [loading, setLoading] = useState(false);
const [isDone, setIsDone] = useState(false);
const toggleUser = (pubkey: string) => {
@ -43,13 +44,22 @@ function Screen() {
try {
if (isDone) return router.history.push(redirect);
// start loading
setLoading(true);
const groups = await ark.set_nstore(
`lume_group_${label}`,
JSON.stringify(users),
);
if (groups) setIsDone(true);
if (groups) {
toast.success("Group has been created successfully.");
// start loading
setIsDone(true);
setLoading(false);
}
} catch (e) {
setLoading(false);
toast.error(e);
}
};
@ -101,14 +111,14 @@ function Screen() {
</div>
</div>
</div>
<div className="fixed z-10 flex items-center justify-center w-full bottom-3">
<div className="fixed z-10 flex items-center justify-center w-full bottom-6">
<button
type="button"
onClick={submit}
disabled={users.length < 1}
className="inline-flex items-center justify-center px-4 font-medium text-white transform bg-blue-500 rounded-full active:translate-y-1 w-36 h-11 hover:bg-blue-600 focus:outline-none disabled:cursor-not-allowed"
className="inline-flex items-center justify-center px-4 font-medium text-white transform bg-blue-500 rounded-full active:translate-y-1 w-26 h-9 hover:bg-blue-600 focus:outline-none disabled:cursor-not-allowed"
>
{isDone ? "Back" : "Update"}
{isDone ? "Back" : loading ? <Spinner /> : "Update"}
</button>
</div>
</Column.Content>

View File

@ -18,6 +18,7 @@ export const Route = createFileRoute("/foryou")({
beforeLoad: async ({ search, context }) => {
const ark = context.ark;
const interests = await ark.get_interest();
const settings = await ark.get_settings();
if (!interests) {
throw redirect({
@ -31,6 +32,7 @@ export const Route = createFileRoute("/foryou")({
return {
interests,
settings,
};
},
component: Screen,
@ -48,7 +50,6 @@ export function Screen() {
interests.hashtags,
20,
pageParam,
true,
);
return events;
},
@ -87,13 +88,12 @@ export function Screen() {
{data.map((item) => renderItem(item))}
</Virtualizer>
)}
{data?.length && hasNextPage ? (
<div className="flex h-20 items-center justify-center">
<button
type="button"
onClick={() => fetchNextPage()}
disabled={isFetchingNextPage || isFetchingNextPage}
disabled={isFetchingNextPage}
className="inline-flex h-12 w-36 items-center justify-center gap-2 rounded-full bg-neutral-100 px-3 font-medium hover:bg-neutral-200 focus:outline-none dark:bg-neutral-900 dark:hover:bg-neutral-800"
>
{isFetchingNextPage ? (

View File

@ -17,7 +17,10 @@ export const Route = createFileRoute("/group")({
},
beforeLoad: async ({ search, context }) => {
const ark = context.ark;
const groups = await ark.get_nstore(`lume_group_${search.label}`);
const groups = (await ark.get_nstore(
`lume_group_${search.label}`,
)) as string[];
const settings = await ark.get_settings();
if (!groups) {
throw redirect({
@ -31,6 +34,7 @@ export const Route = createFileRoute("/group")({
return {
groups,
settings,
};
},
component: Screen,
@ -38,13 +42,13 @@ export const Route = createFileRoute("/group")({
export function Screen() {
const { label, name, account } = Route.useSearch();
const { ark } = Route.useRouteContext();
const { ark, groups } = Route.useRouteContext();
const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage } =
useInfiniteQuery({
queryKey: [name, account],
initialPageParam: 0,
queryFn: async ({ pageParam }: { pageParam: number }) => {
const events = await ark.get_events(20, pageParam);
const events = await ark.get_events(20, pageParam, groups);
return events;
},
getNextPageParam: (lastPage) => {

View File

@ -7,7 +7,6 @@ import { useTranslation } from "react-i18next";
import { toast } from "sonner";
export const Route = createFileRoute("/interests")({
component: Screen,
validateSearch: (search: Record<string, string>): ColumnRouteSearch => {
return {
account: search.account,
@ -15,6 +14,7 @@ export const Route = createFileRoute("/interests")({
name: search.name,
};
},
component: Screen,
});
function Screen() {

View File

@ -6,8 +6,16 @@ export const Route = createFileRoute("/store/community")({
function Screen() {
return (
<div className="flex flex-col gap-3 p-3">
<p>Coming Soon</p>
<div className="flex h-full flex-col items-center justify-center gap-3 p-3">
<div className="size-24 bg-blue-100 flex flex-col items-center justify-end overflow-hidden dark:bg-blue-900 rounded-full">
<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>
<div className="text-center">
<h1 className="font-semibold text-lg">Coming Soon</h1>
<p className="text-sm text-neutral-700 dark:text-neutral-300 leading-tight">
Enhance your experience <br /> by adding column shared by community.
</p>
</div>
</div>
);
}

View File

@ -195,23 +195,20 @@ export class Ark {
hashtags: string[],
limit: number,
asOf?: number,
global?: boolean,
) {
let until: string = undefined;
if (asOf && asOf > 0) until = asOf.toString();
const dedup = true;
const seenIds = new Set<string>();
const dedupQueue = new Set<string>();
const nostrTags = hashtags.map((tag) => tag.replace("#", "").toLowerCase());
const nostrEvents: Event[] = await invoke("get_events_from_interests", {
hashtags,
hashtags: nostrTags,
limit,
until,
global,
});
if (dedup) {
for (const event of nostrEvents) {
const tags = event.tags
.filter((el) => el[0] === "e")
@ -233,9 +230,6 @@ export class Ark {
.sort((a, b) => b.created_at - a.created_at);
}
return nostrEvents.sort((a, b) => b.created_at - a.created_at);
}
public async publish(
content: string,
reply_to?: string,

View File

@ -126,7 +126,7 @@ export function NoteContent({
);
if (compact) {
parsedContent = reactStringReplace(parsedContent, /[\r\n]{2,}/g, () => (
parsedContent = reactStringReplace(parsedContent, /\n*\n/g, () => (
<div key={nanoid()} className="h-1.5" />
));
}

View File

@ -19,7 +19,7 @@ export function MentionNote({
return (
<div
contentEditable={false}
className="my-1 flex w-full cursor-default items-center justify-between rounded-2xl border border-black/10 p-3 dark:border-white/10"
className="my-1 flex w-full cursor-default items-center justify-between rounded-xl border border-black/10 p-3 dark:border-white/10"
>
<p>Loading...</p>
</div>
@ -30,7 +30,7 @@ export function MentionNote({
return (
<div
contentEditable={false}
className="my-1 w-full cursor-default rounded-2xl border border-black/10 p-3 dark:border-white/10"
className="my-1 w-full cursor-default rounded-xl border border-black/10 p-3 dark:border-white/10"
>
{t("note.error")}
</div>

View File

@ -19,16 +19,6 @@
"author": "Lume",
"description": "Collective of people you're interested in."
},
{
"label": "sDbO6XxAGnW5XuUZEgZMn",
"name": "Antenas",
"content": "/antenas",
"logo": "",
"cover": "/antenas.png",
"coverRetina": "/antenas@2x.png",
"author": "Lume",
"description": "Keep track to specific content."
},
{
"label": "gxtcIbgD8YNPbeI5o92I8",
"name": "Trending",

View File

@ -155,7 +155,6 @@ pub async fn get_events_from_interests(
hashtags: Vec<&str>,
limit: usize,
until: Option<&str>,
global: Option<bool>,
state: State<'_, Nostr>,
) -> Result<Vec<Event>, String> {
let client = &state.client;
@ -163,34 +162,11 @@ pub async fn get_events_from_interests(
Some(until) => Timestamp::from_str(until).unwrap(),
None => Timestamp::now(),
};
let authors = match global {
Some(val) => match val {
true => None,
false => {
match client
.get_contact_list_public_keys(Some(Duration::from_secs(10)))
.await
{
Ok(val) => Some(val),
Err(_) => None,
}
}
},
None => None,
};
let filter = match authors {
Some(val) => Filter::new()
.kinds(vec![Kind::TextNote, Kind::Repost])
.authors(val)
.limit(limit)
.until(as_of)
.hashtags(hashtags),
None => Filter::new()
let filter = Filter::new()
.kinds(vec![Kind::TextNote, Kind::Repost])
.limit(limit)
.until(as_of)
.hashtags(hashtags),
};
.hashtags(hashtags);
if let Ok(events) = client
.get_events_of(vec![filter], Some(Duration::from_secs(15)))