diff --git a/apps/desktop2/public/ai.jpg b/apps/desktop2/public/ai.jpg
new file mode 100644
index 00000000..36843631
Binary files /dev/null and b/apps/desktop2/public/ai.jpg differ
diff --git a/apps/desktop2/public/newsfeed.png b/apps/desktop2/public/newsfeed.png
new file mode 100644
index 00000000..4e0a06ad
Binary files /dev/null and b/apps/desktop2/public/newsfeed.png differ
diff --git a/apps/desktop2/public/newsfeed@2x.png b/apps/desktop2/public/newsfeed@2x.png
new file mode 100644
index 00000000..91ec29dc
Binary files /dev/null and b/apps/desktop2/public/newsfeed@2x.png differ
diff --git a/apps/desktop2/src/routes/__root.tsx b/apps/desktop2/src/routes/__root.tsx
index f5b701c3..53312b17 100644
--- a/apps/desktop2/src/routes/__root.tsx
+++ b/apps/desktop2/src/routes/__root.tsx
@@ -25,6 +25,7 @@ interface RouterContext {
// Profile
accounts?: string[];
profile?: Metadata;
+ isNewUser?: boolean;
// Editor
initialValue?: EditorElement[];
}
diff --git a/apps/desktop2/src/routes/auth/new/backup.tsx b/apps/desktop2/src/routes/auth/new/backup.tsx
index 50c3545e..637e147a 100644
--- a/apps/desktop2/src/routes/auth/new/backup.tsx
+++ b/apps/desktop2/src/routes/auth/new/backup.tsx
@@ -1,5 +1,6 @@
import { CheckIcon } from "@lume/icons";
import type { AppRouteSearch } from "@lume/types";
+import { Spinner } from "@lume/ui";
import { displayNsec } from "@lume/utils";
import * as Checkbox from "@radix-ui/react-checkbox";
import { createFileRoute, useNavigate } from "@tanstack/react-router";
@@ -25,6 +26,7 @@ function Screen() {
const [key, setKey] = useState(null);
const [passphase, setPassphase] = useState("");
const [copied, setCopied] = useState(false);
+ const [loading, setLoading] = useState(false);
const [confirm, setConfirm] = useState({ c1: false, c2: false, c3: false });
const navigate = useNavigate();
@@ -42,13 +44,19 @@ function Screen() {
});
}
- const encrypted: string = await invoke("get_encrypted_key", {
+ // start loading
+ setLoading(true);
+
+ invoke("get_encrypted_key", {
npub: account,
password: passphase,
+ }).then((encrypted: string) => {
+ // update state
+ setKey(encrypted);
+ setLoading(false);
});
-
- setKey(encrypted);
} catch (e) {
+ setLoading(false);
toast.error(String(e));
}
};
@@ -180,9 +188,10 @@ function Screen() {
submit()}
+ disabled={loading}
className="inline-flex h-11 w-full shrink-0 items-center justify-center rounded-lg bg-blue-500 font-semibold text-white hover:bg-blue-600 disabled:opacity-50"
>
- {t("global.continue")}
+ {loading ? : t("global.continue")}
diff --git a/apps/desktop2/src/routes/auth/settings.tsx b/apps/desktop2/src/routes/auth/settings.tsx
index 26b72cd9..66513a19 100644
--- a/apps/desktop2/src/routes/auth/settings.tsx
+++ b/apps/desktop2/src/routes/auth/settings.tsx
@@ -85,8 +85,11 @@ function Screen() {
const eventId = await ark.set_settings(newSettings);
if (eventId) {
- console.log("event_id: ", eventId);
- navigate({ to: "/$account/home", params: { account }, replace: true });
+ return navigate({
+ to: "/$account/home",
+ params: { account },
+ replace: true,
+ });
}
} catch (e) {
setLoading(false);
diff --git a/apps/desktop2/src/routes/newsfeed.tsx b/apps/desktop2/src/routes/newsfeed.tsx
index b4c781fb..e58b8dfc 100644
--- a/apps/desktop2/src/routes/newsfeed.tsx
+++ b/apps/desktop2/src/routes/newsfeed.tsx
@@ -6,7 +6,8 @@ import { ArrowRightCircleIcon, ArrowRightIcon } from "@lume/icons";
import { type ColumnRouteSearch, type Event, Kind } from "@lume/types";
import { Spinner } from "@lume/ui";
import { useInfiniteQuery } from "@tanstack/react-query";
-import { Link, createFileRoute } from "@tanstack/react-router";
+import { Link } from "@tanstack/react-router";
+import { createFileRoute } from "@tanstack/react-router";
import { Virtualizer } from "virtua";
export const Route = createFileRoute("/newsfeed")({
@@ -121,8 +122,6 @@ export function Screen() {
}
function Empty() {
- const search = Route.useSearch();
-
return (
@@ -135,29 +134,19 @@ function Empty() {
-
- Show global newsfeed
-
-
- Show trending notes
+ Show trending notes
- Discover trending users
+ Discover trending users
diff --git a/apps/desktop2/src/routes/onboarding.tsx b/apps/desktop2/src/routes/onboarding.tsx
new file mode 100644
index 00000000..8cb91667
--- /dev/null
+++ b/apps/desktop2/src/routes/onboarding.tsx
@@ -0,0 +1,445 @@
+import { ArrowRightIcon, CancelIcon } from "@lume/icons";
+import type { ColumnRouteSearch, LumeColumn } from "@lume/types";
+import { Spinner, User } from "@lume/ui";
+import { cn } from "@lume/utils";
+import { createFileRoute } from "@tanstack/react-router";
+import { invoke } from "@tauri-apps/api/core";
+import { getCurrent } from "@tauri-apps/api/window";
+import { useState } from "react";
+import { useForm } from "react-hook-form";
+import { toast } from "sonner";
+
+export const Route = createFileRoute("/onboarding")({
+ validateSearch: (search: Record): ColumnRouteSearch => {
+ return {
+ account: search.account,
+ label: search.label,
+ name: search.name,
+ };
+ },
+ component: Screen,
+});
+
+function Screen() {
+ const { label } = Route.useSearch();
+ const {
+ register,
+ handleSubmit,
+ reset,
+ formState: { isValid, isSubmitting },
+ } = useForm();
+
+ const [userType, setUserType] = useState<"new" | "veteran">(null);
+
+ const install = async (column: LumeColumn) => {
+ const mainWindow = getCurrent();
+ await mainWindow.emit("columns", { type: "add", column });
+ };
+
+ const close = async () => {
+ const mainWindow = getCurrent();
+ await mainWindow.emit("columns", { type: "remove", label });
+ };
+
+ const friendToFriend = async (data: { npub: string }) => {
+ if (!data.npub.startsWith("npub1"))
+ return toast.warning(
+ "NPUB is invalid. NPUB must be starts with npub1...",
+ );
+
+ try {
+ const connect: boolean = await invoke("friend_to_friend", {
+ npub: data.npub,
+ });
+
+ if (connect) {
+ const column = {
+ label: "newsfeed",
+ name: "Newsfeed",
+ content: "/newsfeed",
+ };
+ const mainWindow = getCurrent();
+ await mainWindow.emit("columns", { type: "add", column });
+
+ // reset form
+ reset();
+ }
+ } catch (e) {
+ toast.error(String(e));
+ }
+ };
+
+ return (
+
+
+
Welcome to Lume
+
+ Here are a few suggestions to help you get started.
+
+
+
+
+
+
+
+
+
+
+
Mide
+
+ 👋 Yo! I'm Mide, and I'll be your friendly guide to Nostr and
+ beyond. Looking forward to our adventure together!
+
+
+
+
+
+
+
You
+
+ How can I get started?
+
+
setUserType("new")}
+ className={cn(
+ "mt-1 px-3 py-2 shadow-primary flex items-center justify-between gap-6 bg-white hover:bg-blue-500 hover:text-white dark:bg-white/10 rounded-lg",
+ userType === "new"
+ ? "bg-blue-500 text-white hover:bg-blue-600"
+ : "",
+ )}
+ >
+ I'm completely new to Nostr.
+
+
+
setUserType("veteran")}
+ className={cn(
+ "mt-1 px-3 py-2 shadow-primary flex items-center justify-between gap-6 bg-white hover:bg-blue-500 hover:text-white dark:bg-white/10 rounded-lg",
+ userType === "veteran"
+ ? "bg-blue-500 text-white hover:bg-blue-600"
+ : "",
+ )}
+ >
+ I've already been using another Nostr client.
+
+
+
+
+ {userType === "veteran" ? (
+
+
+
+
Mide
+
+ So, I'm excited to give you a quick intro to Lume and all the
+ awesome features it has to offer. Let's dive in!
+
+
+
+ ) : null}
+ {userType === "veteran" ? (
+
+
+
+
You
+
+ Thanks! But I already know about Lume.
+
+
+ install({
+ label: "newsfeed",
+ name: "Newsfeed",
+ content: "/newsfeed",
+ })
+ }
+ className="mt-1 px-3 py-2 shadow-primary flex items-center justify-between gap-6 bg-white hover:bg-blue-500 hover:text-white dark:bg-white/10 rounded-lg"
+ >
+ Skip! Show my newsfeed
+
+
+
+
+ ) : null}
+ {userType === "veteran" ? (
+
+
+
+
Mide
+
+ First off, Lume is a social media client for Nostr. It's a
+ place where you can follow friends, dive into chats, and post
+ what's on your mind.
+
+
+
+ ) : null}
+ {userType === "veteran" ? (
+
+
+
+
Mide
+
+ That's not all! What makes Lume unique is the column system.
+ You can enhance your experience by adding new columns from the
+ Lume Store.
+
+
+ If you're confused about the term "Column," you can imagine it
+ as mini-apps, with each column providing its own experience.
+
+
+ Here is a quick guide for how to add a new column:
+
+
+
+
+ Your browser does not support the video tag.
+
+
+
+
+ ) : null}
+ {userType === "veteran" ? (
+
+
+
+
You
+
+ Can you introduce me to the UI? I am still confused.
+
+
+
+ ) : null}
+ {userType === "veteran" ? (
+
+
+
+
Mide
+
+ Of course, here is a quick introduction video for Lume.
+
+
+
+
+ Your browser does not support the video tag.
+
+
+
+
+ ) : null}
+ {userType === "new" ? (
+
+
+
+
Mide
+
+ Diving into new social media platforms like Nostr can be a bit
+ overwhelming, but don't worry! Here are some handy tips to
+ help you navigate and discover what interests you.
+
+
+ install({
+ label: "foryou",
+ name: "For you",
+ content: "/foryou",
+ })
+ }
+ className="mt-1 px-3 py-2 shadow-primary flex items-center justify-between bg-white hover:bg-blue-500 hover:text-white dark:bg-white/10 rounded-lg"
+ >
+ Add some topics that you're interested in.
+
+
+
+ install({
+ label: "trending_users",
+ name: "Trending",
+ content: "/trending/users",
+ })
+ }
+ className="mt-1 px-3 py-2 shadow-primary flex items-center justify-between bg-white hover:bg-blue-500 hover:text-white dark:bg-white/10 rounded-lg"
+ >
+ Follow some users.
+
+
+
+
+ ) : null}
+ {userType === "new" ? (
+
+
+
+
You
+
+ My girlfriend introduced Nostr to me, and I have her NPUB. Can
+ I get the same experiences as her?
+
+
+
+ ) : null}
+ {userType === "new" ? (
+
+
+
+
Mide
+
+ Absolutely! Since your girlfriend shared her NPUB with you,
+ you can dive into Nostr and explore it just like she does.
+ It's a great way to share experiences and discover what Nostr
+ has to offer together!
+
+
+
+
+ ) : null}
+ {userType ? (
+ <>
+
+
+
+
You
+
+ Thank you. I can use Lume and explore Nostr by myself from
+ now on.
+
+
+
+
+
+
+
+
Mide
+
+ If you want to close this onboarding board, you can click
+ the button below.
+
+
close()}
+ className="mt-1 px-3 py-2 shadow-primary flex items-center justify-between bg-white hover:bg-blue-500 hover:text-white dark:bg-white/10 rounded-lg"
+ >
+ Close
+
+
+
+
+ >
+ ) : null}
+
+
+
+ );
+}
+
+function Mide() {
+ return (
+
+ );
+}
+
+function CurrentUser() {
+ const { account } = Route.useSearch();
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/apps/desktop2/src/routes/store.official.tsx b/apps/desktop2/src/routes/store.official.tsx
index 85feaa8d..d257a7b9 100644
--- a/apps/desktop2/src/routes/store.official.tsx
+++ b/apps/desktop2/src/routes/store.official.tsx
@@ -5,7 +5,6 @@ import { getCurrent } from "@tauri-apps/api/window";
import { readTextFile } from "@tauri-apps/plugin-fs";
export const Route = createFileRoute("/store/official")({
- component: Screen,
beforeLoad: async () => {
const resourcePath = await resolveResource(
"resources/official_columns.json",
@@ -18,6 +17,7 @@ export const Route = createFileRoute("/store/official")({
officialColumns,
};
},
+ component: Screen,
});
function Screen() {
diff --git a/package.json b/package.json
index 1e72dd87..d883ef8e 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"tauri": "tauri"
},
"devDependencies": {
- "@biomejs/biome": "^1.7.1",
+ "@biomejs/biome": "1.7.3",
"@tauri-apps/cli": "2.0.0-beta.12",
"turbo": "^1.13.3"
},
diff --git a/packages/ark/src/ark.ts b/packages/ark/src/ark.ts
index 44191b09..d8dc984d 100644
--- a/packages/ark/src/ark.ts
+++ b/packages/ark/src/ark.ts
@@ -1,10 +1,10 @@
import {
- Kind,
type Contact,
type Event,
type EventWithReplies,
type Interests,
type Keys,
+ Kind,
type LumeColumn,
type Metadata,
type Settings,
@@ -194,8 +194,10 @@ export class Ark {
.filter((el) => el[0] === "e")
?.map((item) => item[1]);
- if (eventIds && eventIds.length) {
- eventIds.forEach((id) => seenIds.add(id));
+ if (eventIds?.length) {
+ for (const id of eventIds) {
+ seenIds.add(id);
+ }
}
}
diff --git a/packages/tailwindcss/package.json b/packages/tailwindcss/package.json
index 3d2c2bde..99b41224 100644
--- a/packages/tailwindcss/package.json
+++ b/packages/tailwindcss/package.json
@@ -13,6 +13,7 @@
"@evilmartians/harmony": "^1.2.0",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.13",
+ "tailwind-gradient-mask-image": "^1.2.0",
"tailwind-scrollbar": "^3.1.0",
"tailwindcss": "^3.4.3"
}
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 24a660da..094757b5 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -38,7 +38,6 @@
"slate-react": "^0.102.0",
"sonner": "^1.4.41",
"string-strip-html": "^13.4.8",
- "tailwind-gradient-mask-image": "^1.2.0",
"uqr": "^0.1.2",
"use-debounce": "^10.0.0",
"virtua": "^0.30.2"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9a74365d..a9874cf8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -46,8 +46,8 @@ importers:
version: 2.0.0-beta.3
devDependencies:
'@biomejs/biome':
- specifier: ^1.7.1
- version: 1.7.1
+ specifier: 1.7.3
+ version: 1.7.3
'@tauri-apps/cli':
specifier: 2.0.0-beta.12
version: 2.0.0-beta.12
@@ -283,6 +283,9 @@ importers:
'@tailwindcss/typography':
specifier: ^0.5.13
version: 0.5.13(tailwindcss@3.4.3)
+ tailwind-gradient-mask-image:
+ specifier: ^1.2.0
+ version: 1.2.0
tailwind-scrollbar:
specifier: ^3.1.0
version: 3.1.0(tailwindcss@3.4.3)
@@ -402,9 +405,6 @@ importers:
string-strip-html:
specifier: ^13.4.8
version: 13.4.8
- tailwind-gradient-mask-image:
- specifier: ^1.2.0
- version: 1.2.0
uqr:
specifier: ^0.1.2
version: 0.1.2
@@ -921,24 +921,24 @@ packages:
'@babel/helper-validator-identifier': 7.24.5
to-fast-properties: 2.0.0
- /@biomejs/biome@1.7.1:
- resolution: {integrity: sha512-wb2UNoFXcgaMdKXKT5ytsYntaogl2FSTjDt20CZynF3v7OXQUcIpTrr+be3XoOGpoZRj3Ytq9TSpmplUREXmeA==}
+ /@biomejs/biome@1.7.3:
+ resolution: {integrity: sha512-ogFQI+fpXftr+tiahA6bIXwZ7CSikygASdqMtH07J2cUzrpjyTMVc9Y97v23c7/tL1xCZhM+W9k4hYIBm7Q6cQ==}
engines: {node: '>=14.21.3'}
hasBin: true
requiresBuild: true
optionalDependencies:
- '@biomejs/cli-darwin-arm64': 1.7.1
- '@biomejs/cli-darwin-x64': 1.7.1
- '@biomejs/cli-linux-arm64': 1.7.1
- '@biomejs/cli-linux-arm64-musl': 1.7.1
- '@biomejs/cli-linux-x64': 1.7.1
- '@biomejs/cli-linux-x64-musl': 1.7.1
- '@biomejs/cli-win32-arm64': 1.7.1
- '@biomejs/cli-win32-x64': 1.7.1
+ '@biomejs/cli-darwin-arm64': 1.7.3
+ '@biomejs/cli-darwin-x64': 1.7.3
+ '@biomejs/cli-linux-arm64': 1.7.3
+ '@biomejs/cli-linux-arm64-musl': 1.7.3
+ '@biomejs/cli-linux-x64': 1.7.3
+ '@biomejs/cli-linux-x64-musl': 1.7.3
+ '@biomejs/cli-win32-arm64': 1.7.3
+ '@biomejs/cli-win32-x64': 1.7.3
dev: true
- /@biomejs/cli-darwin-arm64@1.7.1:
- resolution: {integrity: sha512-qfLrIIB58dkgiY/1tgG6fSCBK22PZaSIf6blweZBsG6iMij05mEuJt50ne+zPnNFNUmt8t43NC/qOXT3iFHQBA==}
+ /@biomejs/cli-darwin-arm64@1.7.3:
+ resolution: {integrity: sha512-eDvLQWmGRqrPIRY7AIrkPHkQ3visEItJKkPYSHCscSDdGvKzYjmBJwG1Gu8+QC5ed6R7eiU63LEC0APFBobmfQ==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
@@ -946,8 +946,8 @@ packages:
dev: true
optional: true
- /@biomejs/cli-darwin-x64@1.7.1:
- resolution: {integrity: sha512-OGeyNsEcp5VnKbF9/TBjPCTHNEOm7oHegEve07U3KZmzqfpw2Oe3i9DVW8t6vvj1TYbrwWYCld25H34kBDY7Vg==}
+ /@biomejs/cli-darwin-x64@1.7.3:
+ resolution: {integrity: sha512-JXCaIseKRER7dIURsVlAJacnm8SG5I0RpxZ4ya3dudASYUc68WGl4+FEN03ABY3KMIq7hcK1tzsJiWlmXyosZg==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
@@ -955,8 +955,8 @@ packages:
dev: true
optional: true
- /@biomejs/cli-linux-arm64-musl@1.7.1:
- resolution: {integrity: sha512-giH0/CzLOJ+wbxLxd5Shnr5xQf5fGnTRWLDe3lzjaF7IplVydNCEeZJtncB01SvyA6DAFJsvQ4LNxzAOQfEVCg==}
+ /@biomejs/cli-linux-arm64-musl@1.7.3:
+ resolution: {integrity: sha512-c8AlO45PNFZ1BYcwaKzdt46kYbuP6xPGuGQ6h4j3XiEDpyseRRUy/h+6gxj07XovmyxKnSX9GSZ6nVbZvcVUAw==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
@@ -964,8 +964,8 @@ packages:
dev: true
optional: true
- /@biomejs/cli-linux-arm64@1.7.1:
- resolution: {integrity: sha512-MQDf5wErj1iBvlcxCyOa0XqZYN8WJrupVgbNnqhntO3yVATg8GxduVUn1fDSaolznkDRsj7Pz3Xu1esBFwvfmg==}
+ /@biomejs/cli-linux-arm64@1.7.3:
+ resolution: {integrity: sha512-phNTBpo7joDFastnmZsFjYcDYobLTx4qR4oPvc9tJ486Bd1SfEVPHEvJdNJrMwUQK56T+TRClOQd/8X1nnjA9w==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
@@ -973,8 +973,8 @@ packages:
dev: true
optional: true
- /@biomejs/cli-linux-x64-musl@1.7.1:
- resolution: {integrity: sha512-ySNDtPhsLxU125IFHHAxfpoHBpkM56s4mEXeO70GZtgZay/o1h8IUPWCWf5Z7gKgc4jwgYN1U1U9xabI3hZVAg==}
+ /@biomejs/cli-linux-x64-musl@1.7.3:
+ resolution: {integrity: sha512-UdEHKtYGWEX3eDmVWvQeT+z05T9/Sdt2+F/7zmMOFQ7boANeX8pcO6EkJPK3wxMudrApsNEKT26rzqK6sZRTRA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
@@ -982,8 +982,8 @@ packages:
dev: true
optional: true
- /@biomejs/cli-linux-x64@1.7.1:
- resolution: {integrity: sha512-3wmCsGcC3KZ4pfTknXHfyMMlXPMhgfXVAcG5GlrR+Tq2JGiAw0EUydaLpsSBEbcG7IxH6OiUZEJZ95kAycCHBA==}
+ /@biomejs/cli-linux-x64@1.7.3:
+ resolution: {integrity: sha512-vnedYcd5p4keT3iD48oSKjOIRPYcjSNNbd8MO1bKo9ajg3GwQXZLAH+0Cvlr+eMsO67/HddWmscSQwTFrC/uPA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
@@ -991,8 +991,8 @@ packages:
dev: true
optional: true
- /@biomejs/cli-win32-arm64@1.7.1:
- resolution: {integrity: sha512-8hIDakEqZn0i6+388noYKdZ0ZrovTwnvMU/Qp/oJou0G7EPVdXupOe0oxiQSdRN0W7f6CS/yjPCYuVGzDG6r0g==}
+ /@biomejs/cli-win32-arm64@1.7.3:
+ resolution: {integrity: sha512-unNCDqUKjujYkkSxs7gFIfdasttbDC4+z0kYmcqzRk6yWVoQBL4dNLcCbdnJS+qvVDNdI9rHp2NwpQ0WAdla4Q==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
@@ -1000,8 +1000,8 @@ packages:
dev: true
optional: true
- /@biomejs/cli-win32-x64@1.7.1:
- resolution: {integrity: sha512-3W9k3uH6Ea6VOpAS9xkkAlS0LTfnGQjmIUCegZ8SDtK2NgJ1gO+qdEkGJb0ltahusFTN1QxJ107dM7ASA9IUEg==}
+ /@biomejs/cli-win32-x64@1.7.3:
+ resolution: {integrity: sha512-ZmByhbrnmz/UUFYB622CECwhKIPjJLLPr5zr3edhu04LzbfcOrz16VYeNq5dpO1ADG70FORhAJkaIGdaVBG00w==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
@@ -5912,7 +5912,7 @@ packages:
/tailwind-gradient-mask-image@1.2.0:
resolution: {integrity: sha512-tUJaGhvqbJFiVKJu6EU5n//KvGdVvY3L3VOFNqjztk13+ifAk00pcSNHBTgHfUiBGOEzDn0gFRbSmsftUV1lXA==}
- dev: false
+ dev: true
/tailwind-merge@2.3.0:
resolution: {integrity: sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==}
diff --git a/src-tauri/resources/official_columns.json b/src-tauri/resources/official_columns.json
index 363cbf57..3c783373 100644
--- a/src-tauri/resources/official_columns.json
+++ b/src-tauri/resources/official_columns.json
@@ -1,4 +1,14 @@
[
+ {
+ "label": "lZfXLFgPPR4NNrgjlWDxn",
+ "name": "Newsfeed",
+ "content": "/newsfeed",
+ "logo": "",
+ "cover": "/newsfeed.png",
+ "coverRetina": "/newsfeed@2x.png",
+ "author": "Lume",
+ "description": "Keep up to date with people you're following."
+ },
{
"label": "rRtguZwIpd5G8Wt54OTb7",
"name": "For you",
diff --git a/src-tauri/resources/system_columns.json b/src-tauri/resources/system_columns.json
index 04a28622..032e9c35 100644
--- a/src-tauri/resources/system_columns.json
+++ b/src-tauri/resources/system_columns.json
@@ -1,4 +1,4 @@
[
- { "label": "home", "name": "Home", "content": "/newsfeed" },
- { "label": "open", "name": "Open", "content": "/open" }
+ { "label": "onboarding", "name": "Onboarding", "content": "/onboarding" },
+ { "label": "open", "name": "Open", "content": "/open" }
]
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 7537439a..b204783f 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -121,6 +121,7 @@ fn main() {
nostr::metadata::get_balance,
nostr::metadata::zap_profile,
nostr::metadata::zap_event,
+ nostr::metadata::friend_to_friend,
nostr::event::get_event,
nostr::event::get_events_from,
nostr::event::get_events,
diff --git a/src-tauri/src/nostr/metadata.rs b/src-tauri/src/nostr/metadata.rs
index 94bc7168..0dae4e49 100644
--- a/src-tauri/src/nostr/metadata.rs
+++ b/src-tauri/src/nostr/metadata.rs
@@ -82,6 +82,45 @@ pub async fn get_activities(
}
}
+#[tauri::command]
+pub async fn friend_to_friend(npub: &str, state: State<'_, Nostr>) -> Result {
+ let client = &state.client;
+
+ match PublicKey::from_bech32(npub) {
+ Ok(author) => {
+ let mut contact_list: Vec = Vec::new();
+ let contact_list_filter = Filter::new()
+ .author(author)
+ .kind(Kind::ContactList)
+ .limit(1);
+
+ if let Ok(contact_list_events) = client.get_events_of(vec![contact_list_filter], None).await {
+ for event in contact_list_events.into_iter() {
+ for tag in event.into_iter_tags() {
+ if let Tag::PublicKey {
+ public_key,
+ relay_url,
+ alias,
+ uppercase: false,
+ } = tag
+ {
+ contact_list.push(Contact::new(public_key, relay_url, alias))
+ }
+ }
+ }
+ }
+
+ println!("contact list: {}", contact_list.len());
+
+ match client.set_contact_list(contact_list).await {
+ Ok(_) => Ok(true),
+ Err(err) => Err(err.to_string()),
+ }
+ }
+ Err(err) => Err(err.to_string()),
+ }
+}
+
#[tauri::command]
pub async fn get_current_user_profile(state: State<'_, Nostr>) -> Result {
let client = &state.client;