larkup 0.1.29 → 0.1.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +5 -5
  3. package/.next/diagnostics/route-bundle-stats.json +35 -35
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/next-minimal-server.js.nft.json +1 -1
  6. package/.next/next-server.js.nft.json +1 -1
  7. package/.next/prerender-manifest.json +3 -3
  8. package/.next/required-server-files.js +4 -4
  9. package/.next/required-server-files.json +4 -4
  10. package/.next/server/app/_global-error/page/build-manifest.json +2 -2
  11. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  12. package/.next/server/app/_global-error.html +1 -1
  13. package/.next/server/app/_global-error.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  16. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/.next/server/app/_not-found/page/build-manifest.json +2 -2
  20. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/.next/server/app/_not-found.html +1 -1
  23. package/.next/server/app/_not-found.rsc +16 -16
  24. package/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
  25. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  26. package/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
  27. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  28. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  29. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  30. package/.next/server/app/analytics/page/build-manifest.json +2 -2
  31. package/.next/server/app/analytics/page.js.nft.json +1 -1
  32. package/.next/server/app/analytics/page_client-reference-manifest.js +1 -1
  33. package/.next/server/app/analytics.html +1 -1
  34. package/.next/server/app/analytics.rsc +17 -17
  35. package/.next/server/app/analytics.segments/_full.segment.rsc +17 -17
  36. package/.next/server/app/analytics.segments/_head.segment.rsc +4 -4
  37. package/.next/server/app/analytics.segments/_index.segment.rsc +11 -11
  38. package/.next/server/app/analytics.segments/_tree.segment.rsc +1 -1
  39. package/.next/server/app/analytics.segments/analytics/__PAGE__.segment.rsc +3 -3
  40. package/.next/server/app/analytics.segments/analytics.segment.rsc +3 -3
  41. package/.next/server/app/api/analytics/route.js.nft.json +1 -1
  42. package/.next/server/app/api/chat/route.js.nft.json +1 -1
  43. package/.next/server/app/api/chat/status/route.js.nft.json +1 -1
  44. package/.next/server/app/api/chat/suggestions/route.js.nft.json +1 -1
  45. package/.next/server/app/api/config/route.js.nft.json +1 -1
  46. package/.next/server/app/api/config/test/route.js.nft.json +1 -1
  47. package/.next/server/app/api/config/test-embedding/route.js.nft.json +1 -1
  48. package/.next/server/app/api/config/test-llm/route.js.nft.json +1 -1
  49. package/.next/server/app/api/config/test-provider/route.js +4 -4
  50. package/.next/server/app/api/config/test-provider/route.js.nft.json +1 -1
  51. package/.next/server/app/api/config/verify/route.js +3 -3
  52. package/.next/server/app/api/config/verify/route.js.nft.json +1 -1
  53. package/.next/server/app/api/connections/route.js.nft.json +1 -1
  54. package/.next/server/app/api/connections/webhook/route.js.nft.json +1 -1
  55. package/.next/server/app/api/demo/route.js.nft.json +1 -1
  56. package/.next/server/app/api/deploy/cloud-project/route.js.nft.json +1 -1
  57. package/.next/server/app/api/deploy/ssh/route.js.nft.json +1 -1
  58. package/.next/server/app/api/deployment/blob-setup/route.js.nft.json +1 -1
  59. package/.next/server/app/api/deployment/config/route.js.nft.json +1 -1
  60. package/.next/server/app/api/describe-image/route.js.nft.json +1 -1
  61. package/.next/server/app/api/doc-editor/edit/route.js.nft.json +1 -1
  62. package/.next/server/app/api/doc-editor/export/route.js.nft.json +1 -1
  63. package/.next/server/app/api/doc-editor/extract-text/route.js.nft.json +1 -1
  64. package/.next/server/app/api/doc-editor/parse/route.js.nft.json +1 -1
  65. package/.next/server/app/api/doc-editor/restore/route.js.nft.json +1 -1
  66. package/.next/server/app/api/document/sign/route.js.nft.json +1 -1
  67. package/.next/server/app/api/documents/route.js.nft.json +1 -1
  68. package/.next/server/app/api/firecrawl/local/route.js.nft.json +1 -1
  69. package/.next/server/app/api/index/route.js.nft.json +1 -1
  70. package/.next/server/app/api/integrations/notion/callback/route.js.nft.json +1 -1
  71. package/.next/server/app/api/integrations/notion/route.js.nft.json +1 -1
  72. package/.next/server/app/api/jobs/[id]/route.js.nft.json +1 -1
  73. package/.next/server/app/api/jobs/route.js.nft.json +1 -1
  74. package/.next/server/app/api/marketplace/[toolId]/route.js.nft.json +1 -1
  75. package/.next/server/app/api/marketplace/route.js.nft.json +1 -1
  76. package/.next/server/app/api/media/[id]/route.js.nft.json +1 -1
  77. package/.next/server/app/api/media/process/route.js.nft.json +1 -1
  78. package/.next/server/app/api/media/route.js.nft.json +1 -1
  79. package/.next/server/app/api/media/stream/route.js.nft.json +1 -1
  80. package/.next/server/app/api/models/route.js.nft.json +1 -1
  81. package/.next/server/app/api/parse-file/route.js.nft.json +1 -1
  82. package/.next/server/app/api/proxy/verify/route.js.nft.json +1 -1
  83. package/.next/server/app/api/sandbox/route.js.nft.json +1 -1
  84. package/.next/server/app/api/search/bing/route.js.nft.json +1 -1
  85. package/.next/server/app/api/search/brave/route.js.nft.json +1 -1
  86. package/.next/server/app/api/search/exa/route.js.nft.json +1 -1
  87. package/.next/server/app/api/search/google/route.js.nft.json +1 -1
  88. package/.next/server/app/api/search/route.js.nft.json +1 -1
  89. package/.next/server/app/api/search/tavily/route.js.nft.json +1 -1
  90. package/.next/server/app/api/search/verify/route.js.nft.json +1 -1
  91. package/.next/server/app/api/server/agent/route.js.nft.json +1 -1
  92. package/.next/server/app/api/server/download/route.js.nft.json +1 -1
  93. package/.next/server/app/api/server/generate/route.js.nft.json +1 -1
  94. package/.next/server/app/api/server/local/route.js.nft.json +1 -1
  95. package/.next/server/app/api/servers/route.js.nft.json +1 -1
  96. package/.next/server/app/api/tabular/query/route.js.nft.json +1 -1
  97. package/.next/server/app/api/tabular/route.js.nft.json +1 -1
  98. package/.next/server/app/api/upload-file/route.js.nft.json +1 -1
  99. package/.next/server/app/api/uploads/[...slug]/route.js.nft.json +1 -1
  100. package/.next/server/app/api/vector-stores/install/route.js.nft.json +1 -1
  101. package/.next/server/app/api/vector-stores/status/route.js.nft.json +1 -1
  102. package/.next/server/app/chat/page/build-manifest.json +2 -2
  103. package/.next/server/app/chat/page.js.nft.json +1 -1
  104. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  105. package/.next/server/app/chat.html +1 -1
  106. package/.next/server/app/chat.rsc +17 -17
  107. package/.next/server/app/chat.segments/_full.segment.rsc +17 -17
  108. package/.next/server/app/chat.segments/_head.segment.rsc +4 -4
  109. package/.next/server/app/chat.segments/_index.segment.rsc +11 -11
  110. package/.next/server/app/chat.segments/_tree.segment.rsc +1 -1
  111. package/.next/server/app/chat.segments/chat/__PAGE__.segment.rsc +3 -3
  112. package/.next/server/app/chat.segments/chat.segment.rsc +3 -3
  113. package/.next/server/app/data/page/build-manifest.json +2 -2
  114. package/.next/server/app/data/page.js.nft.json +1 -1
  115. package/.next/server/app/data/page_client-reference-manifest.js +1 -1
  116. package/.next/server/app/data.html +1 -1
  117. package/.next/server/app/data.rsc +17 -17
  118. package/.next/server/app/data.segments/_full.segment.rsc +17 -17
  119. package/.next/server/app/data.segments/_head.segment.rsc +4 -4
  120. package/.next/server/app/data.segments/_index.segment.rsc +11 -11
  121. package/.next/server/app/data.segments/_tree.segment.rsc +1 -1
  122. package/.next/server/app/data.segments/data/__PAGE__.segment.rsc +3 -3
  123. package/.next/server/app/data.segments/data.segment.rsc +3 -3
  124. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  125. package/.next/server/app/index.html +1 -1
  126. package/.next/server/app/index.rsc +16 -16
  127. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  128. package/.next/server/app/index.segments/_full.segment.rsc +16 -16
  129. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  130. package/.next/server/app/index.segments/_index.segment.rsc +11 -11
  131. package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  132. package/.next/server/app/page/build-manifest.json +2 -2
  133. package/.next/server/app/page.js.nft.json +1 -1
  134. package/.next/server/app/page_client-reference-manifest.js +1 -1
  135. package/.next/server/app/settings/page/build-manifest.json +2 -2
  136. package/.next/server/app/settings/page/server-reference-manifest.json +3 -3
  137. package/.next/server/app/settings/page.js.nft.json +1 -1
  138. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  139. package/.next/server/app/settings.html +1 -1
  140. package/.next/server/app/settings.rsc +18 -18
  141. package/.next/server/app/settings.segments/_full.segment.rsc +18 -18
  142. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  143. package/.next/server/app/settings.segments/_index.segment.rsc +11 -11
  144. package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  145. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  146. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  147. package/.next/server/chunks/0598_next_dist_esm_build_templates_app-route_0kbcuk-.js +17 -3
  148. package/.next/server/chunks/0598_next_dist_esm_build_templates_app-route_1f4h7rr.js +1 -1
  149. package/.next/server/chunks/[root-of-the-server]__01al2n0._.js +1 -1
  150. package/.next/server/chunks/[root-of-the-server]__067hiof._.js +18 -6
  151. package/.next/server/chunks/[root-of-the-server]__0a_0ywc._.js +18 -6
  152. package/.next/server/chunks/[root-of-the-server]__0u17zp8._.js +18 -6
  153. package/.next/server/chunks/{[root-of-the-server]__1xuhh_i._.js → [root-of-the-server]__16jk_se._.js} +2 -2
  154. package/.next/server/chunks/[root-of-the-server]__1ahdfq9._.js +18 -6
  155. package/.next/server/chunks/[root-of-the-server]__1o3rcbz._.js +2 -1
  156. package/.next/server/chunks/{[root-of-the-server]__10gcb7d._.js → [root-of-the-server]__1qh2h5v._.js} +2 -2
  157. package/.next/server/chunks/[root-of-the-server]__1s9is1o._.js +2 -1
  158. package/.next/server/chunks/[root-of-the-server]__1vsvck0._.js +18 -6
  159. package/.next/server/chunks/[root-of-the-server]__1wy6wes._.js +1 -1
  160. package/.next/server/chunks/[root-of-the-server]__1zptg4z._.js +2 -1
  161. package/.next/server/chunks/packages_core_src_generator_generate-server_ts_11-w3m3._.js +2 -2
  162. package/.next/server/chunks/packages_core_src_generator_server-runtime_ts_1_68l7t._.js +4 -4
  163. package/.next/server/chunks/packages_marketplace_src_125_g2p._.js +1 -1
  164. package/.next/server/chunks/ssr/{[root-of-the-server]__0wdatpx._.js → [root-of-the-server]__0m21fli._.js} +1 -1
  165. package/.next/server/chunks/ssr/{[root-of-the-server]__1r9ap67._.js → [root-of-the-server]__0t8ud_u._.js} +1 -1
  166. package/.next/server/chunks/ssr/{[root-of-the-server]__046ldu_._.js → [root-of-the-server]__0xyo3ni._.js} +1 -1
  167. package/.next/server/chunks/ssr/{_0k81--x._.js → _0ckxy33._.js} +2 -2
  168. package/.next/server/chunks/ssr/_169pdlf._.js +6 -6
  169. package/.next/server/chunks/ssr/_1hetwwu._.js +4 -3
  170. package/.next/server/chunks/ssr/_1iff9ia._.js +1 -1
  171. package/.next/server/chunks/ssr/_1yqlx1m._.js +1 -1
  172. package/.next/server/chunks/ssr/apps_web_components_analytics_analytics-dashboard_tsx_1056-z3._.js +1 -1
  173. package/.next/server/chunks/ssr/packages_core_src_generator_generate-server_ts_15zzrn2._.js +2 -2
  174. package/.next/server/functions-config-manifest.json +3 -1
  175. package/.next/server/middleware-build-manifest.js +5 -5
  176. package/.next/server/pages/404.html +1 -1
  177. package/.next/server/pages/500.html +1 -1
  178. package/.next/server/server-reference-manifest.js +1 -1
  179. package/.next/server/server-reference-manifest.json +4 -4
  180. package/.next/static/chunks/{1sh7d5tt49x8b.js → 0ff5osu771ajz.js} +6 -6
  181. package/.next/static/chunks/{1z4nte07k3dt6.js → 1-afr-snks55m.js} +1 -1
  182. package/.next/static/chunks/{1dykihoo_1ae5.js → 1fz_0-qb5r5wd.js} +1 -1
  183. package/.next/static/chunks/{3g_wl1fri6jb-.js → 21_6-9hjj2i68.js} +1 -1
  184. package/.next/static/chunks/{13kyiy7q3of41.js → 2jqjx4-rh414_.js} +1 -1
  185. package/.next/static/chunks/2jrpgzxyrmuqp.js +121 -0
  186. package/.next/static/chunks/390ds7l_plpmd.js +1 -0
  187. package/.next/static/chunks/{3een1tiktxr6a.js → 3zw6tgf7mxo39.js} +1 -1
  188. package/.next/static/chunks/{turbopack-2qt7vn_ocj4ao.js → turbopack-2gu-fmc6o5wkn.js} +1 -1
  189. package/CHANGELOG.md +33 -0
  190. package/app/api/chat/route.ts +14 -1
  191. package/app/api/chat/tools.ts +7 -3
  192. package/app/api/config/test-provider/route.ts +16 -18
  193. package/app/api/config/verify/route.ts +5 -7
  194. package/app/api/firecrawl/local/route.ts +7 -4
  195. package/app/api/jobs/route.ts +1 -2
  196. package/app/api/marketplace/[toolId]/route.ts +1 -0
  197. package/archive/redesign-v2/app/configure/page.tsx +53 -0
  198. package/archive/redesign-v2/app/demo/page.tsx +15 -0
  199. package/archive/redesign-v2/app/server/page.tsx +22 -0
  200. package/archive/redesign-v2/app/simple/chat/page.tsx +17 -0
  201. package/archive/redesign-v2/app/simple/docs/page.tsx +21 -0
  202. package/archive/redesign-v2/app/simple/settings/page.tsx +1104 -0
  203. package/archive/redesign-v2/app-routes/configure/page.tsx +53 -0
  204. package/archive/redesign-v2/app-routes/demo/page.tsx +15 -0
  205. package/archive/redesign-v2/app-routes/server/page.tsx +22 -0
  206. package/archive/redesign-v2/app-routes/simple/chat/page.tsx +17 -0
  207. package/archive/redesign-v2/app-routes/simple/docs/page.tsx +21 -0
  208. package/archive/redesign-v2/app-routes/simple/layout.tsx +9 -0
  209. package/archive/redesign-v2/app-routes/simple/settings/page.tsx +1104 -0
  210. package/archive/redesign-v2/components/app-sidebar.tsx +188 -0
  211. package/archive/redesign-v2/components/app-topnav.tsx +195 -0
  212. package/archive/redesign-v2/components/global-settings.tsx +288 -0
  213. package/archive/redesign-v2/components/simple/simple-sidebar.tsx +171 -0
  214. package/archive/redesign-v2/components/simple/simple-topnav.tsx +175 -0
  215. package/components/analytics/analytics-dashboard.tsx +1 -1
  216. package/components/data/firecrawl-notice.tsx +41 -98
  217. package/components/data/media-panel.tsx +0 -3
  218. package/components/data/scrape-panel.tsx +17 -1
  219. package/components/onboarding/welcome-screen.tsx +45 -15
  220. package/components/settings/general-section.tsx +15 -10
  221. package/components/settings/server-section.tsx +3 -3
  222. package/lib/error-formatter.ts +19 -4
  223. package/next-env.d.ts +1 -1
  224. package/package.json +7 -7
  225. package/.next/static/chunks/01qmngac69n9j.js +0 -1
  226. package/.next/static/chunks/102b8vinedggz.js +0 -120
  227. /package/.next/static/{W6QdudzTPo_OVPpNt29f7 → kaW1RhJBmrNB5F_JAJ6QO}/_buildManifest.js +0 -0
  228. /package/.next/static/{W6QdudzTPo_OVPpNt29f7 → kaW1RhJBmrNB5F_JAJ6QO}/_clientMiddlewareManifest.js +0 -0
  229. /package/.next/static/{W6QdudzTPo_OVPpNt29f7 → kaW1RhJBmrNB5F_JAJ6QO}/_ssgManifest.js +0 -0
