diff --git a/apps/desktop/package.json b/apps/desktop/package.json
index 35e48fec..c1d06888 100644
--- a/apps/desktop/package.json
+++ b/apps/desktop/package.json
@@ -10,6 +10,7 @@
"@columns/antenas": "workspace:^",
"@columns/default": "workspace:^",
"@columns/foryou": "workspace:^",
+ "@columns/global": "workspace:^",
"@columns/group": "workspace:^",
"@columns/hashtag": "workspace:^",
"@columns/thread": "workspace:^",
diff --git a/apps/desktop/public/columns/global.jpg b/apps/desktop/public/columns/global.jpg
new file mode 100644
index 00000000..2288bfaf
Binary files /dev/null and b/apps/desktop/public/columns/global.jpg differ
diff --git a/apps/desktop/public/columns/global@2x.jpg b/apps/desktop/public/columns/global@2x.jpg
new file mode 100644
index 00000000..e079bfe1
Binary files /dev/null and b/apps/desktop/public/columns/global@2x.jpg differ
diff --git a/apps/desktop/src/routes/home/index.tsx b/apps/desktop/src/routes/home/index.tsx
index b6e75264..2508bb94 100644
--- a/apps/desktop/src/routes/home/index.tsx
+++ b/apps/desktop/src/routes/home/index.tsx
@@ -1,6 +1,7 @@
import { Antenas } from "@columns/antenas";
import { Default } from "@columns/default";
import { ForYou } from "@columns/foryou";
+import { Global } from "@columns/global";
import { Group } from "@columns/group";
import { Hashtag } from "@columns/hashtag";
import { Thread } from "@columns/thread";
@@ -46,6 +47,8 @@ export function HomeScreen() {
return ;
case COL_TYPES.antenas:
return ;
+ case COL_TYPES.global:
+ return ;
case COL_TYPES.trendingNotes:
return ;
default:
diff --git a/packages/lume-column-default/src/index.tsx b/packages/lume-column-default/src/index.tsx
index bd3be20e..d02dcae4 100644
--- a/packages/lume-column-default/src/index.tsx
+++ b/packages/lume-column-default/src/index.tsx
@@ -115,6 +115,39 @@ export function Default({ column }: { column: IColumn }) {
+
+
+
+
+
+
+
Global
+
+ All things around the world
+
+
+
+
+
);
diff --git a/packages/lume-column-global/package.json b/packages/lume-column-global/package.json
new file mode 100644
index 00000000..ecb36ae9
--- /dev/null
+++ b/packages/lume-column-global/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "@columns/global",
+ "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.4.0",
+ "virtua": "^0.23.0"
+ },
+ "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-global/src/home.tsx b/packages/lume-column-global/src/home.tsx
new file mode 100644
index 00000000..a5ff74e1
--- /dev/null
+++ b/packages/lume-column-global/src/home.tsx
@@ -0,0 +1,126 @@
+import { RepostNote, TextNote, useArk } from "@lume/ark";
+import { ArrowRightCircleIcon, LoaderIcon, SearchIcon } from "@lume/icons";
+import { EmptyFeed } from "@lume/ui";
+import { FETCH_LIMIT } from "@lume/utils";
+import { type NDKEvent, NDKKind } from "@nostr-dev-kit/ndk";
+import { useInfiniteQuery } from "@tanstack/react-query";
+import { useEffect, useMemo, useRef } from "react";
+import { Link } from "react-router-dom";
+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, hasNextPage, isLoading, isFetchingNextPage, fetchNextPage } =
+ useInfiniteQuery({
+ queryKey: [colKey],
+ initialPageParam: 0,
+ queryFn: async ({
+ signal,
+ pageParam,
+ }: {
+ signal: AbortSignal;
+ pageParam: number;
+ }) => {
+ if (!ark.account.contacts.length) return [];
+
+ const events = await ark.getInfiniteEvents({
+ filter: {
+ kinds: [NDKKind.Text, NDKKind.Repost],
+ },
+ limit: FETCH_LIMIT,
+ pageParam,
+ signal,
+ });
+
+ return events;
+ },
+ getNextPageParam: (lastPage) => {
+ const lastEvent = lastPage.at(-1);
+ if (!lastEvent) return;
+ return lastEvent.created_at - 1;
+ },
+ select: (data) => data?.pages.flatMap((page) => page),
+ refetchOnWindowFocus: false,
+ refetchOnMount: false,
+ });
+
+ const renderItem = (event: NDKEvent) => {
+ switch (event.kind) {
+ case NDKKind.Text:
+ return ;
+ case NDKKind.Repost:
+ return ;
+ default:
+ return ;
+ }
+ };
+
+ 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.length ? (
+
+
+
+
+ Find accounts to follow
+
+
+ ) : (
+ data.map((item) => renderItem(item))
+ )}
+
+ {hasNextPage ? (
+
+ ) : null}
+
+
+
+ );
+}
diff --git a/packages/lume-column-global/src/index.tsx b/packages/lume-column-global/src/index.tsx
new file mode 100644
index 00000000..2efddb8f
--- /dev/null
+++ b/packages/lume-column-global/src/index.tsx
@@ -0,0 +1,19 @@
+import { Column } from "@lume/ark";
+import { IColumn } from "@lume/types";
+import { EventRoute, UserRoute } from "@lume/ui";
+import { HomeRoute } from "./home";
+
+export function Global({ column }: { column: IColumn }) {
+ const colKey = `global-${column.id}`;
+
+ return (
+
+
+
+ } />
+ } />
+ } />
+
+
+ );
+}
diff --git a/packages/lume-column-global/tailwind.config.js b/packages/lume-column-global/tailwind.config.js
new file mode 100644
index 00000000..49c48c7a
--- /dev/null
+++ b/packages/lume-column-global/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-global/tsconfig.json b/packages/lume-column-global/tsconfig.json
new file mode 100644
index 00000000..34a32891
--- /dev/null
+++ b/packages/lume-column-global/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "@lume/tsconfig/base.json",
+ "compilerOptions": {
+ "outDir": "dist"
+ },
+ "include": ["src"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/packages/lume-column-timeline/src/home.tsx b/packages/lume-column-timeline/src/home.tsx
index 5a7ae8f0..cacb30e9 100644
--- a/packages/lume-column-timeline/src/home.tsx
+++ b/packages/lume-column-timeline/src/home.tsx
@@ -3,7 +3,7 @@ import { ArrowRightCircleIcon, LoaderIcon, SearchIcon } from "@lume/icons";
import { EmptyFeed } from "@lume/ui";
import { FETCH_LIMIT } from "@lume/utils";
import { NDKEvent, NDKKind } from "@nostr-dev-kit/ndk";
-import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
+import { useInfiniteQuery } from "@tanstack/react-query";
import { useEffect, useMemo, useRef } from "react";
import { Link } from "react-router-dom";
import { CacheSnapshot, VList, VListHandle } from "virtua";
@@ -12,7 +12,6 @@ export function HomeRoute({ colKey }: { colKey: string }) {
const ark = useArk();
const ref = useRef();
const cacheKey = `${colKey}-vlist`;
- const queryClient = useQueryClient();
const [offset, cache] = useMemo(() => {
const serialized = sessionStorage.getItem(cacheKey);
diff --git a/packages/utils/src/constants.ts b/packages/utils/src/constants.ts
index 70dfd3d0..9aa3c539 100644
--- a/packages/utils/src/constants.ts
+++ b/packages/utils/src/constants.ts
@@ -57,6 +57,7 @@ export const COL_TYPES = {
hashtag: 3,
group: 4,
antenas: 5,
+ global: 6,
trendingNotes: 9000,
foryou: 9998,
newsfeed: 9999,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 392e407d..44413422 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -72,6 +72,9 @@ importers:
'@columns/foryou':
specifier: workspace:^
version: link:../../packages/lume-column-foryou
+ '@columns/global':
+ specifier: workspace:^
+ version: link:../../packages/lume-column-global
'@columns/group':
specifier: workspace:^
version: link:../../packages/lume-column-group
@@ -593,6 +596,58 @@ importers:
specifier: ^5.3.3
version: 5.3.3
+ packages/lume-column-global:
+ 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.4.0
+ version: 1.4.0(react-dom@18.2.0)(react@18.2.0)
+ virtua:
+ specifier: ^0.23.0
+ version: 0.23.0(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-group:
dependencies:
'@lume/ark':
@@ -697,6 +752,58 @@ importers:
specifier: ^5.3.3
version: 5.3.3
+ packages/lume-column-relay:
+ 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.4.0
+ version: 1.4.0(react-dom@18.2.0)(react@18.2.0)
+ virtua:
+ specifier: ^0.23.0
+ version: 0.23.0(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-thread:
dependencies:
'@lume/ark':