From b3aa4a4cd3788b85991ab80b32fe42e16f0848e9 Mon Sep 17 00:00:00 2001 From: Guilhem Lemouel Date: Thu, 3 Sep 2026 17:37:08 +0200 Subject: [PATCH] fix(frontend): open the template picker downward and size it from the popover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The popover's default positioning caps its height to the viewport, and the list inside it carried a fixed one, so a capped box overflowed its own frame — visible with the AI composer hidden, where the caption sits high and `placement: top` left almost no room above it. It opens downward now, with flip fallbacks, at a definite `min(72vh, 520px)`; the list fills what the header leaves, which is still the definite height it needs to page. `creating` on the create form becomes `onCreatingChange`: `$bindable(default)` on an optional prop is banned, and this is something the form reports rather than state it shares. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 --- .../components/home/HubTemplatePicker.svelte | 18 ++++----------- .../home/WorkspaceEmptyState.svelte | 17 ++++++++++++-- .../SimpleCreateWorkspace.svelte | 23 ++++++++++++------- .../user/(user)/onboarding/+page.svelte | 5 +++- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/frontend/src/lib/components/home/HubTemplatePicker.svelte b/frontend/src/lib/components/home/HubTemplatePicker.svelte index be594ac831..3930fe47e5 100644 --- a/frontend/src/lib/components/home/HubTemplatePicker.svelte +++ b/frontend/src/lib/components/home/HubTemplatePicker.svelte @@ -16,7 +16,6 @@ let { onPick }: Props = $props() let list: InfiniteList | undefined = $state(undefined) - let loaded = $state(0) // The hub serves its whole catalogue in one response, so paging happens here: the list // asks for a window and gets a slice of what `hubProjectCatalogue` already holds. Should @@ -46,7 +45,9 @@ }) -
+ +

@@ -62,17 +63,8 @@ — imported as a folder in this workspace.

- -
- 4 ? 'h-[420px]' : ''} - > +
+ {#snippet customRow({ item }: { item: HubProjectPick })} {@const Icon = hubAppIcon(item.iconApps[0] ?? '')} diff --git a/frontend/src/lib/components/home/WorkspaceEmptyState.svelte b/frontend/src/lib/components/home/WorkspaceEmptyState.svelte index caa99b7a55..0dc547f2cb 100644 --- a/frontend/src/lib/components/home/WorkspaceEmptyState.svelte +++ b/frontend/src/lib/components/home/WorkspaceEmptyState.svelte @@ -68,9 +68,22 @@ class="border-t border-dashed border-border-light px-4 pb-[22px] pt-[18px] text-center text-[13.5px] leading-relaxed text-hint" > Your scripts, flows and apps will show up here. + e.detail && logFeatureUsage('home', 'template_picker_open')} diff --git a/frontend/src/lib/components/workspaceSettings/SimpleCreateWorkspace.svelte b/frontend/src/lib/components/workspaceSettings/SimpleCreateWorkspace.svelte index 5ce3c163c8..7e79f9e838 100644 --- a/frontend/src/lib/components/workspaceSettings/SimpleCreateWorkspace.svelte +++ b/frontend/src/lib/components/workspaceSettings/SimpleCreateWorkspace.svelte @@ -22,16 +22,23 @@ /** Where to go once the workspace exists. It is already the active one by then. */ onCreated: (workspaceId: string) => void /** - * True from the click until the navigation, so a surface with chrome of its own around - * this form — onboarding's Previous button — can stand down for the hand-over instead - * of offering a way back out of a workspace that now exists. + * Told when the form starts handing over to the new workspace and if it comes back, so + * a surface with chrome of its own around this one — onboarding's Previous button — can + * stand down for the hand-over instead of offering a way back out of a workspace that + * now exists. A callback rather than a bound prop: this is something the form reports, + * not state it shares, and `$bindable(default)` on an optional prop is banned. */ - creating?: boolean + onCreatingChange?: (creating: boolean) => void } - let { onCreated, creating = $bindable(false) }: Props = $props() + let { onCreated, onCreatingChange }: Props = $props() let name = $state('') + let creating = $state(false) + function setCreating(next: boolean) { + creating = next + onCreatingChange?.(next) + } // The full form — id, colour, username, invites — for the person who wants it. Forced on // when the instance does not derive usernames: one is required and a name field has @@ -91,7 +98,7 @@ async function create() { if (problem || creating) return - creating = true + setCreating(true) const workspaceName = name.trim() const started = Date.now() try { @@ -102,7 +109,7 @@ true ) advanced = true - creating = false + setCreating(false) return } await WorkspaceService.createWorkspace({ @@ -123,7 +130,7 @@ } catch (error) { console.error('Could not create the workspace:', error) sendUserToast('Could not create the workspace: ' + (error?.body || error?.message), true) - creating = false + setCreating(false) } } diff --git a/frontend/src/routes/(root)/(logged)/user/(user)/onboarding/+page.svelte b/frontend/src/routes/(root)/(logged)/user/(user)/onboarding/+page.svelte index e574112557..4b3c0f95cc 100644 --- a/frontend/src/routes/(root)/(logged)/user/(user)/onboarding/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/user/(user)/onboarding/+page.svelte @@ -315,7 +315,10 @@ - + (creatingWorkspace = v)} + /> {#if !skippedSurvey && !creatingWorkspace}