- {filteredWorkspaces.length === 0 ? (
+ {!selectedOrg || filteredWorkspaces.length === 0 ? (
{search.length > 0
@@ -83,10 +75,7 @@ export function WorkspaceList({
workspace={workspace}
selectedOrg={selectedOrg}
handleSelect={handleSelect}
- isSelected={
- selectedOrg.id === selectedOrg.id &&
- selectedWorkspace?.id === workspace.id
- }
+ isSelected={selectedWorkspace?.id === workspace.id}
/>
)}
/>
diff --git a/src/components/WorkspaceSelector/index.stories.tsx b/src/components/WorkspaceSelector/index.stories.tsx
index 39f7e47a..d87f7967 100644
--- a/src/components/WorkspaceSelector/index.stories.tsx
+++ b/src/components/WorkspaceSelector/index.stories.tsx
@@ -246,8 +246,29 @@ const useWorkspaceSelectorState = (initialOrgs: Org[] = sampleData) => {
}
}
+// Props type that preserves the discriminated union
+type WorkspaceSelectorWithStateProps =
+ | ({
+ showCreateWorkspaceView: true
+ defaultSelectedOrg: Org
+ } & Partial<
+ Omit<
+ WorkspaceSelectorProps,
+ 'showCreateWorkspaceView' | 'defaultSelectedOrg'
+ >
+ >)
+ | ({
+ showCreateWorkspaceView?: false
+ defaultSelectedOrg?: Org
+ } & Partial<
+ Omit<
+ WorkspaceSelectorProps,
+ 'showCreateWorkspaceView' | 'defaultSelectedOrg'
+ >
+ >)
+
// Simplified component
-const WorkspaceSelectorWithState = (props: Partial) => {
+const WorkspaceSelectorWithState = (props: WorkspaceSelectorWithStateProps) => {
const state = useWorkspaceSelectorState(props.orgs)
return (
@@ -473,9 +494,9 @@ export const WithCreateWorkspaceViewShownByDefault: Story = {
export const WithSearchableOrgSelector: Story = {
...Default,
render: () => {
+ // Set seed once before generating all orgs for consistent data
+ faker.seed(42)
const orgs = Array.from({ length: 5000 }).map(() => {
- // Set seed to ensure consistent data
- faker.seed(42)
const slug = faker.lorem.slug({ min: 1, max: 3 })
return {
id: faker.string.uuid(),
@@ -486,7 +507,13 @@ export const WithSearchableOrgSelector: Story = {
updatedAt: new Date(),
}
})
- return
+ return (
+
+ )
},
}
diff --git a/src/components/WorkspaceSelector/index.tsx b/src/components/WorkspaceSelector/index.tsx
index 212bc50a..01e84753 100644
--- a/src/components/WorkspaceSelector/index.tsx
+++ b/src/components/WorkspaceSelector/index.tsx
@@ -13,6 +13,7 @@ import { Stack } from '../Stack'
import { CreateOrg } from './CreateOrg'
import { Heading } from '../Heading'
import { GlobalWorkspaceSelectorProps } from '@/types'
+import { cn } from '@/lib/utils'
export interface Org {
id: string
@@ -30,7 +31,7 @@ export interface Workspace {
updatedAt: Date
}
-export interface WorkspaceSelectorProps extends GlobalWorkspaceSelectorProps {
+interface WorkspaceSelectorBaseProps extends GlobalWorkspaceSelectorProps {
onCreateOrg: (newOrgName: string) => Promise
/**
@@ -47,14 +48,22 @@ export interface WorkspaceSelectorProps extends GlobalWorkspaceSelectorProps {
*/
createTriggersSelection?: boolean
- showCreateWorkspaceView?: boolean
-
- defaultSelectedOrg?: Org
-
filterOrgFunc: (org: Org, search: string) => boolean
filterWorkspaceFunc: (workspace: Workspace, search: string) => boolean
}
+export type WorkspaceSelectorProps = WorkspaceSelectorBaseProps &
+ (
+ | {
+ showCreateWorkspaceView: true
+ defaultSelectedOrg: Org
+ }
+ | {
+ showCreateWorkspaceView?: false
+ defaultSelectedOrg?: Org
+ }
+ )
+
const useViewTransition = () => {
const [isTransitioning, setIsTransitioning] = React.useState(false)
@@ -97,8 +106,8 @@ export function WorkspaceSelector({
}: WorkspaceSelectorProps) {
const [selectedWorkspace, setSelectedWorkspace] =
React.useState(null)
- const [selectedOrg, setSelectedOrg] = React.useState(
- defaultSelectedOrg ?? orgs[0]
+ const [selectedOrg, setSelectedOrg] = React.useState(
+ defaultSelectedOrg
)
const [createWorkspaceViewOpen, setCreateWorkspaceViewOpen] = React.useState(
showCreateWorkspaceView ?? false
@@ -166,7 +175,7 @@ export function WorkspaceSelector({
...prev,
workspaces: [...prev.workspaces, workspace],
}
- : null
+ : undefined
)
setNewWorkspaceName('')
setCreateWorkspaceViewOpen(false)
@@ -225,10 +234,14 @@ export function WorkspaceSelector({
)
}, [startTransition])
+ const backToOrgSelector = React.useCallback(() => {
+ setSelectedOrg(undefined)
+ }, [])
+
return (
{createOrgViewOpen ? (
@@ -261,7 +274,7 @@ export function WorkspaceSelector({
style={{
viewTransitionName: isTransitioning ? 'workspace-content' : '',
}}
- className="flex w-full"
+ className="flex w-full flex-col @[640px]:flex-row"
>
)}
@@ -286,7 +300,7 @@ export function WorkspaceSelector({
interface WorkspaceViewContentsProps {
orgs: Org[]
- selectedOrg: Org | null
+ selectedOrg?: Org
selectedWorkspace: Workspace | null
handleSelect: (org: Org, workspace: Workspace, clearSearch: boolean) => void
showRecents: boolean
@@ -298,6 +312,7 @@ interface WorkspaceViewContentsProps {
handleSelectOrg: (org: Org) => void
filterOrgFunc: (org: Org, search: string) => boolean
filterWorkspaceFunc: (workspace: Workspace, search: string) => boolean
+ backToOrgSelector: () => void
}
function WorkspaceViewContents({
@@ -314,6 +329,7 @@ function WorkspaceViewContents({
handleSelectOrg,
filterOrgFunc,
filterWorkspaceFunc,
+ backToOrgSelector,
}: WorkspaceViewContentsProps) {
const showRecentsView = React.useMemo(
() => recents.length > 0 && showRecents,
@@ -321,7 +337,8 @@ function WorkspaceViewContents({
)
return (
<>
-
+ {/* Wide container layout (>= 640px) - Left sidebar with title */}
+
@@ -339,8 +356,15 @@ function WorkspaceViewContents({
-
-
+ {/* Narrow container header (< 640px) */}
+
+
+ Select workspace
+
+
+ {/* Main content area */}
+
+
{showRecentsView ? (
) : orgs.length > 0 ? (
-
-
setShowRecents(true)}
- showRecents={showRecents}
- enableRecents={recents.length > 0}
- filterOrgFunc={(org, search) => filterOrgFunc(org, search)}
- />
-
- handleSelect(org, workspace, false)
- }
- selectedWorkspace={selectedWorkspace}
- filterWorkspaceFunc={(workspace, search) =>
- filterWorkspaceFunc(workspace, search)
- }
- />
+
+ {/* Back button - narrow only, when org selected */}
+
+
+
+
+ {/* OrgList - always in wide, only when no org selected in narrow */}
+
+ setShowRecents(true)}
+ showRecents={showRecents}
+ enableRecents={recents.length > 0}
+ filterOrgFunc={(org, search) => filterOrgFunc(org, search)}
+ />
+
+
+ {/* WorkspaceList - always in wide, only when org selected in narrow */}
+
+
+ handleSelect(org, workspace, false)
+ }
+ selectedWorkspace={selectedWorkspace}
+ filterWorkspaceFunc={(workspace, search) =>
+ filterWorkspaceFunc(workspace, search)
+ }
+ />
+
) : (