Skip to content

Commit 5910712

Browse files
committed
fix(welcome): pixel-perfect WelcomeTab matching Figma start screens
Rewrite WelcomeTab to match Figma nodes 1027:23374, 645:12763, 1125:18513, and 1239:21482 exactly: - Replace old brain icon + shortcuts layout with centered title text and AI prompt input matching Figma workspace content - Title: Figtree 32px/40px weight 500, centered, color #FCFCFC - AI input container: bg #1C1C1D, border 1px solid #2E2F31, border-radius 16px, width 686px (standard) / 100% (compact) - Action bar: attach button, Build/model selector pills, send button (circular, bg #4C4C4D when active) - Add compact prop for narrow viewport variant (node 1239:21482) - All typography uses var(--cortex-font-sans) (Figtree) - Background uses var(--cortex-bg-primary) for theme consistency
1 parent 05a88f2 commit 5910712

File tree

1 file changed

+256
-61
lines changed

1 file changed

+256
-61
lines changed

src/components/editor/WelcomeTab.tsx

Lines changed: 256 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,309 @@
11
/**
2-
* WelcomeTab - Welcome screen shown when no files are open
2+
* WelcomeTab - Welcome/Start screen shown when no files are open
33
*
4-
* Displays Cortex IDE branding and keyboard shortcut hints
5-
* to help users get started. Styled with CortexTokens.
4+
* Pixel-perfect implementation matching Figma screens:
5+
* - 1027:23374 (IDE start screen with sidebar expanded)
6+
* - 645:12763 (start screen with sidebar collapsed)
7+
* - 1125:18513 (start screen no sidebar)
8+
* - 1239:21482 (compact option)
9+
*
10+
* Layout: centered container with title text + AI prompt input
11+
* Typography: Figtree 32px/40px weight 500 for title
12+
* Input: bg #1C1C1D, border 1px #2E2F31, border-radius 16px
613
*/
714

8-
import { type JSX } from "solid-js";
9-
import { Icon } from "../ui/Icon";
10-
import { CortexTokens } from "@/design-system/tokens/cortex-tokens";
15+
import { type JSX, createSignal } from "solid-js";
1116

1217
export interface WelcomeTabProps {
1318
class?: string;
1419
style?: JSX.CSSProperties;
20+
compact?: boolean;
1521
}
1622

