diff --git a/.gitignore b/.gitignore index 3699965..9e0e66a 100755 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ ios/App/build/ android/.gradle/ android/build/ android/app/build/ +# Local auth bypass (dev only) +src/lib/auth-bypass.ts diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index d56d8b4..f846e05 100755 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -42,8 +42,8 @@ export default async function DashboardLayout({ : [] return ( - + @@ -84,7 +84,7 @@ export default async function DashboardLayout({ - + ) } diff --git a/src/components/agent/chat-provider.tsx b/src/components/agent/chat-provider.tsx index 33ba088..d1cd371 100755 --- a/src/components/agent/chat-provider.tsx +++ b/src/components/agent/chat-provider.tsx @@ -76,6 +76,10 @@ export function useChatState(): ChatStateValue { return ctx } +export function useChatStateOptional(): ChatStateValue | null { + return React.useContext(ChatStateContext) +} + // --- Render state context --- interface RenderContextValue { diff --git a/src/components/agent/chat-view.tsx b/src/components/agent/chat-view.tsx index 725cf33..97d4927 100755 --- a/src/components/agent/chat-view.tsx +++ b/src/components/agent/chat-view.tsx @@ -81,6 +81,10 @@ type RepoStats = { interface ChatViewProps { readonly variant: "page" | "panel" + readonly minimal?: boolean + readonly hideSuggestions?: boolean + onActivate?: () => void + readonly inputPlaceholder?: string } const REPO = "High-Performance-Structures/compass" @@ -387,6 +391,7 @@ function ChatInput({ onSend, onNewChat, className, + onActivate, }: { readonly textareaRef: React.RefObject< HTMLTextAreaElement | null @@ -398,6 +403,7 @@ function ChatInput({ readonly onSend: (text: string) => void readonly onNewChat?: () => void readonly className?: string + readonly onActivate?: () => void }) { const isRecording = recorder.state === "recording" const isTranscribing = recorder.state === "transcribing" @@ -406,6 +412,8 @@ function ChatInput({ return ( { if (!text.trim() || isGenerating) return onSend(text.trim()) @@ -484,7 +492,13 @@ function ChatInput({ ) } -export function ChatView({ variant }: ChatViewProps) { +export function ChatView({ + variant, + minimal = false, + hideSuggestions = false, + onActivate, + inputPlaceholder, +}: ChatViewProps) { const chat = useChatState() const isPage = variant === "page" const textareaRef = useRef(null) @@ -809,22 +823,45 @@ export function ChatView({ variant }: ChatViewProps) { } // --- PANEL variant --- + if (minimal) { + return ( +
+ +
+ ) + } + return (
{/* Conversation */} {chat.messages.length === 0 ? ( -
- - {suggestions.map((s) => ( - - ))} - +
+ {!hideSuggestions && ( + + {suggestions.map((s) => ( + + ))} + + )}
) : ( chat.messages.map((msg, idx) => ( @@ -851,7 +888,7 @@ export function ChatView({ variant }: ChatViewProps) {
+): string { + const normalized = label + .trim() + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/(^-|-$)/g, "") + const base = normalized.length > 0 ? normalized : "setting" + + let candidate = `custom-${base}` + let suffix = 2 + while (existingTabs.some((tab) => tab.value === candidate)) { + candidate = `custom-${base}-${suffix}` + suffix += 1 + } + return candidate +} + export function SettingsModal({ open, onOpenChange, @@ -44,177 +88,87 @@ export function SettingsModal({ const [pushNotifs, setPushNotifs] = React.useState(true) const [weeklyDigest, setWeeklyDigest] = React.useState(false) const [timezone, setTimezone] = React.useState("America/New_York") + const [signetId, setSignetId] = React.useState("") + const [customTabs, setCustomTabs] = React.useState>([]) + const [activeTab, setActiveTab] = React.useState("general") + const [newSettingName, setNewSettingName] = React.useState("") + const [newSettingPrompt, setNewSettingPrompt] = React.useState("") + // const [isMobileChatOpen, setIsMobileChatOpen] = React.useState(false) + // const chatState = useChatStateOptional() + + const menuTabs = React.useMemo( + () => [...SETTINGS_TABS, ...customTabs], + [customTabs] + ) + + const sendCreateSettingToChat = React.useCallback(() => { + toast.info("AI chat is currently disabled in settings") + }, []) + + const openCreateSettingFlow = React.useCallback(() => { + setActiveTab(CREATE_SETTING_TAB.value) + // setIsMobileChatOpen(true) + // chatState?.sendMessage({ text: "Create a new setting" }) + }, []) + + const handleSectionSelect = React.useCallback((value: string) => { + if (value === CREATE_SETTING_TAB.value) { + openCreateSettingFlow() + return + } + setActiveTab(value) + }, [openCreateSettingFlow]) + + const createCustomSetting = React.useCallback(() => { + const label = newSettingName.trim() + const details = newSettingPrompt.trim() + + if (!label) { + toast.error("Add a setting name first") + return + } + if (!details) { + toast.error("Describe what the setting should do") + return + } + + const nextTab: CustomSettingTab = { + value: makeCustomSettingValue(label, customTabs), + label, + prompt: details, + } + setCustomTabs((prev) => [...prev, nextTab]) + setActiveTab(nextTab.value) + // setIsMobileChatOpen(true) + setNewSettingName("") + setNewSettingPrompt("") + sendCreateSettingToChat() + toast.success(`Added ${nextTab.label} to settings`) + }, [customTabs, newSettingName, newSettingPrompt, sendCreateSettingToChat]) + const native = useNative() const biometric = useBiometricAuth() - const generalPage = ( - <> -
- - -
- - - -
-
- -

- Receive a summary of activity each week. -

-
- -
- - ) - - const notificationsPage = ( - <> -
-
- -

- Get notified about project updates via email. -

-
- -
- - - -
-
- -

- Receive push notifications in your browser. -

-
- -
- - ) - - const appearancePage = - - const integrationsPage = ( - <> - - - - - - - - ) - - const slabMemoryPage = - - const aiModelPage = - - const skillsPage = - - return ( - - - - - - General - - - Notifications - - - Appearance - - - Integrations - - - AI Model - - - Slab Memory - - - Skills - - - - + const renderContent = () => { + switch (activeTab) { + case "general": + return ( +
@@ -222,7 +176,7 @@ export function SettingsModal({
-
+

Receive a summary of activity each week. @@ -234,14 +188,14 @@ export function SettingsModal({ className="shrink-0" />

- +
+ ) - + case "notifications": + return ( +
-
+

Get notified about project updates via email. @@ -257,7 +211,7 @@ export function SettingsModal({

-
+

{native @@ -275,9 +229,8 @@ export function SettingsModal({ {native && biometric.isAvailable && ( <> -

-
+

Require Face ID or fingerprint when returning to the app. @@ -291,49 +244,243 @@ export function SettingsModal({

)} - +
+ ) - - - + case "appearance": + return
- + case "integrations": + return ( +
- +
+ ) - - - + case "ai-model": + return
- - - + case "agent": + return ( +
+
+ + setSignetId(e.target.value)} + placeholder="0x..." + className="h-9 font-mono" + type="password" + /> +
- - - - - - + + + +
+ ) + + case "skills": + return
+ + case CREATE_SETTING_TAB.value: + return ( +
+
+

Create a new setting

+

+ Describe the setting you want, then send it to AI chat. +

+
+ +
+ + setNewSettingName(e.target.value)} + placeholder="Example: Project defaults" + className="h-9" + /> +
+ +
+ +