diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 7e27cc661..1c69fcedb 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -14,6 +14,7 @@ "@columns/hashtag": "workspace:^", "@columns/thread": "workspace:^", "@columns/timeline": "workspace:^", + "@columns/trending-notes": "workspace:^", "@columns/user": "workspace:^", "@getalby/sdk": "^3.2.3", "@lume/ark": "workspace:^", diff --git a/apps/desktop/public/columns/topic.jpg b/apps/desktop/public/columns/topic.jpg deleted file mode 100644 index 927343a9c..000000000 Binary files a/apps/desktop/public/columns/topic.jpg and /dev/null differ diff --git a/apps/desktop/public/columns/trending-notes.jpg b/apps/desktop/public/columns/trending-notes.jpg new file mode 100644 index 000000000..0ae75021b Binary files /dev/null and b/apps/desktop/public/columns/trending-notes.jpg differ diff --git a/apps/desktop/public/columns/topic@2x.jpg b/apps/desktop/public/columns/trending-notes@2x.jpg similarity index 50% rename from apps/desktop/public/columns/topic@2x.jpg rename to apps/desktop/public/columns/trending-notes@2x.jpg index 2d144e4b1..b99e5849a 100644 Binary files a/apps/desktop/public/columns/topic@2x.jpg and b/apps/desktop/public/columns/trending-notes@2x.jpg differ diff --git a/apps/desktop/src/routes/home/index.tsx b/apps/desktop/src/routes/home/index.tsx index b4bc4b64c..b6e75264c 100644 --- a/apps/desktop/src/routes/home/index.tsx +++ b/apps/desktop/src/routes/home/index.tsx @@ -5,6 +5,7 @@ import { Group } from "@columns/group"; import { Hashtag } from "@columns/hashtag"; import { Thread } from "@columns/thread"; import { Timeline } from "@columns/timeline"; +import { TrendingNotes } from "@columns/trending-notes"; import { User } from "@columns/user"; import { useColumnContext } from "@lume/ark"; import { @@ -45,6 +46,8 @@ export function HomeScreen() { return ; case COL_TYPES.antenas: return ; + case COL_TYPES.trendingNotes: + return ; default: return ; } diff --git a/packages/ark/src/ark.ts b/packages/ark/src/ark.ts index 0b60f4e1a..f3e9dc7f2 100644 --- a/packages/ark/src/ark.ts +++ b/packages/ark/src/ark.ts @@ -62,6 +62,10 @@ export class Ark { return sub; } + public getNDKEvent(event: NostrEvent) { + return new NDKEvent(this.ndk, event); + } + public async createEvent({ kind, tags, diff --git a/packages/ark/src/components/column/header.tsx b/packages/ark/src/components/column/header.tsx index 341e604d2..46e11b607 100644 --- a/packages/ark/src/components/column/header.tsx +++ b/packages/ark/src/components/column/header.tsx @@ -101,7 +101,7 @@ export function ColumnHeader({ className="inline-flex items-center gap-3 px-3 text-sm font-medium text-red-500 rounded-lg h-9 hover:bg-red-500 hover:text-red-50 focus:outline-none" > - {t("global.Delete")} + {t("global.delete")} diff --git a/packages/lume-column-default/src/index.tsx b/packages/lume-column-default/src/index.tsx index 728aa267f..bd3be20ea 100644 --- a/packages/lume-column-default/src/index.tsx +++ b/packages/lume-column-default/src/index.tsx @@ -1,5 +1,4 @@ import { Column, useColumnContext } from "@lume/ark"; -import { ColumnIcon } from "@lume/icons"; import { IColumn } from "@lume/types"; import { COL_TYPES } from "@lume/utils"; @@ -8,11 +7,7 @@ export function Default({ column }: { column: IColumn }) { return ( - } - /> + + + + + + + + Trending Notes + + What is trending on Nostr? + + + { + addColumn({ + kind: COL_TYPES.trendingNotes, + title: "", + content: "", + }); + }} + className="shrink-0 w-16 h-8 rounded-lg text-sm font-semibold bg-neutral-100 dark:bg-neutral-900 text-blue-500 hover:bg-neutral-200 dark:hover:bg-neutral-800 inline-flex items-center justify-center" + > + Add + + + ); diff --git a/packages/lume-column-trending-notes/package.json b/packages/lume-column-trending-notes/package.json new file mode 100644 index 000000000..75ae028cc --- /dev/null +++ b/packages/lume-column-trending-notes/package.json @@ -0,0 +1,26 @@ +{ + "name": "@columns/trending-notes", + "version": "0.0.0", + "private": true, + "main": "./src/index.tsx", + "dependencies": { + "@lume/ark": "workspace:^", + "@lume/icons": "workspace:^", + "@lume/ui": "workspace:^", + "@lume/utils": "workspace:^", + "@nostr-dev-kit/ndk": "^2.3.3", + "@tanstack/react-query": "^5.17.19", + "react": "^18.2.0", + "react-router-dom": "^6.21.3", + "sonner": "^1.3.1", + "virtua": "^0.21.1" + }, + "devDependencies": { + "@lume/tailwindcss": "workspace:^", + "@lume/tsconfig": "workspace:^", + "@lume/types": "workspace:^", + "@types/react": "^18.2.48", + "tailwind": "^4.0.0", + "typescript": "^5.3.3" + } +} diff --git a/packages/lume-column-trending-notes/src/home.tsx b/packages/lume-column-trending-notes/src/home.tsx new file mode 100644 index 000000000..0b0f59c7e --- /dev/null +++ b/packages/lume-column-trending-notes/src/home.tsx @@ -0,0 +1,71 @@ +import { TextNote, useArk } from "@lume/ark"; +import { LoaderIcon } from "@lume/icons"; +import { type NDKEvent, type NostrEvent } from "@nostr-dev-kit/ndk"; +import { useQuery } from "@tanstack/react-query"; +import { fetch } from "@tauri-apps/plugin-http"; +import { useEffect, useMemo, useRef } from "react"; +import { CacheSnapshot, VList, VListHandle } from "virtua"; + +export function HomeRoute({ colKey }: { colKey: string }) { + const ark = useArk(); + const ref = useRef(); + const cacheKey = `${colKey}-vlist`; + + const [offset, cache] = useMemo(() => { + const serialized = sessionStorage.getItem(cacheKey); + if (!serialized) return []; + return JSON.parse(serialized) as [number, CacheSnapshot]; + }, []); + + const { data, isLoading } = useQuery({ + queryKey: [colKey], + queryFn: async ({ signal }: { signal: AbortSignal }) => { + const res = await fetch("https://api.nostr.band/v0/trending/notes", { + signal, + }); + + if (!res) throw new Error("Failed to fetch trending notes"); + + const data = await res.json(); + const events = data.notes.map((item: { event: NostrEvent }) => + ark.getNDKEvent(item.event), + ); + + return events as NDKEvent[]; + }, + refetchOnMount: false, + refetchOnWindowFocus: false, + }); + + useEffect(() => { + if (!ref.current) return; + const handle = ref.current; + + if (offset) { + handle.scrollTo(offset); + } + + return () => { + sessionStorage.setItem( + cacheKey, + JSON.stringify([handle.scrollOffset, handle.cache]), + ); + }; + }, []); + + return ( + + + {isLoading ? ( + + + + ) : ( + data.map((item) => ( + + )) + )} + + + ); +} diff --git a/packages/lume-column-trending-notes/src/index.tsx b/packages/lume-column-trending-notes/src/index.tsx new file mode 100644 index 000000000..8cfe690d0 --- /dev/null +++ b/packages/lume-column-trending-notes/src/index.tsx @@ -0,0 +1,23 @@ +import { Column } from "@lume/ark"; +import { IColumn } from "@lume/types"; +import { EventRoute, UserRoute } from "@lume/ui"; +import { HomeRoute } from "./home"; + +export function TrendingNotes({ column }: { column: IColumn }) { + const colKey = `trending-notes-${column.id}`; + + return ( + + + + } /> + } /> + } /> + + + ); +} diff --git a/packages/lume-column-trending-notes/tailwind.config.js b/packages/lume-column-trending-notes/tailwind.config.js new file mode 100644 index 000000000..49c48c7a2 --- /dev/null +++ b/packages/lume-column-trending-notes/tailwind.config.js @@ -0,0 +1,8 @@ +import sharedConfig from "@lume/tailwindcss"; + +const config = { + content: ["./src/**/*.{js,ts,jsx,tsx}"], + presets: [sharedConfig], +}; + +export default config; diff --git a/packages/lume-column-trending-notes/tsconfig.json b/packages/lume-column-trending-notes/tsconfig.json new file mode 100644 index 000000000..34a32891a --- /dev/null +++ b/packages/lume-column-trending-notes/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@lume/tsconfig/base.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/utils/src/constants.ts b/packages/utils/src/constants.ts index 9b2d98e76..70dfd3d0a 100644 --- a/packages/utils/src/constants.ts +++ b/packages/utils/src/constants.ts @@ -57,9 +57,7 @@ export const COL_TYPES = { hashtag: 3, group: 4, antenas: 5, - topic: 6, trendingNotes: 9000, - trendingAccounts: 9001, foryou: 9998, newsfeed: 9999, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 721cea0b6..59533e682 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -84,6 +84,9 @@ importers: '@columns/timeline': specifier: workspace:^ version: link:../../packages/lume-column-timeline + '@columns/trending-notes': + specifier: workspace:^ + version: link:../../packages/lume-column-trending-notes '@columns/user': specifier: workspace:^ version: link:../../packages/lume-column-user @@ -798,6 +801,110 @@ importers: specifier: ^5.3.3 version: 5.3.3 + packages/lume-column-trending-notes: + dependencies: + '@lume/ark': + specifier: workspace:^ + version: link:../ark + '@lume/icons': + specifier: workspace:^ + version: link:../icons + '@lume/ui': + specifier: workspace:^ + version: link:../ui + '@lume/utils': + specifier: workspace:^ + version: link:../utils + '@nostr-dev-kit/ndk': + specifier: ^2.3.3 + version: 2.3.3(typescript@5.3.3) + '@tanstack/react-query': + specifier: ^5.17.19 + version: 5.17.19(react@18.2.0) + react: + specifier: ^18.2.0 + version: 18.2.0 + react-router-dom: + specifier: ^6.21.3 + version: 6.21.3(react-dom@18.2.0)(react@18.2.0) + sonner: + specifier: ^1.3.1 + version: 1.3.1(react-dom@18.2.0)(react@18.2.0) + virtua: + specifier: ^0.21.1 + version: 0.21.1(react-dom@18.2.0)(react@18.2.0) + devDependencies: + '@lume/tailwindcss': + specifier: workspace:^ + version: link:../tailwindcss + '@lume/tsconfig': + specifier: workspace:^ + version: link:../tsconfig + '@lume/types': + specifier: workspace:^ + version: link:../types + '@types/react': + specifier: ^18.2.48 + version: 18.2.48 + tailwind: + specifier: ^4.0.0 + version: 4.0.0 + typescript: + specifier: ^5.3.3 + version: 5.3.3 + + packages/lume-column-trending-users: + dependencies: + '@lume/ark': + specifier: workspace:^ + version: link:../ark + '@lume/icons': + specifier: workspace:^ + version: link:../icons + '@lume/ui': + specifier: workspace:^ + version: link:../ui + '@lume/utils': + specifier: workspace:^ + version: link:../utils + '@nostr-dev-kit/ndk': + specifier: ^2.3.3 + version: 2.3.3(typescript@5.3.3) + '@tanstack/react-query': + specifier: ^5.17.19 + version: 5.17.19(react@18.2.0) + react: + specifier: ^18.2.0 + version: 18.2.0 + react-router-dom: + specifier: ^6.21.3 + version: 6.21.3(react-dom@18.2.0)(react@18.2.0) + sonner: + specifier: ^1.3.1 + version: 1.3.1(react-dom@18.2.0)(react@18.2.0) + virtua: + specifier: ^0.21.1 + version: 0.21.1(react-dom@18.2.0)(react@18.2.0) + devDependencies: + '@lume/tailwindcss': + specifier: workspace:^ + version: link:../tailwindcss + '@lume/tsconfig': + specifier: workspace:^ + version: link:../tsconfig + '@lume/types': + specifier: workspace:^ + version: link:../types + '@types/react': + specifier: ^18.2.48 + version: 18.2.48 + tailwind: + specifier: ^4.0.0 + version: 4.0.0 + typescript: + specifier: ^5.3.3 + version: 5.3.3 + packages/lume-column-user: dependencies: '@lume/ark':
+ What is trending on Nostr? +