nitrostack 1.0.71 → 1.0.73

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 (253) hide show
  1. package/dist/auth/api-key.js.map +1 -1
  2. package/dist/auth/client.js.map +1 -1
  3. package/dist/auth/index.d.ts +2 -1
  4. package/dist/auth/index.d.ts.map +1 -1
  5. package/dist/auth/index.js +3 -0
  6. package/dist/auth/index.js.map +1 -1
  7. package/dist/auth/middleware.d.ts +1 -1
  8. package/dist/auth/middleware.d.ts.map +1 -1
  9. package/dist/auth/middleware.js.map +1 -1
  10. package/dist/auth/secure-secret.d.ts +136 -0
  11. package/dist/auth/secure-secret.d.ts.map +1 -0
  12. package/dist/auth/secure-secret.js +182 -0
  13. package/dist/auth/secure-secret.js.map +1 -0
  14. package/dist/auth/server-metadata.d.ts.map +1 -1
  15. package/dist/auth/server-metadata.js.map +1 -1
  16. package/dist/auth/simple-jwt.d.ts +100 -14
  17. package/dist/auth/simple-jwt.d.ts.map +1 -1
  18. package/dist/auth/simple-jwt.js +19 -9
  19. package/dist/auth/simple-jwt.js.map +1 -1
  20. package/dist/auth/token-store.js +1 -1
  21. package/dist/auth/token-store.js.map +1 -1
  22. package/dist/auth/token-validation.js +1 -1
  23. package/dist/auth/token-validation.js.map +1 -1
  24. package/dist/cli/commands/build.js +1 -1
  25. package/dist/cli/commands/build.js.map +1 -1
  26. package/dist/cli/commands/generate-types.js +12 -12
  27. package/dist/cli/commands/generate-types.js.map +1 -1
  28. package/dist/cli/commands/generate.d.ts +8 -1
  29. package/dist/cli/commands/generate.d.ts.map +1 -1
  30. package/dist/cli/commands/generate.js +13 -12
  31. package/dist/cli/commands/generate.js.map +1 -1
  32. package/dist/cli/commands/init.js +1 -1
  33. package/dist/cli/commands/init.js.map +1 -1
  34. package/dist/cli/commands/upgrade.d.ts +10 -0
  35. package/dist/cli/commands/upgrade.d.ts.map +1 -0
  36. package/dist/cli/commands/upgrade.js +221 -0
  37. package/dist/cli/commands/upgrade.js.map +1 -0
  38. package/dist/cli/index.js +7 -0
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/core/app-decorator.d.ts +4 -3
  41. package/dist/core/app-decorator.d.ts.map +1 -1
  42. package/dist/core/app-decorator.js +67 -28
  43. package/dist/core/app-decorator.js.map +1 -1
  44. package/dist/core/builders.d.ts +19 -7
  45. package/dist/core/builders.d.ts.map +1 -1
  46. package/dist/core/builders.js +15 -8
  47. package/dist/core/builders.js.map +1 -1
  48. package/dist/core/component.d.ts +8 -8
  49. package/dist/core/component.d.ts.map +1 -1
  50. package/dist/core/component.js +3 -2
  51. package/dist/core/component.js.map +1 -1
  52. package/dist/core/config-module.d.ts +11 -4
  53. package/dist/core/config-module.d.ts.map +1 -1
  54. package/dist/core/config-module.js +1 -1
  55. package/dist/core/config-module.js.map +1 -1
  56. package/dist/core/decorators/cache.decorator.d.ts +9 -9
  57. package/dist/core/decorators/cache.decorator.d.ts.map +1 -1
  58. package/dist/core/decorators/cache.decorator.js +3 -3
  59. package/dist/core/decorators/cache.decorator.js.map +1 -1
  60. package/dist/core/decorators/health-check.decorator.d.ts +3 -3
  61. package/dist/core/decorators/health-check.decorator.d.ts.map +1 -1
  62. package/dist/core/decorators/health-check.decorator.js +2 -2
  63. package/dist/core/decorators/health-check.decorator.js.map +1 -1
  64. package/dist/core/decorators/rate-limit.decorator.d.ts +5 -4
  65. package/dist/core/decorators/rate-limit.decorator.d.ts.map +1 -1
  66. package/dist/core/decorators/rate-limit.decorator.js +3 -3
  67. package/dist/core/decorators/rate-limit.decorator.js.map +1 -1
  68. package/dist/core/decorators.d.ts +47 -29
  69. package/dist/core/decorators.d.ts.map +1 -1
  70. package/dist/core/decorators.js +9 -9
  71. package/dist/core/decorators.js.map +1 -1
  72. package/dist/core/di/container.d.ts +21 -4
  73. package/dist/core/di/container.d.ts.map +1 -1
  74. package/dist/core/di/container.js +11 -7
  75. package/dist/core/di/container.js.map +1 -1
  76. package/dist/core/di/injectable.decorator.d.ts +5 -3
  77. package/dist/core/di/injectable.decorator.d.ts.map +1 -1
  78. package/dist/core/di/injectable.decorator.js.map +1 -1
  79. package/dist/core/errors.d.ts +4 -4
  80. package/dist/core/errors.d.ts.map +1 -1
  81. package/dist/core/errors.js.map +1 -1
  82. package/dist/core/events/event-emitter.d.ts +3 -3
  83. package/dist/core/events/event-emitter.d.ts.map +1 -1
  84. package/dist/core/events/event-emitter.js.map +1 -1
  85. package/dist/core/events/event.decorator.d.ts +5 -5
  86. package/dist/core/events/event.decorator.d.ts.map +1 -1
  87. package/dist/core/events/event.decorator.js +10 -6
  88. package/dist/core/events/event.decorator.js.map +1 -1
  89. package/dist/core/events/log-emitter.d.ts +7 -1
  90. package/dist/core/events/log-emitter.d.ts.map +1 -1
  91. package/dist/core/events/log-emitter.js.map +1 -1
  92. package/dist/core/filters/exception-filter.decorator.d.ts +5 -5
  93. package/dist/core/filters/exception-filter.decorator.d.ts.map +1 -1
  94. package/dist/core/filters/exception-filter.decorator.js +3 -3
  95. package/dist/core/filters/exception-filter.decorator.js.map +1 -1
  96. package/dist/core/filters/exception-filter.interface.d.ts +14 -5
  97. package/dist/core/filters/exception-filter.interface.d.ts.map +1 -1
  98. package/dist/core/guards/apikey.guard.d.ts +1 -1
  99. package/dist/core/guards/apikey.guard.d.ts.map +1 -1
  100. package/dist/core/guards/guard.interface.d.ts +1 -1
  101. package/dist/core/guards/guard.interface.d.ts.map +1 -1
  102. package/dist/core/guards/jwt.guard.d.ts +1 -1
  103. package/dist/core/guards/jwt.guard.d.ts.map +1 -1
  104. package/dist/core/guards/oauth.guard.d.ts +1 -1
  105. package/dist/core/guards/oauth.guard.d.ts.map +1 -1
  106. package/dist/core/guards/use-guards.decorator.d.ts +3 -3
  107. package/dist/core/guards/use-guards.decorator.d.ts.map +1 -1
  108. package/dist/core/guards/use-guards.decorator.js +1 -1
  109. package/dist/core/guards/use-guards.decorator.js.map +1 -1
  110. package/dist/core/index.d.ts +2 -2
  111. package/dist/core/index.d.ts.map +1 -1
  112. package/dist/core/index.js.map +1 -1
  113. package/dist/core/interceptors/interceptor.decorator.d.ts +4 -4
  114. package/dist/core/interceptors/interceptor.decorator.d.ts.map +1 -1
  115. package/dist/core/interceptors/interceptor.decorator.js +2 -2
  116. package/dist/core/interceptors/interceptor.decorator.js.map +1 -1
  117. package/dist/core/interceptors/interceptor.interface.d.ts +3 -3
  118. package/dist/core/interceptors/interceptor.interface.d.ts.map +1 -1
  119. package/dist/core/logger.d.ts.map +1 -1
  120. package/dist/core/logger.js.map +1 -1
  121. package/dist/core/middleware/middleware.decorator.d.ts +4 -4
  122. package/dist/core/middleware/middleware.decorator.d.ts.map +1 -1
  123. package/dist/core/middleware/middleware.decorator.js +2 -2
  124. package/dist/core/middleware/middleware.decorator.js.map +1 -1
  125. package/dist/core/middleware/middleware.interface.d.ts +3 -3
  126. package/dist/core/middleware/middleware.interface.d.ts.map +1 -1
  127. package/dist/core/module.d.ts +33 -14
  128. package/dist/core/module.d.ts.map +1 -1
  129. package/dist/core/module.js +11 -6
  130. package/dist/core/module.js.map +1 -1
  131. package/dist/core/oauth-module.d.ts +9 -3
  132. package/dist/core/oauth-module.d.ts.map +1 -1
  133. package/dist/core/oauth-module.js +4 -3
  134. package/dist/core/oauth-module.js.map +1 -1
  135. package/dist/core/pipes/pipe.decorator.d.ts +14 -5
  136. package/dist/core/pipes/pipe.decorator.d.ts.map +1 -1
  137. package/dist/core/pipes/pipe.decorator.js +2 -2
  138. package/dist/core/pipes/pipe.decorator.js.map +1 -1
  139. package/dist/core/pipes/pipe.interface.d.ts +9 -4
  140. package/dist/core/pipes/pipe.interface.d.ts.map +1 -1
  141. package/dist/core/prompt.d.ts +13 -4
  142. package/dist/core/prompt.d.ts.map +1 -1
  143. package/dist/core/prompt.js +2 -2
  144. package/dist/core/prompt.js.map +1 -1
  145. package/dist/core/resource.d.ts +7 -2
  146. package/dist/core/resource.d.ts.map +1 -1
  147. package/dist/core/resource.js +2 -2
  148. package/dist/core/resource.js.map +1 -1
  149. package/dist/core/server.d.ts +49 -3
  150. package/dist/core/server.d.ts.map +1 -1
  151. package/dist/core/server.js +61 -34
  152. package/dist/core/server.js.map +1 -1
  153. package/dist/core/tool.d.ts +44 -16
  154. package/dist/core/tool.d.ts.map +1 -1
  155. package/dist/core/tool.js +19 -6
  156. package/dist/core/tool.js.map +1 -1
  157. package/dist/core/transports/discovery-http-server.d.ts +7 -1
  158. package/dist/core/transports/discovery-http-server.d.ts.map +1 -1
  159. package/dist/core/transports/discovery-http-server.js.map +1 -1
  160. package/dist/core/transports/http-server.d.ts +2 -2
  161. package/dist/core/transports/http-server.d.ts.map +1 -1
  162. package/dist/core/transports/http-server.js +1 -1
  163. package/dist/core/transports/http-server.js.map +1 -1
  164. package/dist/core/transports/streamable-http.d.ts +4 -4
  165. package/dist/core/transports/streamable-http.d.ts.map +1 -1
  166. package/dist/core/transports/streamable-http.js +1 -1
  167. package/dist/core/transports/streamable-http.js.map +1 -1
  168. package/dist/core/types.d.ts +87 -15
  169. package/dist/core/types.d.ts.map +1 -1
  170. package/dist/core/widgets/widget-registry.d.ts +2 -2
  171. package/dist/core/widgets/widget-registry.d.ts.map +1 -1
  172. package/dist/core/widgets/widget-registry.js +1 -1
  173. package/dist/core/widgets/widget-registry.js.map +1 -1
  174. package/dist/testing/index.d.ts +44 -17
  175. package/dist/testing/index.d.ts.map +1 -1
  176. package/dist/testing/index.js +5 -8
  177. package/dist/testing/index.js.map +1 -1
  178. package/dist/ui-next/index.d.ts +1 -1
  179. package/dist/ui-next/index.d.ts.map +1 -1
  180. package/dist/ui-next/index.js.map +1 -1
  181. package/dist/widgets/hooks/useWidgetSDK.d.ts +5 -5
  182. package/dist/widgets/runtime/WidgetLayout.js.map +1 -1
  183. package/dist/widgets/sdk.d.ts +5 -5
  184. package/dist/widgets/sdk.d.ts.map +1 -1
  185. package/dist/widgets/sdk.js.map +1 -1
  186. package/package.json +1 -1
  187. package/src/studio/app/api/auth/fetch-metadata/route.ts +3 -2
  188. package/src/studio/app/api/auth/register-client/route.ts +3 -2
  189. package/src/studio/app/api/chat/route.ts +33 -17
  190. package/src/studio/app/api/health/checks/route.ts +5 -4
  191. package/src/studio/app/api/init/route.ts +3 -2
  192. package/src/studio/app/api/ping/route.ts +3 -2
  193. package/src/studio/app/api/prompts/[name]/route.ts +4 -3
  194. package/src/studio/app/api/prompts/route.ts +3 -2
  195. package/src/studio/app/api/resources/[...uri]/route.ts +3 -2
  196. package/src/studio/app/api/resources/route.ts +3 -2
  197. package/src/studio/app/api/roots/route.ts +3 -2
  198. package/src/studio/app/api/sampling/route.ts +3 -2
  199. package/src/studio/app/api/tools/[name]/call/route.ts +3 -2
  200. package/src/studio/app/api/tools/route.ts +4 -3
  201. package/src/studio/app/api/widget-examples/route.ts +5 -4
  202. package/src/studio/app/auth/callback/page.tsx +9 -8
  203. package/src/studio/app/chat/page.tsx +1535 -468
  204. package/src/studio/app/chat/page.tsx.backup +1046 -187
  205. package/src/studio/app/globals.css +361 -191
  206. package/src/studio/app/health/page.tsx +73 -77
  207. package/src/studio/app/layout.tsx +9 -11
  208. package/src/studio/app/logs/page.tsx +31 -32
  209. package/src/studio/app/page.tsx +136 -232
  210. package/src/studio/app/prompts/page.tsx +115 -97
  211. package/src/studio/app/resources/page.tsx +115 -124
  212. package/src/studio/app/settings/page.tsx +1083 -127
  213. package/src/studio/app/tools/page.tsx +343 -0
  214. package/src/studio/components/EnlargeModal.tsx +76 -65
  215. package/src/studio/components/LogMessage.tsx +6 -6
  216. package/src/studio/components/MarkdownRenderer.tsx +246 -349
  217. package/src/studio/components/Sidebar.tsx +165 -210
  218. package/src/studio/components/SplashScreen.tsx +109 -0
  219. package/src/studio/components/ToolCard.tsx +50 -41
  220. package/src/studio/components/VoiceOrbOverlay.tsx +475 -0
  221. package/src/studio/components/WidgetErrorBoundary.tsx +48 -0
  222. package/src/studio/components/WidgetRenderer.tsx +169 -211
  223. package/src/studio/components/ops/OpsCanvas.tsx +748 -0
  224. package/src/studio/components/ops/OpsNodeDetailPanel.tsx +150 -0
  225. package/src/studio/components/ops/OpsSummaryBar.tsx +90 -0
  226. package/src/studio/components/ops/index.ts +5 -0
  227. package/src/studio/components/ops/nodes/BaseNode.tsx +65 -0
  228. package/src/studio/components/ops/nodes/LLMCallNode.tsx +34 -0
  229. package/src/studio/components/ops/nodes/LLMResponseNode.tsx +33 -0
  230. package/src/studio/components/ops/nodes/ToolCallNode.tsx +30 -0
  231. package/src/studio/components/ops/nodes/ToolResultNode.tsx +43 -0
  232. package/src/studio/components/ops/nodes/UserPromptNode.tsx +34 -0
  233. package/src/studio/components/ops/nodes/WidgetRenderNode.tsx +23 -0
  234. package/src/studio/components/ops/nodes/index.ts +8 -0
  235. package/src/studio/components/tools/ToolsCanvas.tsx +327 -0
  236. package/src/studio/lib/api.ts +61 -42
  237. package/src/studio/lib/http-client-transport.ts +2 -2
  238. package/src/studio/lib/llm-service.ts +126 -47
  239. package/src/studio/lib/mcp-client.ts +9 -6
  240. package/src/studio/lib/ops-store.ts +427 -0
  241. package/src/studio/lib/ops-tracker.ts +416 -0
  242. package/src/studio/lib/ops-types.ts +164 -0
  243. package/src/studio/lib/store.ts +23 -11
  244. package/src/studio/lib/types.ts +228 -38
  245. package/src/studio/lib/widget-loader.ts +2 -2
  246. package/src/studio/package-lock.json +3303 -0
  247. package/src/studio/package.json +3 -1
  248. package/src/studio/public/NitroStudio Isotype Color.png +0 -0
  249. package/src/studio/tailwind.config.ts +63 -17
  250. package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +19 -22
  251. package/dist/cli/build-widgets.mjs +0 -165
  252. package/src/studio/app/auth/page.tsx +0 -560
  253. package/src/studio/app/ping/page.tsx +0 -209
