openship 0.1.0 → 0.1.1

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 (531) hide show
  1. package/.env.example +19 -3
  2. package/CONTRIBUTING.md +69 -19
  3. package/LICENSE +661 -0
  4. package/README.md +304 -108
  5. package/apps/api/Dockerfile +6 -8
  6. package/apps/api/package.json +25 -21
  7. package/apps/api/src/app.ts +46 -3
  8. package/apps/api/src/config/env.ts +81 -7
  9. package/apps/api/src/lib/auth-mode.ts +42 -0
  10. package/apps/api/src/lib/auth.ts +105 -0
  11. package/apps/api/src/lib/cache.ts +128 -0
  12. package/apps/api/src/lib/cloud-auth-proxy.ts +310 -0
  13. package/apps/api/src/lib/cloud-client.ts +103 -0
  14. package/apps/api/src/lib/compose-parser.ts +138 -0
  15. package/apps/api/src/lib/controller-helpers.ts +90 -0
  16. package/apps/api/src/lib/email-templates.ts +94 -0
  17. package/apps/api/src/lib/encryption.ts +102 -0
  18. package/apps/api/src/lib/local-user.ts +65 -0
  19. package/apps/api/src/lib/mail.ts +48 -0
  20. package/apps/api/src/lib/notifications.ts +195 -0
  21. package/apps/api/src/lib/openship-cloud.ts +101 -0
  22. package/apps/api/src/lib/resources.ts +96 -0
  23. package/apps/api/src/lib/screenshots.ts +189 -0
  24. package/apps/api/src/lib/ssh-manager.ts +369 -0
  25. package/apps/api/src/lib/ssl-scheduler.ts +109 -0
  26. package/apps/api/src/lib/stack-detector.ts +708 -0
  27. package/apps/api/src/lib/system-debug.ts +10 -0
  28. package/apps/api/src/middleware/auth.ts +49 -13
  29. package/apps/api/src/middleware/error-handler.ts +23 -3
  30. package/apps/api/src/middleware/index.ts +2 -0
  31. package/apps/api/src/middleware/internal-auth.ts +40 -0
  32. package/apps/api/src/middleware/local-only.ts +20 -0
  33. package/apps/api/src/middleware/rate-limiter.ts +9 -0
  34. package/apps/api/src/modules/analytics/analytics.controller.ts +111 -0
  35. package/apps/api/src/modules/analytics/analytics.routes.ts +29 -0
  36. package/apps/api/src/modules/analytics/analytics.schema.ts +37 -0
  37. package/apps/api/src/modules/analytics/analytics.service.ts +264 -0
  38. package/apps/api/src/modules/auth/auth.routes.ts +233 -6
  39. package/apps/api/src/modules/billing/billing.routes.ts +8 -0
  40. package/apps/api/src/modules/cloud/cloud.controller.ts +225 -0
  41. package/apps/api/src/modules/cloud/cloud.routes.ts +40 -0
  42. package/apps/api/src/modules/deployments/build.service.ts +791 -0
  43. package/apps/api/src/modules/deployments/deployment-lifecycle.ts +138 -0
  44. package/apps/api/src/modules/deployments/deployment.controller.ts +324 -16
  45. package/apps/api/src/modules/deployments/deployment.routes.ts +33 -7
  46. package/apps/api/src/modules/deployments/deployment.schema.ts +37 -5
  47. package/apps/api/src/modules/deployments/deployment.service.ts +178 -11
  48. package/apps/api/src/modules/deployments/preflight.ts +280 -0
  49. package/apps/api/src/modules/deployments/prepare.service.ts +252 -0
  50. package/apps/api/src/modules/deployments/session-manager.ts +283 -0
  51. package/apps/api/src/modules/deployments/ssl.service.ts +73 -0
  52. package/apps/api/src/modules/domains/domain.controller.ts +59 -7
  53. package/apps/api/src/modules/domains/domain.routes.ts +20 -5
  54. package/apps/api/src/modules/domains/domain.schema.ts +35 -0
  55. package/apps/api/src/modules/domains/domain.service.ts +375 -9
  56. package/apps/api/src/modules/github/github.auth.ts +397 -0
  57. package/apps/api/src/modules/github/github.controller.ts +387 -0
  58. package/apps/api/src/modules/github/github.local-auth.ts +251 -0
  59. package/apps/api/src/modules/github/github.routes.ts +50 -0
  60. package/apps/api/src/modules/github/github.schema.ts +52 -0
  61. package/apps/api/src/modules/github/github.service.ts +592 -0
  62. package/apps/api/src/modules/github/github.types.ts +158 -0
  63. package/apps/api/src/modules/github/github.webhook.ts +186 -0
  64. package/apps/api/src/modules/github/index.ts +16 -0
  65. package/apps/api/src/modules/health/health.routes.ts +35 -0
  66. package/apps/api/src/modules/projects/project.controller.ts +481 -12
  67. package/apps/api/src/modules/projects/project.routes.ts +63 -6
  68. package/apps/api/src/modules/projects/project.schema.ts +104 -6
  69. package/apps/api/src/modules/projects/project.service.ts +502 -11
  70. package/apps/api/src/modules/settings/settings.controller.ts +55 -0
  71. package/apps/api/src/modules/settings/settings.routes.ts +25 -0
  72. package/apps/api/src/modules/settings/settings.service.ts +49 -0
  73. package/apps/api/src/modules/system/filesystem.controller.ts +66 -0
  74. package/apps/api/src/modules/system/index.ts +1 -0
  75. package/apps/api/src/modules/system/server-check.controller.ts +475 -0
  76. package/apps/api/src/modules/system/setup-session.ts +255 -0
  77. package/apps/api/src/modules/system/setup.controller.ts +128 -0
  78. package/apps/api/src/modules/system/system.routes.ts +42 -0
  79. package/apps/api/src/modules/webhooks/webhook.controller.ts +57 -15
  80. package/apps/api/src/modules/webhooks/webhook.routes.ts +11 -8
  81. package/apps/api/src/modules/webhooks/webhook.service.ts +46 -5
  82. package/apps/api/src/modules/webhooks/webhook.types.ts +35 -0
  83. package/apps/api/tsconfig.json +3 -1
  84. package/apps/cli/package.json +8 -10
  85. package/apps/cli/tsconfig.json +2 -1
  86. package/apps/dashboard/Dockerfile +4 -6
  87. package/apps/dashboard/components.json +20 -0
  88. package/apps/dashboard/next-env.d.ts +6 -0
  89. package/apps/dashboard/next.config.mjs +11 -1
  90. package/apps/dashboard/package.json +25 -13
  91. package/apps/dashboard/postcss.config.mjs +5 -0
  92. package/apps/dashboard/public/android-chrome-192x192.png +0 -0
  93. package/apps/dashboard/public/android-chrome-512x512.png +0 -0
  94. package/apps/dashboard/public/apple-touch-icon.png +0 -0
  95. package/apps/dashboard/public/favicon-16x16.png +0 -0
  96. package/apps/dashboard/public/favicon-32x32.png +0 -0
  97. package/apps/dashboard/public/favicon.ico +0 -0
  98. package/apps/dashboard/public/site.webmanifest +19 -0
  99. package/apps/dashboard/src/app/(auth)/forgot-password/page.tsx +114 -0
  100. package/apps/dashboard/src/app/(auth)/layout.tsx +18 -3
  101. package/apps/dashboard/src/app/(auth)/login/page.tsx +215 -6
  102. package/apps/dashboard/src/app/(auth)/providers.tsx +34 -0
  103. package/apps/dashboard/src/app/(auth)/register/page.tsx +171 -5
  104. package/apps/dashboard/src/app/(auth)/reset-password/page.tsx +172 -0
  105. package/apps/dashboard/src/app/(auth)/verify-email/page.tsx +190 -0
  106. package/apps/dashboard/src/app/(dashboard)/(deployment)/build/[id]/page.tsx +162 -0
  107. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/BuildSummary.tsx +166 -0
  108. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/DnsConfiguration.tsx +119 -0
  109. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/DomainSettings.tsx +291 -0
  110. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/Header.tsx +71 -0
  111. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/Sidebar.tsx +270 -0
  112. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/SkeletonLoader.tsx +87 -0
  113. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/page.tsx +169 -0
  114. package/apps/dashboard/src/app/(dashboard)/(deployment)/layout.tsx +7 -0
  115. package/apps/dashboard/src/app/(dashboard)/billing/page.tsx +1 -8
  116. package/apps/dashboard/src/app/(dashboard)/deployments/components/CommitDetailsModal.tsx +240 -0
  117. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentCard.tsx +121 -0
  118. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentHeader.tsx +89 -0
  119. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentMenu.tsx +182 -0
  120. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentsContent.tsx +324 -0
  121. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentsFilters.tsx +99 -0
  122. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentsList.tsx +31 -0
  123. package/apps/dashboard/src/app/(dashboard)/deployments/components/EmptyState.tsx +101 -0
  124. package/apps/dashboard/src/app/(dashboard)/deployments/components/LoadingSkeleton.tsx +57 -0
  125. package/apps/dashboard/src/app/(dashboard)/deployments/components/ProjectFilter.tsx +109 -0
  126. package/apps/dashboard/src/app/(dashboard)/deployments/components/index.ts +9 -0
  127. package/apps/dashboard/src/app/(dashboard)/deployments/page.tsx +9 -3
  128. package/apps/dashboard/src/app/(dashboard)/deployments/types.ts +44 -0
  129. package/apps/dashboard/src/app/(dashboard)/deployments/utils.ts +176 -0
  130. package/apps/dashboard/src/app/(dashboard)/domains/page.tsx +1 -6
  131. package/apps/dashboard/src/app/(dashboard)/integrations/page.tsx +321 -0
  132. package/apps/dashboard/src/app/(dashboard)/layout.tsx +22 -32
  133. package/apps/dashboard/src/app/(dashboard)/library/components/ConnectPrompt.tsx +187 -0
  134. package/apps/dashboard/src/app/(dashboard)/library/components/LibrarySidebar.tsx +147 -0
  135. package/apps/dashboard/src/app/(dashboard)/library/components/LoadingSkeleton.tsx +39 -0
  136. package/apps/dashboard/src/app/(dashboard)/library/components/LocalProjects.tsx +548 -0
  137. package/apps/dashboard/src/app/(dashboard)/library/components/RepositoryList.tsx +292 -0
  138. package/apps/dashboard/src/app/(dashboard)/library/components/TemplateGrid.tsx +36 -0
  139. package/apps/dashboard/src/app/(dashboard)/library/components/UrlImport.tsx +74 -0
  140. package/apps/dashboard/src/app/(dashboard)/library/page.tsx +121 -0
  141. package/apps/dashboard/src/app/(dashboard)/library/types.ts +26 -0
  142. package/apps/dashboard/src/app/(dashboard)/monitoring/page.tsx +1 -6
  143. package/apps/dashboard/src/app/(dashboard)/page.tsx +485 -0
  144. package/apps/dashboard/src/app/(dashboard)/projects/[id]/[[...slug]]/layout.tsx +22 -0
  145. package/apps/dashboard/src/app/(dashboard)/projects/[id]/[[...slug]]/page.tsx +286 -0
  146. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/AdvancedSettings.tsx +235 -0
  147. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/BuildSettings.tsx +174 -0
  148. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/DeleteConfirmationDialog.tsx +45 -0
  149. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/DeletionModal.tsx +95 -0
  150. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/Deployments.tsx +11 -0
  151. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/DomainSettings.tsx +523 -0
  152. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/EnvironmentSettings.tsx +246 -0
  153. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/GeneralSettings.tsx +93 -0
  154. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/GitInfo.tsx +261 -0
  155. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/GitSettings.tsx +391 -0
  156. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/LogsSettings.tsx +133 -0
  157. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/ProjectNotFound.tsx +95 -0
  158. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/ProjectsBottomNavigation.tsx +62 -0
  159. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/ResourceSettings.tsx +333 -0
  160. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/SettingSection.tsx +66 -0
  161. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/SettingsNavigation.tsx +27 -0
  162. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/SleepModeSettings.tsx +134 -0
  163. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/ProductionUrl.tsx +25 -0
  164. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/ProjectIdentity.tsx +159 -0
  165. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/ProjectInfo.tsx +58 -0
  166. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/SkeletonLoader.tsx +170 -0
  167. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/StatsCards.tsx +33 -0
  168. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/TopPaths.tsx +56 -0
  169. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/TrafficChart.tsx +157 -0
  170. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/index.ts +14 -0
  171. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/LogsActions.tsx +52 -0
  172. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/ServerLogs.tsx +249 -0
  173. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/TerminalLogs.tsx +682 -0
  174. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/logs.css +127 -0
  175. package/apps/dashboard/src/app/(dashboard)/projects/components/DeploymentCard.tsx +73 -0
  176. package/apps/dashboard/src/app/(dashboard)/projects/components/ProjectCard.tsx +330 -0
  177. package/apps/dashboard/src/app/(dashboard)/projects/page.tsx +326 -4
  178. package/apps/dashboard/src/app/(dashboard)/providers.tsx +23 -0
  179. package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/_components/components-tab.tsx +329 -0
  180. package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/_components/overview-tab.tsx +229 -0
  181. package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/_components/terminal-tab.tsx +38 -0
  182. package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/page.tsx +437 -0
  183. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/checking-state.tsx +15 -0
  184. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/choose-mode.tsx +54 -0
  185. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/component-row.tsx +65 -0
  186. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/error-banner.tsx +13 -0
  187. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/installing-panel.tsx +227 -0
  188. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/results-panel.tsx +90 -0
  189. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/setup-header.tsx +56 -0
  190. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/types.ts +13 -0
  191. package/apps/dashboard/src/app/(dashboard)/servers/new/page.tsx +666 -0
  192. package/apps/dashboard/src/app/(dashboard)/servers/page.tsx +283 -0
  193. package/apps/dashboard/src/app/(dashboard)/settings/_components/BuildPreferences.tsx +110 -0
  194. package/apps/dashboard/src/app/(dashboard)/settings/_components/CloudConnection.tsx +147 -0
  195. package/apps/dashboard/src/app/(dashboard)/settings/_components/InstanceInfo.tsx +54 -0
  196. package/apps/dashboard/src/app/(dashboard)/settings/_components/ServerConnection.tsx +407 -0
  197. package/apps/dashboard/src/app/(dashboard)/settings/_components/SettingsSection.tsx +32 -0
  198. package/apps/dashboard/src/app/(dashboard)/settings/page.tsx +62 -3
  199. package/apps/dashboard/src/app/auth/callback/close/page.tsx +23 -0
  200. package/apps/dashboard/src/app/auth/callback/install/page.tsx +40 -0
  201. package/apps/dashboard/src/app/authorize/page.tsx +137 -0
  202. package/apps/dashboard/src/app/globals.css +57 -3
  203. package/apps/dashboard/src/app/layout.tsx +43 -3
  204. package/apps/dashboard/src/components/auth-shell.tsx +66 -0
  205. package/apps/dashboard/src/components/deployments/types.ts +44 -0
  206. package/apps/dashboard/src/components/global-deployments/index.ts +17 -0
  207. package/apps/dashboard/src/components/i18n-provider.tsx +100 -0
  208. package/apps/dashboard/src/components/import-project/BuildSettings.tsx +376 -0
  209. package/apps/dashboard/src/components/import-project/BuildSkeleton.tsx +161 -0
  210. package/apps/dashboard/src/components/import-project/BuildTerminal.tsx +358 -0
  211. package/apps/dashboard/src/components/import-project/ComposeServices.tsx +455 -0
  212. package/apps/dashboard/src/components/import-project/DeploymentProcessing.tsx +510 -0
  213. package/apps/dashboard/src/components/import-project/DockerSettings.tsx +64 -0
  214. package/apps/dashboard/src/components/import-project/EnvironmentVariables.tsx +481 -0
  215. package/apps/dashboard/src/components/import-project/Frameworks.tsx +90 -0
  216. package/apps/dashboard/src/components/import-project/ProjectSettings.tsx +160 -0
  217. package/apps/dashboard/src/components/import-project/types.ts +82 -0
  218. package/apps/dashboard/src/components/integrations/GithubPermissionModal.tsx +173 -0
  219. package/apps/dashboard/src/components/language-switcher.tsx +36 -0
  220. package/apps/dashboard/src/components/logo.tsx +13 -0
  221. package/apps/dashboard/src/components/network-error-handler.tsx +27 -0
  222. package/apps/dashboard/src/components/oauth-buttons.tsx +81 -0
  223. package/apps/dashboard/src/components/overview/ActivityChart.tsx +247 -0
  224. package/apps/dashboard/src/components/overview/ApiRequestsCard.tsx +111 -0
  225. package/apps/dashboard/src/components/overview/CreditsCard.tsx +137 -0
  226. package/apps/dashboard/src/components/overview/DeploymentsChart.tsx +195 -0
  227. package/apps/dashboard/src/components/overview/EmptyState.tsx +126 -0
  228. package/apps/dashboard/src/components/overview/LoadingSkeleton.tsx +92 -0
  229. package/apps/dashboard/src/components/overview/OverviewHeader.tsx +74 -0
  230. package/apps/dashboard/src/components/overview/OverviewHeroChart.tsx +344 -0
  231. package/apps/dashboard/src/components/overview/ProjectsCard.tsx +134 -0
  232. package/apps/dashboard/src/components/overview/QuickLinks.tsx +119 -0
  233. package/apps/dashboard/src/components/overview/SandboxesCard.tsx +150 -0
  234. package/apps/dashboard/src/components/overview/StatsGrid.tsx +166 -0
  235. package/apps/dashboard/src/components/overview/TokenUsageChart.tsx +206 -0
  236. package/apps/dashboard/src/components/overview/UsageStats.tsx +79 -0
  237. package/apps/dashboard/src/components/overview/index.ts +30 -0
  238. package/apps/dashboard/src/components/overview/types.ts +116 -0
  239. package/apps/dashboard/src/components/page-header.tsx +25 -0
  240. package/apps/dashboard/src/components/project-settings/ServerSideSwitch.jsx +60 -0
  241. package/apps/dashboard/src/components/shared/AlertBox.tsx +39 -0
  242. package/apps/dashboard/src/components/shared/CTASection.tsx +45 -0
  243. package/apps/dashboard/src/components/shared/ErrorState.tsx +176 -0
  244. package/apps/dashboard/src/components/shared/FeatureCard.tsx +20 -0
  245. package/apps/dashboard/src/components/shared/MDXComponents.tsx +24 -0
  246. package/apps/dashboard/src/components/shared/MachineSettingsModal.tsx +286 -0
  247. package/apps/dashboard/src/components/shared/Modal.tsx +39 -0
  248. package/apps/dashboard/src/components/shared/OTPInput.tsx +122 -0
  249. package/apps/dashboard/src/components/shared/PageHero.tsx +21 -0
  250. package/apps/dashboard/src/components/shared/PlatformFeatureCard.tsx +27 -0
  251. package/apps/dashboard/src/components/shared/StatCard.tsx +14 -0
  252. package/apps/dashboard/src/components/shared/ValueCard.tsx +20 -0
  253. package/apps/dashboard/src/components/shared/index.ts +8 -0
  254. package/apps/dashboard/src/components/sidebar.tsx +282 -0
  255. package/apps/dashboard/src/components/theme-provider.tsx +96 -0
  256. package/apps/dashboard/src/components/toast.tsx +106 -0
  257. package/apps/dashboard/src/components/ui/CustomCursor.tsx +107 -0
  258. package/apps/dashboard/src/components/ui/CustomSelect.tsx +126 -0
  259. package/apps/dashboard/src/components/ui/DropdownMenu.tsx +174 -0
  260. package/apps/dashboard/src/components/ui/FileIcon.jsx +59 -0
  261. package/apps/dashboard/src/components/ui/IconPickerModal.tsx +273 -0
  262. package/apps/dashboard/src/components/ui/InfoBanner.jsx +39 -0
  263. package/apps/dashboard/src/components/ui/Logo.tsx +14 -0
  264. package/apps/dashboard/src/components/ui/Modal.tsx +117 -0
  265. package/apps/dashboard/src/components/ui/PageContainer.tsx +12 -0
  266. package/apps/dashboard/src/components/ui/SectionContainer.jsx +7 -0
  267. package/apps/dashboard/src/components/ui/SlidingToggle.tsx +128 -0
  268. package/apps/dashboard/src/components/ui/Toast.tsx +29 -0
  269. package/apps/dashboard/src/components/ui/button.tsx +58 -0
  270. package/apps/dashboard/src/components/ui/card.tsx +60 -0
  271. package/apps/dashboard/src/components/ui/input.tsx +20 -0
  272. package/apps/dashboard/src/components/ui/label.tsx +19 -0
  273. package/apps/dashboard/src/components/ui/select.tsx +10 -0
  274. package/apps/dashboard/src/components/ui/textarea.tsx +9 -0
  275. package/apps/dashboard/src/constants/lang-colors.ts +25 -0
  276. package/apps/dashboard/src/constants/mock.ts +38 -0
  277. package/apps/dashboard/src/context/AuthContext.tsx +91 -0
  278. package/apps/dashboard/src/context/CloudContext.tsx +275 -0
  279. package/apps/dashboard/src/context/DeploymentContext.tsx +71 -0
  280. package/apps/dashboard/src/context/GitHubContext.tsx +288 -0
  281. package/apps/dashboard/src/context/ModalContext.tsx +300 -0
  282. package/apps/dashboard/src/context/NetworkContext.tsx +32 -0
  283. package/apps/dashboard/src/context/ProjectSettingsContext.tsx +727 -0
  284. package/apps/dashboard/src/context/ToastContext.tsx +129 -0
  285. package/apps/dashboard/src/context/deployment/index.ts +3 -0
  286. package/apps/dashboard/src/context/deployment/types.ts +183 -0
  287. package/apps/dashboard/src/context/deployment/useDeploymentBuild.ts +547 -0
  288. package/apps/dashboard/src/context/deployment/useDeploymentConfig.ts +176 -0
  289. package/apps/dashboard/src/hooks/useBuildConnection.ts +334 -0
  290. package/apps/dashboard/src/hooks/useMonitorStream.ts +146 -0
  291. package/apps/dashboard/src/hooks/useProjectData.ts +110 -0
  292. package/apps/dashboard/src/hooks/useSSEConnection.ts +465 -0
  293. package/apps/dashboard/src/hooks/useSSEStream.ts +309 -0
  294. package/apps/dashboard/src/hooks/useSessions.ts +104 -0
  295. package/apps/dashboard/src/hooks/useSetupStream.ts +223 -0
  296. package/apps/dashboard/src/i18n/dictionaries/ar.json +218 -0
  297. package/apps/dashboard/src/i18n/dictionaries/en.json +218 -0
  298. package/apps/dashboard/src/i18n/index.ts +16 -0
  299. package/apps/dashboard/src/lib/api/ai.ts +22 -0
  300. package/apps/dashboard/src/lib/api/auth.ts +13 -0
  301. package/apps/dashboard/src/lib/api/client.ts +199 -0
  302. package/apps/dashboard/src/lib/api/cloud.ts +15 -0
  303. package/apps/dashboard/src/lib/api/deploy.ts +58 -0
  304. package/apps/dashboard/src/lib/api/domains.ts +13 -0
  305. package/apps/dashboard/src/lib/api/endpoints.ts +129 -0
  306. package/apps/dashboard/src/lib/api/github.ts +31 -0
  307. package/apps/dashboard/src/lib/api/icons.ts +12 -0
  308. package/apps/dashboard/src/lib/api/index.ts +41 -0
  309. package/apps/dashboard/src/lib/api/projects.ts +153 -0
  310. package/apps/dashboard/src/lib/api/sandbox.ts +14 -0
  311. package/apps/dashboard/src/lib/api/settings.ts +21 -0
  312. package/apps/dashboard/src/lib/api/system.ts +159 -0
  313. package/apps/dashboard/src/lib/auth-client.ts +54 -0
  314. package/apps/dashboard/src/lib/country.ts +25 -0
  315. package/apps/dashboard/src/lib/server/api.ts +140 -0
  316. package/apps/dashboard/src/lib/server/session.ts +103 -0
  317. package/apps/dashboard/src/lib/sseClient.ts +241 -0
  318. package/apps/dashboard/src/lib/sseMessageProcessors.ts +323 -0
  319. package/apps/dashboard/src/lib/utils.ts +6 -0
  320. package/apps/dashboard/src/proxy.ts +46 -0
  321. package/apps/dashboard/src/styles/Toast.module.css +92 -0
  322. package/apps/dashboard/src/styles/fonts.css +93 -0
  323. package/apps/dashboard/src/styles/theme.css +336 -0
  324. package/apps/dashboard/src/types/research.ts +42 -0
  325. package/apps/dashboard/src/utils/SSEParser.js +150 -0
  326. package/apps/dashboard/src/utils/authWindow.ts +143 -0
  327. package/apps/dashboard/src/utils/codeTheme.ts +127 -0
  328. package/apps/dashboard/src/utils/colors.json +2810 -0
  329. package/apps/dashboard/src/utils/date.ts +121 -0
  330. package/apps/dashboard/src/utils/deployment.ts +128 -0
  331. package/apps/dashboard/src/utils/deploymentPhaseDetector.ts +232 -0
  332. package/apps/dashboard/src/utils/extToLang.js +103 -0
  333. package/apps/dashboard/src/utils/github.ts +62 -0
  334. package/apps/dashboard/src/utils/icons.js +46 -0
  335. package/apps/dashboard/src/utils/repoSlug.ts +110 -0
  336. package/apps/dashboard/src/utils/research-api.ts +163 -0
  337. package/apps/dashboard/src/utils/suggestions.ts +84 -0
  338. package/apps/dashboard/src/utils/theme.js +1 -0
  339. package/apps/dashboard/src/utils/ui-helpers.tsx +30 -0
  340. package/apps/dashboard/src/utils/upload.js +12 -0
  341. package/apps/dashboard/tsconfig.json +27 -5
  342. package/apps/desktop/forge.config.json +36 -0
  343. package/apps/desktop/package.json +26 -0
  344. package/apps/desktop/scripts/dev.mjs +58 -0
  345. package/apps/desktop/src/main/index.ts +675 -0
  346. package/apps/desktop/src/main/types/desktop.d.ts +33 -0
  347. package/apps/desktop/src/preload/index.ts +88 -0
  348. package/apps/desktop/src/renderer/index.html +462 -0
  349. package/apps/desktop/src/renderer/onboarding.js +511 -0
  350. package/apps/desktop/src/renderer/styles.css +1139 -0
  351. package/apps/desktop/tsconfig.json +17 -0
  352. package/apps/web/.source/browser.ts +13 -0
  353. package/apps/web/.source/dynamic.ts +8 -0
  354. package/apps/web/.source/server.ts +22 -0
  355. package/apps/web/.source/source.config.mjs +20 -0
  356. package/apps/web/Dockerfile +4 -6
  357. package/apps/web/content/blog/how-ai-builds-work.mdx +55 -0
  358. package/apps/web/content/blog/introducing-openship.mdx +46 -0
  359. package/apps/web/content/blog/self-hosting-cost-breakdown.mdx +59 -0
  360. package/apps/web/content/docs/_meta.json +14 -0
  361. package/apps/web/content/docs/api.mdx +98 -0
  362. package/apps/web/content/docs/cli.mdx +80 -0
  363. package/apps/web/content/docs/first-deployment.mdx +56 -0
  364. package/apps/web/content/docs/index.mdx +27 -0
  365. package/apps/web/content/docs/installation.mdx +65 -0
  366. package/apps/web/content/docs/quickstart.mdx +45 -0
  367. package/apps/web/next-env.d.ts +6 -0
  368. package/apps/web/next.config.mjs +16 -2
  369. package/apps/web/package.json +19 -12
  370. package/apps/web/postcss.config.mjs +5 -0
  371. package/apps/web/public/android-chrome-192x192.png +0 -0
  372. package/apps/web/public/android-chrome-512x512.png +0 -0
  373. package/apps/web/public/apple-touch-icon.png +0 -0
  374. package/apps/web/public/favicon-16x16.png +0 -0
  375. package/apps/web/public/favicon-32x32.png +0 -0
  376. package/apps/web/public/favicon.ico +0 -0
  377. package/apps/web/public/site.webmanifest +1 -0
  378. package/apps/web/source.config.ts +17 -0
  379. package/apps/web/src/app/(marketing)/layout.tsx +7 -22
  380. package/apps/web/src/app/blog/[...slug]/page.tsx +247 -0
  381. package/apps/web/src/app/blog/blog.css +575 -0
  382. package/apps/web/src/app/blog/layout.tsx +50 -0
  383. package/apps/web/src/app/blog/page.tsx +235 -0
  384. package/apps/web/src/app/docs/[[...slug]]/page.tsx +67 -0
  385. package/apps/web/src/app/docs/layout.tsx +62 -0
  386. package/apps/web/src/app/docs/toc-theme.css +71 -0
  387. package/apps/web/src/app/download/page.tsx +396 -0
  388. package/apps/web/src/app/globals.css +20 -3
  389. package/apps/web/src/app/layout.tsx +57 -3
  390. package/apps/web/src/app/page.tsx +47 -6
  391. package/apps/web/src/app/robots.ts +15 -0
  392. package/apps/web/src/app/sitemap.ts +35 -0
  393. package/apps/web/src/components/blog/share-sidebar.tsx +81 -0
  394. package/apps/web/src/components/blog/writer-sidebar.tsx +81 -0
  395. package/apps/web/src/components/landing/ai-native.tsx +169 -0
  396. package/apps/web/src/components/landing/backups.tsx +139 -0
  397. package/apps/web/src/components/landing/cdn.tsx +109 -0
  398. package/apps/web/src/components/landing/coming-soon.tsx +180 -0
  399. package/apps/web/src/components/landing/dark-section.tsx +166 -0
  400. package/apps/web/src/components/landing/dashboard.tsx +407 -0
  401. package/apps/web/src/components/landing/developer-experience.tsx +224 -0
  402. package/apps/web/src/components/landing/dns-domains.tsx +146 -0
  403. package/apps/web/src/components/landing/download-button.tsx +151 -0
  404. package/apps/web/src/components/landing/features/ai-visual.tsx +48 -0
  405. package/apps/web/src/components/landing/features/cloud-visual.tsx +44 -0
  406. package/apps/web/src/components/landing/features/git-visual.tsx +61 -0
  407. package/apps/web/src/components/landing/features/index.tsx +642 -0
  408. package/apps/web/src/components/landing/features/infra-visual.tsx +69 -0
  409. package/apps/web/src/components/landing/features/rollback-visual.tsx +42 -0
  410. package/apps/web/src/components/landing/features/ssl-visual.tsx +41 -0
  411. package/apps/web/src/components/landing/features/stacks-visual.tsx +54 -0
  412. package/apps/web/src/components/landing/final-cta.tsx +116 -0
  413. package/apps/web/src/components/landing/footer.tsx +145 -0
  414. package/apps/web/src/components/landing/hero.tsx +110 -0
  415. package/apps/web/src/components/landing/how-it-works.tsx +210 -0
  416. package/apps/web/src/components/landing/index.ts +21 -0
  417. package/apps/web/src/components/landing/mail-server.tsx +122 -0
  418. package/apps/web/src/components/landing/navbar.tsx +199 -0
  419. package/apps/web/src/components/landing/no-lockin.tsx +185 -0
  420. package/apps/web/src/components/landing/open-source-cta.tsx +151 -0
  421. package/apps/web/src/components/landing/portability.tsx +190 -0
  422. package/apps/web/src/components/landing/pricing.tsx +263 -0
  423. package/apps/web/src/components/landing/scaling.tsx +209 -0
  424. package/apps/web/src/components/landing/why-openship.tsx +291 -0
  425. package/apps/web/src/hooks/use-gsap-scroll.ts +158 -0
  426. package/apps/web/src/hooks/use-platform.ts +86 -0
  427. package/apps/web/src/lib/source.ts +12 -0
  428. package/apps/web/src/styles/fonts.css +84 -0
  429. package/apps/web/src/styles/landing.css +951 -0
  430. package/apps/web/src/styles/theme.css +227 -0
  431. package/apps/web/tsconfig.json +8 -3
  432. package/bun.lock +3260 -0
  433. package/docker-compose.yml +3 -0
  434. package/docs/screenshots/.gitkeep +0 -0
  435. package/docs/screenshots/screen.png +0 -0
  436. package/openship.code-workspace +7 -0
  437. package/package.json +23 -9
  438. package/packages/adapters/docs/ARCHITECTURE.md +160 -0
  439. package/packages/adapters/docs/BUILD-PIPELINE.md +171 -0
  440. package/packages/adapters/docs/CLOUD.md +239 -0
  441. package/packages/adapters/docs/EXECUTOR.md +174 -0
  442. package/packages/adapters/docs/LOG-STREAMING.md +175 -0
  443. package/packages/adapters/docs/SYSTEM.md +191 -0
  444. package/packages/adapters/package.json +14 -9
  445. package/packages/adapters/src/index.ts +144 -4
  446. package/packages/adapters/src/infra/cloud.ts +42 -0
  447. package/packages/adapters/src/infra/index.ts +9 -0
  448. package/packages/adapters/src/infra/noop.ts +27 -0
  449. package/packages/adapters/src/infra/traefik.ts +297 -0
  450. package/packages/adapters/src/infra/types.ts +36 -0
  451. package/packages/adapters/src/platform.ts +255 -0
  452. package/packages/adapters/src/runtime/bare.ts +567 -0
  453. package/packages/adapters/src/runtime/build-pipeline.ts +237 -0
  454. package/packages/adapters/src/runtime/cloud.ts +791 -0
  455. package/packages/adapters/src/runtime/deploy-pipeline.ts +146 -0
  456. package/packages/adapters/src/runtime/docker.ts +443 -0
  457. package/packages/adapters/src/runtime/index.ts +69 -0
  458. package/packages/adapters/src/runtime/local-build.ts +112 -0
  459. package/packages/adapters/src/runtime/transfer.ts +82 -0
  460. package/packages/adapters/src/runtime/types.ts +138 -0
  461. package/packages/adapters/src/system/catalog.ts +188 -0
  462. package/packages/adapters/src/system/checks.ts +228 -0
  463. package/packages/adapters/src/system/components.ts +45 -0
  464. package/packages/adapters/src/system/debug.ts +18 -0
  465. package/packages/adapters/src/system/environment.ts +168 -0
  466. package/packages/adapters/src/system/errors.ts +34 -0
  467. package/packages/adapters/src/system/executor.ts +600 -0
  468. package/packages/adapters/src/system/index.ts +58 -0
  469. package/packages/adapters/src/system/installer.ts +310 -0
  470. package/packages/adapters/src/system/setup.ts +442 -0
  471. package/packages/adapters/src/system/state.ts +96 -0
  472. package/packages/adapters/src/system/types.ts +116 -0
  473. package/packages/adapters/src/toolchain/catalog.ts +439 -0
  474. package/packages/adapters/src/toolchain/checks.ts +181 -0
  475. package/packages/adapters/src/toolchain/index.ts +38 -0
  476. package/packages/adapters/src/toolchain/installer.ts +189 -0
  477. package/packages/adapters/src/toolchain/types.ts +84 -0
  478. package/packages/adapters/src/types.ts +277 -0
  479. package/packages/adapters/tsconfig.json +3 -1
  480. package/packages/core/package.json +9 -9
  481. package/packages/core/src/constants.ts +44 -1
  482. package/packages/core/src/index.ts +2 -0
  483. package/packages/core/src/stacks.ts +778 -0
  484. package/packages/core/src/system.ts +111 -0
  485. package/packages/core/src/types.ts +22 -1
  486. package/packages/core/src/utils.ts +8 -0
  487. package/packages/core/tsconfig.json +3 -1
  488. package/packages/db/drizzle/0000_init.sql +231 -0
  489. package/packages/db/drizzle/0001_add_server_name.sql +1 -0
  490. package/packages/db/drizzle/meta/_journal.json +20 -0
  491. package/packages/db/drizzle.config.ts +10 -0
  492. package/packages/db/package.json +26 -14
  493. package/packages/db/src/client.ts +119 -0
  494. package/packages/db/src/index.ts +57 -8
  495. package/packages/db/src/repos/account.repo.ts +92 -0
  496. package/packages/db/src/repos/deployment.repo.ts +168 -0
  497. package/packages/db/src/repos/domain.repo.ts +102 -0
  498. package/packages/db/src/repos/git-installation.repo.ts +95 -0
  499. package/packages/db/src/repos/index.ts +43 -0
  500. package/packages/db/src/repos/instance-settings.repo.ts +43 -0
  501. package/packages/db/src/repos/project.repo.ts +159 -0
  502. package/packages/db/src/repos/session.repo.ts +82 -0
  503. package/packages/db/src/repos/settings.repo.ts +51 -0
  504. package/packages/db/src/repos/user.repo.ts +94 -0
  505. package/packages/db/src/schema/auth.ts +56 -0
  506. package/packages/db/src/schema/deployment.ts +87 -0
  507. package/packages/db/src/schema/domain.ts +46 -0
  508. package/packages/db/src/schema/github.ts +24 -0
  509. package/packages/db/src/schema/index.ts +6 -0
  510. package/packages/db/src/schema/project.ts +117 -0
  511. package/packages/db/src/schema/settings.ts +103 -0
  512. package/packages/db/tsconfig.json +3 -1
  513. package/packages/ui/package.json +17 -17
  514. package/packages/ui/src/components/status-dot.tsx +1 -1
  515. package/packages/ui/tsconfig.json +7 -2
  516. package/pnpm-workspace.yaml +0 -1
  517. package/{tooling/tsconfig/base.json → tsconfig.base.json} +0 -1
  518. package/turbo.json +4 -0
  519. package/apps/api/src/modules/auth/auth.controller.ts +0 -26
  520. package/apps/api/src/modules/auth/auth.schema.ts +0 -12
  521. package/apps/api/src/modules/auth/auth.service.ts +0 -23
  522. package/apps/dashboard/src/app/page.tsx +0 -6
  523. package/apps/web/src/app/(marketing)/docs/page.tsx +0 -10
  524. package/packages/adapters/src/base-adapter.ts +0 -49
  525. package/packages/adapters/src/docker-adapter.ts +0 -43
  526. package/packages/adapters/src/oblien-adapter.ts +0 -46
  527. package/packages/adapters/src/registry.ts +0 -22
  528. package/packages/db/prisma/schema.prisma +0 -160
  529. package/tooling/tsconfig/nextjs.json +0 -10
  530. package/tooling/tsconfig/node.json +0 -10
  531. package/tooling/tsconfig/package.json +0 -7
