mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-02 18:13:27 +02:00
refactor(onboarding): put the workspace step on the shared frame
It was the only step still measuring at STEP_COLUMN, so its eyebrow, headline and footer CTA started and ended ~150px inside where every other step's did — the page margins visibly moved when you advanced from step 1 to step 2. The step now sits on STEP_FRAME like the other two, with a new STEP_MEASURE capping the prose and the form inside it. Matching the frame is not the same as widening the field: a workspace name does not want an 800px input, so the form keeps its reading measure and left-aligns to the frame instead. The footer row spans the frame, which is what puts the CTA in the same place on all three screens. STEP_MEASURE deliberately does not centre — centring would pull the content off the frame's left edge, undoing the alignment. Its test pins that. Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
STEP_COLUMN,
|
||||
STEP_FRAME,
|
||||
STEP_GUTTER,
|
||||
STEP_MEASURE,
|
||||
StepShellHeader,
|
||||
} from "./step-shell";
|
||||
|
||||
@@ -56,6 +57,15 @@ describe("onboarding step shell", () => {
|
||||
expect(STEP_BLOCK_PADDING).toMatch(/^py-/);
|
||||
});
|
||||
|
||||
// STEP_MEASURE caps prose and form fields inside a step that sits on the
|
||||
// frame. It must NOT centre: centring it would pull the content off the
|
||||
// frame's left edge, which is the alignment the frame exists to provide.
|
||||
it("keeps the in-frame reading measure left-aligned and padding-free", () => {
|
||||
expect(STEP_MEASURE).toMatch(/max-w-\[\d+px\]/);
|
||||
expect(STEP_MEASURE).not.toContain("mx-auto");
|
||||
expect(STEP_MEASURE).not.toMatch(/\bp[xlr]?-/);
|
||||
});
|
||||
|
||||
it("renders Back only when the step can go back", () => {
|
||||
const { unmount } = renderHeader({ currentStep: "workspace" });
|
||||
expect(screen.queryByRole("button", { name: /back/i })).toBeNull();
|
||||
|
||||
@@ -22,15 +22,24 @@ import type { OnboardingStep } from "@multica/core/onboarding";
|
||||
* - STEP_FRAME is the persistent chrome measure. Back and the step
|
||||
* indicator sit on it, identically, on every step, so the one element
|
||||
* that survives every transition never moves.
|
||||
* - STEP_COLUMN is the reading measure for prose and forms. A step may use
|
||||
* the frame instead when its content genuinely needs the width (the
|
||||
* questionnaire's option grid does); both are centred, so the content
|
||||
* stays on the frame's centreline either way.
|
||||
* - STEP_COLUMN is the reading measure for prose and forms, centred. A step
|
||||
* may use the frame instead when its content needs the width (the
|
||||
* questionnaire's option grid, the runtime list) and cap its own prose
|
||||
* with STEP_MEASURE; both are centred, so content stays on the frame's
|
||||
* centreline either way.
|
||||
*/
|
||||
export const STEP_GUTTER = "px-6 sm:px-10 md:px-14 lg:px-16";
|
||||
export const STEP_FRAME = "mx-auto w-full max-w-[920px]";
|
||||
export const STEP_COLUMN = "mx-auto w-full max-w-[620px]";
|
||||
|
||||
/**
|
||||
* Reading measure applied INSIDE the frame, left-aligned rather than centred.
|
||||
* Use it for prose and form fields on a step that sits on STEP_FRAME: the
|
||||
* page margins then match every other step, while a workspace name still gets
|
||||
* an input someone would want to type into instead of an 800px one.
|
||||
*/
|
||||
export const STEP_MEASURE = "max-w-[620px]";
|
||||
|
||||
/** Vertical rhythm shared by every step's scrolling region. */
|
||||
export const STEP_BLOCK_PADDING = "py-10";
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ import { DragStrip } from "@multica/views/platform";
|
||||
import { useLogout } from "../../auth";
|
||||
import {
|
||||
STEP_BLOCK_PADDING,
|
||||
STEP_COLUMN,
|
||||
STEP_FRAME,
|
||||
STEP_MEASURE,
|
||||
STEP_GUTTER,
|
||||
StepShellHeader,
|
||||
} from "../components/step-shell";
|
||||
@@ -309,7 +310,7 @@ export function StepWorkspace({
|
||||
style={fadeStyle}
|
||||
className={cn("min-h-0 flex-1 overflow-y-auto", STEP_GUTTER)}
|
||||
>
|
||||
<div className={cn(STEP_COLUMN, STEP_BLOCK_PADDING)}>
|
||||
<div className={cn(STEP_FRAME, STEP_BLOCK_PADDING)}>
|
||||
<div className="mb-2 text-caption font-medium uppercase tracking-[0.08em] text-muted-foreground">
|
||||
{reusing
|
||||
? workspaceCreationAllowed
|
||||
@@ -328,7 +329,7 @@ export function StepWorkspace({
|
||||
? t(($) => $.step_workspace.headline_first)
|
||||
: t(($) => $.step_workspace.creation_disabled_headline)}
|
||||
</h1>
|
||||
<p className="mt-4 text-body-lg leading-[1.55] text-foreground">
|
||||
<p className={cn("mt-4 text-body-lg leading-[1.55] text-foreground", STEP_MEASURE)}>
|
||||
{reusing
|
||||
? workspaceCreationAllowed
|
||||
? t(($) => $.step_workspace.lede_resume)
|
||||
@@ -338,7 +339,7 @@ export function StepWorkspace({
|
||||
: t(($) => $.step_workspace.creation_disabled_lede)}
|
||||
</p>
|
||||
|
||||
<div className="mt-10">
|
||||
<div className={cn("mt-10", STEP_MEASURE)}>
|
||||
{reusing ? (
|
||||
<div className="flex flex-col gap-3">
|
||||
<ExistingWorkspaceCard
|
||||
|
||||
Reference in New Issue
Block a user