mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-07-21 23:43:19 +00:00
refactor(frontend): extract oauth primary flow page styles
This commit is contained in:
@@ -49,8 +49,6 @@
|
||||
}
|
||||
|
||||
let loading = $state(true)
|
||||
let showSpinner = $state(false)
|
||||
let loadingTimer: ReturnType<typeof setTimeout> | null = null
|
||||
let error = $state<string | null>(null)
|
||||
let submitting = $state(false)
|
||||
let consentData = $state<ConsentData | null>(null)
|
||||
@@ -140,11 +138,6 @@
|
||||
error = $_('oauth.error.genericError')
|
||||
} finally {
|
||||
loading = false
|
||||
showSpinner = false
|
||||
if (loadingTimer) {
|
||||
clearTimeout(loadingTimer)
|
||||
loadingTimer = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,17 +245,7 @@
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
loadingTimer = setTimeout(() => {
|
||||
if (loading) {
|
||||
showSpinner = true
|
||||
}
|
||||
}, 5000)
|
||||
fetchConsentData()
|
||||
return () => {
|
||||
if (loadingTimer) {
|
||||
clearTimeout(loadingTimer)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let scopeGroups = $derived(consentData ? groupScopesByCategory(consentData.scopes) : [])
|
||||
@@ -297,16 +280,7 @@
|
||||
|
||||
<div class="consent-container">
|
||||
{#if loading}
|
||||
<div class="loading">
|
||||
{#if showSpinner}
|
||||
<div class="loading-content">
|
||||
<div class="spinner"></div>
|
||||
<p>{$_('common.loading')}</p>
|
||||
</div>
|
||||
{:else}
|
||||
<p style="color: var(--text-muted); font-size: 0.875rem;">Loading consent data...</p>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="loading"></div>
|
||||
{:else if error}
|
||||
<div class="error-container">
|
||||
<h1>{$_('oauth.error.title')}</h1>
|
||||
@@ -421,10 +395,10 @@
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="deny-btn" onclick={handleDeny} disabled={submitting}>
|
||||
<button type="button" class="cancel" onclick={handleDeny} disabled={submitting}>
|
||||
{$_('oauth.consent.deny')}
|
||||
</button>
|
||||
<button type="button" class="approve-btn" onclick={submitConsent} disabled={submitting}>
|
||||
<button type="button" onclick={submitConsent} disabled={submitting}>
|
||||
{submitting ? $_('oauth.consent.authorizing') : $_('oauth.consent.authorize')}
|
||||
</button>
|
||||
</div>
|
||||
@@ -443,371 +417,3 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.consent-container {
|
||||
max-width: var(--width-lg);
|
||||
margin: var(--space-7) auto;
|
||||
padding: var(--space-7);
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 200px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.loading-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.loading-content p {
|
||||
margin: 0;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.error-container {
|
||||
text-align: center;
|
||||
max-width: var(--width-sm);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.error {
|
||||
padding: var(--space-3);
|
||||
background: var(--error-bg);
|
||||
border: 1px solid var(--error-border);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--error-text);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.client-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
|
||||
.permissions-panel {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.client-info {
|
||||
text-align: center;
|
||||
padding: var(--space-6);
|
||||
background: var(--bg-secondary);
|
||||
border-radius: var(--radius-xl);
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.client-info {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.client-logo {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: var(--radius-xl);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.client-info h1 {
|
||||
margin: 0 0 var(--space-1) 0;
|
||||
font-size: var(--text-xl);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.client-link {
|
||||
display: inline-block;
|
||||
margin-top: var(--space-2);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.client-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.account-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-1);
|
||||
padding: var(--space-4);
|
||||
background: var(--bg-secondary);
|
||||
border-radius: var(--radius-xl);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.account-info .label {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.account-info .did {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.account-info .handle {
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--font-medium);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.delegation-badge {
|
||||
display: inline-block;
|
||||
padding: var(--space-1) var(--space-2);
|
||||
background: var(--accent);
|
||||
color: var(--text-inverse);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--font-semibold);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.delegation-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.delegation-info .info-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.delegation-info .handle {
|
||||
font-weight: var(--font-medium);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.level-badge {
|
||||
display: inline-block;
|
||||
padding: 2px var(--space-2);
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-primary);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--font-medium);
|
||||
}
|
||||
|
||||
.level-badge.level-owner {
|
||||
background: var(--success-bg);
|
||||
color: var(--success-text);
|
||||
}
|
||||
|
||||
.level-badge.level-admin {
|
||||
background: var(--accent);
|
||||
color: var(--text-inverse);
|
||||
}
|
||||
|
||||
.level-badge.level-editor {
|
||||
background: var(--warning-bg);
|
||||
color: var(--warning-text);
|
||||
}
|
||||
|
||||
.level-badge.level-viewer {
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.permissions-notice {
|
||||
margin-top: var(--space-3);
|
||||
padding: var(--space-3);
|
||||
background: var(--warning-bg);
|
||||
border: 1px solid var(--warning-border);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.notice-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-weight: var(--font-semibold);
|
||||
color: var(--warning-text);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.notice-header svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notice-text {
|
||||
margin: 0;
|
||||
font-size: var(--text-sm);
|
||||
color: var(--warning-text);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.scopes-section {
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.scopes-section h2 {
|
||||
font-size: var(--text-base);
|
||||
margin: 0 0 var(--space-4) 0;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.scope-group {
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.category-title {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--font-semibold);
|
||||
color: var(--text-primary);
|
||||
margin: 0 0 var(--space-2) 0;
|
||||
padding-bottom: var(--space-1);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.scope-item {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-3);
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-lg);
|
||||
margin-bottom: var(--space-2);
|
||||
cursor: pointer;
|
||||
transition: border-color var(--transition-fast);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scope-item:hover:not(.required) {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.scope-item.required {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.scope-item.read-only {
|
||||
background: var(--bg-secondary);
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.scope-item input[type="checkbox"] {
|
||||
flex-shrink: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.scope-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scope-name {
|
||||
font-weight: var(--font-medium);
|
||||
color: var(--text-primary);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.scope-description {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.required-badge {
|
||||
display: inline-block;
|
||||
font-size: 0.625rem;
|
||||
padding: 2px var(--space-2);
|
||||
background: var(--warning-bg);
|
||||
color: var(--warning-text);
|
||||
border-radius: var(--radius-sm);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin-top: var(--space-1);
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.remember-choice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
margin-top: var(--space-5);
|
||||
cursor: pointer;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.remember-choice input {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: var(--space-4);
|
||||
margin-top: var(--space-6);
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.actions {
|
||||
max-width: 400px;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.actions button {
|
||||
flex: 1;
|
||||
padding: var(--space-3);
|
||||
border: none;
|
||||
border-radius: var(--radius-lg);
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--font-medium);
|
||||
cursor: pointer;
|
||||
transition: background-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.actions button:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.deny-btn {
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.deny-btn:hover:not(:disabled) {
|
||||
background: var(--error-bg);
|
||||
border-color: var(--error-border);
|
||||
color: var(--error-text);
|
||||
}
|
||||
|
||||
.approve-btn {
|
||||
background: var(--accent);
|
||||
color: var(--text-inverse);
|
||||
}
|
||||
|
||||
.approve-btn:hover:not(:disabled) {
|
||||
background: var(--accent-hover);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -401,7 +401,7 @@
|
||||
{/if}
|
||||
|
||||
<form onsubmit={handleSubmit}>
|
||||
<div class="field">
|
||||
<div>
|
||||
<label for="username">{$_('register.handle')}</label>
|
||||
<input
|
||||
id="username"
|
||||
@@ -425,7 +425,7 @@
|
||||
disabled={submitting || ssoLoading !== null}
|
||||
>
|
||||
{#if ssoLoading === provider.provider}
|
||||
<span class="spinner sm"></span>
|
||||
<span>{$_('common.loading')}</span>
|
||||
{:else}
|
||||
<SsoIcon provider={provider.icon} size={20} />
|
||||
{/if}
|
||||
@@ -445,7 +445,7 @@
|
||||
<h3>{$_('oauth.login.signInWithPasskey')}</h3>
|
||||
<button
|
||||
type="button"
|
||||
class="passkey-btn"
|
||||
style="width: 100%"
|
||||
class:passkey-unavailable={!hasPasskeys || checkingSecurityStatus || !securityStatusChecked}
|
||||
onclick={handlePasskeyLogin}
|
||||
disabled={submitting || !hasPasskeys || !username || checkingSecurityStatus || !securityStatusChecked}
|
||||
@@ -494,7 +494,7 @@
|
||||
<span>{$_('oauth.login.rememberDevice')}</span>
|
||||
</label>
|
||||
|
||||
<button type="submit" class="submit-btn" disabled={submitting || !username || !password}>
|
||||
<button type="submit" disabled={submitting || !username || !password}>
|
||||
{submitting ? $_('oauth.login.signingIn') : $_('oauth.login.title')}
|
||||
</button>
|
||||
</div>
|
||||
@@ -502,13 +502,13 @@
|
||||
</div>
|
||||
|
||||
<div class="cancel-row">
|
||||
<button type="button" class="cancel-btn-subtle" onclick={handleCancel} disabled={submitting}>
|
||||
<button type="button" class="ghost sm" onclick={handleCancel} disabled={submitting}>
|
||||
{$_('common.cancel')}
|
||||
</button>
|
||||
</div>
|
||||
{:else}
|
||||
{#if hasPassword || !securityStatusChecked}
|
||||
<div class="field">
|
||||
<div>
|
||||
<label for="password">{$_('oauth.login.password')}</label>
|
||||
<input
|
||||
id="password"
|
||||
@@ -526,14 +526,14 @@
|
||||
</label>
|
||||
|
||||
<div class="actions">
|
||||
<button type="submit" class="submit-btn" disabled={submitting || !username || !password}>
|
||||
<button type="submit" disabled={submitting || !username || !password}>
|
||||
{submitting ? $_('oauth.login.signingIn') : $_('oauth.login.title')}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="cancel-row">
|
||||
<button type="button" class="cancel-btn-subtle" onclick={handleCancel} disabled={submitting}>
|
||||
<button type="button" class="ghost sm" onclick={handleCancel} disabled={submitting}>
|
||||
{$_('common.cancel')}
|
||||
</button>
|
||||
</div>
|
||||
@@ -544,286 +544,3 @@
|
||||
<a href={getFullUrl(routes.resetPassword)}>{$_('login.forgotPassword')}</a> · <a href={getFullUrl(routes.requestPasskeyRecovery)}>{$_('login.lostPasskey')}</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.help-links {
|
||||
text-align: center;
|
||||
margin-top: var(--space-4);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.help-links a {
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.help-links a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.auth-methods {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-5);
|
||||
margin-top: var(--space-4);
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.auth-methods {
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
align-items: start;
|
||||
}
|
||||
}
|
||||
|
||||
.auth-methods.single-method {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.auth-methods.single-method {
|
||||
grid-template-columns: 1fr;
|
||||
max-width: 400px;
|
||||
margin: var(--space-4) auto 0;
|
||||
}
|
||||
}
|
||||
|
||||
.passkey-method,
|
||||
.password-method {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
padding: var(--space-5);
|
||||
background: var(--bg-secondary);
|
||||
border-radius: var(--radius-xl);
|
||||
}
|
||||
|
||||
.passkey-method h3,
|
||||
.password-method h3 {
|
||||
margin: 0;
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--font-semibold);
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
|
||||
.method-divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-muted);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.method-divider {
|
||||
flex-direction: column;
|
||||
padding: 0 var(--space-3);
|
||||
}
|
||||
|
||||
.method-divider::before,
|
||||
.method-divider::after {
|
||||
content: '';
|
||||
width: 1px;
|
||||
height: var(--space-6);
|
||||
background: var(--border-color);
|
||||
}
|
||||
|
||||
.method-divider span {
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: mixed;
|
||||
transform: rotate(180deg);
|
||||
padding: var(--space-2) 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 599px) {
|
||||
.method-divider {
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.method-divider::before,
|
||||
.method-divider::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--border-color);
|
||||
}
|
||||
}
|
||||
|
||||
.remember-device {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
cursor: pointer;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.remember-device input {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: var(--space-4);
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
|
||||
.actions button {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.cancel-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: var(--space-4);
|
||||
}
|
||||
|
||||
.cancel-btn-subtle {
|
||||
padding: var(--space-2) var(--space-4);
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
cursor: pointer;
|
||||
transition: color var(--transition-fast);
|
||||
}
|
||||
|
||||
.cancel-btn-subtle:hover:not(:disabled) {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.cancel-btn-subtle:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
background: var(--accent);
|
||||
color: var(--text-inverse);
|
||||
}
|
||||
|
||||
.submit-btn:hover:not(:disabled) {
|
||||
background: var(--accent-hover);
|
||||
}
|
||||
|
||||
.passkey-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
width: 100%;
|
||||
padding: var(--space-3);
|
||||
background: var(--accent);
|
||||
color: var(--text-inverse);
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
cursor: pointer;
|
||||
transition: background-color var(--transition-fast), border-color var(--transition-fast), opacity var(--transition-fast);
|
||||
}
|
||||
|
||||
.passkey-btn:hover:not(:disabled) {
|
||||
background: var(--accent-hover);
|
||||
border-color: var(--accent-hover);
|
||||
}
|
||||
|
||||
.passkey-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.passkey-btn.passkey-unavailable {
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text-secondary);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.passkey-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.passkey-text {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.sso-section {
|
||||
margin-top: var(--space-6);
|
||||
}
|
||||
|
||||
.sso-section-top {
|
||||
margin-top: var(--space-4);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.sso-section-top .sso-divider {
|
||||
margin-top: var(--space-5);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.sso-divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
margin-bottom: var(--space-4);
|
||||
color: var(--text-muted);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.sso-divider::before,
|
||||
.sso-divider::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--border-color);
|
||||
}
|
||||
|
||||
.sso-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-3);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sso-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-2) var(--space-4);
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
cursor: pointer;
|
||||
transition: background-color var(--transition-fast), border-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.sso-btn-prominent {
|
||||
padding: var(--space-3) var(--space-5);
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--font-medium);
|
||||
}
|
||||
|
||||
.sso-btn:hover:not(:disabled) {
|
||||
background: var(--bg-tertiary);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.sso-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -308,10 +308,7 @@
|
||||
|
||||
<div class="oauth-register-container">
|
||||
{#if loadingServerInfo}
|
||||
<div class="loading">
|
||||
<div class="spinner"></div>
|
||||
<p>{$_('common.loading')}</p>
|
||||
</div>
|
||||
<div class="loading"></div>
|
||||
{:else if flow}
|
||||
<header class="page-header">
|
||||
<h1>{$_('oauth.register.title')}</h1>
|
||||
@@ -345,7 +342,7 @@
|
||||
<div class="split-layout">
|
||||
<div class="form-section">
|
||||
<form onsubmit={handleInfoSubmit}>
|
||||
<div class="field">
|
||||
<div>
|
||||
<label for="handle">{$_('register.handle')}</label>
|
||||
<HandleInput
|
||||
value={flow.info.handle}
|
||||
@@ -484,7 +481,7 @@
|
||||
</fieldset>
|
||||
|
||||
{#if serverInfo?.inviteCodeRequired}
|
||||
<div class="field">
|
||||
<div>
|
||||
<label for="invite-code">{$_('register.inviteCode')} <span class="required">*</span></label>
|
||||
<input
|
||||
id="invite-code"
|
||||
@@ -504,10 +501,10 @@
|
||||
</div>
|
||||
|
||||
<div class="secondary-actions">
|
||||
<button type="button" class="link-btn" onclick={goToLogin}>
|
||||
<button type="button" class="link" onclick={goToLogin}>
|
||||
{$_('oauth.register.haveAccount')}
|
||||
</button>
|
||||
<button type="button" class="link-btn" onclick={handleCancel}>
|
||||
<button type="button" class="link" onclick={handleCancel}>
|
||||
{$_('common.cancel')}
|
||||
</button>
|
||||
</div>
|
||||
@@ -540,7 +537,6 @@
|
||||
|
||||
{:else if flow.state.step === 'creating'}
|
||||
<div class="creating">
|
||||
<div class="spinner"></div>
|
||||
<p>{$_('registerPasskey.creatingAccount')}</p>
|
||||
</div>
|
||||
|
||||
@@ -582,203 +578,8 @@
|
||||
|
||||
{:else if flow.state.step === 'activating'}
|
||||
<div class="creating">
|
||||
<div class="spinner"></div>
|
||||
<p>{$_('registerPasskey.activatingAccount')}</p>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.oauth-register-container {
|
||||
max-width: var(--width-lg);
|
||||
margin: var(--space-9) auto;
|
||||
padding: var(--space-7);
|
||||
}
|
||||
|
||||
.loading, .creating {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
padding: var(--space-8);
|
||||
}
|
||||
|
||||
.loading p, .creating p {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
margin: 0 0 var(--space-2) 0;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.form-links {
|
||||
margin-top: var(--space-6);
|
||||
}
|
||||
|
||||
.link-text {
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.link-text a {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--font-medium);
|
||||
}
|
||||
|
||||
input, select {
|
||||
padding: var(--space-3);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
background: var(--bg-input);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
input:focus, select:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-muted);
|
||||
margin: var(--space-1) 0 0 0;
|
||||
}
|
||||
|
||||
.error {
|
||||
padding: var(--space-3);
|
||||
background: var(--error-bg);
|
||||
border: 1px solid var(--error-border);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--error-text);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: var(--space-4);
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
|
||||
button.primary {
|
||||
flex: 1;
|
||||
padding: var(--space-3);
|
||||
background: var(--accent);
|
||||
color: var(--text-inverse);
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
cursor: pointer;
|
||||
transition: background-color var(--transition-fast);
|
||||
}
|
||||
|
||||
button.primary:hover:not(:disabled) {
|
||||
background: var(--accent-hover);
|
||||
}
|
||||
|
||||
button.primary:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.secondary-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: var(--space-4);
|
||||
margin-top: var(--space-4);
|
||||
}
|
||||
|
||||
.link-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--accent);
|
||||
cursor: pointer;
|
||||
font-size: var(--text-sm);
|
||||
padding: var(--space-2);
|
||||
}
|
||||
|
||||
.link-btn:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.contact-fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.required {
|
||||
color: var(--error-text);
|
||||
}
|
||||
|
||||
.passkey-step {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.passkey-step h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.passkey-step p {
|
||||
color: var(--text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-4);
|
||||
}
|
||||
|
||||
legend {
|
||||
padding: 0 var(--space-2);
|
||||
font-weight: var(--font-medium);
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 3px solid var(--border-color);
|
||||
border-top-color: var(--accent);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user