@@ -0,0 +1,69 @@
1
+ export function InfraVisual() {
2
+ return (
3
+ <svg viewBox="0 0 520 260" fill="none" className="w-full h-auto">
4
+ {/* Central app node */}
5
+ <rect x="200" y="86" width="120" height="52" rx="12"
6
+ fill="currentColor" fillOpacity={0.08} stroke="currentColor" strokeWidth="1.8" strokeOpacity={0.5} />
7
+ <text x="260" y="116" textAnchor="middle" fontSize="15" fontWeight="600" fill="currentColor" fillOpacity={0.8}>Your App</text>
8
+
9
+ {/* ── Top row services ── */}
10
+ {/* PostgreSQL */}
11
+ <rect x="30" y="22" width="100" height="40" rx="8"
12
+ fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.25} />
13
+ <circle cx="52" cy="42" r="4" fill="currentColor" fillOpacity={0.15} stroke="currentColor" strokeWidth="1" strokeOpacity={0.3} />
14
+ <text x="88" y="47" textAnchor="middle" fontSize="11" fontWeight="500" fill="currentColor" fillOpacity={0.55}>Postgres</text>
15
+ {/* Connection to app */}
16
+ <line x1="130" y1="46" x2="200" y2="100" stroke="currentColor" strokeWidth="1" strokeOpacity={0.15} strokeDasharray="3 3" />
17
+
18
+ {/* Redis */}
19
+ <rect x="210" y="10" width="100" height="40" rx="8"
20
+ fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.25} />
21
+ <circle cx="232" cy="30" r="4" fill="currentColor" fillOpacity={0.15} stroke="currentColor" strokeWidth="1" strokeOpacity={0.3} />
22
+ <text x="270" y="35" textAnchor="middle" fontSize="11" fontWeight="500" fill="currentColor" fillOpacity={0.55}>Redis</text>
23
+ {/* Connection */}
24
+ <line x1="260" y1="50" x2="260" y2="86" stroke="currentColor" strokeWidth="1" strokeOpacity={0.15} strokeDasharray="3 3" />
25
+
26
+ {/* MongoDB */}
27
+ <rect x="390" y="22" width="100" height="40" rx="8"
28
+ fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.25} />
29
+ <circle cx="412" cy="42" r="4" fill="currentColor" fillOpacity={0.15} stroke="currentColor" strokeWidth="1" strokeOpacity={0.3} />
30
+ <text x="448" y="47" textAnchor="middle" fontSize="11" fontWeight="500" fill="currentColor" fillOpacity={0.55}>MongoDB</text>
31
+ {/* Connection */}
32
+ <line x1="390" y1="46" x2="320" y2="100" stroke="currentColor" strokeWidth="1" strokeOpacity={0.15} strokeDasharray="3 3" />
33
+
34
+ {/* ── Bottom row services ── */}
35
+ {/* API Gateway */}
36
+ <rect x="14" y="168" width="110" height="40" rx="8"
37
+ fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.25} />
38
+ <circle cx="36" cy="188" r="4" fill="currentColor" fillOpacity={0.15} stroke="currentColor" strokeWidth="1" strokeOpacity={0.3} />
39
+ <text x="78" y="193" textAnchor="middle" fontSize="11" fontWeight="500" fill="currentColor" fillOpacity={0.55}>API Gateway</text>
40
+ <line x1="124" y1="182" x2="210" y2="138" stroke="currentColor" strokeWidth="1" strokeOpacity={0.15} strokeDasharray="3 3" />
41
+
42
+ {/* WebSocket */}
43
+ <rect x="148" y="180" width="106" height="40" rx="8"
44
+ fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.25} />
45
+ <circle cx="170" cy="200" r="4" fill="currentColor" fillOpacity={0.15} stroke="currentColor" strokeWidth="1" strokeOpacity={0.3} />
46
+ <text x="210" y="205" textAnchor="middle" fontSize="11" fontWeight="500" fill="currentColor" fillOpacity={0.55}>WebSocket</text>
47
+ <line x1="230" y1="180" x2="248" y2="138" stroke="currentColor" strokeWidth="1" strokeOpacity={0.15} strokeDasharray="3 3" />
48
+
49
+ {/* Worker */}
50
+ <rect x="278" y="180" width="100" height="40" rx="8"
51
+ fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.25} />
52
+ <circle cx="300" cy="200" r="4" fill="currentColor" fillOpacity={0.15} stroke="currentColor" strokeWidth="1" strokeOpacity={0.3} />
53
+ <text x="336" y="205" textAnchor="middle" fontSize="11" fontWeight="500" fill="currentColor" fillOpacity={0.55}>Worker</text>
54
+ <line x1="300" y1="180" x2="275" y2="138" stroke="currentColor" strokeWidth="1" strokeOpacity={0.15} strokeDasharray="3 3" />
55
+
56
+ {/* S3 / Storage */}
57
+ <rect x="402" y="168" width="100" height="40" rx="8"
58
+ fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.25} />
59
+ <circle cx="424" cy="188" r="4" fill="currentColor" fillOpacity={0.15} stroke="currentColor" strokeWidth="1" strokeOpacity={0.3} />
60
+ <text x="460" y="193" textAnchor="middle" fontSize="11" fontWeight="500" fill="currentColor" fillOpacity={0.55}>Storage</text>
61
+ <line x1="402" y1="182" x2="320" y2="138" stroke="currentColor" strokeWidth="1" strokeOpacity={0.15} strokeDasharray="3 3" />
62
+
63
+ {/* "One click" badge */}
64
+ <rect x="187" y="232" width="146" height="24" rx="12"
65
+ fill="currentColor" fillOpacity={0.06} stroke="currentColor" strokeWidth="1" strokeOpacity={0.2} />
66
+ <text x="260" y="248" textAnchor="middle" fontSize="10" fontWeight="600" fill="currentColor" fillOpacity={0.5} letterSpacing=".06em">ONE CLICK SETUP</text>
67
+ </svg>
68
+ );
69
+ }
@@ -0,0 +1,42 @@
1
+ export function RollbackVisual() {
2
+ return (
3
+ <svg viewBox="0 0 520 260" fill="none" className="w-full h-auto">
4
+ {/* Timeline */}
5
+ <line x1="50" y1="110" x2="470" y2="110" stroke="currentColor" strokeWidth="2" strokeOpacity={0.3} strokeLinecap="round" />
6
+
7
+ {/* Rollback arrow */}
8
+ <path d="M415 98 C405 54 325 46 300 80" stroke="currentColor" strokeWidth="1.8" strokeOpacity={0.45} strokeLinecap="round" fill="none" strokeDasharray="5 4" />
9
+ <path d="M304 72 L296 86 L310 84" fill="none" stroke="currentColor" strokeWidth="1.8" strokeOpacity={0.5} strokeLinecap="round" strokeLinejoin="round" />
10
+ <text x="358" y="56" textAnchor="middle" fontSize="13" fontWeight="600" fill="currentColor" fillOpacity={0.65}>rollback</text>
11
+
12
+ {/* v1.0 */}
13
+ <circle cx="100" cy="110" r="8" fill="currentColor" fillOpacity={0.06} stroke="currentColor" strokeWidth="1.8" strokeOpacity={0.35} />
14
+ <circle cx="100" cy="110" r="3" fill="currentColor" fillOpacity={0.55} />
15
+ <text x="100" y="142" textAnchor="middle" fontSize="13" fontFamily="monospace" fontWeight="500" fill="currentColor" fillOpacity={0.6}>v1.0</text>
16
+ <text x="100" y="160" textAnchor="middle" fontSize="10" fill="currentColor" fillOpacity={0.3}>2 days ago</text>
17
+
18
+ {/* v1.1 */}
19
+ <circle cx="210" cy="110" r="8" fill="currentColor" fillOpacity={0.06} stroke="currentColor" strokeWidth="1.8" strokeOpacity={0.35} />
20
+ <circle cx="210" cy="110" r="3" fill="currentColor" fillOpacity={0.55} />
21
+ <text x="210" y="142" textAnchor="middle" fontSize="13" fontFamily="monospace" fontWeight="500" fill="currentColor" fillOpacity={0.6}>v1.1</text>
22
+ <text x="210" y="160" textAnchor="middle" fontSize="10" fill="currentColor" fillOpacity={0.3}>yesterday</text>
23
+
24
+ {/* v1.2 — rollback target — emphasized */}
25
+ <circle cx="320" cy="110" r="10" fill="currentColor" fillOpacity={0.12} stroke="currentColor" strokeWidth="2.2" strokeOpacity={0.6} />
26
+ <circle cx="320" cy="110" r="4" fill="currentColor" fillOpacity={0.75} />
27
+ <text x="320" y="144" textAnchor="middle" fontSize="14" fontFamily="monospace" fontWeight="600" fill="currentColor" fillOpacity={0.8}>v1.2</text>
28
+ <text x="320" y="162" textAnchor="middle" fontSize="10" fontWeight="500" fill="currentColor" fillOpacity={0.45}>3h ago</text>
29
+ {/* Snapshot card */}
30
+ <rect x="285" y="174" width="70" height="46" rx="8" fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1" strokeOpacity={0.15} />
31
+ <line x1="296" y1="190" x2="344" y2="190" stroke="currentColor" strokeWidth=".8" strokeOpacity={0.15} />
32
+ <line x1="296" y1="200" x2="336" y2="200" stroke="currentColor" strokeWidth=".8" strokeOpacity={0.1} />
33
+ <line x1="296" y1="210" x2="340" y2="210" stroke="currentColor" strokeWidth=".8" strokeOpacity={0.08} />
34
+
35
+ {/* v1.3 — current (faded) */}
36
+ <circle cx="430" cy="110" r="8" fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.8" strokeOpacity={0.2} />
37
+ <circle cx="430" cy="110" r="3" fill="currentColor" fillOpacity={0.3} />
38
+ <text x="430" y="142" textAnchor="middle" fontSize="13" fontFamily="monospace" fill="currentColor" fillOpacity={0.35}>v1.3</text>
39
+ <text x="430" y="160" textAnchor="middle" fontSize="10" fill="currentColor" fillOpacity={0.2}>current</text>
40
+ </svg>
41
+ );
42
+ }
@@ -0,0 +1,41 @@
1
+ export function SslVisual() {
2
+ return (
3
+ <svg viewBox="0 0 520 260" fill="none" className="w-full h-auto">
4
+ {/* Central lock */}
5
+ <path d="M240 78 V58 C240 34 280 34 280 58 V78" fill="none" stroke="currentColor" strokeWidth="2" strokeOpacity={0.5} strokeLinecap="round" />
6
+ <rect x="226" y="78" width="68" height="56" rx="10" fill="currentColor" fillOpacity={0.06} stroke="currentColor" strokeWidth="1.8" strokeOpacity={0.45} />
7
+ <circle cx="260" cy="102" r="5" fill="currentColor" fillOpacity={0.08} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.4} />
8
+ <line x1="260" y1="106" x2="260" y2="118" stroke="currentColor" strokeWidth="1.5" strokeOpacity={0.4} strokeLinecap="round" />
9
+ <text x="260" y="154" textAnchor="middle" fontSize="14" fontWeight="600" fill="currentColor" fillOpacity={0.85} letterSpacing=".04em">HTTPS</text>
10
+
11
+ {/* Left: Domain card */}
12
+ <rect x="20" y="58" width="170" height="56" rx="10" fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.2} />
13
+ <circle cx="38" cy="80" r="4" fill="currentColor" fillOpacity={0.08} stroke="currentColor" strokeWidth="1" strokeOpacity={0.3} />
14
+ <path d="M36 80 L37.5 82 L40.5 78" stroke="currentColor" strokeWidth="1" strokeOpacity={0.45} strokeLinecap="round" fill="none" />
15
+ <text x="50" y="84" fontSize="11" fontFamily="monospace" fill="currentColor" fillOpacity={0.6}>app.company.com</text>
16
+ <text x="105" y="126" textAnchor="middle" fontSize="11" fontWeight="500" fill="currentColor" fillOpacity={0.35}>Custom domain</text>
17
+
18
+ {/* Connection: domain → lock */}
19
+ <line x1="192" y1="86" x2="224" y2="98" stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.15} strokeDasharray="4 4" />
20
+
21
+ {/* Right: Certificate card */}
22
+ <rect x="330" y="52" width="160" height="72" rx="10" fill="currentColor" fillOpacity={0.04} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.2} />
23
+ <line x1="348" y1="72" x2="472" y2="72" stroke="currentColor" strokeOpacity={0.12} strokeWidth=".8" />
24
+ <line x1="348" y1="86" x2="460" y2="86" stroke="currentColor" strokeOpacity={0.08} strokeWidth=".8" />
25
+ <line x1="348" y1="100" x2="466" y2="100" stroke="currentColor" strokeOpacity={0.08} strokeWidth=".8" />
26
+ {/* Seal */}
27
+ <circle cx="408" cy="110" r="7" fill="currentColor" fillOpacity={0.06} stroke="currentColor" strokeWidth="1" strokeOpacity={0.3} />
28
+ <path d="M405 110 L407 112 L412 108" stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.5} strokeLinecap="round" fill="none" />
29
+ <text x="408" y="138" textAnchor="middle" fontSize="11" fontWeight="500" fill="currentColor" fillOpacity={0.35}>SSL certificate</text>
30
+
31
+ {/* Connection: lock → cert */}
32
+ <line x1="296" y1="98" x2="328" y2="88" stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.15} strokeDasharray="4 4" />
33
+
34
+ {/* Bottom: DNS records */}
35
+ <rect x="60" y="176" width="400" height="48" rx="10" fill="currentColor" fillOpacity={0.03} stroke="currentColor" strokeWidth="1.2" strokeOpacity={0.15} />
36
+ <text x="190" y="204" textAnchor="middle" fontSize="11" fontFamily="monospace" fill="currentColor" fillOpacity={0.45}>A 143.198.42.17</text>
37
+ <line x1="260" y1="186" x2="260" y2="214" stroke="currentColor" strokeOpacity={0.1} strokeWidth=".6" />
38
+ <text x="350" y="204" textAnchor="middle" fontSize="11" fontFamily="monospace" fill="currentColor" fillOpacity={0.45}>CNAME edge.os.dev</text>
39
+ </svg>
40
+ );
41
+ }
@@ -0,0 +1,54 @@
1
+ export function StacksVisual() {
2
+ const stacks = [
3
+ { name: "Go", slug: "go" },
4
+ { name: "Rust", slug: "rust" },
5
+ { name: "Python", slug: "python" },
6
+ { name: "Node.js", slug: "nodedotjs" },
7
+ { name: "Ruby", slug: "ruby" },
8
+ { name: "PHP", slug: "php" },
9
+ { name: "Java", slug: "openjdk" },
10
+ { name: ".NET", slug: "dotnet" },
11
+ { name: "Elixir", slug: "elixir" },
12
+ { name: "Docker", slug: "docker" },
13
+ { name: "Bun", slug: "bun" },
14
+ { name: "Deno", slug: "deno" },
15
+ { name: "Rails", slug: "rubyonrails" },
16
+ { name: "Django", slug: "django" },
17
+ { name: "Laravel", slug: "laravel" },
18
+ { name: "PostgreSQL", slug: "postgresql" },
19
+ { name: "Redis", slug: "redis" },
20
+ { name: "Nginx", slug: "nginx" },
21
+ ];
22
+
23
+ return (
24
+ <div className="w-full">
25
+ <div className="grid grid-cols-6 gap-[1px] rounded-xl overflow-hidden">
26
+ {stacks.map((s) => (
27
+ <div
28
+ key={s.name}
29
+ className="feat-build-item relative flex flex-col items-center justify-center gap-2.5 py-5 px-1.5"
30
+ style={{ background: "rgba(255,255,255,0.05)" }}
31
+ >
32
+ {/* Icon — currentColor (inherits theme text color) */}
33
+ <span
34
+ className="h-6 w-6 block"
35
+ style={{
36
+ background: "currentColor",
37
+ opacity: 0.55,
38
+ maskImage: `url(https://cdn.simpleicons.org/${s.slug}/ffffff)`,
39
+ WebkitMaskImage: `url(https://cdn.simpleicons.org/${s.slug}/ffffff)`,
40
+ maskSize: "contain",
41
+ WebkitMaskSize: "contain",
42
+ maskRepeat: "no-repeat",
43
+ WebkitMaskRepeat: "no-repeat",
44
+ maskPosition: "center",
45
+ WebkitMaskPosition: "center",
46
+ }}
47
+ />
48
+ <span className="text-[11px] font-semibold leading-none text-center" style={{ color: "currentColor", opacity: 0.40 }}>{s.name}</span>
49
+ </div>
50
+ ))}
51
+ </div>
52
+ </div>
53
+ );
54
+ }
@@ -0,0 +1,116 @@
1
+ "use client";
2
+
3
+ export function FinalCta() {
4
+ return (
5
+ <section className="relative py-28 sm:py-36">
6
+ <div className="section-divider mx-auto mb-28 max-w-4xl sm:mb-36" />
7
+
8
+ <div className="mx-auto max-w-7xl px-6">
9
+ <div className="relative overflow-hidden rounded-3xl border border-[var(--th-card-bd)] bg-[var(--th-card-bg)] px-8 py-16 shadow-[0_8px_40px_rgba(0,0,0,.06)] sm:px-14 sm:py-20">
10
+ {/* Ambient blobs */}
11
+ <div
12
+ className="pointer-events-none absolute -left-24 -top-24 h-[300px] w-[300px] rounded-full blur-[80px]"
13
+ style={{ background: "var(--th-clr-plum-blob)" }}
14
+ />
15
+ <div
16
+ className="pointer-events-none absolute -bottom-20 -right-20 h-[260px] w-[260px] rounded-full blur-[80px]"
17
+ style={{ background: "var(--th-clr-sea-blob)" }}
18
+ />
19
+ <div
20
+ className="pointer-events-none absolute right-1/3 top-1/4 h-[180px] w-[180px] rounded-full blur-[60px]"
21
+ style={{ background: "var(--th-clr-terra-blob)" }}
22
+ />
23
+
24
+ {/* Grid lines (decorative) */}
25
+ <div className="pointer-events-none absolute inset-0 opacity-[0.03]" style={{
26
+ backgroundImage: "linear-gradient(var(--th-on-100) 1px, transparent 1px), linear-gradient(90deg, var(--th-on-100) 1px, transparent 1px)",
27
+ backgroundSize: "48px 48px",
28
+ }} />
29
+
30
+ <div className="relative text-center">
31
+ {/* Terminal-style prompt */}
32
+ <div className="mx-auto mb-8 inline-flex items-center gap-2.5 rounded-full border border-[var(--th-on-06)] bg-white/70 px-5 py-2 font-mono text-[13px] shadow-[0_2px_8px_rgba(0,0,0,.04)] backdrop-blur-sm">
33
+ <span style={{ color: "var(--th-clr-sea)" }}>$</span>
34
+ <span className="th-text-secondary">git push origin main</span>
35
+ <span className="animate-pulse th-text-muted">▌</span>
36
+ </div>
37
+
38
+ <h2>
39
+ <span className="block text-[clamp(2.75rem,6vw,4.75rem)] font-semibold leading-[1.06] tracking-[-0.035em] th-text-heading">
40
+ Ready to ship?
41
+ </span>
42
+ <span
43
+ className="block text-[clamp(2.75rem,6vw,4.75rem)] font-semibold leading-[1.06] tracking-[-0.035em]"
44
+ style={{ color: "var(--th-on-40)" }}
45
+ >
46
+ Deploy in minutes.
47
+ </span>
48
+ </h2>
49
+
50
+ <p className="mx-auto mt-6 max-w-lg text-[16px] leading-[1.65] th-text-body">
51
+ Use our cloud or deploy to your own servers. No credit card,
52
+ no vendor lock-in, no surprises. Start free in seconds.
53
+ </p>
54
+
55
+ <div className="mt-10 flex flex-wrap items-center justify-center gap-4">
56
+ <a
57
+ href="/login"
58
+ className="th-btn group rounded-full px-8 py-3.5 text-[15px] font-medium"
59
+ >
60
+ Start Free
61
+ <svg
62
+ className="ml-1.5 h-4 w-4 transition-transform group-hover:translate-x-0.5"
63
+ fill="none"
64
+ viewBox="0 0 24 24"
65
+ stroke="currentColor"
66
+ strokeWidth={2.2}
67
+ >
68
+ <path strokeLinecap="round" strokeLinejoin="round" d="M13 7l5 5m0 0l-5 5m5-5H6" />
69
+ </svg>
70
+ </a>
71
+ <a
72
+ href="https://github.com/openshiporg/openship"
73
+ target="_blank"
74
+ rel="noopener noreferrer"
75
+ className="th-btn-ghost rounded-full px-8 py-3.5 text-[15px] font-medium"
76
+ >
77
+ <svg className="mr-2 inline-block h-4 w-4" viewBox="0 0 24 24" fill="currentColor">
78
+ <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
79
+ </svg>
80
+ View on GitHub
81
+ </a>
82
+ </div>
83
+
84
+ {/* Trust row */}
85
+ <div className="mx-auto mt-10 flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-[13px] th-text-muted">
86
+ <span className="flex items-center gap-1.5">
87
+ <svg className="h-3.5 w-3.5" style={{ color: "var(--th-clr-sea)" }} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
88
+ <path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
89
+ </svg>
90
+ Desktop app
91
+ </span>
92
+ <span className="flex items-center gap-1.5">
93
+ <svg className="h-3.5 w-3.5" style={{ color: "var(--th-clr-sea)" }} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
94
+ <path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
95
+ </svg>
96
+ Cloud or self-hosted
97
+ </span>
98
+ <span className="flex items-center gap-1.5">
99
+ <svg className="h-3.5 w-3.5" style={{ color: "var(--th-clr-sea)" }} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
100
+ <path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
101
+ </svg>
102
+ No credit card
103
+ </span>
104
+ <span className="flex items-center gap-1.5">
105
+ <svg className="h-3.5 w-3.5" style={{ color: "var(--th-clr-sea)" }} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
106
+ <path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
107
+ </svg>
108
+ Open source
109
+ </span>
110
+ </div>
111
+ </div>
112
+ </div>
113
+ </div>
114
+ </section>
115
+ );
116
+ }
@@ -0,0 +1,145 @@
1
+ import Link from "next/link";
2
+
3
+ const footerLinks = {
4
+ Product: [
5
+ { label: "Features", href: "/#features" },
6
+ { label: "Download", href: "/download" },
7
+ { label: "Pricing", href: "/pricing" },
8
+ { label: "Docs", href: "/docs" },
9
+ ],
10
+ Developers: [
11
+ { label: "CLI Reference", href: "/docs/cli" },
12
+ { label: "API Reference", href: "/docs/api" },
13
+ { label: "MCP Integration", href: "/docs/mcp" },
14
+ { label: "Self-Hosting Guide", href: "/docs/self-hosting" },
15
+ ],
16
+ Company: [
17
+ { label: "Blog", href: "/blog" },
18
+ { label: "About", href: "/about" },
19
+ { label: "Contact", href: "/contact" },
20
+ { label: "Brand", href: "/brand" },
21
+ ],
22
+ Legal: [
23
+ { label: "Privacy", href: "/privacy" },
24
+ { label: "Terms", href: "/terms" },
25
+ { label: "License (MIT)", href: "https://github.com/openshiporg/openship/blob/main/LICENSE" },
26
+ ],
27
+ };
28
+
29
+ export function Footer() {
30
+ return (
31
+ <footer className="border-t border-[var(--th-bd-subtle)]">
32
+ <div className="mx-auto max-w-7xl px-6 py-16 sm:py-20">
33
+ <div className="grid gap-12 sm:grid-cols-2 lg:grid-cols-5">
34
+ {/* Brand column */}
35
+ <div className="lg:col-span-1">
36
+ <Link href="/" className="flex items-center gap-2.5">
37
+ <div
38
+ className="h-7 w-7 shrink-0 rounded-full border-[2px] border-[var(--th-text-heading)]"
39
+ aria-hidden="true"
40
+ />
41
+ <span className="th-text-heading text-base font-semibold tracking-tight">
42
+ Openship
43
+ </span>
44
+ </Link>
45
+ <p className="th-text-muted mt-4 max-w-xs text-sm leading-relaxed">
46
+ Open-source desktop app for deploying anything to your server. Download, connect, deploy.
47
+ </p>
48
+ </div>
49
+
50
+ {/* Link columns */}
51
+ {Object.entries(footerLinks).map(([heading, links]) => (
52
+ <div key={heading}>
53
+ <h4 className="th-text-strong text-sm font-semibold">{heading}</h4>
54
+ <ul className="mt-4 space-y-3">
55
+ {links.map((link) => (
56
+ <li key={link.label}>
57
+ <Link
58
+ href={link.href}
59
+ className="th-text-secondary text-sm transition-colors hover:text-[var(--th-text-strong)]"
60
+ >
61
+ {link.label}
62
+ </Link>
63
+ </li>
64
+ ))}
65
+ </ul>
66
+ </div>
67
+ ))}
68
+ </div>
69
+
70
+ {/* Bottom bar */}
71
+ <div className="section-divider mt-12" />
72
+ <div className="mt-8 flex flex-col items-center justify-between gap-6 sm:flex-row">
73
+ <p className="th-text-muted text-sm">
74
+ &copy; {new Date().getFullYear()} Oblien LLC. All rights reserved.
75
+ </p>
76
+
77
+ {/* Oblien attribution */}
78
+ <a
79
+ href="https://oblien.com"
80
+ target="_blank"
81
+ rel="noopener noreferrer"
82
+ className="flex items-center gap-2 th-text-muted transition-colors hover:text-[var(--th-text-strong)]"
83
+ >
84
+ <span className="text-[13px]">An</span>
85
+ <span
86
+ className="inline-block h-[16px] w-[60px]"
87
+ style={{
88
+ backgroundColor: "var(--th-text-heading)",
89
+ maskImage: "url(https://oblien.com/logo.svg)",
90
+ WebkitMaskImage: "url(https://oblien.com/logo.svg)",
91
+ maskSize: "contain",
92
+ WebkitMaskSize: "contain",
93
+ maskRepeat: "no-repeat",
94
+ WebkitMaskRepeat: "no-repeat",
95
+ maskPosition: "center",
96
+ WebkitMaskPosition: "center",
97
+ }}
98
+ aria-label="Oblien"
99
+ />
100
+ <span className="text-[13px]">project</span>
101
+ </a>
102
+
103
+ <div className="flex items-center gap-5">
104
+ {/* GitHub */}
105
+ <a
106
+ href="https://github.com/openshiporg/openship"
107
+ target="_blank"
108
+ rel="noopener noreferrer"
109
+ className="th-text-muted transition-colors hover:text-[var(--th-text-strong)]"
110
+ aria-label="GitHub"
111
+ >
112
+ <svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
113
+ <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
114
+ </svg>
115
+ </a>
116
+ {/* X / Twitter */}
117
+ <a
118
+ href="https://x.com/openship"
119
+ target="_blank"
120
+ rel="noopener noreferrer"
121
+ className="th-text-muted transition-colors hover:text-[var(--th-text-strong)]"
122
+ aria-label="X (Twitter)"
123
+ >
124
+ <svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
125
+ <path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z" />
126
+ </svg>
127
+ </a>
128
+ {/* Discord */}
129
+ <a
130
+ href="https://discord.gg/openship"
131
+ target="_blank"
132
+ rel="noopener noreferrer"
133
+ className="th-text-muted transition-colors hover:text-[var(--th-text-strong)]"
134
+ aria-label="Discord"
135
+ >
136
+ <svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
137
+ <path d="M20.317 4.37a19.791 19.791 0 00-4.885-1.515.074.074 0 00-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 00-5.487 0 12.64 12.64 0 00-.617-1.25.077.077 0 00-.079-.037A19.736 19.736 0 003.677 4.37a.07.07 0 00-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 00.031.057 19.9 19.9 0 005.993 3.03.078.078 0 00.084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 00-.041-.106 13.107 13.107 0 01-1.872-.892.077.077 0 01-.008-.128 10.2 10.2 0 00.372-.292.074.074 0 01.077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 01.078.01c.12.098.246.198.373.292a.077.077 0 01-.006.127 12.299 12.299 0 01-1.873.892.077.077 0 00-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 00.084.028 19.839 19.839 0 006.002-3.03.077.077 0 00.032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 00-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.947 2.418-2.157 2.418z" />
138
+ </svg>
139
+ </a>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </footer>
144
+ );
145
+ }
@@ -0,0 +1,110 @@
1
+ "use client";
2
+
3
+ import { DownloadButton } from "./download-button";
4
+
5
+ const STACKS = [
6
+ { name: 'Next.js', icon: 'https://cdn.simpleicons.org/nextdotjs/000000' },
7
+ { name: 'Node', icon: 'https://cdn.simpleicons.org/nodedotjs/5FA04E' },
8
+ { name: 'Python', icon: 'https://cdn.simpleicons.org/python/3776AB' },
9
+ { name: 'Go', icon: 'https://cdn.simpleicons.org/go/00ADD8' },
10
+ { name: 'Rust', icon: 'https://cdn.simpleicons.org/rust/000000' },
11
+ { name: 'Docker', icon: 'https://cdn.simpleicons.org/docker/2496ED' },
12
+ { name: 'Postgres', icon: 'https://cdn.simpleicons.org/postgresql/4169E1' },
13
+ { name: 'Redis', icon: 'https://cdn.simpleicons.org/redis/FF4438' },
14
+ { name: 'Rails', icon: 'https://cdn.simpleicons.org/rubyonrails/D30001' },
15
+ { name: 'Laravel', icon: 'https://cdn.simpleicons.org/laravel/FF2D20' },
16
+ { name: 'Django', icon: 'https://cdn.simpleicons.org/django/092E20' },
17
+ { name: 'Bun', icon: 'https://cdn.simpleicons.org/bun/000000' },
18
+ ];
19
+
20
+ export function Hero() {
21
+ return (
22
+ <section className="hero-section relative flex min-h-[100dvh] flex-col items-center justify-center overflow-hidden">
23
+ {/* ═══════════════ Background layers ═══════════════ */}
24
+ <div className="hero-grain absolute inset-0" aria-hidden="true" />
25
+ <div className="hero-grid absolute inset-0" aria-hidden="true" />
26
+
27
+ {/* ── Bottom aurora glow ── */}
28
+ <div className="hero-aurora" aria-hidden="true">
29
+ <div className="hero-aurora-core" />
30
+ <div className="hero-aurora-wing hero-aurora-wing--left" />
31
+ <div className="hero-aurora-wing hero-aurora-wing--right" />
32
+ </div>
33
+
34
+ {/* ═══════════════ Content ═══════════════ */}
35
+ <div className="relative z-20 mx-auto w-full max-w-[860px] px-6 text-center">
36
+ {/* Badge */}
37
+ <div className="animate-fade-in-up mb-7 inline-flex items-center gap-2 rounded-full border border-[var(--th-on-06)] bg-white/60 px-4 py-1.5 shadow-[0_1px_3px_rgba(0,0,0,.04)] backdrop-blur-sm">
38
+ <span className="relative flex h-1.5 w-1.5">
39
+ <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--th-accent-violet)] opacity-50" />
40
+ <span className="relative inline-flex h-1.5 w-1.5 rounded-full bg-[var(--th-accent-violet)]" />
41
+ </span>
42
+ <span className="text-[12px] font-medium tracking-[0.02em] th-text-secondary">
43
+ Open Source &middot; Cloud or Self-Hosted
44
+ </span>
45
+ </div>
46
+
47
+ {/* Headline */}
48
+ <h1 className="animate-fade-in-up animate-delay-100">
49
+ <span className="block text-[clamp(2.75rem,6vw,4.75rem)] font-semibold leading-[1.06] tracking-[-0.035em] th-text-heading">
50
+ Deploy Anything.
51
+ </span>
52
+ <span className="hero-headline-second block text-[clamp(2.75rem,6vw,4.75rem)] font-semibold leading-[1.06] tracking-[-0.035em]">
53
+ Own Everything.
54
+ </span>
55
+ </h1>
56
+
57
+ {/* Sub */}
58
+ <p className="animate-fade-in-up animate-delay-200 mx-auto mt-6 max-w-[520px] text-[16px] leading-[1.65] th-text-body">
59
+ Push your code&nbsp;&mdash; AI handles the build, config, and deployment. Use our cloud or connect your own servers. Zero&nbsp;lock&#8209;in, completely&nbsp;open&#8209;source.
60
+ </p>
61
+
62
+ {/* CTAs */}
63
+ <div className="animate-fade-in-up animate-delay-300 mt-9 flex flex-col items-center justify-center gap-3.5 sm:flex-row">
64
+ <DownloadButton size="large" />
65
+ <a
66
+ href="/login"
67
+ className="th-btn-ghost group rounded-full px-7 py-3 text-[15px] font-medium"
68
+ >
69
+ Start Free
70
+ <svg
71
+ className="ml-1.5 -mr-1.5 h-4 w-4 transition-transform group-hover:translate-x-0.5"
72
+ fill="none"
73
+ viewBox="0 0 24 24"
74
+ stroke="currentColor"
75
+ strokeWidth={2.2}
76
+ >
77
+ <path strokeLinecap="round" strokeLinejoin="round" d="M13 7l5 5m0 0l-5 5m5-5H6" />
78
+ </svg>
79
+ </a>
80
+ </div>
81
+ </div>
82
+
83
+ {/* ═══════════════ Stack ticker ═══════════════ */}
84
+ <div className="animate-fade-in-up animate-delay-500 relative z-10 mt-16 w-full max-w-[820px] px-6">
85
+ <p className="mb-6 text-center text-[13px] font-medium uppercase tracking-[0.1em] th-text-muted">
86
+ Designed for your favorite stack
87
+ </p>
88
+ <div className="hero-ticker-mask overflow-hidden">
89
+ <div className="hero-ticker flex w-max items-center gap-12">
90
+ {[0, 1].map((i) => (
91
+ <div key={i} className="flex shrink-0 items-center gap-12">
92
+ {STACKS.map((s) => (
93
+ <div key={`${i}-${s.name}`} className="flex shrink-0 items-center gap-2.5 opacity-50" style={{ filter: 'grayscale(1) brightness(0.45) contrast(1.1)' }}>
94
+ {/* eslint-disable-next-line @next/next/no-img-element */}
95
+ <img src={s.icon} alt={s.name} className="h-[26px] w-[26px] object-contain" loading="lazy" />
96
+ <span className="whitespace-nowrap text-[14px] font-medium th-text-secondary">{s.name}</span>
97
+ </div>
98
+ ))}
99
+ </div>
100
+ ))}
101
+ </div>
102
+ </div>
103
+ </div>
104
+
105
+ {/* Edge fades */}
106
+ <div className="hero-edge-fade-top absolute top-0 left-0 right-0 h-20" aria-hidden="true" />
107
+ <div className="hero-edge-fade-bottom absolute bottom-0 left-0 right-0 h-40" aria-hidden="true" />
108
+ </section>
109
+ );
110
+ }