-
Notifications
You must be signed in to change notification settings - Fork 3.4k
fix: emcn component library design engineering polish #3672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: staging
Are you sure you want to change the base?
Changes from all commits
9229227
d9fa7f7
9547361
0a2562b
977f4cb
2f83f87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -356,7 +356,7 @@ export default function LoginPage({ | |
| <h1 className='font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'> | ||
| Sign in | ||
| </h1> | ||
| <p className='font-[430] font-season text-[#F6F6F6]/60 text-[18px] leading-[125%] tracking-[0.02em]'> | ||
| <p className='font-[430] font-season text-[var(--text-primary)]/60 text-lg leading-[125%] tracking-[0.02em]'> | ||
| Enter your details | ||
| </p> | ||
| </div> | ||
|
|
@@ -374,7 +374,7 @@ export default function LoginPage({ | |
|
|
||
| {/* Password reset success message */} | ||
| {resetSuccessMessage && ( | ||
| <div className='mt-1 space-y-1 text-[#4CAF50] text-xs'> | ||
| <div className='mt-1 space-y-1 text-[var(--success)] text-xs'> | ||
| <p>{resetSuccessMessage}</p> | ||
| </div> | ||
| )} | ||
|
|
@@ -387,76 +387,100 @@ export default function LoginPage({ | |
| <div className='flex items-center justify-between'> | ||
| <Label htmlFor='email'>Email</Label> | ||
| </div> | ||
| <Input | ||
| id='email' | ||
| name='email' | ||
| placeholder='Enter your email' | ||
| required | ||
| autoCapitalize='none' | ||
| autoComplete='email' | ||
| autoCorrect='off' | ||
| value={email} | ||
| onChange={handleEmailChange} | ||
| className={cn( | ||
| showEmailValidationError && | ||
| emailErrors.length > 0 && | ||
| 'border-red-500 focus:border-red-500' | ||
| )} | ||
| /> | ||
| {showEmailValidationError && emailErrors.length > 0 && ( | ||
| <div className='mt-1 space-y-1 text-red-400 text-xs'> | ||
| {emailErrors.map((error, index) => ( | ||
| <p key={index}>{error}</p> | ||
| ))} | ||
| <div className='relative'> | ||
| <Input | ||
| id='email' | ||
| name='email' | ||
| placeholder='Enter your email' | ||
| required | ||
| autoCapitalize='none' | ||
| autoComplete='email' | ||
| autoCorrect='off' | ||
| value={email} | ||
| onChange={handleEmailChange} | ||
| className={cn( | ||
| showEmailValidationError && | ||
| emailErrors.length > 0 && | ||
| 'border-red-500 focus:border-red-500' | ||
| )} | ||
| /> | ||
| <div | ||
| className={cn( | ||
| 'absolute right-0 left-0 z-10 grid transition-[grid-template-rows] duration-200 ease-out', | ||
| showEmailValidationError && emailErrors.length > 0 | ||
| ? 'grid-rows-[1fr]' | ||
| : 'grid-rows-[0fr]' | ||
| )} | ||
| aria-live='polite' | ||
| > | ||
| <div className='overflow-hidden'> | ||
| <div className='mt-1 space-y-1 text-red-400 text-xs'> | ||
| {emailErrors.map((error, index) => ( | ||
| <p key={index}>{error}</p> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| )} | ||
| </div> | ||
| </div> | ||
| <div className='space-y-2'> | ||
| <div className='flex items-center justify-between'> | ||
| <Label htmlFor='password'>Password</Label> | ||
| <button | ||
| type='button' | ||
| onClick={() => setForgotPasswordOpen(true)} | ||
| className='font-medium text-[#999] text-xs transition hover:text-[#ECECEC]' | ||
| className='font-medium text-[var(--text-subtle)] text-xs transition hover:text-[var(--landing-text)]' | ||
| > | ||
| Forgot password? | ||
| </button> | ||
| </div> | ||
| <div className='relative'> | ||
| <Input | ||
| id='password' | ||
| name='password' | ||
| required | ||
| type={showPassword ? 'text' : 'password'} | ||
| autoCapitalize='none' | ||
| autoComplete='current-password' | ||
| autoCorrect='off' | ||
| placeholder='Enter your password' | ||
| value={password} | ||
| onChange={handlePasswordChange} | ||
| <div className='relative'> | ||
| <Input | ||
| id='password' | ||
| name='password' | ||
| required | ||
| type={showPassword ? 'text' : 'password'} | ||
| autoCapitalize='none' | ||
| autoComplete='current-password' | ||
| autoCorrect='off' | ||
| placeholder='Enter your password' | ||
| value={password} | ||
| onChange={handlePasswordChange} | ||
| className={cn( | ||
| 'pr-10', | ||
| showValidationError && | ||
| passwordErrors.length > 0 && | ||
| 'border-red-500 focus:border-red-500' | ||
| )} | ||
| /> | ||
| <button | ||
| type='button' | ||
| onClick={() => setShowPassword(!showPassword)} | ||
| className='-translate-y-1/2 absolute top-1/2 right-3 text-[var(--text-subtle)] transition hover:text-[var(--landing-text)]' | ||
| aria-label={showPassword ? 'Hide password' : 'Show password'} | ||
| > | ||
| {showPassword ? <EyeOff size={18} /> : <Eye size={18} />} | ||
| </button> | ||
| </div> | ||
| <div | ||
| className={cn( | ||
| 'pr-10', | ||
| showValidationError && | ||
| passwordErrors.length > 0 && | ||
| 'border-red-500 focus:border-red-500' | ||
| 'absolute right-0 left-0 z-10 grid transition-[grid-template-rows] duration-200 ease-out', | ||
| showValidationError && passwordErrors.length > 0 | ||
| ? 'grid-rows-[1fr]' | ||
| : 'grid-rows-[0fr]' | ||
| )} | ||
| /> | ||
| <button | ||
| type='button' | ||
| onClick={() => setShowPassword(!showPassword)} | ||
| className='-translate-y-1/2 absolute top-1/2 right-3 text-[#999] transition hover:text-[#ECECEC]' | ||
| aria-label={showPassword ? 'Hide password' : 'Show password'} | ||
| aria-live='polite' | ||
| > | ||
| {showPassword ? <EyeOff size={18} /> : <Eye size={18} />} | ||
| </button> | ||
| </div> | ||
| {showValidationError && passwordErrors.length > 0 && ( | ||
| <div className='mt-1 space-y-1 text-red-400 text-xs'> | ||
| {passwordErrors.map((error, index) => ( | ||
| <p key={index}>{error}</p> | ||
| ))} | ||
| <div className='overflow-hidden'> | ||
| <div className='mt-1 space-y-1 text-red-400 text-xs'> | ||
| {passwordErrors.map((error, index) => ( | ||
| <p key={index}>{error}</p> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| )} | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
|
|
@@ -465,6 +489,7 @@ export default function LoginPage({ | |
| disabled={isLoading} | ||
| loading={isLoading} | ||
| loadingText='Signing in' | ||
| className='!mt-6' | ||
| > | ||
| Sign in | ||
| </BrandedButton> | ||
|
|
@@ -475,10 +500,10 @@ export default function LoginPage({ | |
| {showDivider && ( | ||
| <div className='relative my-6 font-light'> | ||
| <div className='absolute inset-0 flex items-center'> | ||
| <div className='w-full border-[#2A2A2A] border-t' /> | ||
| <div className='w-full border-[var(--surface-4)] border-t' /> | ||
| </div> | ||
| <div className='relative flex justify-center text-sm'> | ||
| <span className='bg-[#1C1C1C] px-4 font-[340] text-[#999]'>Or continue with</span> | ||
| <span className='bg-[var(--text-primary)] px-4 font-[340] text-[var(--text-subtle)]'>Or continue with</span> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Divider span background matches surrounding section backgroundMedium Severity The "Or continue with" divider text uses Additional Locations (1) |
||
| </div> | ||
| </div> | ||
| )} | ||
|
|
@@ -504,24 +529,24 @@ export default function LoginPage({ | |
|
|
||
| {/* Only show signup link if email/password signup is enabled */} | ||
| {!isFalsy(getEnv('NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED')) && ( | ||
| <div className='pt-6 text-center font-light text-[14px]'> | ||
| <div className='pt-6 text-center font-light text-sm'> | ||
| <span className='font-normal'>Don't have an account? </span> | ||
| <Link | ||
| href={isInviteFlow ? `/signup?invite_flow=true&callbackUrl=${callbackUrl}` : '/signup'} | ||
| className='font-medium text-[#ECECEC] underline-offset-4 transition hover:text-white hover:underline' | ||
| className='font-medium text-[var(--landing-text)] underline-offset-4 transition hover:text-white hover:underline' | ||
| > | ||
| Sign up | ||
| </Link> | ||
| </div> | ||
| )} | ||
|
|
||
| <div className='absolute right-0 bottom-0 left-0 px-8 pb-8 text-center font-[340] text-[#999] text-[13px] leading-relaxed sm:px-8 md:px-[44px]'> | ||
| <div className='absolute right-0 bottom-0 left-0 px-8 pb-8 text-center font-[340] text-[var(--text-subtle)] text-small leading-relaxed sm:px-8 md:px-[44px]'> | ||
| By signing in, you agree to our{' '} | ||
| <Link | ||
| href='/terms' | ||
| target='_blank' | ||
| rel='noopener noreferrer' | ||
| className='text-[#999] underline-offset-4 transition hover:text-[#ECECEC] hover:underline' | ||
| className='text-[var(--text-subtle)] underline-offset-4 transition hover:text-[var(--landing-text)] hover:underline' | ||
| > | ||
| Terms of Service | ||
| </Link>{' '} | ||
|
|
@@ -530,7 +555,7 @@ export default function LoginPage({ | |
| href='/privacy' | ||
| target='_blank' | ||
| rel='noopener noreferrer' | ||
| className='text-[#999] underline-offset-4 transition hover:text-[#ECECEC] hover:underline' | ||
| className='text-[var(--text-subtle)] underline-offset-4 transition hover:text-[var(--landing-text)] hover:underline' | ||
| > | ||
| Privacy Policy | ||
| </Link> | ||
|
|
@@ -558,17 +583,33 @@ export default function LoginPage({ | |
| resetStatus.type === 'error' && 'border-red-500 focus:border-red-500' | ||
| )} | ||
| /> | ||
| {resetStatus.type === 'error' && ( | ||
| <div className='mt-1 text-red-400 text-xs'> | ||
| <p>{resetStatus.message}</p> | ||
| <div | ||
| className={cn( | ||
| 'grid transition-[grid-template-rows] duration-200 ease-out', | ||
| resetStatus.type === 'error' ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]' | ||
| )} | ||
| aria-live='polite' | ||
| > | ||
| <div className='overflow-hidden'> | ||
| <div className='mt-1 text-red-400 text-xs'> | ||
| <p>{resetStatus.message}</p> | ||
| </div> | ||
| </div> | ||
| )} | ||
| </div> | ||
| </div> | ||
| {resetStatus.type === 'success' && ( | ||
| <div className='mt-1 text-[#4CAF50] text-xs'> | ||
| <p>{resetStatus.message}</p> | ||
| <div | ||
| className={cn( | ||
| 'grid transition-[grid-template-rows] duration-200 ease-out', | ||
| resetStatus.type === 'success' ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]' | ||
| )} | ||
| aria-live='polite' | ||
| > | ||
| <div className='overflow-hidden'> | ||
| <div className='mt-1 text-[var(--success)] text-xs'> | ||
| <p>{resetStatus.message}</p> | ||
| </div> | ||
| </div> | ||
| )} | ||
| </div> | ||
| <BrandedButton | ||
| type='button' | ||
| onClick={handleForgotPassword} | ||
|
|
@@ -584,4 +625,4 @@ export default function LoginPage({ | |
| </Modal> | ||
| </> | ||
| ) | ||
| } | ||
| } | ||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auth dark backgrounds become light using text-primary token
High Severity
Auth pages explicitly set the
.darkclass, where--text-primaryresolves to#e6e6e6(light). Replacingbg-[#1C1C1C](near-black) withbg-[var(--text-primary)]turns dark backgrounds light — the auth background, header, and "Or continue with" divider span all become light gray instead of near-black, breaking the dark auth page design entirely.Additional Locations (2)
apps/sim/app/(auth)/auth-layout-client.tsx#L17-L18apps/sim/app/(auth)/login/login-form.tsx#L535-L536