Skip to content

Commit aca474a

Browse files
committed
feat(core): restyle two-factor selection and challenge pages
Provider tiles become list rows with an icon chip, description in maxcontrast and a chevron, with hover and visible focus styles. Secondary actions (another method, backup code, cancel) are grouped in one block under a divider with button-like hit areas. The code input and submit button get a larger, full-width style shared through .two-factor-code-input and .two-factor-submit, and the backup code input uses autocomplete="one-time-code". The setup selection and setup challenge pages use the same classes. Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
1 parent af0233a commit aca474a

7 files changed

Lines changed: 187 additions & 66 deletions

File tree

‎apps/twofactor_backupcodes/templates/challenge.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<p><?php p($l->t('Use one of the backup codes you saved when setting up two-factor authentication.')) ?></p>
1414

1515
<form method="POST" class="challenge-form">
16-
<input type="text" class="challenge" name="challenge" required="required" autofocus autocomplete="off" autocapitalize="off" placeholder="<?php p($l->t('Backup code')) ?>">
16+
<input type="text" class="challenge two-factor-code-input" name="challenge" required="required" autofocus autocomplete="one-time-code" autocapitalize="off" placeholder="<?php p($l->t('Backup code')) ?>">
1717
<button class="two-factor-submit primary" type="submit">
1818
<?php p($l->t('Submit')); ?>
1919
</button>

‎core/css/guest.scss‎

Lines changed: 143 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -438,61 +438,179 @@ form .warning input[type='checkbox']+label {
438438
// Same size as login box and dashboard panels
439439
width: 320px;
440440
box-sizing: border-box;
441+
padding: calc(4 * var(--default-grid-baseline));
442+
}
443+
444+
.two-factor-providers {
445+
display: flex;
446+
flex-direction: column;
447+
gap: calc(2 * var(--default-grid-baseline));
448+
margin-top: calc(4 * var(--default-grid-baseline));
441449
}
442450