@@ -0,0 +1,171 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { usePathname } from "next/navigation";
5
+ import {
6
+ MessageCircle,
7
+ FileStack,
8
+ SlidersHorizontal,
9
+ type LucideIcon,
10
+ } from "lucide-react";
11
+ import { cn } from "@/lib/utils";
12
+ import {
13
+ Tooltip,
14
+ TooltipContent,
15
+ TooltipProvider,
16
+ TooltipTrigger,
17
+ } from "@/components/ui/tooltip";
18
+ import {
19
+ useThemeCustomizer,
20
+ type PanelBgVariant,
21
+ } from "@/components/theme-customizer-provider";
22
+ import { ThemeSwitcher } from "@/components/theme-switcher";
23
+
24
+ const NAV_BG_COLORS: Record<PanelBgVariant, string | undefined> = {
25
+ "panel-default": undefined,
26
+ "panel-white": "#FFFFFF",
27
+ "panel-fafafa": "#F4F4F4",
28
+ "panel-warm": "#F7F1EA",
29
+ "panel-soft": "#FBFAF8",
30
+ "panel-silver": "#F8F8F8",
31
+ "panel-stone": "#F5F5F2",
32
+ };
33
+
34
+ interface NavItem {
35
+ id: string;
36
+ label: string;
37
+ href: string;
38
+ icon: LucideIcon;
39
+ description: string;
40
+ }
41
+
42
+ const SIMPLE_NAV: NavItem[] = [
43
+ {
44
+ id: "chat",
45
+ label: "Chat",
46
+ href: "/simple/chat",
47
+ icon: MessageCircle,
48
+ description: "Chat with your knowledge base using AI.",
49
+ },
50
+ {
51
+ id: "docs",
52
+ label: "Docs",
53
+ href: "/simple/docs",
54
+ icon: FileStack,
55
+ description: "Upload, paste, or manage your documents.",
56
+ },
57
+ {
58
+ id: "settings",
59
+ label: "Settings",
60
+ href: "/simple/settings",
61
+ icon: SlidersHorizontal,
62
+ description: "Configure provider, API keys, and advanced settings.",
63
+ },
64
+ ];
65
+
66
+ export function SimpleSidebar() {
67
+ const pathname = usePathname();
68
+ const { pageStyle, navBg } = useThemeCustomizer();
69
+
70
+ const navColor = navBg ? NAV_BG_COLORS[navBg] : undefined;
71
+ const navStyle = navColor ? { backgroundColor: navColor } : undefined;
72
+
73
+ return (
74
+ <TooltipProvider delay={150}>
75
+ <aside
76
+ className={cn(
77
+ "sticky top-0 hidden h-screen w-[84px] shrink-0 flex-col items-center gap-1 self-start py-3 md:flex",
78
+ !navColor ? "bg-background" : "",
79
+ pageStyle === "fused" ? "border-r border-border" : "",
80
+ )}
81
+ style={navStyle}
82
+ >
83
+ {/* Brand */}
84
+ <Tooltip>
85
+ <TooltipTrigger
86
+ render={
87
+ <Link
88
+ href="/simple/chat"
89
+ aria-label="larkup home"
90
+ className="mb-2 flex size-11 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-sm transition-transform hover:scale-105"
91
+ />
92
+ }
93
+ >
94
+ <img src={"/logo9.png"} className="size-6.5" alt="logo" />
95
+ </TooltipTrigger>
96
+ <TooltipContent side="right" sideOffset={10}>
97
+ Larkup
98
+ </TooltipContent>
99
+ </Tooltip>
100
+
101
+ {/* Navigation */}
102
+ <nav className="flex flex-1 flex-col items-center gap-2.5">
103
+ {SIMPLE_NAV.map((item) => {
104
+ const Icon = item.icon;
105
+ const active = pathname?.startsWith(item.href);
106
+
107
+ return (
108
+ <Tooltip key={item.id}>
109
+ <TooltipTrigger
110
+ render={
111
+ <Link
112
+ href={item.href}
113
+ aria-current={active ? "page" : undefined}
114
+ className="group relative flex w-16 flex-col items-center gap-0.5 rounded-2xl py-1 outline-none focus-visible:ring-2 focus-visible:ring-ring"
115
+ />
116
+ }
117
+ >
118
+ {/* Active accent bar */}
119
+ <span
120
+ className={cn(
121
+ "absolute left-0 top-1/2 h-6 w-1 -translate-y-1/2 rounded-r-full bg-primary transition-opacity",
122
+ active ? "opacity-100" : "opacity-0",
123
+ )}
124
+ />
125
+ <span
126
+ className={cn(
127
+ "relative flex size-9 items-center justify-center rounded-xl transition-colors",
128
+ active
129
+ ? "bg-white border text-primary"
130
+ : "text-foreground/70 group-hover:bg-white/90 group-hover:text-foreground",
131
+ )}
132
+ >
133
+ <Icon
134
+ className="size-[19px]"
135
+ strokeWidth={active ? 2.25 : 2}
136
+ />
137
+ </span>
138
+ <span
139
+ className={cn(
140
+ "text-[10px] leading-none tracking-tight",
141
+ active
142
+ ? "font-semibold text-primary"
143
+ : "text-muted-foreground",
144
+ )}
145
+ >
146
+ {item.label}
147
+ </span>
148
+ </TooltipTrigger>
149
+ <TooltipContent
150
+ side="right"
151
+ sideOffset={10}
152
+ className="max-w-56"
153
+ >
154
+ <div className="flex flex-col gap-0.5">
155
+ <span className="font-medium">{item.label}</span>
156
+ <span className="text-[11px] leading-snug opacity-80">
157
+ {item.description}
158
+ </span>
159
+ </div>
160
+ </TooltipContent>
161
+ </Tooltip>
162
+ );
163
+ })}
164
+ </nav>
165
+
166
+ {/* Footer */}
167
+ <ThemeSwitcher floating={false} />
168
+ </aside>
169
+ </TooltipProvider>
170
+ );
171
+ }
@@ -0,0 +1,175 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { usePathname } from "next/navigation";
5
+ import { cn } from "@/lib/utils";
6
+ import {
7
+ Tooltip,
8
+ TooltipContent,
9
+ TooltipProvider,
10
+ TooltipTrigger,
11
+ } from "@/components/ui/tooltip";
12
+ import { useWorkspace } from "@/components/workspace/workspace-provider";
13
+ import { ThemeSwitcher } from "@/components/theme-switcher";
14
+ import { useThemeCustomizer, type PanelBgVariant } from "@/components/theme-customizer-provider";
15
+ import { MessageCircle, FileStack, SlidersHorizontal, type LucideIcon } from "lucide-react";
16
+
17
+ const NAV_BG_COLORS: Record<PanelBgVariant, string | undefined> = {
18
+ "panel-default": undefined,
19
+ "panel-white": "#FFFFFF",
20
+ "panel-fafafa": "#F4F4F4",
21
+ "panel-warm": "#F7F1EA",
22
+ "panel-soft": "#FBFAF8",
23
+ "panel-silver": "#F8F8F8",
24
+ "panel-stone": "#F5F5F2",
25
+ };
26
+
27
+ interface NavItem {
28
+ id: string;
29
+ label: string;
30
+ href: string;
31
+ icon: LucideIcon;
32
+ description: string;
33
+ }
34
+
35
+ const SIMPLE_NAV: NavItem[] = [
36
+ {
37
+ id: "chat",
38
+ label: "Chat",
39
+ href: "/simple/chat",
40
+ icon: MessageCircle,
41
+ description: "Chat with your knowledge base using AI.",
42
+ },
43
+ {
44
+ id: "docs",
45
+ label: "Docs",
46
+ href: "/simple/docs",
47
+ icon: FileStack,
48
+ description: "Upload, paste, or manage your documents.",
49
+ },
50
+ {
51
+ id: "settings",
52
+ label: "Settings",
53
+ href: "/simple/settings",
54
+ icon: SlidersHorizontal,
55
+ description: "Configure provider, API keys, and advanced settings.",
56
+ },
57
+ ];
58
+
59
+ export function SimpleTopNav() {
60
+ const pathname = usePathname();
61
+ const { username } = useWorkspace();
62
+ const { navBg } = useThemeCustomizer();
63
+
64
+ const navColor = navBg ? NAV_BG_COLORS[navBg] : undefined;
65
+ const navStyle = navColor ? { backgroundColor: navColor } : undefined;
66
+
67
+ return (
68
+ <TooltipProvider delay={150}>
69
+ <header
70
+ className={cn(
71
+ "sticky top-0 z-50 flex h-16 shrink-0 items-center gap-4 border-b border-border px-4 md:px-6",
72
+ !navColor ? "bg-white" : "",
73
+ )}
74
+ style={navStyle}
75
+ >
76
+ {/* Brand */}
77
+ <Link
78
+ href="/simple/chat"
79
+ aria-label="larkup home"
80
+ className="flex size-10 shrink-0 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-sm transition-transform hover:scale-105"
81
+ >
82
+ <img src={"/logo9.png"} className="size-5" alt="logo" />
83
+ </Link>
84
+ <span className="font-semibold tracking-tight hidden sm:inline-block">
85
+ Larkup
86
+ </span>
87
+
88
+ {/* Navigation */}
89
+ <nav className="flex flex-1 h-full items-end pb-0 gap-2 md:gap-4 ml-4">
90
+ {SIMPLE_NAV.map((item, index) => {
91
+ const Icon = item.icon;
92
+ const active = pathname?.startsWith(item.href);
93
+
94
+ return (
95
+ <Tooltip key={item.id}>
96
+ <TooltipTrigger
97
+ render={
98
+ <Link
99
+ href={item.href}
100
+ aria-current={active ? "page" : undefined}
101
+ className={cn(
102
+ "group relative flex items-center gap-2 h-10 px-3 rounded-md transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring",
103
+ active ? "bg-muted/0" : "hover:bg-muted/30",
104
+ )}
105
+ />
106
+ }
107
+ >
108
+ <div className="flex items-center">
109
+ <span
110
+ className={cn(
111
+ "flex size-9 items-center justify-center rounded-lg transition-colors",
112
+ active
113
+ ? "text-primary"
114
+ : "text-muted-foreground group-hover:text-foreground",
115
+ )}
116
+ >
117
+ <Icon
118
+ className="size-[18px]"
119
+ strokeWidth={active ? 2.25 : 2}
120
+ />
121
+ </span>
122
+ <span
123
+ className={cn(
124
+ "hidden md:block text-[13px] tracking-tight",
125
+ active
126
+ ? "font-semibold text-primary"
127
+ : "text-muted-foreground group-hover:text-foreground",
128
+ )}
129
+ >
130
+ {item.label}
131
+ </span>
132
+ {/* active accent bar (bottom) */}
133
+ <span
134
+ className={cn(
135
+ "absolute bottom-0 left-0 h-0.5 w-full bg-primary transition-opacity",
136
+ active
137
+ ? "opacity-100"
138
+ : "opacity-0 group-hover:opacity-100",
139
+ )}
140
+ />
141
+ </div>
142
+ </TooltipTrigger>
143
+ <TooltipContent
144
+ side="bottom"
145
+ sideOffset={10}
146
+ className="max-w-56"
147
+ >
148
+ <div className="flex flex-col gap-0.5">
149
+ <span className="font-medium">
150
+ {item.label}
151
+ </span>
152
+ <span className="text-[11px] leading-snug opacity-80">
153
+ {item.description}
154
+ </span>
155
+ </div>
156
+ </TooltipContent>
157
+ </Tooltip>
158
+ );
159
+ })}
160
+ </nav>
161
+
162
+ {/* Right side: Workspace & Theme Customizer */}
163
+ <div className="flex items-center gap-3">
164
+ {username && (
165
+ <span className="hidden text-sm text-muted-foreground md:block">
166
+ Hi,{" "}
167
+ <span className="font-medium text-foreground">{username}</span>
168
+ </span>
169
+ )}
170
+ <ThemeSwitcher floating={false} />
171
+ </div>
172
+ </header>
173
+ </TooltipProvider>
174
+ );
175
+ }
@@ -74,7 +74,7 @@ function formatCost(cost: number): string {
74
74
  }
