From a393469c1724a8e60c3c2f47cb6dfc6edf6202d1 Mon Sep 17 00:00:00 2001 From: Jure <44338+hoornet@users.noreply.github.com> Date: Sat, 11 Apr 2026 22:29:25 +0200 Subject: [PATCH] Add interest selection step to new-user onboarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New users now choose topics after backing up their key. Selected interests are saved to localStorage (wrystr_interests) and surfaced as clickable hashtag pills in the Following feed empty state, giving new users a path into content without auto-following strangers. Flow: welcome → create → backup → interests → app Login path is unchanged. --- src/components/feed/Feed.tsx | 22 +++++ src/components/onboarding/OnboardingFlow.tsx | 89 +++++++++++++++++++- 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/src/components/feed/Feed.tsx b/src/components/feed/Feed.tsx index 5eb0f1d..d484635 100644 --- a/src/components/feed/Feed.tsx +++ b/src/components/feed/Feed.tsx @@ -41,6 +41,7 @@ export function Feed() { const contentMatchesMutedKeyword = useMuteStore((s) => s.contentMatchesMutedKeyword); const tab = useUIStore((s) => s.feedTab); const setTab = useUIStore((s) => s.setFeedTab); + const openHashtag = useUIStore((s) => s.openHashtag); const feedLanguageFilter = useUIStore((s) => s.feedLanguageFilter); const setFeedLanguageFilter = useUIStore((s) => s.setFeedLanguageFilter); const [followNotes, setFollowNotes] = useState([]); @@ -224,6 +225,27 @@ export function Feed() { ? "Try clearing the script filter or refreshing." : "Try refreshing or switching tabs."}

+ {isFollowing && follows.length === 0 && (() => { + const stored = localStorage.getItem("wrystr_interests"); + const interests: string[] = stored ? JSON.parse(stored) : []; + if (interests.length === 0) return null; + return ( +
+

Explore your interests:

+
+ {interests.map((tag) => ( + + ))} +
+
+ ); + })()} )} diff --git a/src/components/onboarding/OnboardingFlow.tsx b/src/components/onboarding/OnboardingFlow.tsx index 4703220..25f54fa 100644 --- a/src/components/onboarding/OnboardingFlow.tsx +++ b/src/components/onboarding/OnboardingFlow.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import { useUserStore } from "../../stores/user"; -type Step = "welcome" | "create" | "backup" | "login"; +type Step = "welcome" | "create" | "backup" | "interests" | "login"; interface OnboardingFlowProps { onComplete: () => void; @@ -29,6 +29,87 @@ function Body({ children }: { children: React.ReactNode }) { return

{children}

; } +// ─── Interest topics ───────────────────────────────────────────────────────── + +const INTEREST_TOPICS = [ + { emoji: "₿", label: "Bitcoin", tag: "bitcoin" }, + { emoji: "⚡", label: "Nostr", tag: "nostr" }, + { emoji: "💻", label: "Tech", tag: "technology" }, + { emoji: "🔒", label: "Privacy", tag: "privacy" }, + { emoji: "🎨", label: "Art", tag: "art" }, + { emoji: "🎵", label: "Music", tag: "music" }, + { emoji: "📷", label: "Photography", tag: "photography" }, + { emoji: "🎮", label: "Gaming", tag: "gaming" }, + { emoji: "🔬", label: "Science", tag: "science" }, + { emoji: "📚", label: "Books", tag: "books" }, + { emoji: "🐧", label: "Linux", tag: "linux" }, + { emoji: "🤔", label: "Philosophy", tag: "philosophy" }, + { emoji: "💰", label: "Finance", tag: "finance" }, + { emoji: "🏃", label: "Health", tag: "health" }, + { emoji: "🍕", label: "Food", tag: "food" }, + { emoji: "✈️", label: "Travel", tag: "travel" }, + { emoji: "⚽", label: "Sports", tag: "sports" }, + { emoji: "📰", label: "News", tag: "news" }, +]; + +// ─── Step: Interests ───────────────────────────────────────────────────────── + +function InterestsStep({ onComplete }: { onComplete: () => void }) { + const [selected, setSelected] = useState>(new Set()); + + const toggle = (tag: string) => + setSelected((prev) => { + const next = new Set(prev); + next.has(tag) ? next.delete(tag) : next.add(tag); + return next; + }); + + const handleConfirm = () => { + localStorage.setItem("wrystr_interests", JSON.stringify([...selected])); + onComplete(); + }; + + return ( + + What are you into? + Pick a few topics to get your feed started. You can always change this later. + +
+ {INTEREST_TOPICS.map(({ emoji, label, tag }) => { + const active = selected.has(tag); + return ( + + ); + })} +
+ + + +
+ ); +} + // ─── Step: Welcome ─────────────────────────────────────────────────────────── function WelcomeStep({ onCreateNew, onHaveKey }: { onCreateNew: () => void; onHaveKey: () => void }) { @@ -313,7 +394,11 @@ export function OnboardingFlow({ onComplete }: OnboardingFlowProps) { } if (step === "backup" && generatedSigner) { - return ; + return setStep("interests")} />; + } + + if (step === "interests") { + return ; } if (step === "login") {