443451
.two-factor-provider {
444452
display: flex;
445-
border-radius: 3px; /* --border-radius */
446-
margin: 12px 0;
447-
border: 1px solid transparent;
448-
text-align: start;
449453
align-items: center;
454+
box-sizing: border-box;
455+
width: 100%;
456+
gap: calc(2.5 * var(--default-grid-baseline));
457+
padding: calc(3 * var(--default-grid-baseline)) calc(2 * var(--default-grid-baseline));
458+
border-radius: var(--border-radius-large);
459+
text-align: start;
450460
text-decoration: none !important;
451461

452462
&:hover,
453-
&:focus,
454-
&:active {
455-
border: 1px solid #fff;
463+
&:focus-visible {
464+
background-color: var(--color-background-hover);
456465
}
457-
img {
458-
width: 64px;
459-
height: 64px;
460-
padding: 0 12px;
466+
467+
&:focus-visible {
468+
outline: 2px solid var(--color-main-text);
469+
outline-offset: -2px;
470+
}
471+
472+
&::after {
473+
content: '';
474+
flex: none;
475+
width: 12px;
476+
height: 12px;
477+
background: url('../img/actions/arrow-right.svg') no-repeat center / 12px;
478+
filter: var(--background-invert-if-dark);
479+
opacity: .6;
480+
}
481+
482+
&:dir(rtl)::after {
483+
transform: scaleX(-1);
461484
}
485+
462486
div {
463-
margin: 12px 0;
487+
flex: 1;
488+
min-width: 0;
464489
}
490+
465491
h3 {
466492
margin: 0;
467493
}
494+
468495
p {
496+
margin: var(--default-grid-baseline) 0 0;
469497
font-weight: normal;
498+
font-size: var(--font-size-small, 13px);
499+
line-height: 1.35;
500+
color: var(--color-text-maxcontrast);
501+
}
502+
}
503+
504+
.two-factor-provider-icon {
505+
display: grid;
506+
flex: none;
507+
place-items: center;
508+
width: 40px;
509+
height: 40px;
510+
border-radius: 50%;
511+
background-color: var(--color-primary-element-light);
512+
513+
img {
514+
width: 24px;
515+
height: 24px;
516+
filter: var(--background-invert-if-bright);
470517
}
471518
}
472519

473520
.two-factor-icon {
474-
width: 100px;
475521
display: block;
476-
margin: 0 auto;
522+
width: 48px;
523+
margin: 0 auto calc(3 * var(--default-grid-baseline));
524+
filter: var(--background-invert-if-bright);
525+
}
526+
527+
.two-factor-code-input {
528+
width: 100% !important;
529+
height: 52px !important;
530+
margin: 0 0 calc(3 * var(--default-grid-baseline)) !important;
531+
font-size: 20px !important;
532+
text-align: center;
533+
534+
&::placeholder {
535+
font-size: inherit;
536+
}
537+
}
538+
539+
.two-factor-code-digits {
540+
padding-inline-start: .5em !important;
541+
font-family: ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace;
542+
font-size: 26px !important;
543+
font-weight: bold;
544+
letter-spacing: .5em;
545+
546+
&::placeholder {
547+
color: var(--color-text-maxcontrast);
548+
}
477549
}
478550

479-
.two-factor-submit {
551+
.two-factor .two-factor-submit {
480552
width: 100%;
481-
padding: 10px;
482-
margin: 0 0 5px 0;
483-
border-radius: 100px; /* --border-radius-pill */
484-
font-size: 20px;
553+
min-height: 48px;
554+
margin: 0;
555+
border-radius: var(--border-radius-element);
556+
font-size: 16px;
557+
font-weight: bold;
485558
}
486559

487560
.two-factor-primary {
488-
/* Fix for 'Use backup codes' button not taking correct styles */
489-
padding: 14px !important;
490-
width: 226px;
561+
display: block !important;
562+
width: 100%;
563+
margin-top: calc(3 * var(--default-grid-baseline));
491564
}
492565

493-
.two-factor-secondary {
494-
display: inline-block;
495-
padding: 12px;
566+
.two-factor-actions {
567+
display: flex;
568+
flex-direction: column;
569+
gap: calc(2 * var(--default-grid-baseline));
570+
margin-top: calc(6 * var(--default-grid-baseline));
571+
padding-top: calc(5 * var(--default-grid-baseline));
572+
border-top: 1px solid var(--color-border-dark);
573+
574+
a {
575+
display: flex;
576+
align-items: center;
577+
justify-content: center;
578+
gap: calc(2 * var(--default-grid-baseline));
579+
min-height: var(--default-clickable-area);
580+
border-radius: var(--border-radius-element);
581+
font-weight: bold;
582+
583+
&:hover,
584+
&:focus-visible {
585+
background-color: var(--color-background-hover);
586+
}
587+
588+
&:focus-visible {
589+
outline: 2px solid var(--color-main-text);
590+
outline-offset: -2px;
591+
}
592+
}
593+
594+
.two-factor-action-switch::before,
595+
.two-factor-action-backup::before {
596+
content: '';
597+
width: 16px;
598+
height: 16px;
599+
background: no-repeat center / 16px;
600+
filter: var(--background-invert-if-dark);
601+
}
602+
603+
.two-factor-action-switch::before {
604+
background-image: url('../img/actions/change.svg');
605+
}
606+
607+
.two-factor-action-backup::before {
608+
background-image: url('../img/actions/password.svg');
609+
}
610+
611+
#cancel-login {
612+
color: var(--color-text-error);
613+
}
496614
}
497615

498616

‎core/css/styles.scss‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,6 @@ body {
106106
text-align: center;
107107
}
108108

109-
.two-factor-provider {
110-
text-align: center;
111-
width: 100% !important;
112-
display: inline-block;
113-
margin-bottom: 0 !important;
114-
background-color: var(--color-background-darker) !important;
115-
border: none !important;
116-
}
117-
118109
.two-factor-link {
119110
display: inline-block;
120111
padding: 12px;

‎core/templates/twofactorselectchallenge.php‎

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<?php endif; ?>
3838
</p>
3939
<?php else: ?>
40-
<ul>
40+
<ul class="two-factor-providers">
4141
<?php foreach ($_['providers'] as $provider): ?>
4242
<li>
4343
<a class="two-factor-provider"
@@ -54,7 +54,7 @@
5454
$icon = image_path('core', 'actions/password-white.svg');
5555
}
5656
?>
57-
<img src="<?php p($icon) ?>" alt="" />
57+
<span class="two-factor-provider-icon"><img src="<?php p($icon) ?>" alt="" /></span>
5858
<div>
5959
<h3><?php p($provider->getDisplayName()) ?></h3>
6060
<p><?php p($provider->getDescription()) ?></p>
@@ -64,19 +64,29 @@
6464
<?php endforeach; ?>
6565
</ul>
6666
<?php endif ?>
67-
<?php if (!is_null($_['backupProvider'])): ?>
68-
<p>
69-
<a class="<?php if ($noProviders): ?>button primary two-factor-primary<?php else: ?>two-factor-secondary<?php endif ?>" href="<?php p(\OCP\Server::get(\OCP\IURLGenerator::class)->linkToRoute('core.TwoFactorChallenge.showChallenge',
67+
<?php if (!is_null($_['backupProvider']) && $noProviders): ?>
68+
<a class="button primary two-factor-primary" href="<?php p(\OCP\Server::get(\OCP\IURLGenerator::class)->linkToRoute('core.TwoFactorChallenge.showChallenge',
69+
[
70+
'challengeProviderId' => $_['backupProvider']->getId(),
71+
'redirect_url' => $_['redirect_url'],
72+
]
73+
)) ?>">
74+
<?php p($l->t('Use backup code')) ?>
75+
</a>
76+
<?php endif; ?>
77+
<div class="two-factor-actions">
78+
<?php if (!is_null($_['backupProvider']) && !$noProviders): ?>
79+
<a class="two-factor-action-backup" href="<?php p(\OCP\Server::get(\OCP\IURLGenerator::class)->linkToRoute('core.TwoFactorChallenge.showChallenge',
7080
[
7181
'challengeProviderId' => $_['backupProvider']->getId(),
7282
'redirect_url' => $_['redirect_url'],
7383
]
7484
)) ?>">
7585
<?php p($l->t('Use backup code')) ?>
7686
</a>
77-
</p>
78-
<?php endif; ?>
79-
<p><a id="cancel-login" class="two-factor-secondary" href="<?php print_unescaped($_['logout_url']); ?>">
80-
<?php p($l->t('Cancel login')) ?>
81-
</a></p>
87+
<?php endif; ?>
88+
<a id="cancel-login" href="<?php print_unescaped($_['logout_url']); ?>">
89+
<?php p($l->t('Cancel login')) ?>
90+
</a>
91+
</div>
8292
</div>

