Skip to content

Commit 96efc2e

Browse files
authored
Adjust login screen for Studio Code UI to align with otehr screens (#3733)
1 parent a9ef350 commit 96efc2e

2 files changed

Lines changed: 147 additions & 23 deletions

File tree

‎apps/studio/src/components/studio-code-session/index.tsx‎

Lines changed: 78 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import {
55
} from '@studio/common/ai/sessions/entry-types';
66
import { QueryClientProvider } from '@tanstack/react-query';
77
import { Spinner } from '@wordpress/components';
8-
import { createInterpolateElement } from '@wordpress/element';
98
import { __ } from '@wordpress/i18n';
10-
import { chevronDown } from '@wordpress/icons';
9+
import { check, chevronDown, Icon as WpIcon } from '@wordpress/icons';
1110
import { privateApis } from '@wordpress/theme';
1211
import { Button as UiButton, Icon } from '@wordpress/ui';
1312
import {
@@ -22,6 +21,9 @@ import {
2221
} from 'react';
2322
import { ArrowIcon } from 'src/components/arrow-icon';
2423
import Button from 'src/components/button';
24+
import { IllustrationGrid } from 'src/components/illustration-grid';
25+
import offlineIcon from 'src/components/offline-icon';
26+
import { Tooltip } from 'src/components/tooltip';
2527
import { useAuth } from 'src/hooks/use-auth';
2628
import { useOffline } from 'src/hooks/use-offline';
2729
import { cx } from 'src/lib/cx';
@@ -33,6 +35,7 @@ import { queryClient } from './query-client';
3335
import { QueuedPrompts } from './queued-prompts';
3436
import { isScrolledToBottom } from './scroll-utils';
3537
import { SiteCreatedDialog } from './site-created-dialog';
38+
import { StudioCodeTabImage } from './studio-code-tab-image';
3639
import styles from './style.module.css';
3740
import { AgentRunProvider, useAgentRun } from './use-agent-run';
3841
import { useExamplePrompts } from './use-example-prompts';
@@ -101,27 +104,80 @@ function SessionHeader( { onNewConversation }: { onNewConversation: () => void }
101104
);
102105
}
103106

104-
function UnauthenticatedNotice( { onAuthenticate }: { onAuthenticate: () => void } ) {
107+
function NoAuth() {
108+
const isOffline = useOffline();
109+
const { authenticate } = useAuth();
110+
const offlineMessage = __( "You're currently offline." );
111+
105112
return (
106-
<div className="px-4 pb-4">
107-
<div className="p-3 rounded border border-frame-border bg-frame/45">
108-
<div className="mb-3 a8c-label-semibold">{ __( 'Hold up!' ) }</div>
109-
<div className="mb-1">
110-
{ __( 'You need to log in to your WordPress.com account to use Studio Code.' ) }
111-
</div>
112-
<div className="mb-3">
113-
{ createInterpolateElement(
114-
__( "If you don't have an account yet, <a>create one for free</a>." ),
115-
{
116-
a: <Button variant="link" onClick={ () => getIpcApi().authenticate( true ) } />,
117-
}
113+
<div className="p-8 flex justify-between max-w-3xl gap-4 overflow-hidden">
114+
<div className="flex flex-col">
115+
<div className="a8c-subtitle mb-1">{ __( 'Build with Studio Code' ) }</div>
116+
<div className="w-[40ch] text-frame-text-secondary a8c-body">
117+
{ __(
118+
'Your AI coding agent for WordPress. Describe what you want and Studio Code builds, edits, and debugs your site.'
118119
) }
119120
</div>
120-
<Button variant="primary" onClick={ onAuthenticate }>
121-
{ __( 'Log in to WordPress.com' ) }
122-
<ArrowIcon />
123-
</Button>
121+
<div className="mt-6">
122+
{ [
123+
__( 'Create and edit themes, plugins, and content.' ),
124+
__( 'Debug issues and run WP-CLI commands.' ),
125+
__( 'Build with built-in feedback loops and agent skills.' ),
126+
].map( ( text ) => (
127+
<div key={ text } className="text-frame-text-secondary a8c-body flex items-center">
128+
<WpIcon className="fill-frame-theme ltr:mr-2 rtl:ml-2 shrink-0" icon={ check } />
129+
{ text }
130+
</div>
131+
) ) }
132+
</div>
133+
<div className="mt-8">
134+
<Tooltip disabled={ ! isOffline } icon={ offlineIcon } text={ offlineMessage }>
135+
<Button
136+
aria-description={ isOffline ? offlineMessage : '' }
137+
aria-disabled={ isOffline }
138+
variant="primary"
139+
onClick={ () => {
140+
if ( isOffline ) {
141+
return;
142+
}
143+
authenticate();
144+
} }
145+
>
146+
{ __( 'Log in to WordPress.com' ) }
147+
<ArrowIcon />
148+
</Button>
149+
</Tooltip>
150+
</div>
151+
<div className="mt-3 w-[40ch] text-frame-text-secondary a8c-body">
152+
<Tooltip
153+
disabled={ ! isOffline }
154+
icon={ offlineIcon }
155+
text={ offlineMessage }
156+
placement="bottom-start"
157+
>
158+
<span>
159+
{ __( 'A WordPress.com account is required to use Studio Code.' ) }{ ' ' }
160+
<Button
161+
aria-description={ isOffline ? offlineMessage : '' }
162+
aria-disabled={ isOffline }
163+
className="!p-0 text-frame-theme hover:opacity-80 h-auto inline-flex items-center"
164+
onClick={ () => {
165+
if ( isOffline ) {
166+
return;
167+
}
168+
getIpcApi().authenticate( true );
169+
} }
170+
>
171+
{ __( 'Create a free account' ) }
172+
<ArrowIcon />
173+
</Button>
174+
</span>
175+
</Tooltip>
176+
</div>
124177
</div>
178+
<IllustrationGrid>
179+
<StudioCodeTabImage />
180+
</IllustrationGrid>
125181
</div>
126182
);
127183
}
@@ -377,11 +433,10 @@ function SessionContent( { selectedSite }: { selectedSite: SiteDetails } ) {
377433
}
378434

379435
function SessionGate( { selectedSite }: { selectedSite: SiteDetails } ) {
380-
const { isAuthenticated, authenticate } = useAuth();
381-
const isOffline = useOffline();
436+
const { isAuthenticated } = useAuth();
382437

383-
if ( ! isAuthenticated && ! isOffline ) {
384-
return <UnauthenticatedNotice onAuthenticate={ authenticate } />;
438+
if ( ! isAuthenticated ) {
439+
return <NoAuth />;
385440
}
386441

387442
return <SessionContent selectedSite={ selectedSite } />;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
export const StudioCodeTabImage = () => (
2+
<svg
3+
width="220"
4+
height="200"
5+
viewBox="0 0 220 200"
6+
fill="none"
7+
xmlns="http://www.w3.org/2000/svg"
8+
>
9+
<style>
10+
{ `
11+
.scti-card { fill: var(--color-frame-surface); }
12+
.scti-dot { fill: var(--color-frame-text); fill-opacity: 0.3; }
13+
.scti-bubble-in { fill: var(--color-frame-text); fill-opacity: 0.08; }
14+
.scti-line { fill: var(--color-frame-text); fill-opacity: 0.25; }
15+
.scti-line-light { fill: white; fill-opacity: 0.7; }
16+
` }
17+
</style>
18+
19+
<g filter="url(#scti-shadow)">
20+
<rect x="24" y="34" width="172" height="132" rx="10" className="scti-card" />
21+
</g>
22+
23+
<circle cx="42" cy="52" r="2.5" className="scti-dot" />
24+
<circle cx="50" cy="52" r="2.5" className="scti-dot" />
25+
<circle cx="58" cy="52" r="2.5" className="scti-dot" />
26+
27+
<rect x="40" y="72" width="92" height="24" rx="12" className="scti-bubble-in" />
28+
<rect x="52" y="81" width="68" height="4" rx="2" className="scti-line" />
29+
30+
<rect x="40" y="104" width="64" height="18" rx="9" className="scti-bubble-in" />
31+
<rect x="52" y="111" width="40" height="4" rx="2" className="scti-line" />
32+
33+
<rect x="92" y="132" width="88" height="24" rx="12" fill="#3858E9" />
34+
<rect x="104" y="141" width="64" height="4" rx="2" className="scti-line-light" />
35+
36+
<path
37+
d="M178 24C178 29 174 34 166 36C174 38 178 43 178 48C178 43 182 38 190 36C182 34 178 29 178 24Z"
38+
fill="#3858E9"
39+
/>
40+
41+
<circle cx="36" cy="120" r="4" fill="#01C404" />
42+
<circle cx="194" cy="150" r="3.5" className="scti-dot" />
43+
44+
<defs>
45+
<filter
46+
id="scti-shadow"
47+
x="14"
48+
y="28"
49+
width="192"
50+
height="152"
51+
filterUnits="userSpaceOnUse"
52+
colorInterpolationFilters="sRGB"
53+
>
54+
<feFlood floodOpacity="0" result="BackgroundImageFix" />
55+
<feColorMatrix
56+
in="SourceAlpha"
57+
type="matrix"
58+
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
59+
result="hardAlpha"
60+
/>
61+
<feOffset dy="3" />
62+
<feGaussianBlur stdDeviation="5" />
63+
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.08 0" />
64+
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow" />
65+
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape" />
66+
</filter>
67+
</defs>
68+
</svg>
69+
);

0 commit comments

Comments
 (0)