summaryrefslogtreecommitdiffhomepage
path: root/cloud/web/src/pages/components
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-08-29 23:32:17 -0400
committerFrank <[email protected]>2025-08-29 23:32:17 -0400
commit37f284f9a97d3354143d64fc76c2eb9f7d9ccf9e (patch)
tree053db9abcb2178c71b22ebeadd07f920750ef5d2 /cloud/web/src/pages/components
parent0178eab29bda2f1b37a29543cd313ede48ad3977 (diff)
downloadopencode-37f284f9a97d3354143d64fc76c2eb9f7d9ccf9e.tar.gz
opencode-37f284f9a97d3354143d64fc76c2eb9f7d9ccf9e.zip
wip: cloud
Diffstat (limited to 'cloud/web/src/pages/components')
-rw-r--r--cloud/web/src/pages/components/context-api.tsx24
-rw-r--r--cloud/web/src/pages/components/context-workspace.tsx38
-rw-r--r--cloud/web/src/pages/components/layout.module.css199
-rw-r--r--cloud/web/src/pages/components/layout.tsx96
4 files changed, 0 insertions, 357 deletions
diff --git a/cloud/web/src/pages/components/context-api.tsx b/cloud/web/src/pages/components/context-api.tsx
deleted file mode 100644
index 0a348f48f..000000000
--- a/cloud/web/src/pages/components/context-api.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { hc } from "hono/client"
-import { ApiType } from "@opencode/cloud-function/src/gateway"
-import { useWorkspace } from "./context-workspace"
-import { useOpenAuth } from "../../components/context-openauth"
-
-export function useApi() {
- const workspace = useWorkspace()
- const auth = useOpenAuth()
- return hc<ApiType>(import.meta.env.VITE_API_URL, {
- async fetch(...args: Parameters<typeof fetch>): Promise<Response> {
- const [input, init] = args
- const request = input instanceof Request ? input : new Request(input, init)
- const headers = new Headers(request.headers)
- headers.set("authorization", `Bearer ${await auth.access()}`)
- headers.set("x-opencode-workspace", workspace.id)
- return fetch(
- new Request(request, {
- ...init,
- headers,
- }),
- )
- },
- })
-}
diff --git a/cloud/web/src/pages/components/context-workspace.tsx b/cloud/web/src/pages/components/context-workspace.tsx
deleted file mode 100644
index 6bad39840..000000000
--- a/cloud/web/src/pages/components/context-workspace.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { useNavigate, useParams } from "@solidjs/router"
-import { createInitializedContext } from "../../util/context"
-import { useAccount } from "../../components/context-account"
-import { createEffect, createMemo } from "solid-js"
-
-export const { use: useWorkspace, provider: WorkspaceProvider } =
- createInitializedContext("WorkspaceProvider", () => {
- const params = useParams()
- const account = useAccount()
- const workspace = createMemo(() =>
- account.current?.workspaces.find(
- (x) => x.id === params.workspace || x.slug === params.workspace,
- ),
- )
- const nav = useNavigate()
-
- createEffect(() => {
- if (!workspace()) nav("/")
- })
-
- const result = () => workspace()!
- result.ready = true
-
- return {
- get id() {
- return workspace()!.id
- },
- get slug() {
- return workspace()!.slug
- },
- get name() {
- return workspace()!.name
- },
- get ready() {
- return workspace() !== undefined
- },
- }
- })
diff --git a/cloud/web/src/pages/components/layout.module.css b/cloud/web/src/pages/components/layout.module.css
deleted file mode 100644
index c64faa18e..000000000
--- a/cloud/web/src/pages/components/layout.module.css
+++ /dev/null
@@ -1,199 +0,0 @@
-.root {
- --padding: var(--space-10);
- --vertical-padding: var(--space-8);
- --heading-font-size: var(--font-size-4xl);
- --sidebar-width: 200px;
- --mobile-breakpoint: 40rem;
- --topbar-height: 60px;
-
- margin: var(--space-4);
- border: 2px solid var(--color-border);
- height: calc(100vh - var(--space-8));
- display: flex;
- flex-direction: row;
- overflow: hidden;
- /* Prevent overall scrolling */
- position: relative;
-}
-
-[data-component="mobile-top-bar"] {
- display: none;
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- height: var(--topbar-height);
- background: var(--color-background);
- border-bottom: 2px solid var(--color-border);
- z-index: 20;
- align-items: center;
- padding: 0 var(--space-4) 0 0;
-
- [data-slot="logo"] {
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
-
- div {
- text-transform: uppercase;
- font-weight: 600;
- letter-spacing: -0.03125rem;
- }
-
- svg {
- height: 28px;
- width: auto;
- color: var(--color-white);
- }
- }
-
- [data-slot="toggle"] {
- background: transparent;
- border: none;
- padding: var(--space-4);
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
-
- & svg {
- width: 24px;
- height: 24px;
- color: var(--color-foreground);
- }
- }
-}
-
-[data-component="sidebar"] {
- width: var(--sidebar-width);
- border-right: 2px solid var(--color-border);
- display: flex;
- flex-direction: column;
- padding: calc(var(--padding) / 2);
- overflow-y: auto;
- /* Allow scrolling if needed */
- position: sticky;
- top: 0;
- height: 100%;
- background-color: var(--color-background);
- z-index: 10;
-
- [data-slot="logo"] {
- margin-top: 2px;
- margin-bottom: var(--space-7);
- color: var(--color-white);
-
- & svg {
- height: 32px;
- width: auto;
- }
- }
-
- [data-slot="nav"] {
- flex: 1;
-
- ul {
- list-style-type: none;
- padding: 0;
- }
-
- li {
- margin-bottom: calc(var(--vertical-padding) / 2);
- text-transform: uppercase;
- font-weight: 500;
- }
-
- a {
- display: block;
- padding: var(--space-2) 0;
- }
- }
-
- [data-slot="user"] {
- [data-component="button"] {
- padding-left: 0;
- padding-bottom: 0;
- height: auto;
- }
- }
-}
-
-.navActiveLink {
- cursor: default;
- text-decoration: none;
-}
-
-[data-slot="main-content"] {
- flex: 1;
- display: flex;
- flex-direction: column;
- height: 100%;
- /* Full height */
- overflow: hidden;
- /* Prevent overflow */
- position: relative;
- /* For positioning footer */
- width: 100%;
- /* Full width */
-}
-
-/* Backdrop for mobile */
-[data-component="backdrop"] {
- display: none;
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- /* background-color: rgba(0, 0, 0, 0.5); */
- z-index: 25;
- backdrop-filter: blur(2px);
-}
-
-/* Mobile styles */
-@media (max-width: 40rem) {
- .root {
- margin: 0;
- border: none;
- height: 100vh;
- }
-
- [data-component="mobile-top-bar"] {
- display: flex;
- }
-
- [data-component="backdrop"] {
- display: block;
- }
-
- [data-component="sidebar"] {
- position: fixed;
- left: -100%;
- top: 0;
- height: 100vh;
- width: 80%;
- max-width: 280px;
- transition: left 0.3s ease-in-out;
- box-shadow: none;
- z-index: 30;
- padding: var(--space-8);
- background-color: var(--color-bg);
-
- &[data-opened="true"] {
- left: 0;
- box-shadow: 8px 0 0px 0px var(--color-gray-4);
- }
- }
-
- [data-slot="main-content"] {
- padding-top: var(--topbar-height);
- /* Add space for the top bar */
- overflow-y: auto;
- }
-
- /* Hide the logo in the sidebar on mobile since it's in the top bar */
- [data-component="sidebar"] [data-slot="logo"] {
- display: none;
- }
-}
diff --git a/cloud/web/src/pages/components/layout.tsx b/cloud/web/src/pages/components/layout.tsx
deleted file mode 100644
index 711ed8fc2..000000000
--- a/cloud/web/src/pages/components/layout.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import style from "./layout.module.css"
-import { useAccount } from "../../components/context-account"
-import { Button } from "../../ui/button"
-import { IconLogomark } from "../../ui/svg"
-import { IconBars3BottomLeft } from "../../ui/svg/icons"
-import { ParentProps, createMemo, createSignal } from "solid-js"
-import { A, useLocation } from "@solidjs/router"
-import { useOpenAuth } from "../../components/context-openauth"
-
-export default function Layout(props: ParentProps) {
- const auth = useOpenAuth()
- const account = useAccount()
- const [sidebarOpen, setSidebarOpen] = createSignal(false)
- const location = useLocation()
-
- const workspaceId = createMemo(() => account.current?.workspaces[0].id)
- const pageTitle = createMemo(() => {
- const path = location.pathname
- if (path.endsWith("/billing")) return "Billing"
- if (path.endsWith("/keys")) return "API Keys"
- return null
- })
-
- function handleLogout() {
- auth.logout(auth.subject?.id!)
- }
-
- return (
- <div class={style.root}>
- {/* Mobile top bar */}
- <div data-component="mobile-top-bar">
- <button data-slot="toggle" onClick={() => setSidebarOpen(!sidebarOpen())}>
- <IconBars3BottomLeft />
- </button>
-
- <div data-slot="logo">
- {pageTitle() ? (
- <div>{pageTitle()}</div>
- ) : (
- <A href="/">
- <IconLogomark />
- </A>
- )}
- </div>
- </div>
-
- {/* Backdrop for mobile sidebar - closes sidebar when clicked */}
- {sidebarOpen() && <div data-component="backdrop" onClick={() => setSidebarOpen(false)}></div>}
-
- <div data-component="sidebar" data-opened={sidebarOpen() ? "true" : "false"}>
- <div data-slot="logo">
- <A href="/">
- <IconLogomark />
- </A>
- </div>
-
- <nav data-slot="nav">
- <ul>
- <li>
- <A end activeClass={style.navActiveLink} href={`/${workspaceId()}`} onClick={() => setSidebarOpen(false)}>
- Chat
- </A>
- </li>
- <li>
- <A
- activeClass={style.navActiveLink}
- href={`/${workspaceId()}/billing`}
- onClick={() => setSidebarOpen(false)}
- >
- Billing
- </A>
- </li>
- <li>
- <A
- activeClass={style.navActiveLink}
- href={`/${workspaceId()}/keys`}
- onClick={() => setSidebarOpen(false)}
- >
- API Keys
- </A>
- </li>
- </ul>
- </nav>
-
- <div data-slot="user">
- <Button color="ghost" onClick={handleLogout} title={account.current?.email || ""}>
- Logout
- </Button>
- </div>
- </div>
-
- {/* Main Content */}
- <div data-slot="main-content">{props.children}</div>
- </div>
- )
-}