‎core/templates/twofactorsetupchallenge.php‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
<div class="body-login-container update">
1515
<h2 class="two-factor-header"><?php p($provider->getDisplayName()); ?></h2>
1616
<?php print_unescaped($template); ?>
17-
<p><a id="cancel-login" class="two-factor-secondary" href="<?php print_unescaped($_['logout_url']); ?>">
17+
<div class="two-factor-actions">
18+
<a id="cancel-login" href="<?php print_unescaped($_['logout_url']); ?>">
1819
<?php p($l->t('Cancel login')) ?>
19-
</a></p>
20+
</a>
21+
</div>
2022
</div>

‎core/templates/twofactorsetupselection.php‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
*/
77

88
?>
9-
<div class="body-login-container update">
9+
<div class="body-login-container update two-factor">
1010
<h2 class="two-factor-header"><?php p($l->t('Set up two-factor authentication')) ?></h2>
1111
<?php p($l->t('Enhanced security is enforced for your account. Choose which provider to set up:')) ?>
12-
<ul>
12+
<ul class="two-factor-providers">
1313
<?php foreach ($_['providers'] as $provider): ?>
1414
<li>
1515
<a class="two-factor-provider"
@@ -26,7 +26,7 @@
2626
$icon = image_path('core', 'actions/password-white.svg');
2727
}
2828
?>
29-
<img src="<?php p($icon) ?>" alt="" />
29+
<span class="two-factor-provider-icon"><img src="<?php p($icon) ?>" alt="" /></span>
3030
<div>
3131
<h3><?php p($provider->getDisplayName()) ?></h3>
3232
<p><?php p($provider->getDescription()) ?></p>
@@ -35,7 +35,9 @@
3535
</li>
3636
<?php endforeach; ?>
3737
</ul>
38-
<p><a id="cancel-login" class="two-factor-secondary" href="<?php print_unescaped($_['logout_url']); ?>">
39-
<?php p($l->t('Cancel login')) ?>
40-
</a></p>
38+
<div class="two-factor-actions">
39+
<a id="cancel-login" href="<?php print_unescaped($_['logout_url']); ?>">
40+
<?php p($l->t('Cancel login')) ?>
41+
</a>
42+
</div>
4143
</div>

‎core/templates/twofactorshowchallenge.php‎

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,28 @@
2626
<?php endif; ?>
2727
<?php endif; ?>
2828
<?php print_unescaped($template); ?>
29-
<?php if ($_['hasOtherProviders']): ?>
30-
<p>
31-
<a class="two-factor-secondary" href="<?php p(\OCP\Server::get(\OCP\IURLGenerator::class)->linkToRoute('core.TwoFactorChallenge.selectChallenge',
29+
<div class="two-factor-actions">
30+
<?php if ($_['hasOtherProviders']): ?>
31+
<a class="two-factor-action-switch" href="<?php p(\OCP\Server::get(\OCP\IURLGenerator::class)->linkToRoute('core.TwoFactorChallenge.selectChallenge',
3232
[
3333
'redirect_url' => $_['redirect_url'],
3434
]
3535
)) ?>">
3636
<?php p($l->t('Use another method')) ?>
3737
</a>
38-
</p>
39-
<?php endif; ?>
40-
<?php if (!is_null($_['backupProvider'])): ?>
41-
<p>
42-
<a class="two-factor-secondary" href="<?php p(\OCP\Server::get(\OCP\IURLGenerator::class)->linkToRoute('core.TwoFactorChallenge.showChallenge',
38+
<?php endif; ?>
39+
<?php if (!is_null($_['backupProvider'])): ?>
40+
<a class="two-factor-action-backup" href="<?php p(\OCP\Server::get(\OCP\IURLGenerator::class)->linkToRoute('core.TwoFactorChallenge.showChallenge',
4341
[
4442
'challengeProviderId' => $_['backupProvider']->getId(),
4543
'redirect_url' => $_['redirect_url'],
4644
]
4745
)) ?>">
4846
<?php p($l->t('Use backup code')) ?>
4947
</a>
50-
</p>
51-
<?php endif; ?>
52-
<p><a id="cancel-login" class="two-factor-secondary" href="<?php print_unescaped($_['logout_url']); ?>">
53-
<?php p($l->t('Cancel login')) ?>
54-
</a></p>
48+
<?php endif; ?>
49+
<a id="cancel-login" href="<?php print_unescaped($_['logout_url']); ?>">
50+
<?php p($l->t('Cancel login')) ?>
51+
</a>
52+
</div>
5553
</div>

0 commit comments

Comments
 (0)