summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-10-10 19:39:01 -0400
committerFrank <[email protected]>2025-10-10 19:39:01 -0400
commitf14cd4a3db12161eab93ce6538528ed882439a50 (patch)
tree57a37735611124334190509448e1058de8b74845
parent48008f91ac9d11fef82f2149e5b937381780f577 (diff)
downloadopencode-f14cd4a3db12161eab93ce6538528ed882439a50.tar.gz
opencode-f14cd4a3db12161eab93ce6538528ed882439a50.zip
wip: zen
-rw-r--r--packages/console/app/src/component/modal.css66
-rw-r--r--packages/console/app/src/component/modal.tsx24
-rw-r--r--packages/console/app/src/routes/workspace-picker.css35
-rw-r--r--packages/console/app/src/routes/workspace-picker.tsx28
4 files changed, 125 insertions, 28 deletions
diff --git a/packages/console/app/src/component/modal.css b/packages/console/app/src/component/modal.css
new file mode 100644
index 000000000..23b6831c9
--- /dev/null
+++ b/packages/console/app/src/component/modal.css
@@ -0,0 +1,66 @@
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ }
+}
+
+@keyframes slideUp {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+[data-component="modal"][data-slot="overlay"] {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 9999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(0, 0, 0, 0.5);
+ animation: fadeIn 0.2s ease;
+
+ @media (prefers-color-scheme: dark) {
+ background-color: rgba(0, 0, 0, 0.7);
+ }
+
+ [data-slot="content"] {
+ background-color: var(--color-bg);
+ border: 1px solid var(--color-border);
+ border-radius: var(--border-radius-md);
+ padding: var(--space-6);
+ min-width: 400px;
+ max-width: 90vw;
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
+ animation: slideUp 0.2s ease;
+
+ @media (max-width: 30rem) {
+ min-width: 300px;
+ padding: var(--space-4);
+ }
+
+ @media (prefers-color-scheme: dark) {
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
+ }
+ }
+
+ [data-slot="title"] {
+ margin: 0 0 var(--space-4) 0;
+ font-size: var(--font-size-lg);
+ font-weight: 600;
+ color: var(--color-text);
+ }
+} \ No newline at end of file
diff --git a/packages/console/app/src/component/modal.tsx b/packages/console/app/src/component/modal.tsx
new file mode 100644
index 000000000..d6dc8a3de
--- /dev/null
+++ b/packages/console/app/src/component/modal.tsx
@@ -0,0 +1,24 @@
+import { JSX, Show } from "solid-js"
+import "./modal.css"
+
+interface ModalProps {
+ open: boolean
+ onClose: () => void
+ title?: string
+ children: JSX.Element
+}
+
+export function Modal(props: ModalProps) {
+ return (
+ <Show when={props.open}>
+ <div data-component="modal" data-slot="overlay" onClick={props.onClose}>
+ <div data-slot="content" onClick={(e) => e.stopPropagation()}>
+ <Show when={props.title}>
+ <h2 data-slot="title">{props.title}</h2>
+ </Show>
+ {props.children}
+ </div>
+ </div>
+ </Show>
+ )
+}
diff --git a/packages/console/app/src/routes/workspace-picker.css b/packages/console/app/src/routes/workspace-picker.css
index c174cabe5..dec482286 100644
--- a/packages/console/app/src/routes/workspace-picker.css
+++ b/packages/console/app/src/routes/workspace-picker.css
@@ -1,15 +1,15 @@
[data-component="workspace-picker"] {
position: relative;
- /* Override blue accent colors with neutral colors */
- --color-accent: var(--color-border);
- --color-accent-hover: var(--color-border);
- --color-accent-active: var(--color-border);
- --color-primary: var(--color-border);
- --color-primary-hover: var(--color-border);
- --color-primary-active: var(--color-border);
- --color-primary-alpha-20: transparent;
[data-slot="trigger"] {
+ /* Override blue accent colors with neutral colors for dropdown trigger */
+ --color-accent: var(--color-border);
+ --color-accent-hover: var(--color-border);
+ --color-accent-active: var(--color-border);
+ --color-primary: var(--color-border);
+ --color-primary-hover: var(--color-border);
+ --color-primary-active: var(--color-border);
+ --color-primary-alpha-20: transparent;
display: flex;
align-items: center;
justify-content: space-between;
@@ -73,22 +73,19 @@
}
[data-slot="create-form"] {
- margin-top: var(--space-4);
- padding: var(--space-4);
- border: 1px solid var(--color-border);
- border-radius: var(--border-radius-sm);
- background-color: var(--color-surface);
+ width: 100%;
}
[data-slot="create-input-group"] {
display: flex;
- gap: var(--space-2);
- align-items: center;
+ flex-direction: column;
+ gap: var(--space-3);
+ }
- @media (max-width: 30rem) {
- flex-direction: column;
- align-items: stretch;
- }
+ [data-slot="button-group"] {
+ display: flex;
+ gap: var(--space-2);
+ justify-content: flex-end;
}
[data-slot="create-input"] {
diff --git a/packages/console/app/src/routes/workspace-picker.tsx b/packages/console/app/src/routes/workspace-picker.tsx
index fb77d8f45..51de4cef1 100644
--- a/packages/console/app/src/routes/workspace-picker.tsx
+++ b/packages/console/app/src/routes/workspace-picker.tsx
@@ -8,6 +8,7 @@ import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.j
import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js"
import { Workspace } from "@opencode-ai/console-core/workspace.js"
import { IconChevron } from "~/component/icon"
+import { Modal } from "~/component/modal"
import "./workspace-picker.css"
const getWorkspaces = query(async () => {
@@ -46,6 +47,7 @@ export function WorkspacePicker() {
showDropdown: false,
})
let dropdownRef: HTMLDivElement | undefined
+ let inputRef: HTMLInputElement | undefined
const currentWorkspace = () => {
const ws = workspaces()?.find((w) => w.id === params.id)
@@ -56,6 +58,12 @@ export function WorkspacePicker() {
setStore({ showForm: true, showDropdown: false })
}
+ createEffect(() => {
+ if (store.showForm && inputRef) {
+ setTimeout(() => inputRef?.focus(), 0)
+ }
+ })
+
const handleSelectWorkspace = (workspaceID: string) => {
if (workspaceID === params.id) {
setStore("showDropdown", false)
@@ -112,26 +120,28 @@ export function WorkspacePicker() {
</Show>
</div>
- <Show when={store.showForm}>
+ <Modal open={store.showForm} onClose={() => setStore("showForm", false)} title="Create New Workspace">
<form data-slot="create-form" action={createWorkspace} method="post">
<div data-slot="create-input-group">
<input
+ ref={inputRef}
data-slot="create-input"
type="text"
name="workspaceName"
placeholder="Enter workspace name"
required
- autofocus
/>
- <button type="submit" data-color="primary">
- Create
- </button>
- <button type="button" onClick={() => setStore("showForm", false)}>
- Cancel
- </button>
+ <div data-slot="button-group">
+ <button type="button" data-color="ghost" onClick={() => setStore("showForm", false)}>
+ Cancel
+ </button>
+ <button type="submit" data-color="primary">
+ Create
+ </button>
+ </div>
</div>
</form>
- </Show>
+ </Modal>
</div>
)
}