+
@@ -33,25 +55,51 @@ export function CalendarSelection({
}
return (
-
- {groups.map((group) => (
-
-
- {group.sourceName}
-
-
- {group.calendars.map((cal) => (
- onToggle(cal, enabled)}
- />
- ))}
-
-
- ))}
-
+
+ {groups.map((group) => {
+ const enabledCount = group.calendars.filter((c) => c.enabled).length;
+
+ return (
+
+
+
+
+ {group.sourceName}
+
+
+ {enabledCount}/{group.calendars.length}
+
+
+
+
+
+ {group.calendars.map((cal) => (
+ onToggle(cal, enabled)}
+ />
+ ))}
+
+
+
+ );
+ })}
+
);
}
diff --git a/apps/desktop/src/hooks/useOnboardingState.ts b/apps/desktop/src/hooks/useOnboardingState.ts
deleted file mode 100644
index 87f4c6f10f..0000000000
--- a/apps/desktop/src/hooks/useOnboardingState.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { useLocation } from "@tanstack/react-router";
-import { useMemo } from "react";
-
-export function useOnboardingState() {
- const location = useLocation();
-
- return useMemo(
- () => location.pathname.startsWith("/app/onboarding"),
- [location.pathname],
- );
-}
diff --git a/apps/desktop/src/routeTree.gen.ts b/apps/desktop/src/routeTree.gen.ts
index ba529a44bb..23d98b7ea4 100644
--- a/apps/desktop/src/routeTree.gen.ts
+++ b/apps/desktop/src/routeTree.gen.ts
@@ -13,9 +13,7 @@ import { Route as AppRouteRouteImport } from './routes/app/route'
import { Route as AuthCallbackRouteImport } from './routes/auth/callback'
import { Route as AppExtHostRouteImport } from './routes/app/ext-host'
import { Route as AppControlRouteImport } from './routes/app/control'
-import { Route as AppOnboardingLayoutRouteImport } from './routes/app/onboarding/_layout'
import { Route as AppMainLayoutRouteImport } from './routes/app/main/_layout'
-import { Route as AppOnboardingLayoutIndexRouteImport } from './routes/app/onboarding/_layout.index'
import { Route as AppMainLayoutIndexRouteImport } from './routes/app/main/_layout.index'
const AppRouteRoute = AppRouteRouteImport.update({
@@ -38,22 +36,11 @@ const AppControlRoute = AppControlRouteImport.update({
path: '/control',
getParentRoute: () => AppRouteRoute,
} as any)
-const AppOnboardingLayoutRoute = AppOnboardingLayoutRouteImport.update({
- id: '/onboarding/_layout',
- path: '/onboarding',
- getParentRoute: () => AppRouteRoute,
-} as any)
const AppMainLayoutRoute = AppMainLayoutRouteImport.update({
id: '/main/_layout',
path: '/main',
getParentRoute: () => AppRouteRoute,
} as any)
-const AppOnboardingLayoutIndexRoute =
- AppOnboardingLayoutIndexRouteImport.update({
- id: '/',
- path: '/',
- getParentRoute: () => AppOnboardingLayoutRoute,
- } as any)
const AppMainLayoutIndexRoute = AppMainLayoutIndexRouteImport.update({
id: '/',
path: '/',
@@ -66,9 +53,7 @@ export interface FileRoutesByFullPath {
'/app/ext-host': typeof AppExtHostRoute
'/auth/callback': typeof AuthCallbackRoute
'/app/main': typeof AppMainLayoutRouteWithChildren
- '/app/onboarding': typeof AppOnboardingLayoutRouteWithChildren
'/app/main/': typeof AppMainLayoutIndexRoute
- '/app/onboarding/': typeof AppOnboardingLayoutIndexRoute
}
export interface FileRoutesByTo {
'/app': typeof AppRouteRouteWithChildren
@@ -76,7 +61,6 @@ export interface FileRoutesByTo {
'/app/ext-host': typeof AppExtHostRoute
'/auth/callback': typeof AuthCallbackRoute
'/app/main': typeof AppMainLayoutIndexRoute
- '/app/onboarding': typeof AppOnboardingLayoutIndexRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
@@ -85,9 +69,7 @@ export interface FileRoutesById {
'/app/ext-host': typeof AppExtHostRoute
'/auth/callback': typeof AuthCallbackRoute
'/app/main/_layout': typeof AppMainLayoutRouteWithChildren
- '/app/onboarding/_layout': typeof AppOnboardingLayoutRouteWithChildren
'/app/main/_layout/': typeof AppMainLayoutIndexRoute
- '/app/onboarding/_layout/': typeof AppOnboardingLayoutIndexRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
@@ -97,17 +79,9 @@ export interface FileRouteTypes {
| '/app/ext-host'
| '/auth/callback'
| '/app/main'
- | '/app/onboarding'
| '/app/main/'
- | '/app/onboarding/'
fileRoutesByTo: FileRoutesByTo
- to:
- | '/app'
- | '/app/control'
- | '/app/ext-host'
- | '/auth/callback'
- | '/app/main'
- | '/app/onboarding'
+ to: '/app' | '/app/control' | '/app/ext-host' | '/auth/callback' | '/app/main'
id:
| '__root__'
| '/app'
@@ -115,9 +89,7 @@ export interface FileRouteTypes {
| '/app/ext-host'
| '/auth/callback'
| '/app/main/_layout'
- | '/app/onboarding/_layout'
| '/app/main/_layout/'
- | '/app/onboarding/_layout/'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
@@ -155,13 +127,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AppControlRouteImport
parentRoute: typeof AppRouteRoute
}
- '/app/onboarding/_layout': {
- id: '/app/onboarding/_layout'
- path: '/onboarding'
- fullPath: '/app/onboarding'
- preLoaderRoute: typeof AppOnboardingLayoutRouteImport
- parentRoute: typeof AppRouteRoute
- }
'/app/main/_layout': {
id: '/app/main/_layout'
path: '/main'
@@ -169,13 +134,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AppMainLayoutRouteImport
parentRoute: typeof AppRouteRoute
}
- '/app/onboarding/_layout/': {
- id: '/app/onboarding/_layout/'
- path: '/'
- fullPath: '/app/onboarding/'
- preLoaderRoute: typeof AppOnboardingLayoutIndexRouteImport
- parentRoute: typeof AppOnboardingLayoutRoute
- }
'/app/main/_layout/': {
id: '/app/main/_layout/'
path: '/'
@@ -198,29 +156,16 @@ const AppMainLayoutRouteWithChildren = AppMainLayoutRoute._addFileChildren(
AppMainLayoutRouteChildren,
)
-interface AppOnboardingLayoutRouteChildren {
- AppOnboardingLayoutIndexRoute: typeof AppOnboardingLayoutIndexRoute
-}
-
-const AppOnboardingLayoutRouteChildren: AppOnboardingLayoutRouteChildren = {
- AppOnboardingLayoutIndexRoute: AppOnboardingLayoutIndexRoute,
-}
-
-const AppOnboardingLayoutRouteWithChildren =
- AppOnboardingLayoutRoute._addFileChildren(AppOnboardingLayoutRouteChildren)
-
interface AppRouteRouteChildren {
AppControlRoute: typeof AppControlRoute
AppExtHostRoute: typeof AppExtHostRoute
AppMainLayoutRoute: typeof AppMainLayoutRouteWithChildren
- AppOnboardingLayoutRoute: typeof AppOnboardingLayoutRouteWithChildren
}
const AppRouteRouteChildren: AppRouteRouteChildren = {
AppControlRoute: AppControlRoute,
AppExtHostRoute: AppExtHostRoute,
AppMainLayoutRoute: AppMainLayoutRouteWithChildren,
- AppOnboardingLayoutRoute: AppOnboardingLayoutRouteWithChildren,
}
const AppRouteRouteWithChildren = AppRouteRoute._addFileChildren(
diff --git a/apps/desktop/src/routes/app/main/_layout.index.tsx b/apps/desktop/src/routes/app/main/_layout.index.tsx
index c93f4cbb38..9354ea5d91 100644
--- a/apps/desktop/src/routes/app/main/_layout.index.tsx
+++ b/apps/desktop/src/routes/app/main/_layout.index.tsx
@@ -13,6 +13,7 @@ import { Body } from "../../../components/main/body";
import { LeftSidebar } from "../../../components/main/sidebar";
import { useSearch } from "../../../contexts/search/ui";
import { useShell } from "../../../contexts/shell";
+import { useTabs } from "../../../store/zustand/tabs";
import { commands } from "../../../types/tauri.gen";
export const Route = createFileRoute("/app/main/_layout/")({
@@ -24,12 +25,20 @@ const CHAT_MIN_WIDTH_PX = 280;
function Component() {
const { leftsidebar, chat } = useShell();
const { query } = useSearch();
+ const currentTab = useTabs((state) => state.currentTab);
+ const isOnboarding = currentTab?.type === "onboarding";
const previousModeRef = useRef(chat.mode);
const previousQueryRef = useRef(query);
const bodyPanelRef = useRef
>(null);
const isChatOpen = chat.mode === "RightPanelOpen";
+ useEffect(() => {
+ if (isOnboarding && leftsidebar.expanded) {
+ leftsidebar.setExpanded(false);
+ }
+ }, [isOnboarding, leftsidebar]);
+
useEffect(() => {
const isOpeningRightPanel =
chat.mode === "RightPanelOpen" &&
@@ -48,7 +57,7 @@ function Component() {
const isStartingSearch =
query.trim() !== "" && previousQueryRef.current.trim() === "";
- if (isStartingSearch && !leftsidebar.expanded) {
+ if (isStartingSearch && !leftsidebar.expanded && !isOnboarding) {
leftsidebar.setExpanded(true);
commands.resizeWindowForSidebar().catch(console.error);
}
@@ -61,7 +70,7 @@ function Component() {
className="flex h-full overflow-hidden gap-1 p-1"
data-testid="main-app-shell"
>
- {leftsidebar.expanded && }
+ {leftsidebar.expanded && !isOnboarding && }
;
-
-export const Route = createFileRoute("/app/onboarding/_layout/")({
- validateSearch,
- component: Component,
-});
-
-function Component() {
- const search = Route.useSearch();
- const navigate = useNavigate();
- const [isMuted, setIsMuted] = useState(false);
-
- useEffect(() => {
- void analyticsCommands.event({
- event: "onboarding_step_viewed",
- step: search.step,
- platform: search.platform,
- skip_login: search.skipLogin ?? false,
- });
- }, [search.step]);
-
- useEffect(() => {
- sfxCommands.play("BGM").catch(console.error);
- return () => {
- sfxCommands.stop("BGM").catch(console.error);
- };
- }, []);
-
- useEffect(() => {
- sfxCommands.setVolume("BGM", isMuted ? 0 : 1).catch(console.error);
- }, [isMuted]);
-
- const toggleMute = useCallback(() => {
- setIsMuted((prev) => !prev);
- }, []);
-
- const onNavigate = useCallback(
- (ctx: NavigateTarget) => {
- const { step, ...rest } = ctx;
- void navigate({ to: "/app/onboarding", search: { step, ...rest } });
- },
- [navigate],
- );
-
- const currentConfig = STEP_CONFIGS.find((s) => s.id === search.step);
- if (!currentConfig) {
- return null;
- }
-
- return (
-
-
-
-
-
- );
-}
diff --git a/apps/desktop/src/routes/app/onboarding/_layout.tsx b/apps/desktop/src/routes/app/onboarding/_layout.tsx
deleted file mode 100644
index 51df26b714..0000000000
--- a/apps/desktop/src/routes/app/onboarding/_layout.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { createFileRoute, Outlet } from "@tanstack/react-router";
-
-import { useDeeplinkHandler } from "../../../hooks/useDeeplinkHandler";
-
-export const Route = createFileRoute("/app/onboarding/_layout")({
- component: Component,
-});
-
-function Component() {
- useDeeplinkHandler();
-
- return ;
-}
diff --git a/apps/desktop/src/store/tinybase/store/initialize.ts b/apps/desktop/src/store/tinybase/store/initialize.ts
index 94689b54d7..e323f02ee3 100644
--- a/apps/desktop/src/store/tinybase/store/initialize.ts
+++ b/apps/desktop/src/store/tinybase/store/initialize.ts
@@ -32,20 +32,5 @@ function initializeStore(store: Store): void {
org_id: "",
});
}
-
- if (
- !store.getTableIds().includes("sessions") ||
- store.getRowIds("sessions").length === 0
- ) {
- const sessionId = crypto.randomUUID();
- const now = new Date().toISOString();
-
- store.setRow("sessions", sessionId, {
- user_id: DEFAULT_USER_ID,
- created_at: now,
- title: "Welcome to Hyprnote",
- raw_md: "",
- });
- }
});
}
diff --git a/apps/desktop/src/store/zustand/tabs/schema.ts b/apps/desktop/src/store/zustand/tabs/schema.ts
index 90c9c63ffa..a71ee9fbf8 100644
--- a/apps/desktop/src/store/zustand/tabs/schema.ts
+++ b/apps/desktop/src/store/zustand/tabs/schema.ts
@@ -111,7 +111,8 @@ export type Tab =
| (BaseTab & {
type: "chat";
state: ChatState;
- });
+ })
+ | (BaseTab & { type: "onboarding" });
export const getDefaultState = (tab: TabInput): Tab => {
const base = { active: false, slotId: "", pinned: false };
@@ -217,6 +218,8 @@ export const getDefaultState = (tab: TabInput): Tab => {
chatType: null,
},
};
+ case "onboarding":
+ return { ...base, type: "onboarding" };
default:
const _exhaustive: never = tab;
return _exhaustive;
@@ -259,6 +262,8 @@ export const uniqueIdfromTab = (tab: Tab): string => {
return `search`;
case "chat":
return `chat`;
+ case "onboarding":
+ return `onboarding`;
}
};
diff --git a/plugins/windows/js/bindings.gen.ts b/plugins/windows/js/bindings.gen.ts
index f42494643f..67bce5ff89 100644
--- a/plugins/windows/js/bindings.gen.ts
+++ b/plugins/windows/js/bindings.gen.ts
@@ -71,7 +71,7 @@ windowDestroyed: "plugin:windows:window-destroyed"
export type AiState = { tab: AiTab | null }
export type AiTab = "transcription" | "intelligence" | "templates" | "shortcuts" | "prompts"
-export type AppWindow = { type: "onboarding" } | { type: "main" } | { type: "control" }
+export type AppWindow = { type: "main" } | { type: "control" }
export type ChangelogState = { previous: string | null; current: string }
export type ChatShortcutsState = { isWebMode: boolean | null; selectedMineId: string | null; selectedWebIndex: number | null }
export type ChatState = { groupId: string | null; initialMessage: string | null; chatType: ChatType | null }
@@ -85,7 +85,7 @@ export type OpenTab = { tab: TabInput }
export type PromptsState = { selectedTask: string | null }
export type SearchState = { selectedTypes: string[] | null; initialQuery: string | null }
export type SessionsState = { view: EditorView | null; autoStart: boolean | null }
-export type TabInput = { type: "sessions"; id: string; state?: SessionsState | null } | { type: "contacts"; state?: ContactsState | null } | { type: "templates"; state?: TemplatesState | null } | { type: "prompts"; state?: PromptsState | null } | { type: "chat_shortcuts"; state?: ChatShortcutsState | null } | { type: "extensions"; state?: ExtensionsState | null } | { type: "humans"; id: string } | { type: "organizations"; id: string } | { type: "folders"; id: string | null } | { type: "empty" } | { type: "extension"; extensionId: string; state?: Partial<{ [key in string]: JsonValue }> | null } | { type: "calendar" } | { type: "changelog"; state: ChangelogState } | { type: "settings" } | { type: "ai"; state?: AiState | null } | { type: "search"; state?: SearchState | null } | { type: "chat"; state?: ChatState | null }
+export type TabInput = { type: "sessions"; id: string; state?: SessionsState | null } | { type: "contacts"; state?: ContactsState | null } | { type: "templates"; state?: TemplatesState | null } | { type: "prompts"; state?: PromptsState | null } | { type: "chat_shortcuts"; state?: ChatShortcutsState | null } | { type: "extensions"; state?: ExtensionsState | null } | { type: "humans"; id: string } | { type: "organizations"; id: string } | { type: "folders"; id: string | null } | { type: "empty" } | { type: "extension"; extensionId: string; state?: Partial<{ [key in string]: JsonValue }> | null } | { type: "calendar" } | { type: "changelog"; state: ChangelogState } | { type: "settings" } | { type: "ai"; state?: AiState | null } | { type: "search"; state?: SearchState | null } | { type: "chat"; state?: ChatState | null } | { type: "onboarding" }
export type TemplatesState = { showHomepage: boolean | null; isWebMode: boolean | null; selectedMineId: string | null; selectedWebIndex: number | null }
export type VisibilityEvent = { window: AppWindow; visible: boolean }
export type WindowDestroyed = { window: AppWindow }
diff --git a/plugins/windows/src/events.rs b/plugins/windows/src/events.rs
index 4222f8e6b3..843f14b31a 100644
--- a/plugins/windows/src/events.rs
+++ b/plugins/windows/src/events.rs
@@ -15,10 +15,6 @@ pub fn on_window_event(window: &tauri::Window, event: &tauri::Window
if w == AppWindow::Main && w.hide(app).is_ok() {
api.prevent_close();
}
- if w == AppWindow::Onboarding {
- use tauri_plugin_sfx::SfxPluginExt;
- app.sfx().stop(tauri_plugin_sfx::AppSounds::BGM);
- }
}
}
}
diff --git a/plugins/windows/src/tab/mod.rs b/plugins/windows/src/tab/mod.rs
index f668e7ddca..2b09c36e5b 100644
--- a/plugins/windows/src/tab/mod.rs
+++ b/plugins/windows/src/tab/mod.rs
@@ -80,5 +80,7 @@ common_derives! {
#[serde(skip_serializing_if = "Option::is_none")]
state: Option,
},
+ #[serde(rename = "onboarding")]
+ Onboarding,
}
}
diff --git a/plugins/windows/src/window/v1.rs b/plugins/windows/src/window/v1.rs
index 118a0825da..889c456b93 100644
--- a/plugins/windows/src/window/v1.rs
+++ b/plugins/windows/src/window/v1.rs
@@ -3,8 +3,6 @@ use crate::WindowImpl;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, specta::Type, PartialEq, Eq, Hash)]
#[serde(tag = "type", content = "value")]
pub enum AppWindow {
- #[serde(rename = "onboarding")]
- Onboarding,
#[serde(rename = "main")]
Main,
#[serde(rename = "control")]
@@ -14,7 +12,6 @@ pub enum AppWindow {
impl std::fmt::Display for AppWindow {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
- Self::Onboarding => write!(f, "onboarding"),
Self::Main => write!(f, "main"),
Self::Control => write!(f, "control"),
}
@@ -26,7 +23,6 @@ impl std::str::FromStr for AppWindow {
fn from_str(s: &str) -> Result {
match s {
- "onboarding" => return Ok(Self::Onboarding),
"main" => return Ok(Self::Main),
"control" => return Ok(Self::Control),
_ => {}
@@ -105,7 +101,6 @@ impl AppWindow {
impl WindowImpl for AppWindow {
fn title(&self) -> String {
match self {
- Self::Onboarding => "Onboarding".into(),
Self::Main => "Hyprnote".into(),
Self::Control => "Control".into(),
}
@@ -118,15 +113,6 @@ impl WindowImpl for AppWindow {
use tauri::LogicalSize;
let window = match self {
- Self::Onboarding => {
- let builder = self
- .window_builder(app, "/app/onboarding")
- .resizable(false)
- .min_inner_size(400.0, 600.0);
- let window = builder.build()?;
- window.set_size(LogicalSize::new(400.0, 600.0))?;
- window
- }
Self::Main => {
let builder = self
.window_builder(app, "/app/main")