From 27acdf2d61c95ef51b9cc8bbcb9667daf6b375c1 Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:13:28 -0500 Subject: [PATCH] feat(docs): add mobile search icon to trigger DocSearch modal (#5732) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add SearchIcon component (magnifying glass SVG) - Add mobile search button in the header's right-actions section - Add openDocSearch function to programmatically trigger DocSearch modal - Add CSS styles for mobile-search-btn (hidden on desktop, visible on mobile) - Button appears on viewports ≤768px and opens Algolia DocSearch when tapped Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com> --- packages/kilo-docs/components/TopNav.tsx | 523 +++++++++++++++++++++++ 1 file changed, 523 insertions(+) create mode 100644 packages/kilo-docs/components/TopNav.tsx diff --git a/packages/kilo-docs/components/TopNav.tsx b/packages/kilo-docs/components/TopNav.tsx new file mode 100644 index 00000000000..c81e4a6c26e --- /dev/null +++ b/packages/kilo-docs/components/TopNav.tsx @@ -0,0 +1,523 @@ +import React, { useState, useRef, useEffect } from "react" +import Link from "next/link" +import { useRouter } from "next/router" +import docsearch from "@docsearch/js" +import { ThemeToggle } from "./ThemeToggle" + +interface NavItem { + label: string + href: string +} + +interface DropdownItem { + label: string + href: string + description?: string +} + +interface DropdownMenuProps { + label: string + items: DropdownItem[] + isOpen: boolean + onToggle: () => void + onClose: () => void +} + +const mainNavItems: NavItem[] = [ + { label: "Get Started", href: "/getting-started" }, + { label: "Code with AI", href: "/code-with-ai" }, + { label: "Customize", href: "/customize" }, + { label: "Collaborate", href: "/collaborate" }, + { label: "Automate", href: "/automate" }, + { label: "Deploy & Secure", href: "/deploy-secure" }, + { label: "Contributing", href: "/contributing" }, +] + +const contributingItems: DropdownItem[] = [ + { label: "Contributing Guide", href: "/contributing", description: "How to contribute to Kilo Code" }, + { + label: "Code of Conduct", + href: "https://github.com/Kilo-Org/kilocode?tab=coc-ov-file", + description: "Our community guidelines", + }, + { label: "GitHub Repository", href: "https://github.com/Kilo-Org/", description: "View source and issues" }, + { label: "Discord Community", href: "https://kilo.ai/discord", description: "Join our community" }, +] + +const helpItems: DropdownItem[] = [ + { label: "Documentation", href: "/", description: "Browse all documentation" }, + { label: "FAQ", href: "/getting-started/faq", description: "Frequently asked questions" }, + { label: "Support", href: "https://kilo.ai/support", description: "Get help from the team" }, + { + label: "Changelog", + href: "https://github.com/Kilo-Org/kilocode/releases", + description: "Latest updates and releases", + }, +] + +function ChevronDownIcon({ className }: { className?: string }) { + return ( + + + + ) +} + +function SparkleIcon({ className }: { className?: string }) { + return ( + + + + ) +} + +function SearchIcon({ className }: { className?: string }) { + return ( + + + + + ) +} + +function HamburgerIcon({ isOpen }: { isOpen: boolean }) { + return ( +
+ + + +
+ ) +} + +function DropdownMenu({ label, items, isOpen, onToggle, onClose }: DropdownMenuProps) { + const dropdownRef = useRef(null) + + useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + onClose() + } + } + + if (isOpen) { + document.addEventListener("mousedown", handleClickOutside) + } + + return () => { + document.removeEventListener("mousedown", handleClickOutside) + } + }, [isOpen, onClose]) + + return ( +
+ + {isOpen && ( +
+
+ {items.map((item) => ( + + + {item.label} + + {item.description && ( + + {item.description} + + )} + + ))} +
+
+ )} +
+ ) +} + +function NavTab({ item, isActive }: { item: NavItem; isActive: boolean }) { + return ( + + {item.label} + {isActive && } + + ) +} + +interface TopNavProps { + onMobileMenuToggle?: () => void + isMobileMenuOpen?: boolean + showMobileMenuButton?: boolean +} + +export function TopNav({ onMobileMenuToggle, isMobileMenuOpen = false, showMobileMenuButton = true }: TopNavProps) { + const router = useRouter() + const [openDropdown, setOpenDropdown] = useState(null) + + const handleDropdownToggle = (name: string) => { + setOpenDropdown(openDropdown === name ? null : name) + } + + const handleDropdownClose = () => { + setOpenDropdown(null) + } + + const isActiveTab = (href: string) => { + if (href === "/docs") { + return router.pathname === "/docs" || router.pathname === "/docs/index" + } + return router.pathname.startsWith(href) + } + + // Open DocSearch modal programmatically + const openDocSearch = () => { + const searchButton = document.querySelector(".DocSearch-Button") as HTMLButtonElement + if (searchButton) { + searchButton.click() + } + } + + // Initialize DocSearch + useEffect(() => { + docsearch({ + container: "#docsearch", + appId: process.env.NEXT_PUBLIC_ALGOLIA_APP_ID || "PMZUYBQDAK", + indexName: process.env.NEXT_PUBLIC_ALGOLIA_INDEX_NAME || "docsearch", + apiKey: process.env.NEXT_PUBLIC_ALGOLIA_API_KEY || "24b09689d5b4223813d9b8e48563c8f6", + askAi: process.env.NEXT_PUBLIC_ALGOLIA_ASSISTANT_ID || "askAIDemo", + }) + }, []) + + return ( +
+ {/* Top bar */} +
+ {/* Mobile menu button */} + {showMobileMenuButton && ( + + )} + + + + + +
+ Kilo Code + DOCS +
+ + + {/* Center - Search and Ask AI (desktop only) */} +
+
+ + {/* */} +
+ +
+ {/* Mobile search button */} + + + + GitHub + + + Sign in + +
+
+ + {/* Secondary nav bar (desktop only) */} +
+ + +
+ handleDropdownToggle("contributing")} + onClose={handleDropdownClose} + /> + handleDropdownToggle("help")} + onClose={handleDropdownClose} + /> +
+
+ + +
+ ) +}