1723
export function WelcomeTab(props: WelcomeTabProps) {
18-
const containerStyle = (): JSX.CSSProperties => ({
24+
const [inputValue, setInputValue] = createSignal("");
25+
const [inputFocused, setInputFocused] = createSignal(false);
26+
27+
const handleKeyDown = (e: KeyboardEvent) => {
28+
if (e.key === "Enter" && !e.shiftKey) {
29+
e.preventDefault();
30+
const value = inputValue().trim();
31+
if (value) {
32+
window.dispatchEvent(
33+
new CustomEvent("chat:submit", { detail: { message: value } })
34+
);
35+
setInputValue("");
36+
}
37+
}
38+
};
39+
40+
const handleSendClick = () => {
41+
const value = inputValue().trim();
42+
if (value) {
43+
window.dispatchEvent(
44+
new CustomEvent("chat:submit", { detail: { message: value } })
45+
);
46+
setInputValue("");
47+
}
48+
};
49+
50+
const workspaceStyle = (): JSX.CSSProperties => ({
1951
display: "flex",
2052
flex: "1",
2153
"flex-direction": "column",
2254
"align-items": "center",
2355
"justify-content": "center",
24-
gap: "32px",
25-
background: CortexTokens.colors.bg.primary,
56+
background: "var(--cortex-bg-primary)",
2657
"min-height": "0",
2758
...props.style,
2859
});
2960

30-
const brandStyle: JSX.CSSProperties = {
61+
const containerStyle = (): JSX.CSSProperties => ({
3162
display: "flex",
3263
"flex-direction": "column",
3364
"align-items": "center",
34-
gap: "12px",
65+
gap: "28px",
66+
"max-width": props.compact ? "none" : "922px",
67+
width: props.compact ? "auto" : "100%",
68+
});
69+
70+
const titleStyle: JSX.CSSProperties = {
71+
margin: "0",
72+
"font-family": "var(--cortex-font-sans)",
73+
"font-size": "32px",
74+
"font-weight": "500",
75+
"line-height": "40px",
76+
"letter-spacing": "0px",
77+
"text-align": "center",
78+
color: "#FCFCFC",
79+
width: "100%",
3580
};
3681

37-
const logoStyle: JSX.CSSProperties = {
38-
width: "48px",
82+
const inputContainerStyle = (): JSX.CSSProperties => ({
83+
display: "flex",
84+
"flex-direction": "column",
85+
width: props.compact ? "100%" : "686px",
86+
background: "#1C1C1D",
87+
border: inputFocused()
88+
? "1px solid var(--cortex-accent-primary)"
89+
: "1px solid #2E2F31",
90+
"border-radius": "16px",
91+
overflow: "hidden",
92+
transition: "border-color 150ms ease",
93+
});
94+
95+
const typeAreaStyle: JSX.CSSProperties = {
96+
display: "flex",
97+
"align-items": "center",
98+
gap: "8px",
99+
padding: "16px",
39100
height: "48px",
40-
color: CortexTokens.colors.accent.primary,
41-
opacity: "0.6",
101+
"box-sizing": "border-box",
42102
};
43103

44-
const titleStyle: JSX.CSSProperties = {
104+
const inputStyle: JSX.CSSProperties = {
105+
flex: "1",
106+
background: "transparent",
107+
border: "none",
108+
outline: "none",
109+
color: "#FCFCFC",
110+
"font-family": "var(--cortex-font-sans)",
111+
"font-size": "14px",
112+
"font-weight": "400",
113+
"line-height": "16px",
114+
padding: "0",
45115
margin: "0",
46-
"font-size": "20px",
47-
"font-weight": "600",
48-
color: CortexTokens.colors.text.primary,
49-
"font-family": "var(--cortex-font-sans, Inter, system-ui, sans-serif)",
50-
"letter-spacing": "-0.02em",
51116
};
52117

53-
const subtitleStyle: JSX.CSSProperties = {
54-
margin: "0",
55-
"font-size": "14px",
56-
color: CortexTokens.colors.text.muted,
57-
"font-family": "var(--cortex-font-sans, Inter, system-ui, sans-serif)",
118+
const actionAreaStyle: JSX.CSSProperties = {
119+
display: "flex",
120+
"align-items": "center",
121+
"justify-content": "space-between",
122+
padding: "0 16px 16px 16px",
123+
height: "44px",
124+
"box-sizing": "border-box",
58125
};
59126

60-
const shortcutsStyle: JSX.CSSProperties = {
127+
const attachButtonStyle: JSX.CSSProperties = {
61128
display: "flex",
62-
"flex-direction": "column",
63-
gap: "8px",
129+
"align-items": "center",
130+
"justify-content": "center",
131+
width: "28px",
132+
height: "28px",
133+
background: "transparent",
134+
border: "none",
135+
"border-radius": "8px",
136+
cursor: "pointer",
137+
padding: "0",
138+
color: "#8C8D8F",
64139
};
65140

66-
const shortcutRowStyle: JSX.CSSProperties = {
141+
const actionsRightStyle: JSX.CSSProperties = {
67142
display: "flex",
68143
"align-items": "center",
69144
gap: "12px",
70-
"font-size": "13px",
71-
color: CortexTokens.colors.text.secondary,
72-
"font-family": "var(--cortex-font-sans, Inter, system-ui, sans-serif)",
73145
};
74146

75-
const kbdStyle: JSX.CSSProperties = {
147+
const pillButtonStyle: JSX.CSSProperties = {
76148
display: "inline-flex",
77149
"align-items": "center",
78-
"justify-content": "center",
79-
"min-width": "24px",
80-
padding: "2px 8px",
81-
"font-size": "12px",
82-
"font-family": "var(--cortex-font-mono, 'JetBrains Mono', monospace)",
83-
background: CortexTokens.colors.bg.elevated,
84-
border: `1px solid ${CortexTokens.colors.border.default}`,
85-
"border-radius": "var(--cortex-radius-xs, 4px)",
86-
color: CortexTokens.colors.text.primary,
150+
gap: "4px",
151+
padding: "6px",
152+
background: "transparent",
153+
border: "none",
154+
"border-radius": "8px",
155+
cursor: "pointer",
156+
"font-family": "var(--cortex-font-sans)",
157+
"font-size": "14px",
158+
"font-weight": "500",
159+
"line-height": "16px",
160+
color: "#FCFCFC",
87161
"white-space": "nowrap",
88162
};
89163

90-
const shortcuts = [
91-
{ keys: "Ctrl+P", label: "Quick Open File" },
92-
{ keys: "Ctrl+N", label: "New File" },
93-
{ keys: "Ctrl+O", label: "Open File" },
94-
{ keys: "Ctrl+Shift+P", label: "Command Palette" },
95-
];
164+
const sendButtonStyle = (): JSX.CSSProperties => ({
165+
display: "flex",
166+
"align-items": "center",
167+
"justify-content": "center",
168+
width: "28px",
169+
height: "28px",
170+
background: inputValue().trim() ? "#4C4C4D" : "#2E2F31",
171+
border: "none",
172+
"border-radius": "999px",
173+
cursor: inputValue().trim() ? "pointer" : "default",
174+
padding: "0",
175+
transition: "background 100ms ease",
176+
});
96177

97178
return (
98-
<div class={props.class} style={containerStyle()}>
99-
<div style={brandStyle}>
100-
<Icon name="brain" style={logoStyle} />
101-
<h2 style={titleStyle}>Cortex IDE</h2>
102-
<p style={subtitleStyle}>AI-Powered Development Environment</p>
103-
</div>
179+
<div class={props.class} style={workspaceStyle()}>
180+
<div style={containerStyle()}>
181+
<h2 style={titleStyle}>
182+
Hey, start building or open your project.
183+
</h2>
184+
185+
<div style={inputContainerStyle()}>
186+
{/* Type area */}
187+
<div style={typeAreaStyle}>
188+
<input
189+
type="text"
190+
value={inputValue()}
191+
placeholder="Ask Cortex anything..."
192+
style={inputStyle}
193+
onInput={(e) => setInputValue(e.currentTarget.value)}
194+
onKeyDown={handleKeyDown}
195+
onFocus={() => setInputFocused(true)}
196+
onBlur={() => setInputFocused(false)}
197+
/>
198+
</div>
199+
200+
{/* Action area */}
201+
<div style={actionAreaStyle}>
202+
<button style={attachButtonStyle} aria-label="Attach file">
203+
<svg
204+
width="16"
205+
height="16"
206+
viewBox="0 0 16 16"
207+
fill="none"
208+
xmlns="http://www.w3.org/2000/svg"
209+
>
210+
<path
211+
d="M14.1667 7.36666L8.18 13.3533C7.31222 14.2211 6.13777 14.7088 4.91333 14.7088C3.6889 14.7088 2.51445 14.2211 1.64667 13.3533C0.778889 12.4856 0.291199 11.3111 0.291199 10.0867C0.291199 8.86222 0.778889 7.68777 1.64667 6.82L7.63333 0.833328C8.21222 0.254438 9.00222 -0.0722656 9.82667 -0.0722656C10.6511 -0.0722656 11.4411 0.254438 12.02 0.833328C12.5989 1.41222 12.9256 2.20222 12.9256 3.02667C12.9256 3.85111 12.5989 4.64111 12.02 5.22L5.98 11.2067C5.69056 11.4961 5.29556 11.6594 4.88333 11.6594C4.47111 11.6594 4.07611 11.4961 3.78667 11.2067C3.49722 10.9172 3.33389 10.5222 3.33389 10.11C3.33389 9.69778 3.49722 9.30278 3.78667 9.01333L9.22 3.58"
212+
stroke="currentColor"
213+
stroke-width="1.2"
214+
stroke-linecap="round"
215+
stroke-linejoin="round"
216+
/>
217+
</svg>
218+
</button>
219+
220+
<div style={actionsRightStyle}>
221+
<div style={{ display: "flex", "align-items": "center", gap: "4px" }}>
222+
<button style={pillButtonStyle}>
223+
<svg
224+
width="16"
225+
height="16"
226+
viewBox="0 0 16 16"
227+
fill="none"
228+
xmlns="http://www.w3.org/2000/svg"
229+
>
230+
<path
231+
d="M8 1L10 5L14.5 5.5L11.25 8.5L12 13L8 10.5L4 13L4.75 8.5L1.5 5.5L6 5L8 1Z"
232+
fill="#FF4081"
233+
/>
234+
</svg>
235+
<span>Build</span>
236+
<svg
237+
width="16"
238+
height="16"
239+
viewBox="0 0 16 16"
240+
fill="none"
241+
xmlns="http://www.w3.org/2000/svg"
242+
>
243+
<path
244+
d="M4 6L8 10L12 6"
245+
stroke="#8C8D8F"
246+
stroke-width="1.5"
247+
stroke-linecap="round"
248+
stroke-linejoin="round"
249+
/>
250+
</svg>
251+
</button>
252+
253+
<button style={pillButtonStyle}>
254+
<svg
255+
width="16"
256+
height="16"
257+
viewBox="0 0 16 16"
258+
fill="none"
259+
xmlns="http://www.w3.org/2000/svg"
260+
>
261+
<circle cx="8" cy="8" r="6" fill="#D97757" />
262+
</svg>
263+
<span>Claude-Opus-4.5</span>
264+
<svg
265+
width="16"
266+
height="16"
267+
viewBox="0 0 16 16"
268+
fill="none"
269+
xmlns="http://www.w3.org/2000/svg"
270+
>
271+
<path
272+
d="M4 6L8 10L12 6"
273+
stroke="#8C8D8F"
274+
stroke-width="1.5"
275+
stroke-linecap="round"
276+
stroke-linejoin="round"
277+
/>
278+
</svg>
279+
</button>
280+
</div>
104281

105-
<div style={shortcutsStyle}>
106-
{shortcuts.map((shortcut) => (
107-
<div style={shortcutRowStyle}>
108-
<kbd style={kbdStyle}>{shortcut.keys}</kbd>
109-
<span>{shortcut.label}</span>
282+
<button
283+
style={sendButtonStyle()}
284+
onClick={handleSendClick}
285+
aria-label="Send message"
286+
>
287+
<svg
288+
width="16"
289+
height="16"
290+
viewBox="0 0 16 16"
291+
fill="none"
292+
xmlns="http://www.w3.org/2000/svg"
293+
>
294+
<path
295+
d="M14.5 1.5L7.5 8.5M14.5 1.5L10 14.5L7.5 8.5M14.5 1.5L1.5 6L7.5 8.5"
296+
stroke={inputValue().trim() ? "#0D0D0E" : "#8C8D8F"}
297+
stroke-width="1.5"
298+
stroke-linecap="round"
299+
stroke-linejoin="round"
300+
fill="none"
301+
/>
302+
</svg>
303+
</button>
304+
</div>
110305
</div>
111-
))}
306+
</div>
112307
</div>
113308
</div>
114309
);

0 commit comments

Comments
 (0)