diff --git a/src/interface/web/app/agents/page.tsx b/src/interface/web/app/agents/page.tsx index 614e4ef9..0ec76839 100644 --- a/src/interface/web/app/agents/page.tsx +++ b/src/interface/web/app/agents/page.tsx @@ -29,8 +29,10 @@ import { import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; +import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; import { AppSidebar } from "../components/appSidebar/appSidebar"; +import { Separator } from "@/components/ui/separator"; +import { KhojLogoType } from "../components/logo/khojLogo"; export interface AgentData { slug: string; @@ -279,111 +281,123 @@ export default function Agents() { return ( - -
-
-
-
-

Agents

-
- +
+ + + {isMobileWidth ? ( + + ) : ( +

Agents

+ )} +
+
+
+
+
+

Agents

+
+ +
+
+ {showLoginPrompt && ( + -
-
- {showLoginPrompt && ( - - )} - - - - How it works Use any of these - specialized personas to tune your conversation to your needs. - - -
-
- {personalAgents.map((agent) => ( - + + - ))} + How it works Use any of these + specialized personas to tune your conversation to your needs. + + +
+
+ {personalAgents.map((agent) => ( + + ))} +
-
-
-

Explore

-
- {publicAgents.map((agent) => ( - - ))} +
+

Explore

+
+ {publicAgents.map((agent) => ( + + ))} +
-
-
+
+
); } diff --git a/src/interface/web/app/automations/page.tsx b/src/interface/web/app/automations/page.tsx index 2cc70399..fa88958b 100644 --- a/src/interface/web/app/automations/page.tsx +++ b/src/interface/web/app/automations/page.tsx @@ -67,8 +67,10 @@ import { useToast } from "@/components/ui/use-toast"; import { ToastAction } from "@/components/ui/toast"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Drawer, DrawerContent, DrawerTitle, DrawerTrigger } from "@/components/ui/drawer"; -import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; +import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; import { AppSidebar } from "../components/appSidebar/appSidebar"; +import { Separator } from "@/components/ui/separator"; +import { KhojLogoType } from "../components/logo/khojLogo"; const automationsFetcher = () => window @@ -1026,93 +1028,114 @@ export default function Automations() { return ( - -
-
-
-
-

Automations

-
+ +
+ + + {isMobileWidth ? ( + + ) : ( +

Automations

+ )} +
+
+
+
+
+

Automations

+
+ {authenticatedData ? ( + + + {authenticatedData.email} + + ) : null} + {locationData && ( + + + {locationData + ? `${locationData.city}, ${locationData.country}` + : "Unknown"} + + )} + {locationData && ( + + + {locationData ? `${locationData.timezone}` : "Unknown"} + + )} +
+
+ {showLoginPrompt && ( + + )} + + + + How it works Automations help + you structure your time by automating tasks you do regularly. + Build your own, or try out our presets. Get results straight to + your inbox. + + +
{authenticatedData ? ( - - - {authenticatedData.email} - - ) : null} - {locationData && ( - - - {locationData - ? `${locationData.city}, ${locationData.country}` - : "Unknown"} - - )} - {locationData && ( - - - {locationData ? `${locationData.timezone}` : "Unknown"} - + + ) : ( + )}
-
- {showLoginPrompt && ( - - )} - - - - How it works Automations help you - structure your time by automating tasks you do regularly. Build your - own, or try out our presets. Get results straight to your inbox. - - -
- {authenticatedData ? ( - + - ) : ( - - )} -
- - - - {isLoading && } -
- {personalAutomations && - personalAutomations.map((automation) => ( + + {isLoading && } +
+ {personalAutomations && + personalAutomations.map((automation) => ( + + ))} + {allNewAutomations.map((automation) => ( ))} - {allNewAutomations.map((automation) => ( - - ))} -
-

Explore

-
- {suggestedAutomations.map((automation) => ( - - ))} +
+

Explore

+
+ {suggestedAutomations.map((automation) => ( + + ))} +
-
-
+ +
); } diff --git a/src/interface/web/app/chat/chat.module.css b/src/interface/web/app/chat/chat.module.css index 2a7a7ff1..9bd95434 100644 --- a/src/interface/web/app/chat/chat.module.css +++ b/src/interface/web/app/chat/chat.module.css @@ -1,5 +1,5 @@ div.main { - height: 100dvh; + height: 100%; color: hsla(var(--foreground)); margin-left: auto; margin-right: auto; diff --git a/src/interface/web/app/chat/page.tsx b/src/interface/web/app/chat/page.tsx index c86b4f45..91a7c12b 100644 --- a/src/interface/web/app/chat/page.tsx +++ b/src/interface/web/app/chat/page.tsx @@ -26,8 +26,10 @@ import { import { useAuthenticatedData } from "../common/auth"; import { AgentData } from "../agents/page"; import { ChatSessionActionMenu } from "../components/allConversations/allConversations"; -import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; +import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; import { AppSidebar } from "../components/appSidebar/appSidebar"; +import { Separator } from "@/components/ui/separator"; +import { KhojLogoType } from "../components/logo/khojLogo"; interface ChatBodyDataProps { chatOptionsData: ChatOptions | null; @@ -386,49 +388,60 @@ export default function Chat() { return ( - -
- - {`${defaultTitle}${!!title && title !== defaultTitle ? `: ${title}` : ""}`} - -
-
- {conversationId && ( -
- {title && ( -

- {title} -

- )} - +
+ + + {conversationId && ( +
+ {isMobileWidth ? ( + + ) : ( + title && ( + <> +

+ {title} +

+ + + ) + )} +
+ )} +
+
+ + {`${defaultTitle}${!!title && title !== defaultTitle ? `: ${title}` : ""}`} + +
+
+ }> + -
- )} - }> - - + +
-
+ ); } diff --git a/src/interface/web/app/components/logo/khojLogo.tsx b/src/interface/web/app/components/logo/khojLogo.tsx index 66cb2396..297a5520 100644 --- a/src/interface/web/app/components/logo/khojLogo.tsx +++ b/src/interface/web/app/components/logo/khojLogo.tsx @@ -1,17 +1,17 @@ export function KhojLogoType({ className }: { className?: string }) { - const classes = className ?? "fill-zinc-950 dark:fill-zinc-300"; + const fillClasses = "fill-zinc-950 dark:fill-zinc-300"; return ( - - - - + + + + - + - - - - - - - - + + + + + + + + diff --git a/src/interface/web/app/search/page.tsx b/src/interface/web/app/search/page.tsx index ab6a4443..b700e5c1 100644 --- a/src/interface/web/app/search/page.tsx +++ b/src/interface/web/app/search/page.tsx @@ -29,8 +29,10 @@ import { Button } from "@/components/ui/button"; import Link from "next/link"; import { getIconFromFilename } from "../common/iconUtils"; import { useIsMobileWidth } from "../common/utils"; -import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; +import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; import { AppSidebar } from "../components/appSidebar/appSidebar"; +import { Separator } from "@/components/ui/separator"; +import { KhojLogoType } from "../components/logo/khojLogo"; interface AdditionalData { file: string; @@ -90,7 +92,7 @@ function Note(props: NoteResultProps) { const fileIcon = getIconFromFilename(fileName || ".txt", "h-4 w-4 inline mr-2"); return ( - + {getNoteTypeIcon(note.additional.source)} @@ -230,106 +232,120 @@ export default function Search() { return ( - -
-
-
-
-
- setSearchQuery(e.currentTarget.value)} - onKeyDown={(e) => e.key === "Enter" && search()} - type="search" - placeholder="Search Documents" - /> - -
- {focusSearchResult && ( -
- - {focusNote(focusSearchResult)} + + Find +
- )} - {!focusSearchResult && searchResults && searchResults.length > 0 && ( -
- - {searchResults.map((result, index) => { - return ( - - ); - })} - -
- )} - {searchResults == null && ( - - - - - - - Search across your documents - - - - {exampleQuery} - - - )} - {searchResults && searchResults.length === 0 && ( - - - - - - - No documents found - - - -
- To use search, upload your docs to your account. -
- + + {focusNote(focusSearchResult)} +
+ )} + {!focusSearchResult && + searchResults && + searchResults.length > 0 && ( +
+ + {searchResults.map((result, index) => { + return ( + + ); + })} + +
+ )} + {searchResults == null && ( + + + + + + + Search across your documents + + + + {exampleQuery} + + + )} + {searchResults && searchResults.length === 0 && ( + + + + + + + No documents found + + + +
+ To use search, upload your docs to your account.
- -
-
- )} + +
+ Learn More +
+ + + + )} +
-
+
); } diff --git a/src/interface/web/app/search/search.module.css b/src/interface/web/app/search/search.module.css index b2e82d67..dc507324 100644 --- a/src/interface/web/app/search/search.module.css +++ b/src/interface/web/app/search/search.module.css @@ -2,7 +2,7 @@ div.searchLayout { display: grid; grid-template-columns: 1fr; gap: 1rem; - height: 100vh; + height: 100%; } @media screen and (max-width: 768px) { diff --git a/src/interface/web/app/settings/page.tsx b/src/interface/web/app/settings/page.tsx index 3631533d..3178824b 100644 --- a/src/interface/web/app/settings/page.tsx +++ b/src/interface/web/app/settings/page.tsx @@ -76,8 +76,10 @@ import { } from "@/components/ui/alert-dialog"; import { Progress } from "@/components/ui/progress"; import Link from "next/link"; -import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; +import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; import { AppSidebar } from "../components/appSidebar/appSidebar"; +import { Separator } from "@/components/ui/separator"; +import { KhojLogoType } from "../components/logo/khojLogo"; const ManageFilesModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { const [syncedFiles, setSyncedFiles] = useState([]); @@ -857,676 +859,704 @@ export default function SettingsView() { return ( - -
- {title} -
-
- }> -
-
-
Profile
-
- - - - Name - - -

- What should Khoj refer to you as? -

- setName(e.target.value)} - value={name} - className="w-full border border-gray-300 rounded-lg p-4 py-6" - /> -
- - - -
- - - - Subscription - - -

Current Plan

- {(userConfig.subscription_state === "trial" && ( - <> -

- Futurist (Trial) -

-

- You are on a{" "} - {userConfig.length_of_free_trial} day - trial of the Khoj Futurist plan. Your - trial ends on{" "} - {userConfig.subscription_renewal_date}. - Check{" "} - - pricing page - {" "} - to compare plans. -

- - )) || - (userConfig.subscription_state === - "subscribed" && ( + +
+ + + {isMobileWidth ? ( + + ) : ( +

Settings

+ )} +
+
+ {title} +
+
+ }> +
+
+
Profile
+
+ + + + Name + + +

+ What should Khoj refer to you as? +

+ setName(e.target.value)} + value={name} + className="w-full border border-gray-300 rounded-lg p-4 py-6" + /> +
+ + + +
+ + + + Subscription + + +

Current Plan

+ {(userConfig.subscription_state === "trial" && ( <>

- Futurist + Futurist (Trial)

- Subscription renews on{" "} - - { - userConfig.subscription_renewal_date - } - + You are on a{" "} + {userConfig.length_of_free_trial}{" "} + day trial of the Khoj Futurist plan. + Your trial ends on{" "} + { + userConfig.subscription_renewal_date + } + . Check{" "} + + pricing page + {" "} + to compare plans.

)) || - (userConfig.subscription_state === - "unsubscribed" && ( - <> -

Futurist

-

- Subscription ends on{" "} - - { - userConfig.subscription_renewal_date - } - -

- - )) || - (userConfig.subscription_state === - "expired" && ( - <> -

Humanist

- {(userConfig.subscription_renewal_date && ( + (userConfig.subscription_state === + "subscribed" && ( + <> +

+ Futurist +

- Subscription expired on{" "} + Subscription renews on{" "} { userConfig.subscription_renewal_date }

- )) || ( + + )) || + (userConfig.subscription_state === + "unsubscribed" && ( + <> +

Futurist

- Check{" "} - - pricing page - {" "} - to compare plans. + Subscription ends on{" "} + + { + userConfig.subscription_renewal_date + } +

- )} - - ))} -
- - {(userConfig.subscription_state == "subscribed" && ( - - )) || - (userConfig.subscription_state == - "unsubscribed" && ( + + )) || + (userConfig.subscription_state === + "expired" && ( + <> +

Humanist

+ {(userConfig.subscription_renewal_date && ( +

+ Subscription expired{" "} + on{" "} + + { + userConfig.subscription_renewal_date + } + +

+ )) || ( +

+ Check{" "} + + pricing page + {" "} + to compare plans. +

+ )} + + ))} + + + {(userConfig.subscription_state == + "subscribed" && ( )) || - (userConfig.subscription_enabled_trial_at && ( - - )) || ( - - )} - -
+ (userConfig.subscription_state == + "unsubscribed" && ( + + )) || + (userConfig.subscription_enabled_trial_at && ( + + )) || ( + + )} + + +
-
- {isManageFilesModalOpen && ( - setIsManageFilesModalOpen(false)} - /> - )} -
-
Content
-
- - - - Files - {userConfig.enabled_content_source.computer && ( - - )} - - - Manage your synced files - - - - - - - - - - Github - - - Set Github repositories to index - - - - - - - - - - Notion - {userConfig.enabled_content_source.notion && ( - - )} - - -

- Sync your Notion workspace. -

- {!userConfig.notion_oauth_url && ( - - setNotionToken(e.target.value) - } - value={notionToken || ""} - placeholder="Enter API Key of your Khoj integration on Notion" - className="w-full border border-gray-300 rounded-lg px-4 py-6" - /> - )} -
- - { - /* Show connect to notion button if notion oauth url setup and user disconnected*/ - userConfig.notion_oauth_url && - !userConfig.enabled_content_source.notion ? ( - - ) : /* Show sync button if user connected to notion and API key unchanged */ - userConfig.enabled_content_source.notion && - notionToken === userConfig.notion_token ? ( - - ) : /* Show set API key button notion oauth url not set setup */ - !userConfig.notion_oauth_url ? ( - - ) : ( - <> - ) - } - - -
-
-
-
-
Models
-
- {userConfig.chat_model_options.length > 0 && ( - - - - Chat - - -

- Pick the chat model to generate text - responses -

- -
- - {!userConfig.is_active && ( -

- Subscribe to switch model -

- )} -
-
- )} - {userConfig.paint_model_options.length > 0 && ( - - - - Paint - - -

- Pick the paint model to generate image - responses -

- -
- - {!userConfig.is_active && ( -

- Subscribe to switch model -

- )} -
-
- )} - {userConfig.voice_model_options.length > 0 && ( - - - - Voice - - -

- Pick the voice model to generate speech - responses -

- -
- - {!userConfig.is_active && ( -

- Subscribe to switch model -

- )} -
-
- )} -
-
-
-
- Clients -
-
- {!userConfig.anonymous_mode && ( - - - - - API Keys - - - - -

- Access Khoj from the{" "} - - Desktop - - ,{" "} - - Obsidian - - ,{" "} - - Emacs - {" "} - apps and more. -

- - - {apiKeys.map((key) => ( - - - {key.name} - - - - {`${key.token.slice(0, 6)}...${key.token.slice(-4)}`} - -
- { - toast({ - title: `🔑 Copied API Key: ${key.name}`, - description: `Set this API key in the Khoj apps you want to connect to this Khoj account`, - }); - copyAPIKey( - key.token, - ); - }} - /> - { - toast({ - title: `🔑 Deleted API Key: ${key.name}`, - description: `Apps using this API key will no longer connect to this Khoj account`, - }); - deleteAPIKey( - key.token, - ); - }} - /> -
-
-
- ))} -
-
-
- -
- )} - - - - Chat on Whatsapp - {(numberValidationState === - PhoneNumberValidationState.Verified && ( - - )) || - (numberValidationState !== - PhoneNumberValidationState.Setup && ( - - ))} - - -

- Connect your number to chat with Khoj on - WhatsApp. Learn more about the integration{" "} - - here - - . -

-
- - {numberValidationState === - PhoneNumberValidationState.VerifyOTP && ( - <> -

{`Enter the OTP sent to your number: ${phoneNumber}`}

- - setNumberValidationState( - PhoneNumberValidationState.VerifyOTP, - ) - } - > - - - - - - - - - - - )} -
-
- - {(numberValidationState === - PhoneNumberValidationState.VerifyOTP && ( - - )) || ( + +
+ + + + Github + + + Set Github repositories to index + + + - )} - {numberValidationState === - PhoneNumberValidationState.Verified && ( + + + + + + Notion + {userConfig.enabled_content_source.notion && ( + + )} + + +

+ Sync your Notion workspace. +

+ {!userConfig.notion_oauth_url && ( + + setNotionToken(e.target.value) + } + value={notionToken || ""} + placeholder="Enter API Key of your Khoj integration on Notion" + className="w-full border border-gray-300 rounded-lg px-4 py-6" + /> + )} +
+ + { + /* Show connect to notion button if notion oauth url setup and user disconnected*/ + userConfig.notion_oauth_url && + !userConfig.enabled_content_source + .notion ? ( + + ) : /* Show sync button if user connected to notion and API key unchanged */ + userConfig.enabled_content_source.notion && + notionToken === + userConfig.notion_token ? ( + + ) : /* Show set API key button notion oauth url not set setup */ + !userConfig.notion_oauth_url ? ( + + ) : ( + <> + ) + } + - )} - -
+ + +
+
+
+
Models
+
+ {userConfig.chat_model_options.length > 0 && ( + + + + Chat + + +

+ Pick the chat model to generate text + responses +

+ +
+ + {!userConfig.is_active && ( +

+ Subscribe to switch model +

+ )} +
+
+ )} + {userConfig.paint_model_options.length > 0 && ( + + + + Paint + + +

+ Pick the paint model to generate image + responses +

+ +
+ + {!userConfig.is_active && ( +

+ Subscribe to switch model +

+ )} +
+
+ )} + {userConfig.voice_model_options.length > 0 && ( + + + + Voice + + +

+ Pick the voice model to generate speech + responses +

+ +
+ + {!userConfig.is_active && ( +

+ Subscribe to switch model +

+ )} +
+
+ )} +
+
+
+
+ Clients +
+
+ {!userConfig.anonymous_mode && ( + + + + + API Keys + + + + +

+ Access Khoj from the{" "} + + Desktop + + ,{" "} + + Obsidian + + ,{" "} + + Emacs + {" "} + apps and more. +

+ + + {apiKeys.map((key) => ( + + + {key.name} + + + + {`${key.token.slice(0, 6)}...${key.token.slice(-4)}`} + +
+ { + toast({ + title: `🔑 Copied API Key: ${key.name}`, + description: `Set this API key in the Khoj apps you want to connect to this Khoj account`, + }); + copyAPIKey( + key.token, + ); + }} + /> + { + toast({ + title: `🔑 Deleted API Key: ${key.name}`, + description: `Apps using this API key will no longer connect to this Khoj account`, + }); + deleteAPIKey( + key.token, + ); + }} + /> +
+
+
+ ))} +
+
+
+ +
+ )} + + + + Chat on Whatsapp + {(numberValidationState === + PhoneNumberValidationState.Verified && ( + + )) || + (numberValidationState !== + PhoneNumberValidationState.Setup && ( + + ))} + + +

+ Connect your number to chat with Khoj on + WhatsApp. Learn more about the integration{" "} + + here + + . +

+
+ + {numberValidationState === + PhoneNumberValidationState.VerifyOTP && ( + <> +

{`Enter the OTP sent to your number: ${phoneNumber}`}

+ + setNumberValidationState( + PhoneNumberValidationState.VerifyOTP, + ) + } + > + + + + + + + + + + + )} +
+
+ + {(numberValidationState === + PhoneNumberValidationState.VerifyOTP && ( + + )) || ( + + )} + {numberValidationState === + PhoneNumberValidationState.Verified && ( + + )} + +
+
-
- + +
-
+ ); } diff --git a/src/interface/web/app/share/chat/page.tsx b/src/interface/web/app/share/chat/page.tsx index 4310d710..1320fb95 100644 --- a/src/interface/web/app/share/chat/page.tsx +++ b/src/interface/web/app/share/chat/page.tsx @@ -18,8 +18,10 @@ import { } from "@/app/components/chatInputArea/chatInputArea"; import { StreamMessage } from "@/app/components/chatMessage/chatMessage"; import { AgentData } from "@/app/agents/page"; -import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; +import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; import { AppSidebar } from "@/app/components/appSidebar/appSidebar"; +import { Separator } from "@/components/ui/separator"; +import { KhojLogoType } from "@/app/components/logo/khojLogo"; interface ChatBodyDataProps { chatOptionsData: ChatOptions | null; @@ -187,41 +189,65 @@ export default function SharedChat() { return ( - -
- {title} -
-
- {!isMobileWidth && title && ( -
- {title && ( -

- {title} -

- )} -
- )} - }> - - + +
+ + + {conversationId && ( +
+ {isMobileWidth ? ( + + ) : ( + title && ( + <> +

+ {title} +

+ + ) + )} +
+ )} +
+
+ {title} +
+
+ {!isMobileWidth && title && ( +
+ {title && ( +

+ {title} +

+ )} +
+ )} + }> + + +
-
+ ); }