Skip to content

Commit ac7f774

Browse files
committed
fix: pixel-perfect workspace/login screens to match Figma specs
- HomeChat: title changed to 'Hey, start building or open your project.' with 32px font, removed logo/subtitle/quick-action buttons, 922px container - CortexPromptInput: 680px max-width, 16px border-radius, separated type area and action bar, 28px send button with full rounding, attach button replaces plus/upload, 28px model selector with 4px gap - CortexAccountPanel: centered sign-in layout with 100px icon area, 'Sign In' title, description text, 32px height buttons with 8px gap and 8px radius - Updated tests to match new UI structure and text content - Removed unused AnimatedLogo, ICON_16, avatarStyle, CortexButton import
1 parent 427d2fa commit ac7f774

File tree

6 files changed

+180
-272
lines changed

6 files changed

+180
-272
lines changed

src/components/cortex/CortexAccountPanel.tsx

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -111,25 +111,79 @@ const ProfileContent: Component = () => {
111111
const [appVersion] = createResource(() => getVersion().catch(() => "0.1.0"));
112112

113113
return (
114-
<div style={{ padding: "24px 20px", display: "flex", "flex-direction": "column", gap: "24px" }}>
115-
<div style={{ display: "flex", "align-items": "center", gap: "16px" }}>
116-
<div style={avatarStyle}>
117-
<CortexIcon name="user" size={32} color="var(--cortex-text-inactive)" />
114+
<div style={{
115+
padding: "12px",
116+
display: "flex",
117+
"flex-direction": "column",
118+
"align-items": "flex-end",
119+
position: "relative",
120+
}}>
121+
{/* Contents: Figma 1304:21901 - column, center, gap 16px */}
122+
<div style={{
123+
display: "flex",
124+
"flex-direction": "column",
125+
"align-items": "center",
126+
gap: "16px",
127+
width: "100%",
128+
}}>
129+
{/* Logo + Sign In title */}
130+
<div style={{
131+
display: "flex",
132+
"flex-direction": "column",
133+
"align-items": "center",
134+
width: "100px",
135+
}}>
136+
<div style={{
137+
width: "100px",
138+
height: "100px",
139+
"border-radius": "12px",
140+
display: "flex",
141+
"align-items": "center",
142+
"justify-content": "center",
143+
}}>
144+
<CortexIcon name="user" size={48} color="var(--cortex-text-inactive)" />
145+
</div>
146+
<div style={{
147+
"font-family": "var(--cortex-font-sans)",
148+
"font-size": "16px",
149+
"font-weight": "500",
150+
color: "var(--cortex-text-primary)",
151+
"text-align": "center",
152+
"line-height": "16px",
153+
width: "100%",
154+
}}>Sign In</div>
118155
</div>
119-
<div>
120-
<div style={{ "font-size": "16px", "font-weight": "500", color: "var(--cortex-text-primary)" }}>User</div>
121-
<div style={{ "font-size": "13px", color: "var(--cortex-text-inactive)", "margin-top": "2px" }}>Not signed in</div>
156+
157+
{/* Description */}
158+
<div style={{
159+
"font-family": "var(--cortex-font-sans)",
160+
"font-size": "12px",
161+
"font-weight": "400",
162+
color: "var(--cortex-text-inactive)",
163+
"text-align": "center",
164+
"line-height": "15px",
165+
width: "100%",
166+
}}>In order to use AI functions you need to connect your Google or GitHub account</div>
167+
168+
{/* Buttons: Figma 1304:21893 - column, gap 8px */}
169+
<div style={{
170+
display: "flex",
171+
"flex-direction": "column",
172+
gap: "8px",
173+
width: "100%",
174+
}}>
175+
<button style={signInBtnStyle}>
176+
<CortexIcon name="git-logo" size={16} color="var(--cortex-text-primary)" />
177+
<span>Continue with GitHub</span>
178+
</button>
179+
<button style={signInBtnStyle}>
180+
<CortexIcon name="globe" size={16} color="var(--cortex-text-primary)" />
181+
<span>Continue with Google</span>
182+
</button>
122183
</div>
123184
</div>
124-
<button style={signInBtnStyle}>
125-
<CortexIcon name="git-logo" size={16} color="var(--cortex-text-primary)" />
126-
<span>Continue with GitHub</span>
127-
</button>
128-
<button style={{ ...signInBtnStyle, "margin-top": "-12px" }}>
129-
<CortexIcon name="globe" size={16} color="var(--cortex-text-primary)" />
130-
<span>Continue with Google</span>
131-
</button>
132-
<div style={{ "margin-top": "auto", "font-size": "12px", color: "var(--cortex-text-inactive)" }}>
185+
186+
<div style={{ "margin-top": "auto", "font-size": "12px", color: "var(--cortex-text-inactive)", padding: "12px 0 0" }}>
133187
Cortex Desktop v{appVersion() ?? "0.1.0"}
134188
</div>
135189
</div>
@@ -252,19 +306,13 @@ const tabIndicatorStyle = {
252306

253307
const contentStyle = { flex: "1", overflow: "auto" as const };
254308

255-
const avatarStyle = {
256-
width: "64px", height: "64px", "border-radius": "var(--cortex-radius-full)",
257-
background: "var(--cortex-bg-hover)",
258-
border: "2px solid var(--cortex-border-default)",
259-
display: "flex", "align-items": "center", "justify-content": "center", "flex-shrink": "0",
260-
};
261-
262309
const signInBtnStyle = {
263-
display: "flex", "align-items": "center", "justify-content": "center", gap: "8px",
264-
padding: "10px 16px", background: "var(--cortex-bg-hover)",
265-
border: "1px solid var(--cortex-border-default)",
266-
"border-radius": "var(--cortex-radius-md)", color: "var(--cortex-text-primary)",
267-
"font-size": "13px", "font-family": "var(--cortex-font-sans)", cursor: "pointer",
310+
display: "flex", "align-items": "center", "justify-content": "center", gap: "4px",
311+
padding: "8px", background: "var(--cortex-border-default)",
312+
border: "none",
313+
"border-radius": "8px", color: "var(--cortex-text-primary)",
314+
"font-size": "14px", "font-weight": "500", "font-family": "var(--cortex-font-sans)",
315+
cursor: "pointer", height: "32px", width: "100%",
268316
};
269317

270318
const placeholderStyle = {

src/components/cortex/CortexChatPanel.tsx

Lines changed: 11 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*/
1111

1212
import { Component, JSX, splitProps, Show, For } from "solid-js";
13-
import { CortexPromptInput, CortexButton } from "./primitives";
13+
import { CortexPromptInput } from "./primitives";
1414
import { ChatMessageBubble } from "./CortexChatMessageBubble";
1515

1616
export type ChatPanelState = "home" | "minimized" | "expanded";
@@ -90,16 +90,7 @@ const PromptInputBlock: Component<InputProps & { style?: JSX.CSSProperties }> =
9090
/>
9191
);
9292

93-
const AnimatedLogo: Component<{ size?: number }> = (props) => (
94-
<img
95-
src="/assets/claude-logo.svg"
96-
alt="Claude"
97-
style={{ width: `${props.size || 120}px`, height: `${props.size || 120}px` }}
98-
/>
99-
);
100-
10193
const FONT = "var(--cortex-font-sans, 'Figtree', sans-serif)";
102-
const ICON_16: JSX.CSSProperties = { width: "16px", height: "16px" };
10394

10495
export const CortexChatPanel: Component<CortexChatPanelProps> = (props) => {
10596
const [local] = splitProps(props, [
@@ -138,76 +129,34 @@ const HomeChat: Component<Omit<CortexChatPanelProps, "state" | "messages">> = (p
138129
width: "100%",
139130
height: "100%",
140131
background: "var(--cortex-bg-primary)",
141-
gap: "24px",
142-
padding: "48px",
143132
position: "relative",
144133
overflow: "hidden",
145134
...props.style,
146135
}}>
147-
<AnimatedLogo size={120} />
148-
149-
{/* Title Container: Figma layout_BJ5RLN - column, center, gap 8px */}
136+
{/* Container: Figma 1239:21710 - column, center, gap 28px, width 922px */}
150137
<div style={{
151138
display: "flex",
152139
"flex-direction": "column",
153140
"align-items": "center",
154-
gap: "8px",
141+
"justify-content": "center",
142+
width: "922px",
143+
"max-width": "100%",
144+
gap: "28px",
155145
}}>
156-
{/* Title: Figtree 56px weight 500, lineHeight 1.14em */}
146+
{/* Title: Figma 1239:21711 - Figtree 32px Medium, lineHeight 40px (125%), centered */}
157147
<h1 style={{
158148
"font-family": FONT,
159-
"font-size": "56px",
149+
"font-size": "32px",
160150
"font-weight": "500",
161151
color: "var(--cortex-text-primary)",
162152
"text-align": "center",
163-
"line-height": "1.14em",
153+
"line-height": "40px",
164154
"letter-spacing": "0px",
165155
margin: "0",
166-
}}>What would you like to build</h1>
167-
168-
{/* Subtitle: Figtree 20px weight 500, lineHeight 1.2em */}
169-
<p style={{
170-
"font-family": FONT,
171-
"font-size": "20px",
172-
"font-weight": "500",
173-
color: "var(--cortex-text-secondary)",
174-
"text-align": "center",
175-
"line-height": "1.2em",
176-
margin: "0",
177-
}}>Start a conversation or open a project</p>
178-
</div>
156+
width: "100%",
157+
}}>Hey, start building or open your project.</h1>
179158

180-
{/* Prompt + Import Options: Figma layout_NRGR04 - column, gap 12px */}
181-
<div style={{
182-
display: "flex",
183-
"flex-direction": "column",
184-
gap: "12px",
185-
}}>
186159
<PromptInputBlock {...props} />
187-
188-
{/* Import Options: Figma layout_L2GHFF - row, justify end, gap 16px, padding 0 16px, width 802px */}
189-
<div style={{
190-
display: "flex",
191-
"align-items": "center",
192-
"justify-content": "flex-end",
193-
gap: "16px",
194-
padding: "0 16px",
195-
width: "802px",
196-
"max-width": "100%",
197-
}}>
198-
<CortexButton variant="secondary" size="xs" onClick={props.onImportDesignClick}>
199-
<img src="/assets/palette.svg" alt="" style={ICON_16} />
200-
Import Design
201-
</CortexButton>
202-
<CortexButton variant="secondary" size="xs" onClick={props.onImportCodeClick}>
203-
<img src="/assets/code.svg" alt="" style={ICON_16} />
204-
Import Code
205-
</CortexButton>
206-
<CortexButton variant="secondary" size="xs" onClick={props.onBuildClick}>
207-
<img src="/assets/brackets-square.svg" alt="" style={ICON_16} />
208-
Build
209-
</CortexButton>
210-
</div>
211160
</div>
212161
</div>
213162
);

src/components/cortex/__tests__/CortexAccountPanel.test.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ describe("CortexAccountPanel", () => {
4343

4444
it("should show Profile tab content by default", () => {
4545
const { container } = render(() => <CortexAccountPanel />);
46-
expect(container.textContent).toContain("User");
47-
expect(container.textContent).toContain("Not signed in");
46+
expect(container.textContent).toContain("Sign In");
47+
expect(container.textContent).toContain("Continue with GitHub");
4848
});
4949
});
5050

@@ -54,10 +54,10 @@ describe("CortexAccountPanel", () => {
5454
expect(container.querySelector('[data-testid="icon-user"]')).toBeTruthy();
5555
});
5656

57-
it("should show User label when not signed in", () => {
57+
it("should show Sign In label when not signed in", () => {
5858
const { container } = render(() => <CortexAccountPanel />);
59-
expect(container.textContent).toContain("User");
60-
expect(container.textContent).toContain("Not signed in");
59+
expect(container.textContent).toContain("Sign In");
60+
expect(container.textContent).toContain("In order to use AI functions you need to connect your Google or GitHub account");
6161
});
6262

6363
it("should display app version placeholder or resolved version", async () => {

src/components/cortex/__tests__/CortexChatPanel.test.tsx

Lines changed: 6 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -174,97 +174,27 @@ describe("CortexChatPanel", () => {
174174
describe("Home State", () => {
175175
it("should render home state by default", () => {
176176
const { container } = render(() => <CortexChatPanel />);
177-
expect(container.textContent).toContain("What would you like to build");
177+
expect(container.textContent).toContain("Hey, start building or open your project.");
178178
});
179179

180180
it("should render home state when state is home", () => {
181181
const { container } = render(() => <CortexChatPanel state="home" />);
182-
expect(container.textContent).toContain("What would you like to build");
183-
expect(container.textContent).toContain("Start a conversation or open a project");
182+
expect(container.textContent).toContain("Hey, start building or open your project.");
184183
});
185184

186185
it("should render prompt input in home state", () => {
187186
const { getByTestId } = render(() => <CortexChatPanel state="home" />);
188187
expect(getByTestId("prompt-input")).toBeTruthy();
189188
});
190189

191-
it("should render quick action buttons in home state", () => {
192-
const { container } = render(() => <CortexChatPanel state="home" />);
193-
expect(container.textContent).toContain("Build");
194-
expect(container.textContent).toContain("Import Code");
195-
expect(container.textContent).toContain("Import Design");
196-
});
197-
198-
it("should call onBuildClick when Build button is clicked", async () => {
199-
const onBuildClick = vi.fn();
200-
const { container } = render(() => (
201-
<CortexChatPanel state="home" onBuildClick={onBuildClick} />
202-
));
203-
204-
const buildButton = Array.from(container.querySelectorAll("button")).find(
205-
(btn) => btn.textContent?.includes("Build")
206-
);
207-
if (buildButton) {
208-
await fireEvent.click(buildButton);
209-
}
210-
211-
expect(onBuildClick).toHaveBeenCalled();
212-
});
213-
214-
it("should call onImportCodeClick when Import Code button is clicked", async () => {
215-
const onImportCodeClick = vi.fn();
216-
const { container } = render(() => (
217-
<CortexChatPanel state="home" onImportCodeClick={onImportCodeClick} />
218-
));
219-
220-
const importButton = Array.from(container.querySelectorAll("button")).find(
221-
(btn) => btn.textContent?.includes("Import Code")
222-
);
223-
if (importButton) {
224-
await fireEvent.click(importButton);
225-
}
226-
227-
expect(onImportCodeClick).toHaveBeenCalled();
228-
});
229-
230-
it("should call onImportDesignClick when Import Design button is clicked", async () => {
231-
const onImportDesignClick = vi.fn();
232-
const { container } = render(() => (
233-
<CortexChatPanel state="home" onImportDesignClick={onImportDesignClick} />
234-
));
235-
236-
const importButton = Array.from(container.querySelectorAll("button")).find(
237-
(btn) => btn.textContent?.includes("Import Design")
238-
);
239-
if (importButton) {
240-
await fireEvent.click(importButton);
241-
}
242-
243-
expect(onImportDesignClick).toHaveBeenCalled();
244-
});
245-
246-
it("should render logo image in home state", () => {
247-
const { container } = render(() => <CortexChatPanel state="home" />);
248-
const logo = container.querySelector("img");
249-
expect(logo).toBeTruthy();
250-
expect(logo?.getAttribute("src")).toBe("/assets/claude-logo.svg");
251-
});
252-
253-
it("should render title as h1 with 56px font size", () => {
190+
it("should render title as h1 with 32px font size", () => {
254191
const { container } = render(() => <CortexChatPanel state="home" />);
255192
const h1 = container.querySelector("h1");
256193
expect(h1).toBeTruthy();
257-
expect(h1?.style.fontSize).toBe("56px");
194+
expect(h1?.style.fontSize).toBe("32px");
258195
expect(h1?.style.fontWeight).toBe("500");
259196
});
260197

261-
it("should render subtitle as p element", () => {
262-
const { container } = render(() => <CortexChatPanel state="home" />);
263-
const subtitle = container.querySelector("p");
264-
expect(subtitle).toBeTruthy();
265-
expect(subtitle?.textContent).toBe("Start a conversation or open a project");
266-
});
267-
268198
it("should center content in home state", () => {
269199
const { container } = render(() => <CortexChatPanel state="home" />);
270200
const root = container.firstElementChild as HTMLElement;
@@ -276,7 +206,7 @@ describe("CortexChatPanel", () => {
276206
describe("Minimized State", () => {
277207
it("should render minimized state", () => {
278208
const { container } = render(() => <CortexChatPanel state="minimized" />);
279-
expect(container.textContent).toContain("What would you like to build");
209+
expect(container.textContent).toContain("What would you like to build?");
280210
});
281211

282212
it("should render minimized title as h2", () => {
@@ -681,7 +611,7 @@ describe("CortexChatPanel", () => {
681611
const { container } = render(() => <CortexChatPanel />);
682612
const h1 = container.querySelector("h1");
683613
expect(h1).toBeTruthy();
684-
expect(container.textContent).toContain("What would you like to build");
614+
expect(container.textContent).toContain("Hey, start building or open your project.");
685615
});
686616
});
687617

0 commit comments

Comments
 (0)