@@ -1,42 +1,49 @@
1
1
  'use client';
2
2
 
3
3
  import { useStudioStore } from '@/lib/store';
4
+ import { api } from '@/lib/api';
4
5
  import type { TabType } from '@/lib/types';
5
6
  import { useRouter, usePathname } from 'next/navigation';
6
7
  import { useEffect, useState } from 'react';
7
8
  import Image from 'next/image';
8
- import {
9
- Wrench,
10
- MessageSquare,
11
- Package,
12
- FileText,
13
- Activity,
14
- Shield,
15
- Wifi,
16
- Zap,
17
- Settings,
18
- Sparkles,
19
- Terminal
20
- } from 'lucide-react';
9
+ import {
10
+ WrenchScrewdriverIcon,
11
+ ChatBubbleLeftIcon,
12
+ CubeIcon,
13
+ DocumentTextIcon,
14
+ HeartIcon,
15
+ ShieldCheckIcon,
16
+ WifiIcon,
17
+ Cog6ToothIcon,
18
+ CommandLineIcon
19
+ } from '@heroicons/react/24/outline';
21
20
 
22
- const navItems: Array<{ id: TabType | 'settings' | 'logs'; label: string; icon: any; path: string }> = [
23
- { id: 'tools', label: 'Tools', icon: Wrench, path: '/' },
24
- { id: 'chat', label: 'AI Chat', icon: MessageSquare, path: '/chat' },
25
- { id: 'resources', label: 'Resources', icon: Package, path: '/resources' },
26
- { id: 'prompts', label: 'Prompts', icon: FileText, path: '/prompts' },
27
- { id: 'health', label: 'Health', icon: Activity, path: '/health' },
28
- { id: 'logs', label: 'Logs', icon: Terminal, path: '/logs' },
29
- { id: 'auth', label: 'OAuth 2.1', icon: Shield, path: '/auth' },
30
- { id: 'ping', label: 'Ping', icon: Wifi, path: '/ping' },
31
- { id: 'settings', label: 'Settings', icon: Settings, path: '/settings' },
21
+ const navItems = [
22
+ {
23
+ id: 'app',
24
+ label: 'App',
25
+ icon: CubeIcon,
26
+ path: '/',
27
+ children: [
28
+ { id: 'tools', label: 'Tools', icon: WrenchScrewdriverIcon, path: '/tools' },
29
+ { id: 'resources', label: 'Resources', icon: CubeIcon, path: '/resources' },
30
+ { id: 'prompts', label: 'Prompts', icon: DocumentTextIcon, path: '/prompts' },
31
+ ]
32
+ },
33
+ { id: 'chat', label: 'AI Chat', icon: ChatBubbleLeftIcon, path: '/chat' },
34
+ { id: 'health', label: 'Health', icon: HeartIcon, path: '/health' },
35
+ { id: 'logs', label: 'Logs', icon: CommandLineIcon, path: '/logs' },
36
+ { id: 'settings', label: 'Settings', icon: Cog6ToothIcon, path: '/settings' },
32
37
  ];
33
38
 
34
39
  export function Sidebar() {
35
- const { connection } = useStudioStore();
40
+ const { connection, setConnection } = useStudioStore();
36
41
  const router = useRouter();
37
42
  const pathname = usePathname();
38
43
  const [mounted, setMounted] = useState(false);
39
44
  const [isCollapsed, setIsCollapsed] = useState(false);
45
+ // Default expanded parents
46
+ const [expandedItems, setExpandedItems] = useState<string[]>(['app']);
40
47
 
41
48
  useEffect(() => {
42
49
  setMounted(true);
@@ -45,12 +52,34 @@ export function Sidebar() {
45
52
  // Load collapse state from localStorage
46
53
  const saved = localStorage.getItem('sidebar_collapsed');
47
54
  if (saved !== null) setIsCollapsed(saved === 'true');
55
+
56
+ // Initialize Connection (Global)
57
+ const initConnection = async () => {
58
+ try {
59
+ await api.initialize();
60
+ const health = await api.checkConnection();
61
+ setConnection({
62
+ connected: health.connected,
63
+ status: health.connected ? 'connected' : 'disconnected',
64
+ });
65
+ } catch (e) {
66
+ setConnection({ connected: false, status: 'disconnected' });
67
+ }
68
+ };
69
+ initConnection();
48
70
  }, []);
49
71
 
50
72
  const handleNavigation = (path: string) => {
51
73
  router.push(path);
52
74
  };
53
75
 
76
+ const toggleExpand = (id: string, e: React.MouseEvent) => {
77
+ e.stopPropagation();
78
+ setExpandedItems(prev =>
79
+ prev.includes(id) ? prev.filter(item => item !== id) : [...prev, id]
80
+ );
81
+ };
82
+
54
83
  const getConnectionStatus = () => {
55
84
  if (connection.status === 'connected') return 'connected';
56
85
  if (connection.status === 'connecting') return 'connecting';
@@ -61,235 +90,161 @@ export function Sidebar() {
61
90
  const newState = !isCollapsed;
62
91
  setIsCollapsed(newState);
63
92
  localStorage.setItem('sidebar_collapsed', String(newState));
64
- // Dispatch custom event to update layout
65
93
  window.dispatchEvent(new Event('sidebar-toggle'));
66
94
  };
67
95
 
96
+ interface NavChild {
97
+ id: string;
98
+ label: string;
99
+ icon: React.ComponentType<{ className?: string }>;
100
+ path: string;
101
+ }
102
+
103
+ interface NavItem {
104
+ id: string;
105
+ label: string;
106
+ icon: React.ComponentType<{ className?: string }>;
107
+ path: string;
108
+ children?: NavChild[];
109
+ }
110
+
111
+ const renderNavItem = (item: NavItem, depth = 0) => {
112
+ const Icon = item.icon;
113
+ const isActive = pathname === item.path || (item.children && item.children.some((child) => pathname === child.path));
114
+ const isExpanded = expandedItems.includes(item.id);
115
+ const hasChildren = item.children && item.children.length > 0;
116
+
117
+ return (
118
+ <div key={item.id} className="w-full">
119
+ <button
120
+ onClick={(e) => {
121
+ if (hasChildren && !isCollapsed) {
122
+ toggleExpand(item.id, e);
123
+ // Also navigate if it has a path
124
+ if (item.path && item.path !== '#') handleNavigation(item.path);
125
+ } else {
126
+ handleNavigation(item.path);
127
+ }
128
+ }}
129
+ title={isCollapsed ? item.label : undefined}
130
+ className={`
131
+ relative flex items-center gap-2 text-sm font-medium rounded-lg transition-all duration-300 group overflow-hidden
132
+ ${isCollapsed ? 'w-10 h-10 justify-center mx-auto mb-1' : 'w-full px-3 py-2'}
133
+ ${isActive && !hasChildren
134
+ ? 'bg-gradient-to-r from-primary/15 to-secondary/10 text-primary shadow-md ring-1 ring-primary/30'
135
+ : 'text-foreground/70 hover:bg-primary/5 hover:text-primary'
136
+ }
137
+ ${depth > 0 && !isCollapsed ? 'ml-4 w-[calc(100%-1rem)] border-l border-border/50 pl-2' : ''}
138
+ `}
139
+ >
140
+ {/* Active indicator (Left strip) - Only for leaf nodes or exact match */}
141
+ {isActive && !isCollapsed && !hasChildren && (
142
+ <div className="absolute left-0 top-1/2 -translate-y-1/2 w-0.5 h-6 bg-gradient-to-b from-primary to-secondary rounded-r-full" />
143
+ )}
144
+
145
+ {/* Icon */}
146
+ <div className={`relative flex-shrink-0 ${isActive ? 'scale-105' : 'group-hover:scale-105'} transition-transform duration-300`}>
147
+ <Icon
148
+ className={`h-5 w-5 ${isActive
149
+ ? 'text-primary'
150
+ : 'text-muted-foreground group-hover:text-primary'
151
+ }`}
152
+ />
153
+ </div>
154
+
155
+ {/* Label & Chevron - only show when expanded */}
156
+ {!isCollapsed && (
157
+ <div className="flex-1 flex items-center justify-between overflow-hidden">
158
+ <span className="text-xs whitespace-nowrap overflow-hidden">
159
+ {item.label}
160
+ </span>
161
+ {hasChildren && (
162
+ <div className={`transition-transform duration-200 ${isExpanded ? 'rotate-90' : ''}`}>
163
+ <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-muted-foreground/50">
164
+ <path d="M9 18l6-6-6-6" />
165
+ </svg>
166
+ </div>
167
+ )}
168
+ </div>
169
+ )}
170
+ </button>
171
+
172
+ {/* Render Children */}
173
+ {!isCollapsed && hasChildren && isExpanded && (
174
+ <div className="mt-0.5 space-y-0.5">
175
+ {item.children!.map((child) => renderNavItem(child as NavItem, depth + 1))}
176
+ </div>
177
+ )}
178
+ </div>
179
+ );
180
+ };
181
+
68
182
  if (!mounted) return null;
69
183
 
70
184
  return (
71
- <nav className={`fixed left-0 top-0 h-screen glass flex flex-col z-50 border-r border-border/50 transition-all duration-300 ease-in-out ${
72
- isCollapsed ? 'w-16' : 'w-60 md:w-60'
73
- } ${isCollapsed ? '' : 'max-md:w-16'}`}>
74
- {/* Compact Professional Header */}
185
+ <nav className={`fixed left-0 top-0 h-screen glass flex flex-col z-50 border-r border-border/50 transition-all duration-300 ease-in-out ${isCollapsed ? 'w-16' : 'w-60 md:w-60'} ${isCollapsed ? '' : 'max-md:w-16'}`}>
186
+ {/* Header */}
75
187
  <div className="relative p-3 border-b border-border/50 bg-gradient-to-b from-card/80 to-transparent">
76
188
  <div className="flex items-center justify-between mb-2">
77
- {/* Minimalist Professional Logo */}
78
- <div
79
- className="flex items-center gap-2 group cursor-pointer flex-1"
80
- onClick={() => handleNavigation('/')}
81
- >
189
+ {/* Logo */}
190
+ <div className="flex items-center gap-2 group cursor-pointer flex-1" onClick={() => handleNavigation('/')}>
82
191
  <div className="relative flex-shrink-0">
83
- <div className="absolute inset-0 rounded-lg bg-gradient-to-br from-primary to-amber-500 blur opacity-30 group-hover:opacity-50 transition-opacity duration-300" />
84
- <div className="relative w-9 h-9 rounded-lg bg-gradient-to-br from-slate-900 to-slate-800 border border-primary/30 flex items-center justify-center shadow-lg group-hover:shadow-primary/30 transition-all duration-300 overflow-hidden">
85
- {/* NitroCloud Logo */}
86
- <Image
87
- src="/nitrocloud.png"
88
- alt="NitroCloud Logo"
89
- width={36}
90
- height={36}
91
- className="relative z-10 object-contain"
92
- unoptimized
93
- />
94
- {/* Subtle glow effect */}
95
- <div className="absolute inset-0 bg-gradient-to-tr from-primary/20 to-amber-500/20 group-hover:opacity-100 opacity-0 transition-opacity duration-300" />
192
+ <div className="relative w-10 h-10 rounded bg-white/5 border border-primary/20 flex items-center justify-center shadow-lg group-hover:border-primary/40 transition-all duration-300 overflow-hidden backdrop-blur-sm">
193
+ <Image src="/NitroStudio Isotype Color.png" alt="NitroStudio Logo" width={28} height={28} className="relative z-10 object-contain" unoptimized />
96
194
  </div>
97
- </div>
98
-
195
+ </div>
99
196
  {!isCollapsed && (
100
- <div className="flex-1 overflow-hidden">
101
- <h1 className="text-base font-bold bg-gradient-to-r from-primary to-amber-500 bg-clip-text text-transparent tracking-tight whitespace-nowrap">
102
- NitroStudio
103
- </h1>
104
- <p className="text-[9px] text-muted-foreground font-medium uppercase tracking-wider">
105
- MCP Suite
106
- </p>
197
+ <div className="flex-1 overflow-hidden ml-2.5">
198
+ <h1 className="text-sm font-bold bg-gradient-to-r from-primary via-primary to-secondary bg-clip-text text-transparent tracking-wide whitespace-nowrap leading-tight" style={{ fontFamily: 'Space Grotesk, sans-serif' }}>NitroStudio</h1>
199
+ <p className="text-[8px] text-muted-foreground/70 font-semibold uppercase tracking-wider leading-none mt-0.5" style={{ fontFamily: 'IBM Plex Sans, sans-serif' }}>MCP Suite</p>
107
200
  </div>
108
201
  )}
109
202
  </div>
110
-
111
- {/* Toggle Button */}
112
- <button
113
- onClick={toggleSidebar}
114
- className="flex-shrink-0 w-7 h-7 rounded-md bg-muted/50 hover:bg-muted border border-border/50 hover:border-primary/30 flex items-center justify-center transition-all duration-300 group/toggle"
115
- title={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
116
- >
117
- <svg
118
- width="14"
119
- height="14"
120
- viewBox="0 0 24 24"
121
- fill="none"
122
- className={`text-muted-foreground group-hover/toggle:text-primary transition-all duration-300 ${
123
- isCollapsed ? 'rotate-180' : ''
124
- }`}
125
- >
126
- <path d="M15 18L9 12L15 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
127
- </svg>
203
+ {/* Toggle */}
204
+ <button onClick={toggleSidebar} className="flex-shrink-0 w-7 h-7 rounded-md bg-muted/50 hover:bg-muted border border-border/50 flex items-center justify-center transition-all duration-300">
205
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" className={`text-muted-foreground transition-all duration-300 ${isCollapsed ? 'rotate-180' : ''}`}><path d="M15 18L9 12L15 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /></svg>
128
206
  </button>
129
207
  </div>
130
208
 
131
- {/* Compact Status Indicators */}
209
+ {/* Status */}
132
210
  {!isCollapsed ? (
133
211
  <div className="space-y-1.5">
134
- {/* Connection Status */}
135
212
  <div className="relative group">
136
213
  <div className="relative flex items-center gap-2 px-2 py-1.5 rounded-md bg-card/60 border border-border/50 backdrop-blur-sm group-hover:border-primary/30 transition-all duration-300">
137
- <div className="relative flex items-center justify-center flex-shrink-0">
138
- {getConnectionStatus() === 'connected' && (
139
- <div className="absolute inset-0 rounded-full bg-emerald-500/30 animate-ping" />
140
- )}
141
- <div
142
- className={`relative w-2 h-2 rounded-full transition-all duration-300 ${
143
- getConnectionStatus() === 'connected'
144
- ? 'bg-emerald-500'
145
- : getConnectionStatus() === 'connecting'
146
- ? 'bg-amber-500 animate-pulse'
147
- : 'bg-rose-500'
148
- }`}
149
- style={{
150
- boxShadow: getConnectionStatus() === 'connected'
151
- ? '0 0 8px rgba(34, 197, 94, 0.6)'
152
- : getConnectionStatus() === 'connecting'
153
- ? '0 0 8px rgba(245, 158, 11, 0.6)'
154
- : '0 0 8px rgba(239, 68, 68, 0.6)'
155
- }}
156
- />
157
- </div>
158
- <span className="text-[10px] font-semibold uppercase tracking-wide text-foreground">
159
- {connection.status}
160
- </span>
161
- </div>
162
- </div>
163
-
164
- {/* Transport Mode */}
214
+ <div className={`relative w-2 h-2 rounded-full transition-all duration-300 ${getConnectionStatus() === 'connected' ? 'bg-emerald-500' : getConnectionStatus() === 'connecting' ? 'bg-status-warning animate-pulse' : 'bg-rose-500'}`} />
215
+ <span className="text-[10px] font-semibold uppercase tracking-wide text-foreground">{connection.status}</span>
216
+ </div>
217
+ </div>
165
218
  <div className="relative group">
166
219
  <div className="relative px-2 py-1.5 rounded-md bg-primary/5 border border-primary/20 backdrop-blur-sm group-hover:border-primary/30 transition-all duration-300">
167
220
  <div className="flex items-center justify-between text-[10px]">
168
221
  <span className="font-medium text-muted-foreground">Transport:</span>
169
- <span className="font-bold text-primary uppercase">
170
- STDIO
171
- </span>
222
+ <span className="font-bold text-primary uppercase">STDIO</span>
172
223
  </div>
173
224
  </div>
174
225
  </div>
175
226
  </div>
176
227
  ) : (
177
228
  <div className="flex flex-col items-center gap-1.5">
178
- {/* Collapsed: Just the status dot */}
179
- <div
180
- className="relative w-7 h-7 rounded-md bg-card/60 border border-border/50 flex items-center justify-center group hover:border-primary/30 transition-all"
181
- title={`Status: ${connection.status}`}
182
- >
183
- {getConnectionStatus() === 'connected' && (
184
- <div className="absolute inset-0 rounded-md bg-emerald-500/20 animate-ping" />
185
- )}
186
- <div
187
- className={`relative w-2 h-2 rounded-full ${
188
- getConnectionStatus() === 'connected'
189
- ? 'bg-emerald-500'
190
- : getConnectionStatus() === 'connecting'
191
- ? 'bg-amber-500 animate-pulse'
192
- : 'bg-rose-500'
193
- }`}
194
- style={{
195
- boxShadow: getConnectionStatus() === 'connected'
196
- ? '0 0 8px rgba(34, 197, 94, 0.8)'
197
- : getConnectionStatus() === 'connecting'
198
- ? '0 0 8px rgba(245, 158, 11, 0.8)'
199
- : '0 0 8px rgba(239, 68, 68, 0.8)'
200
- }}
201
- />
202
- </div>
229
+ <div className={`relative w-2 h-2 rounded-full ${getConnectionStatus() === 'connected' ? 'bg-emerald-500' : 'bg-rose-500'}`} />
203
230
  </div>
204
231
  )}
205
232
  </div>
206
233
 
207
- {/* Compact Navigation */}
234
+ {/* Navigation */}
208
235
  <div className="flex-1 overflow-y-auto py-2 px-2 scrollbar-thin scrollbar-thumb-border scrollbar-track-transparent">
209
236
  <div className={`space-y-0.5 ${isCollapsed ? 'flex flex-col items-center' : ''}`}>
210
- {navItems.map((item) => {
211
- const Icon = item.icon;
212
- const isActive = pathname === item.path;
213
-
214
- return (
215
- <button
216
- key={item.id}
217
- onClick={() => handleNavigation(item.path)}
218
- title={isCollapsed ? item.label : undefined}
219
- className={`
220
- relative flex items-center gap-2 text-sm font-medium rounded-lg transition-all duration-300 group overflow-hidden
221
- ${isCollapsed ? 'w-10 h-10 justify-center' : 'w-full px-3 py-2'}
222
- ${isActive
223
- ? 'bg-gradient-to-r from-primary/15 to-amber-500/10 text-primary shadow-md ring-1 ring-primary/30'
224
- : 'text-foreground/70 hover:bg-primary/5 hover:text-primary'
225
- }
226
- `}
227
- >
228
- {/* Active indicator */}
229
- {isActive && !isCollapsed && (
230
- <div className="absolute left-0 top-1/2 -translate-y-1/2 w-0.5 h-6 bg-gradient-to-b from-primary to-amber-500 rounded-r-full" />
231
- )}
232
-
233
- {/* Icon */}
234
- <div className={`relative flex-shrink-0 ${isActive ? 'scale-105' : 'group-hover:scale-105'} transition-transform duration-300`}>
235
- <Icon
236
- className={`w-4 h-4 ${
237
- isActive
238
- ? 'text-primary'
239
- : 'text-muted-foreground group-hover:text-primary'
240
- }`}
241
- strokeWidth={isActive ? 2.5 : 2}
242
- />
243
- </div>
244
-
245
- {/* Label - only show when expanded */}
246
- {!isCollapsed && (
247
- <span className="text-xs whitespace-nowrap overflow-hidden">
248
- {item.label}
249
- </span>
250
- )}
251
-
252
- {/* Subtle shine effect */}
253
- <div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/5 to-transparent -translate-x-full group-hover:translate-x-full transition-transform duration-700 ease-out pointer-events-none" />
254
- </button>
255
- );
256
- })}
237
+ {navItems.map((item) => renderNavItem(item))}
257
238
  </div>
258
239
  </div>
259
240
 
260
- {/* Compact Footer */}
241
+ {/* Footer */}
261
242
  <div className="p-2 border-t border-border/50 bg-gradient-to-t from-card/60 to-transparent backdrop-blur-sm">
262
243
  {!isCollapsed ? (
263
- <div className="space-y-1.5">
264
- {/* Version info */}
265
- <div className="px-2 py-1.5 rounded-md bg-muted/30 border border-border/30">
266
- <div className="flex items-center justify-between text-[9px]">
267
- <span className="font-medium text-muted-foreground uppercase tracking-wide">MCP v1.0</span>
268
- <span className="font-bold text-foreground">NitroStack</span>
269
- </div>
270
- </div>
271
-
272
- {/* Copyright */}
273
- <div className="text-center">
274
- <p className="text-[8px] text-muted-foreground/50 font-medium">
275
- © 2025 NitroCloud
276
- </p>
277
- </div>
278
- </div>
279
- ) : (
280
- <div className="flex flex-col items-center">
281
- {/* Collapsed: Minimal version indicator */}
282
- <div
283
- className="w-10 h-10 rounded-md bg-muted/30 border border-border/30 flex items-center justify-center group hover:border-primary/30 transition-all"
284
- title="MCP v1.0 • NitroStack"
285
- >
286
- <span className="text-[9px] font-bold text-primary group-hover:scale-110 transition-transform">
287
- v1
288
- </span>
289
- </div>
290
- </div>
291
- )}
244
+ <div className="text-center"><p className="text-[8px] text-muted-foreground/50 font-medium">© 2025 NitroCloud</p></div>
245
+ ) : null}
292
246
  </div>
247
+
293
248
  </nav>
294
249
  );
295
250
  }
@@ -0,0 +1,109 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+ import Image from 'next/image';
5
+
6
+ const LOADING_TEXTS = [
7
+ "Initializing NitroStudio...",
8
+ "Waking up the agents...",
9
+ "Aligning gradients...",
10
+ "Charging flux capacitors...",
11
+ "Assembling pixels...",
12
+ "Connecting to the matrix...",
13
+ "Spinning up the studio...",
14
+ "Almost there..."
15
+ ];
16
+
17
+ export function SplashScreen() {
18
+ const [show, setShow] = useState(true);
19
+ const [textIndex, setTextIndex] = useState(0);
20
+ const [fadeOut, setFadeOut] = useState(false);
21
+
22
+ useEffect(() => {
23
+ // Initial load delay logic
24
+ const timer = setTimeout(() => {
25
+ setFadeOut(true);
26
+ setTimeout(() => setShow(false), 500); // 500ms fade out duration
27
+ }, 3000); // Slightly longer for the "system check" vibe
28
+
29
+ return () => clearTimeout(timer);
30
+ }, []);
31
+
32
+ useEffect(() => {
33
+ if (!show) return;
34
+
35
+ // Cycle text every 800ms
36
+ const interval = setInterval(() => {
37
+ setTextIndex((prev) => (prev + 1) % LOADING_TEXTS.length);
38
+ }, 800);
39
+
40
+ return () => clearInterval(interval);
41
+ }, [show]);
42
+
43
+ if (!show) return null;
44
+
45
+ return (
46
+ <div
47
+ className={`fixed inset-0 z-[100] flex flex-col items-center justify-center bg-background transition-opacity duration-500 font-mono ${fadeOut ? 'opacity-0' : 'opacity-100'
48
+ }`}
49
+ >
50
+ {/* Tech Background Grid - Subtle & Professional */}
51
+ <div
52
+ className="absolute inset-0 opacity-[0.03]"
53
+ style={{
54
+ backgroundImage: `linear-gradient(#fff 1px, transparent 1px), linear-gradient(90deg, #fff 1px, transparent 1px)`,
55
+ backgroundSize: '40px 40px',
56
+ mask: 'radial-gradient(circle at center, black 40%, transparent 100%)',
57
+ WebkitMask: 'radial-gradient(circle at center, black 40%, transparent 100%)'
58
+ }}
59
+ />
60
+
61
+ {/* Center Content */}
62
+ <div className="relative flex items-center justify-center mb-8">
63
+ {/* Glowing Gradient Ring Container */}
64
+ {/* Outer pulsing glow */}
65
+ <div className="absolute inset-[-12px] rounded-full animate-pulse bg-primary/10 blur-xl"></div>
66
+
67
+ {/* Spinning Gradient Ring */}
68
+ <div className="absolute inset-[-4px] rounded-full animate-spin-slow"
69
+ style={{
70
+ background: 'conic-gradient(from 0deg, transparent 0deg, var(--primary) 360deg)',
71
+ mask: 'radial-gradient(farthest-side, transparent calc(100% - 2px), black calc(100% - 2px))',
72
+ WebkitMask: 'radial-gradient(farthest-side, transparent calc(100% - 2px), black calc(100% - 2px))'
73
+ }}
74
+ ></div>
75
+
76
+ {/* Secondary thinner ring for detail */}
77
+ <div className="absolute inset-[-8px] rounded-full animate-spin-slow"
78
+ style={{
79
+ animationDirection: 'reverse',
80
+ opacity: 0.3,
81
+ background: 'conic-gradient(from 0deg, transparent 0deg, var(--primary) 360deg)',
82
+ mask: 'radial-gradient(farthest-side, transparent calc(100% - 1px), black calc(100% - 1px))',
83
+ WebkitMask: 'radial-gradient(farthest-side, transparent calc(100% - 1px), black calc(100% - 1px))'
84
+ }}
85
+ ></div>
86
+
87
+ {/* Logo Container */}
88
+ <div className="relative z-10 bg-background rounded-full p-8 shadow-2xl border border-primary/10">
89
+ <div className="relative w-20 h-20">
90
+ <Image
91
+ src="/NitroStudio Isotype Color.png"
92
+ alt="NitroStudio Logo"
93
+ fill
94
+ className="object-contain"
95
+ priority
96
+ />
97
+ </div>
98
+ </div>
99
+ </div>
100
+
101
+ {/* Loading Text with Glitch-like Vibe */}
102
+ <div className="h-6 overflow-hidden flex flex-col items-center justify-center">
103
+ <p className="text-xs font-mono text-primary/80 animate-pulse tracking-[0.2em] uppercase">
104
+ {LOADING_TEXTS[textIndex]}
105
+ </p>
106
+ </div>
107
+ </div>
108
+ );
109
+ }