Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/desktop/src/components/chat/body/empty.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function ChatBodyEmpty({
const openNew = useTabs((state) => state.openNew);

const handleGoToSettings = useCallback(() => {
openNew({ type: "settings", state: { tab: "intelligence" } });
openNew({ type: "ai", state: { tab: "intelligence" } });
}, [openNew]);

const handleOpenChatShortcuts = useCallback(() => {
Expand Down
27 changes: 14 additions & 13 deletions apps/desktop/src/components/main-app-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,20 @@ const useNavigationEvents = () => {
.navigate(webview)
.listen(({ payload }) => {
if (payload.path === "/app/settings") {
const tab = (payload.search?.tab as string) ?? "general";
openNew({
type: "settings",
state: {
tab: tab as
| "general"
| "calendar"
| "notifications"
| "transcription"
| "intelligence"
| "account",
},
});
let tab = (payload.search?.tab as string) ?? "general";
if (tab === "notifications" || tab === "account") {
tab = "general";
}
if (tab === "calendar") {
openNew({ type: "calendar" });
} else if (tab === "transcription" || tab === "intelligence") {
openNew({
type: "ai",
state: { tab: tab as "transcription" | "intelligence" },
});
} else {
openNew({ type: "settings" });
}
} else {
navigate({ to: payload.path, search: payload.search ?? undefined });
}
Expand Down
94 changes: 94 additions & 0 deletions apps/desktop/src/components/main/body/ai.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { AudioLinesIcon, SparklesIcon } from "lucide-react";
import { useCallback } from "react";

import { Button } from "@hypr/ui/components/ui/button";
import { cn } from "@hypr/utils";

import { type Tab, useTabs } from "../../../store/zustand/tabs";
import { LLM } from "../../settings/ai/llm";
import { STT } from "../../settings/ai/stt";
import { StandardTabWrapper } from "./index";
import { type TabItem, TabItemBase } from "./shared";

type AITabKey = "transcription" | "intelligence";

export const TabItemAI: TabItem<Extract<Tab, { type: "ai" }>> = ({
tab,
tabIndex,
handleCloseThis,
handleSelectThis,
handleCloseOthers,
handleCloseAll,
}) => {
return (
<TabItemBase
icon={<SparklesIcon className="w-4 h-4" />}
title={"AI"}
selected={tab.active}
tabIndex={tabIndex}
handleCloseThis={() => handleCloseThis(tab)}
handleSelectThis={() => handleSelectThis(tab)}
handleCloseOthers={handleCloseOthers}
handleCloseAll={handleCloseAll}
/>
);
};

export function TabContentAI({ tab }: { tab: Extract<Tab, { type: "ai" }> }) {
return (
<StandardTabWrapper>
<AIView tab={tab} />
</StandardTabWrapper>
);
}

function AIView({ tab }: { tab: Extract<Tab, { type: "ai" }> }) {
const updateAiTabState = useTabs((state) => state.updateAiTabState);
const activeTab = tab.state.tab;

const setActiveTab = useCallback(
(newTab: AITabKey) => {
updateAiTabState(tab, { tab: newTab });
},
[updateAiTabState, tab],
);

const headerAction = (
<div className="flex gap-1">
<Button
variant="ghost"
size="sm"
onClick={() => setActiveTab("transcription")}
className={cn([
"gap-1.5 h-7 px-2",
activeTab === "transcription" && "bg-neutral-200",
])}
>
<AudioLinesIcon size={14} />
<span className="text-xs">Transcription</span>
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => setActiveTab("intelligence")}
className={cn([
"gap-1.5 h-7 px-2",
activeTab === "intelligence" && "bg-neutral-200",
])}
>
<SparklesIcon size={14} />
<span className="text-xs">Intelligence</span>
</Button>
</div>
);

return (
<div className="flex-1 w-full overflow-y-auto scrollbar-hide p-6">
{activeTab === "transcription" ? (
<STT headerAction={headerAction} />
) : (
<LLM headerAction={headerAction} />
)}
</div>
);
}
38 changes: 38 additions & 0 deletions apps/desktop/src/components/main/body/calendar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { CalendarDays } from "lucide-react";

import { type Tab } from "../../../../store/zustand/tabs";
import { SettingsCalendar } from "../../../settings/calendar";
import { StandardTabWrapper } from "../index";
import { type TabItem, TabItemBase } from "../shared";

export const TabItemCalendar: TabItem<Extract<Tab, { type: "calendar" }>> = ({
tab,
tabIndex,
handleCloseThis,
handleSelectThis,
handleCloseOthers,
handleCloseAll,
}) => {
return (
<TabItemBase
icon={<CalendarDays className="w-4 h-4" />}
title={"Calendar"}
selected={tab.active}
tabIndex={tabIndex}
handleCloseThis={() => handleCloseThis(tab)}
handleSelectThis={() => handleSelectThis(tab)}
handleCloseOthers={handleCloseOthers}
handleCloseAll={handleCloseAll}
/>
);
};

export function TabContentCalendar() {
return (
<StandardTabWrapper>
<div className="flex-1 w-full overflow-y-auto scrollbar-hide p-6">
<SettingsCalendar />
</div>
</StandardTabWrapper>
);
}
32 changes: 32 additions & 0 deletions apps/desktop/src/components/main/body/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
import { ChatFloatingButton } from "../../chat";
import { TrafficLights } from "../../window/traffic-lights";
import { useNewNote } from "../shared";
import { TabContentAI, TabItemAI } from "./ai";
import { TabContentCalendar, TabItemCalendar } from "./calendar";
import { TabContentChatShortcut, TabItemChatShortcut } from "./chat-shortcuts";
import { TabContentContact, TabItemContact } from "./contacts";
import { TabContentEmpty, TabItemEmpty } from "./empty";
Expand Down Expand Up @@ -326,6 +328,18 @@ function TabItem({
/>
);
}
if (tab.type === "calendar") {
return (
<TabItemCalendar
tab={tab}
tabIndex={tabIndex}
handleCloseThis={handleClose}
handleSelectThis={handleSelect}
handleCloseOthers={handleCloseOthers}
handleCloseAll={handleCloseAll}
/>
);
}
if (tab.type === "extension") {
return (
<TabItemExtension
Expand Down Expand Up @@ -362,6 +376,18 @@ function TabItem({
/>
);
}
if (tab.type === "ai") {
return (
<TabItemAI
tab={tab}
tabIndex={tabIndex}
handleCloseThis={handleClose}
handleSelectThis={handleSelect}
handleCloseOthers={handleCloseOthers}
handleCloseAll={handleCloseAll}
/>
);
}

return null;
}
Expand Down Expand Up @@ -394,6 +420,9 @@ function ContentWrapper({ tab }: { tab: Tab }) {
if (tab.type === "empty") {
return <TabContentEmpty tab={tab} />;
}
if (tab.type === "calendar") {
return <TabContentCalendar />;
}
if (tab.type === "extension") {
return <TabContentExtension tab={tab} />;
}
Expand All @@ -403,6 +432,9 @@ function ContentWrapper({ tab }: { tab: Tab }) {
if (tab.type === "settings") {
return <TabContentSettings tab={tab} />;
}
if (tab.type === "ai") {
return <TabContentAI tab={tab} />;
}

return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function ListenSplitButton({

const handleAction = useCallback(() => {
onPrimaryClick();
openNew({ type: "settings", state: { tab: "transcription" } });
openNew({ type: "ai", state: { tab: "transcription" } });
}, [onPrimaryClick, openNew]);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function ConfigError({ status }: { status: LLMConnectionStatus }) {
const openNew = useTabs((state) => state.openNew);

const handleConfigureClick = () => {
openNew({ type: "settings", state: { tab: "intelligence" } });
openNew({ type: "ai", state: { tab: "intelligence" } });
};

const message = getMessageForStatus(status);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ function StartButton({ sessionId }: { sessionId: string }) {
const openNew = useTabs((state) => state.openNew);

const handleConfigureAction = useCallback(() => {
openNew({ type: "settings", state: { tab: "transcription" } });
openNew({ type: "ai", state: { tab: "transcription" } });
}, [openNew]);

const button = (
Expand Down
42 changes: 42 additions & 0 deletions apps/desktop/src/components/main/body/settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { SettingsIcon } from "lucide-react";

import { type Tab } from "../../../store/zustand/tabs";
import { SettingsGeneral } from "../../settings/general";
import { StandardTabWrapper } from "./index";
import { type TabItem, TabItemBase } from "./shared";

export const TabItemSettings: TabItem<Extract<Tab, { type: "settings" }>> = ({
tab,
tabIndex,
handleCloseThis,
handleSelectThis,
handleCloseOthers,
handleCloseAll,
}) => {
return (
<TabItemBase
icon={<SettingsIcon className="w-4 h-4" />}
title={"Settings"}
selected={tab.active}
tabIndex={tabIndex}
handleCloseThis={() => handleCloseThis(tab)}
handleSelectThis={() => handleSelectThis(tab)}
handleCloseOthers={handleCloseOthers}
handleCloseAll={handleCloseAll}
/>
);
};

export function TabContentSettings({
tab: _tab,
}: {
tab: Extract<Tab, { type: "settings" }>;
}) {
return (
<StandardTabWrapper>
<div className="flex-1 w-full overflow-y-auto scrollbar-hide p-6">
<SettingsGeneral />
</div>
</StandardTabWrapper>
);
}
Loading
Loading