From e90c7da5d702b2976a8a360307da7ede671de8c0 Mon Sep 17 00:00:00 2001 From: ComputelessComputer Date: Sun, 22 Feb 2026 10:03:34 +0900 Subject: [PATCH 1/8] feat: improve onboarding step visual states Update onboarding step component to better distinguish between active, completed, and upcoming states. Move completed step indicator to a circular icon with checkmark and reduce title size. Add blur effect with reduced opacity for upcoming steps to clearly indicate they are not yet accessible. Adjust spacing and styling to improve visual hierarchy across different states. --- .../src/components/onboarding/shared.tsx | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/apps/desktop/src/components/onboarding/shared.tsx b/apps/desktop/src/components/onboarding/shared.tsx index 0abe4c0e7d..c8a4662102 100644 --- a/apps/desktop/src/components/onboarding/shared.tsx +++ b/apps/desktop/src/components/onboarding/shared.tsx @@ -32,24 +32,34 @@ export function OnboardingSection({ const isActive = status === "active"; const isCompleted = status === "completed"; + const isUpcoming = status === "upcoming"; return (
+ {isCompleted && ( +
+ +
+ )}
-

+

{title}

- {isCompleted && ( - - )} {import.meta.env.DEV && isActive && (onBack || onNext) && (
{onBack && ( @@ -93,6 +103,12 @@ export function OnboardingSection({ )} + + {isUpcoming && ( +
+
{children}
+
+ )}
); } From 788ae5a63129b19bea6825f4e8ca641ab840a189 Mon Sep 17 00:00:00 2001 From: ComputelessComputer Date: Sun, 22 Feb 2026 14:55:59 +0900 Subject: [PATCH 2/8] feat: improve onboarding step completion indicator Replace circular background container with direct CheckIcon display. Use green color instead of white on dark background for better visual feedback. Increase icon size from 3 to 4 for improved visibility and remove unnecessary wrapper div to simplify markup. --- apps/desktop/src/components/onboarding/shared.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/components/onboarding/shared.tsx b/apps/desktop/src/components/onboarding/shared.tsx index c8a4662102..a4db4c4955 100644 --- a/apps/desktop/src/components/onboarding/shared.tsx +++ b/apps/desktop/src/components/onboarding/shared.tsx @@ -44,9 +44,10 @@ export function OnboardingSection({ ])} > {isCompleted && ( -
- -
+ )}
From 6003ede8eafc21e28bf0e94295c563e5c30ddcd9 Mon Sep 17 00:00:00 2001 From: ComputelessComputer Date: Sun, 22 Feb 2026 15:02:58 +0900 Subject: [PATCH 3/8] refactor: simplify BeforeLogin component layout Consolidate SigninButton and ControlRegion components into a single BeforeLogin component. Replace OnboardingButton with standard button styling and improve the layout by repositioning elements in a more compact arrangement. Update button text to be more user-friendly and conditionally show troubleshooting option only when needed. --- .../onboarding/account/before-login.tsx | 62 ++++++------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/apps/desktop/src/components/onboarding/account/before-login.tsx b/apps/desktop/src/components/onboarding/account/before-login.tsx index 237ddf5970..9555707f1f 100644 --- a/apps/desktop/src/components/onboarding/account/before-login.tsx +++ b/apps/desktop/src/components/onboarding/account/before-login.tsx @@ -1,60 +1,38 @@ import { useEffect, useState } from "react"; import { useAuth } from "../../../auth"; -import { OnboardingButton } from "../shared"; -export function BeforeLogin({ onContinue }: { onContinue: () => void }) { - return ( -
- - -
- ); -} - -function SigninButton() { +export function BeforeLogin({ + onContinue: _onContinue, +}: { + onContinue: () => void; +}) { const auth = useAuth(); - const triggered = useAutoTriggerSignin(); - - return ( - auth?.signIn()} disabled={triggered}> - {triggered ? "Click here to Sign in" : "Signing in on your browser..."} - - ); -} - -function ControlRegion(_: { handleContinue: () => void }) { - const auth = useAuth(); const [showCallbackUrlInput, setShowCallbackUrlInput] = useState(false); return (
- {showCallbackUrlInput ? : null} - -
+
- - / - - {/* or - */} + {triggered && ( + + )}
+ {showCallbackUrlInput && }
); } From da05749539d8fee7b430dbe3a0ce9fe1578464e5 Mon Sep 17 00:00:00 2001 From: ComputelessComputer Date: Sun, 22 Feb 2026 15:14:52 +0900 Subject: [PATCH 4/8] feat: add icons and improve onboarding layout Replace text-based social links with iconified buttons using @iconify-icon/react. Add Discord, GitHub, and X icons to social links for better visual appeal. Restructure onboarding layout by moving title to sticky header and implementing auto-scroll navigation between onboarding steps for improved user experience during setup flow. --- .../components/main/body/onboarding/index.tsx | 152 ++++++++++-------- .../src/components/onboarding/final.tsx | 43 ++--- .../src/components/onboarding/shared.tsx | 26 ++- 3 files changed, 125 insertions(+), 96 deletions(-) diff --git a/apps/desktop/src/components/main/body/onboarding/index.tsx b/apps/desktop/src/components/main/body/onboarding/index.tsx index 9c1e8be010..1659b4d93b 100644 --- a/apps/desktop/src/components/main/body/onboarding/index.tsx +++ b/apps/desktop/src/components/main/body/onboarding/index.tsx @@ -1,7 +1,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { platform } from "@tauri-apps/plugin-os"; import { Volume2Icon, VolumeXIcon } from "lucide-react"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { commands as analyticsCommands } from "@hypr/plugin-analytics"; import { commands as sfxCommands } from "@hypr/plugin-sfx"; @@ -115,74 +115,100 @@ export function TabContentOnboarding({ } }, [close, currentTab, queryClient]); + const scrollRef = useRef(null); + + useEffect(() => { + const timeout = setTimeout(() => { + const el = scrollRef.current?.querySelector( + `[data-step="${currentStep}"]`, + ); + if (el) { + el.scrollIntoView({ behavior: "smooth", block: "start" }); + } + }, 350); + return () => clearTimeout(timeout); + }, [currentStep]); + return ( -
- - -
+
+

Welcome to Char

- - - - - - setIsMuted((prev) => !prev)} + className="p-1.5 rounded-full hover:bg-neutral-100 transition-colors" + aria-label={isMuted ? "Unmute" : "Mute"} > - - - - - - - - - - - - void finishOnboarding(handleFinish)} - > - - + {isMuted ? ( + + ) : ( + + )} + +
+ +
+
+ + + + + + + + + + + + + + + + + void finishOnboarding(handleFinish)} + > + + +
diff --git a/apps/desktop/src/components/onboarding/final.tsx b/apps/desktop/src/components/onboarding/final.tsx index 28813dfcf7..a54b9c1495 100644 --- a/apps/desktop/src/components/onboarding/final.tsx +++ b/apps/desktop/src/components/onboarding/final.tsx @@ -1,3 +1,5 @@ +import { Icon } from "@iconify-icon/react"; + import { commands as analyticsCommands } from "@hypr/plugin-analytics"; import { commands as openerCommands } from "@hypr/plugin-opener2"; import { commands as sfxCommands } from "@hypr/plugin-sfx"; @@ -6,29 +8,34 @@ import { commands } from "../../types/tauri.gen"; import { OnboardingButton } from "./shared"; const SOCIALS = [ - { label: "Discord", url: "https://discord.gg/CX8gTH2tj9" }, - { label: "GitHub", url: "https://github.com/fastrepl/hyprnote" }, - { label: "X", url: "https://x.com/getcharnotes" }, + { + label: "Discord", + icon: "simple-icons:discord", + url: "https://discord.gg/CX8gTH2tj9", + }, + { + label: "GitHub", + icon: "simple-icons:github", + url: "https://github.com/fastrepl/hyprnote", + }, + { label: "X", icon: "simple-icons:x", url: "https://x.com/getcharnotes" }, ] as const; export function FinalSection({ onContinue }: { onContinue: () => void }) { return (
-
-

- Join our community and stay updated: -

-
- {SOCIALS.map(({ label, url }) => ( - - ))} -
+
+ Join our community and stay updated: + {SOCIALS.map(({ label, icon, url }) => ( + + ))}
void finishOnboarding(onContinue)}> diff --git a/apps/desktop/src/components/onboarding/shared.tsx b/apps/desktop/src/components/onboarding/shared.tsx index a4db4c4955..c2fe2be4b2 100644 --- a/apps/desktop/src/components/onboarding/shared.tsx +++ b/apps/desktop/src/components/onboarding/shared.tsx @@ -14,33 +14,35 @@ import { cn } from "@hypr/utils"; export type SectionStatus = "completed" | "active" | "upcoming"; export function OnboardingSection({ + stepId, title, + completedTitle, description, status, onBack, onNext, children, }: { + stepId: string; title: string; + completedTitle?: string; description?: string; status: SectionStatus | null; onBack?: () => void; onNext?: () => void; children: ReactNode; }) { - if (!status) return null; + if (!status || status === "upcoming") return null; const isActive = status === "active"; const isCompleted = status === "completed"; - const isUpcoming = status === "upcoming"; return ( -
+
{isCompleted && ( @@ -53,13 +55,13 @@ export function OnboardingSection({

- {title} + {isCompleted && completedTitle ? completedTitle : title}

{import.meta.env.DEV && isActive && (onBack || onNext) && (
@@ -104,12 +106,6 @@ export function OnboardingSection({ )} - - {isUpcoming && ( -
-
{children}
-
- )}
); } @@ -120,7 +116,7 @@ export function OnboardingButton( return ( ))}
From f796b353680b04d12d1f0f273ca818eeea96a7d4 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 22 Feb 2026 07:34:49 +0000 Subject: [PATCH 6/8] refactor: clean up onboarding scroll, props, and magic values - Move scroll-to-active logic into OnboardingSection via useRef + useEffect (self-contained) - Remove stepId prop, data-step attribute, and querySelector pattern from parent - Extract SCROLL_DELAY_MS and DEFAULT_ICON_SIZE named constants - Remove unused onContinue prop from BeforeLogin - Rename 'triggered' to 'autoSignInCompleted' for clarity Co-Authored-By: yujonglee --- .../components/main/body/onboarding/index.tsx | 23 ++-------------- .../onboarding/account/before-login.tsx | 14 ++++------ .../components/onboarding/account/index.tsx | 2 +- .../src/components/onboarding/final.tsx | 27 ++++++++++--------- .../src/components/onboarding/shared.tsx | 20 ++++++++++---- 5 files changed, 38 insertions(+), 48 deletions(-) diff --git a/apps/desktop/src/components/main/body/onboarding/index.tsx b/apps/desktop/src/components/main/body/onboarding/index.tsx index 1659b4d93b..bffbb36690 100644 --- a/apps/desktop/src/components/main/body/onboarding/index.tsx +++ b/apps/desktop/src/components/main/body/onboarding/index.tsx @@ -1,7 +1,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { platform } from "@tauri-apps/plugin-os"; import { Volume2Icon, VolumeXIcon } from "lucide-react"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { commands as analyticsCommands } from "@hypr/plugin-analytics"; import { commands as sfxCommands } from "@hypr/plugin-sfx"; @@ -115,20 +115,6 @@ export function TabContentOnboarding({ } }, [close, currentTab, queryClient]); - const scrollRef = useRef(null); - - useEffect(() => { - const timeout = setTimeout(() => { - const el = scrollRef.current?.querySelector( - `[data-step="${currentStep}"]`, - ); - if (el) { - el.scrollIntoView({ behavior: "smooth", block: "start" }); - } - }, 350); - return () => clearTimeout(timeout); - }, [currentStep]); - return (
@@ -149,10 +135,9 @@ export function TabContentOnboarding({
-
+
void; -}) { +export function BeforeLogin() { const auth = useAuth(); - const triggered = useAutoTriggerSignin(); + const autoSignInCompleted = useAutoTriggerSignin(); const [showCallbackUrlInput, setShowCallbackUrlInput] = useState(false); return ( @@ -16,14 +12,14 @@ export function BeforeLogin({
- {triggered && ( + {autoSignInCompleted && ( - ))} + {SOCIALS.map(({ label, icon, url, ...rest }) => { + const size = "size" in rest ? rest.size : DEFAULT_ICON_SIZE; + return ( + + ); + })}
void finishOnboarding(onContinue)}> diff --git a/apps/desktop/src/components/onboarding/shared.tsx b/apps/desktop/src/components/onboarding/shared.tsx index c2fe2be4b2..e064571dbc 100644 --- a/apps/desktop/src/components/onboarding/shared.tsx +++ b/apps/desktop/src/components/onboarding/shared.tsx @@ -7,14 +7,15 @@ import { XCircleIcon, } from "lucide-react"; import { AnimatePresence, motion } from "motion/react"; -import type { ReactNode } from "react"; +import { type ReactNode, useEffect, useRef } from "react"; import { cn } from "@hypr/utils"; +const SCROLL_DELAY_MS = 350; + export type SectionStatus = "completed" | "active" | "upcoming"; export function OnboardingSection({ - stepId, title, completedTitle, description, @@ -23,7 +24,6 @@ export function OnboardingSection({ onNext, children, }: { - stepId: string; title: string; completedTitle?: string; description?: string; @@ -32,13 +32,23 @@ export function OnboardingSection({ onNext?: () => void; children: ReactNode; }) { - if (!status || status === "upcoming") return null; + const sectionRef = useRef(null); const isActive = status === "active"; const isCompleted = status === "completed"; + useEffect(() => { + if (!isActive) return; + const timeout = setTimeout(() => { + sectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }); + }, SCROLL_DELAY_MS); + return () => clearTimeout(timeout); + }, [isActive]); + + if (!status || status === "upcoming") return null; + return ( -
+
Date: Sun, 22 Feb 2026 07:48:59 +0000 Subject: [PATCH 7/8] fix: address review feedback on onboarding PR - Restore upcoming steps visibility with blurred/faded preview - Add completedTitle fallback (completedTitle ?? title) - Explicit size on all social icon entries, remove runtime check - Use OnboardingButton in BeforeLogin instead of duplicated styles Co-Authored-By: yujonglee --- .../onboarding/account/before-login.tsx | 6 +++--- apps/desktop/src/components/onboarding/final.tsx | 9 ++++----- .../desktop/src/components/onboarding/shared.tsx | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/desktop/src/components/onboarding/account/before-login.tsx b/apps/desktop/src/components/onboarding/account/before-login.tsx index 4a4cf2ba71..f0e8aa4852 100644 --- a/apps/desktop/src/components/onboarding/account/before-login.tsx +++ b/apps/desktop/src/components/onboarding/account/before-login.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from "react"; import { useAuth } from "../../../auth"; +import { OnboardingButton } from "../shared"; export function BeforeLogin() { const auth = useAuth(); @@ -10,15 +11,14 @@ export function BeforeLogin() { return (
- + {autoSignInCompleted && (