75
75
 
76
76
  export function AnalyticsDashboard() {
77
- const [activeTab, setActiveTab] = useState('overview');
77
+ const [activeTab, setActiveTab] = useState('indexing');
78
78
  const [timeframe, setTimeframe] = useState('14d');
79
79
 
80
80
  const {
@@ -1,21 +1,12 @@
1
- "use client";
1
+ 'use client';
2
2
 
3
- import { useState, useEffect } from "react";
4
- import useSWR from "swr";
5
- import {
6
- CheckCircle2,
7
- KeyRound,
8
- Loader2,
9
- Play,
10
- Server,
11
- Square,
12
- TriangleAlert,
13
- } from "lucide-react";
14
- import { toast } from "sonner";
15
- import { formatErrorMessage } from "@/lib/error-formatter";
16
- import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
17
- import { Button } from "@/components/ui/button";
18
- import { Badge } from "@/components/ui/badge";
3
+ import { useState, useEffect } from 'react';
4
+ import { useRouter } from 'next/navigation';
5
+ import useSWR from 'swr';
6
+ import { Loader2, Play, Square } from 'lucide-react';
7
+ import { toast } from 'sonner';
8
+ import { formatErrorMessage } from '@/lib/error-formatter';
9
+ import { Button } from '@/components/ui/button';
19
10
 
20
11
  interface LocalState {
21
12
  running: boolean;
@@ -33,7 +24,7 @@ interface DockerState {
33
24
  interface LocalResponse {
34
25
  state: LocalState;
35
26
  docker: DockerState;
36
- runtimeEnv?: "web" | "desktop" | "docker";
27
+ runtimeEnv?: 'web' | 'desktop' | 'docker';
37
28
  }
38
29
 
39
30
  const fetcher = (url: string) => fetch(url).then((r) => r.json());
@@ -57,19 +48,15 @@ export function FirecrawlNotice({
57
48
  onChange?: () => void;
58
49
  onErrorChange?: (hasError: boolean) => void;
59
50
  }) {
60
- const { data, mutate, isLoading } = useSWR<LocalResponse>(
61
- "/api/firecrawl/local",
62
- fetcher,
63
- {
64
- refreshInterval: (d) =>
65
- d?.state.running || d?.state.startedAt ? 8000 : 0,
66
- },
67
- );
68
- const [busy, setBusy] = useState<"start" | "stop" | null>(null);
51
+ const router = useRouter();
52
+ const { data, mutate, isLoading } = useSWR<LocalResponse>('/api/firecrawl/local', fetcher, {
53
+ refreshInterval: (d) => (d?.state.running || d?.state.startedAt ? 8000 : 0),
54
+ });
55
+ const [busy, setBusy] = useState<'start' | 'stop' | null>(null);
69
56
 
70
57
  const state = data?.state;
71
58
  const docker = data?.docker;
72
- const runtimeEnv = data?.runtimeEnv ?? "web";
59
+ const runtimeEnv = data?.runtimeEnv ?? 'web';
73
60
  const running = state?.running ?? false;
74
61
  const dockerReady = docker?.compose ?? false;
75
62
  const hasError = !cloudConfigured && (!dockerReady || !!state?.lastError);
@@ -80,49 +67,45 @@ export function FirecrawlNotice({
80
67
  }
81
68
  }, [hasError, isLoading, onErrorChange]);
82
69
 
83
- async function control(action: "start" | "stop") {
70
+ async function control(action: 'start' | 'stop') {
84
71
  setBusy(action);
85
- if (action === "start") {
72
+ if (action === 'start') {
86
73
  toast.info(
87
- runtimeEnv === "docker"
88
- ? "Connecting to crawler service…"
89
- : "Launching web crawler…",
74
+ runtimeEnv === 'docker' ? 'Connecting to crawler service…' : 'Launching web crawler…',
90
75
  {
91
76
  description:
92
- runtimeEnv === "docker"
93
- ? "Checking if the crawler service is available on the network."
94
- : "Pulling images and starting containers. This can take a minute on first run.",
77
+ runtimeEnv === 'docker'
78
+ ? 'Checking if the crawler service is available on the network.'
79
+ : 'Pulling images and starting containers. This can take a minute on first run.',
95
80
  },
96
81
  );
97
82
  }
98
83
  try {
99
- const res = await fetch("/api/firecrawl/local", {
100
- method: "POST",
101
- headers: { "Content-Type": "application/json" },
84
+ const res = await fetch('/api/firecrawl/local', {
85
+ method: 'POST',
86
+ headers: { 'Content-Type': 'application/json' },
102
87
  body: JSON.stringify({ action }),
103
88
  });
104
89
  const json = (await res.json()) as { state?: LocalState; error?: string };
105
- if (!res.ok) throw new Error(json.error || "Request failed");
90
+ if (!res.ok) throw new Error(json.error || 'Request failed');
106
91
 
107
- if (action === "start") {
92
+ if (action === 'start') {
108
93
  if (json.state?.running) {
109
- toast.success("Web crawler is running", {
110
- description: "Web scraping is now active.",
94
+ toast.success('Web crawler is running', {
95
+ description: 'Web scraping is now active.',
111
96
  });
112
97
  } else {
113
- toast.warning("Crawler started", {
114
- description:
115
- json.state?.lastError ??
116
- "Waiting for the service to become healthy.",
98
+ toast.warning('Web crawler is starting', {
99
+ description: 'It may take a moment to become available. Try again shortly.',
117
100
  });
118
101
  }
119
102
  } else {
120
- toast.success("Web crawler stopped");
103
+ toast.success('Web crawler stopped');
121
104
  }
122
105
  await mutate();
123
106
  onChange?.();
124
107
  } catch (err) {
125
- toast.error("Could not control web crawler", {
108
+ toast.error('Could not connect to the web crawler', {
126
109
  description: formatErrorMessage(err),
127
110
  });
128
111
  } finally {
@@ -130,31 +113,16 @@ export function FirecrawlNotice({
130
113
  }
131
114
  }
132
115
 
133
- // Both cloud and local options are kept available.
134
-
135
- // Description text based on environment
136
- const idleDescription = (() => {
137
- if (runtimeEnv === "docker") {
138
- return dockerReady
139
- ? "A crawler service was found on the network. Click to connect."
140
- : "Start your deployment with the crawler profile to enable web scraping: docker compose --profile crawler up";
141
- }
142
- if (cloudConfigured) {
143
- return "You have a cloud key set. You can also run the crawler locally via Docker.";
144
- }
145
- return "Launch a self-hosted web crawler via Docker. A key is generated automatically — no signup required. Pasting and uploading work without it.";
146
- })();
147
-
148
116
  return (
149
117
  <div className="flex items-center gap-2">
150
118
  {running ? (
151
119
  <Button
152
120
  variant="outline"
153
121
  className="h-10 gap-1.5 rounded-md bg-red-500 hover:bg-red-600 text-white hover:text-white hover:border-red-200 text-sm px-4 shadow-none"
154
- onClick={() => control("stop")}
122
+ onClick={() => control('stop')}
155
123
  disabled={busy !== null}
156
124
  >
157
- {busy === "stop" ? (
125
+ {busy === 'stop' ? (
158
126
  <Loader2 className="size-3 animate-spin" />
159
127
  ) : (
160
128
  <Square className="size-3" />
@@ -164,45 +132,20 @@ export function FirecrawlNotice({
164
132
  ) : (
165
133
  <Button
166
134
  variant="outline"
167
- onClick={() => control("start")}
168
- disabled={
169
- busy !== null ||
170
- isLoading ||
171
- (!dockerReady && runtimeEnv !== "docker")
172
- }
135
+ onClick={() => {
136
+ control('start');
137
+ }}
138
+ disabled={busy !== null || isLoading}
173
139
  className="h-10 gap-1.5 rounded-md text-sm px-4 shadow-none bg-orange-500 text-white hover:bg-orange-600 hover:text-white"
174
140
  >
175
- {busy === "start" ? (
141
+ {busy === 'start' ? (
176
142
  <Loader2 className="size-3 animate-spin text-muted-foreground" />
177
143
  ) : (
178
- <img
179
- src="/icons/firecrawl2.png"
180
- alt=""
181
- className="size-3 object-contain"
182
- />
144
+ <img src="/icons/firecrawl2.png" alt="" className="size-3 object-contain" />
183
145
  )}
184
- {runtimeEnv === "docker" ? "Connect Crawler" : "Launch Crawler"}
146
+ {runtimeEnv === 'docker' && dockerReady ? 'Connect Crawler' : 'Launch Crawler'}
185
147
  </Button>
186
148
  )}
187
-
188
- {state?.lastError && !running && (
189
- <span
190
- className="text-[10px] text-destructive flex items-center gap-1 max-w-[200px] truncate"
191
- title={state.lastError}
192
- >
193
- <TriangleAlert className="size-3 shrink-0" />
194
- <span className="truncate">Error starting crawler</span>
195
- </span>
196
- )}
197
- {!isLoading && !dockerReady && !running && docker?.message && (
198
- <span
199
- className="text-[10px] text-destructive flex items-center gap-1 max-w-[200px] truncate"
200
- title={docker.message}
201
- >
202
- <TriangleAlert className="size-3 shrink-0" />
203
- <span className="truncate">Docker issue</span>
204
- </span>
205
- )}
206
149
  </div>
207
150
  );
208
151
  }
@@ -1634,9 +1634,6 @@ function ActiveIndexingList({
1634
1634
  {asset.processingMessage || 'Preparing media indexing...'}
1635
1635
  </p>
1636
1636
  </div>
1637
- {asset.processingSteps?.length ? (
1638
- <PipelineSteps steps={asset.processingSteps} />
1639
- ) : null}
1640
1637
  </div>
1641
1638
  );
1642
1639
  })}
@@ -36,6 +36,7 @@ import { GenericAlert } from '@/components/alerts/generic-alert';
36
36
  import { cn } from '@/lib/utils';
37
37
  import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
38
38
  import useSWR from 'swr';
39
+ import { useRouter } from 'next/navigation';
39
40
  import type { RagConfig } from '@larkup/core/types';
40
41
 
41
42
  const fetcher = (url: string) => fetch(url).then((r) => r.json() as Promise<{ config: RagConfig }>);
@@ -85,6 +86,7 @@ export function ScrapePanel({
85
86
  onStarted: () => void;
86
87
  crawlerControl?: React.ReactNode;
87
88
  }) {
89
+ const router = useRouter();
88
90
  const {
89
91
  query,
90
92
  setQuery,
@@ -124,6 +126,15 @@ export function ScrapePanel({
124
126
  const inputRef = useRef<HTMLInputElement>(null);
125
127
  const dropdownRef = useRef<HTMLDivElement>(null);
126
128
 
129
+ function showCrawlerSettings() {
130
+ toast.error('Web crawler is not available. Choose a crawler provider in Settings.', {
131
+ action: {
132
+ label: 'Open settings',
133
+ onClick: () => router.push('/settings?section=general#web-crawler'),
134
+ },
135
+ });
136
+ }
137
+
127
138
  useEffect(() => {
128
139
  function handleClickOutside(event: MouseEvent) {
129
140
  if (
@@ -222,7 +233,12 @@ export function ScrapePanel({
222
233
  fetchProviderTotalCount(q, activeProvider);
223
234
  }
224
235
  } catch (err) {
225
- toast.error(formatErrorMessage(err));
236
+ const message = formatErrorMessage(err);
237
+ if (/crawler|firecrawl|not running|api key/i.test(message)) {
238
+ showCrawlerSettings();
239
+ } else {
240
+ toast.error(message);
241
+ }
226
242
  }
227
243
  }
228
244