refactor(ui): the settings family migrates; two colour bugs and a dead class
CI & Build / Python lint (push) Successful in 7s
CI & Build / Plugin hooks (push) Successful in 36s
CI & Build / TypeScript typecheck (push) Successful in 49s
CI & Build / integration (push) Successful in 2m16s
CI & Build / Python tests (push) Successful in 2m51s
CI & Build / Build & push image (push) Successful in 1m15s
CI & Build / Python lint (push) Successful in 7s
CI & Build / Plugin hooks (push) Successful in 36s
CI & Build / TypeScript typecheck (push) Successful in 49s
CI & Build / integration (push) Successful in 2m16s
CI & Build / Python tests (push) Successful in 2m51s
CI & Build / Build & push image (push) Successful in 1m15s
SettingsView and UserManagementView had near-identical button vocabularies — btn-delete, btn-cancel-delete, btn-confirm-delete, btn-toggle/-open/-close — defined separately in each. Parallel duplication (#2278's shape), and it had already diverged twice: - .btn-confirm-delete used --color-danger in UserManagement and --color-action-destructive in Settings. Those are different colours on purpose: the house style keeps error (something went wrong) distinct from destructive (something is about to). A delete confirmation is destructive. UserManagement was showing the error colour for a button nothing had failed in yet. - .btn-remove-slot's hover reached for --color-danger for the same reason, and is the same correction. It turned out to be dead anyway — style rules only, no template reference anywhere in the app — so it is gone. .btn-danger-outline was defined TWICE inside SettingsView, at 0.4rem 0.9rem and 0.45rem 1rem. One file, one class, two geometries, ~1200 lines apart. That is the clearest single argument for this whole task that I have found: the drift does not need two files, only enough distance that nobody sees both at once. The registration toggle keeps .btn-toggle-close, and only that. It is bound dynamically (:class="registrationOpen ? … : …"), so a name-based scan reads it as unused — checked before deleting. .btn-toggle-open went, because btn-primary now says the same thing; the close state stays because it must NOT read as the primary action it sits on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs
This commit is contained in:
@@ -1165,7 +1165,7 @@ function formatUserDate(iso: string): string {
|
||||
<p class="field-hint">Click Detect to auto-fill from your browser.</p>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveTimezone" :disabled="savingTimezone">
|
||||
<button class="btn-primary" @click="saveTimezone" :disabled="savingTimezone">
|
||||
{{ savingTimezone ? 'Saving…' : 'Save' }}
|
||||
</button>
|
||||
<span v-if="timezoneSaved" class="saved-msg">Saved!</span>
|
||||
@@ -1190,7 +1190,7 @@ function formatUserDate(iso: string): string {
|
||||
<p class="field-hint">Set to <strong>0</strong> to keep deleted items forever (never auto-purge).</p>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveRetention" :disabled="savingRetention">
|
||||
<button class="btn-primary" @click="saveRetention" :disabled="savingRetention">
|
||||
{{ savingRetention ? 'Saving…' : 'Save' }}
|
||||
</button>
|
||||
<span v-if="retentionSaved" class="saved-msg">Saved!</span>
|
||||
@@ -1313,7 +1313,7 @@ function formatUserDate(iso: string): string {
|
||||
</p>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveKbInject" :disabled="savingKbInject">
|
||||
<button class="btn-primary" @click="saveKbInject" :disabled="savingKbInject">
|
||||
{{ savingKbInject ? 'Saving…' : 'Save' }}
|
||||
</button>
|
||||
<span v-if="kbInjectSaved" class="saved-msg">Saved!</span>
|
||||
@@ -1361,7 +1361,7 @@ function formatUserDate(iso: string): string {
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button
|
||||
class="btn-save"
|
||||
class="btn-primary"
|
||||
@click="changeEmail"
|
||||
:disabled="changingEmail || !emailPassword"
|
||||
>
|
||||
@@ -1409,7 +1409,7 @@ function formatUserDate(iso: string): string {
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button
|
||||
class="btn-save"
|
||||
class="btn-primary"
|
||||
@click="changePassword"
|
||||
:disabled="changingPassword || !currentPassword || newPassword.length < 8 || newPassword !== confirmNewPassword"
|
||||
>
|
||||
@@ -1465,7 +1465,7 @@ function formatUserDate(iso: string): string {
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveProfile" :disabled="profileSaving">{{ profileSaving ? 'Saving…' : 'Save' }}</button>
|
||||
<button class="btn-primary" @click="saveProfile" :disabled="profileSaving">{{ profileSaving ? 'Saving…' : 'Save' }}</button>
|
||||
<span v-if="profileSaved" class="saved-msg">Saved!</span>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1491,7 +1491,7 @@ function formatUserDate(iso: string): string {
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveProfile" :disabled="profileSaving">{{ profileSaving ? 'Saving…' : 'Save' }}</button>
|
||||
<button class="btn-primary" @click="saveProfile" :disabled="profileSaving">{{ profileSaving ? 'Saving…' : 'Save' }}</button>
|
||||
<span v-if="profileSaved" class="saved-msg">Saved!</span>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1501,7 +1501,7 @@ function formatUserDate(iso: string): string {
|
||||
<p class="section-desc">Topics you care about — used to personalise the journal's daily prep and chat responses.</p>
|
||||
<TagInput v-model="profile.interests" placeholder="Add an interest…" :fetchTags="emptyTagsFetch" />
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveProfile" :disabled="profileSaving">{{ profileSaving ? 'Saving…' : 'Save' }}</button>
|
||||
<button class="btn-primary" @click="saveProfile" :disabled="profileSaving">{{ profileSaving ? 'Saving…' : 'Save' }}</button>
|
||||
<span v-if="profileSaved" class="saved-msg">Saved!</span>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1533,7 +1533,7 @@ function formatUserDate(iso: string): string {
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveProfile" :disabled="profileSaving">{{ profileSaving ? 'Saving…' : 'Save' }}</button>
|
||||
<button class="btn-primary" @click="saveProfile" :disabled="profileSaving">{{ profileSaving ? 'Saving…' : 'Save' }}</button>
|
||||
<span v-if="profileSaved" class="saved-msg">Saved!</span>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1562,7 +1562,7 @@ function formatUserDate(iso: string): string {
|
||||
<p class="field-hint">Emails for logins, logouts, and password changes.</p>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveNotifications" :disabled="savingNotifications">
|
||||
<button class="btn-primary" @click="saveNotifications" :disabled="savingNotifications">
|
||||
{{ savingNotifications ? "Saving..." : "Save" }}
|
||||
</button>
|
||||
<span v-if="notificationsSaved" class="saved-msg">Saved!</span>
|
||||
@@ -1589,7 +1589,7 @@ function formatUserDate(iso: string): string {
|
||||
placeholder="Enter a search query..."
|
||||
@keydown="onSearchKeydown"
|
||||
/>
|
||||
<button class="btn-save" @click="testSearch" :disabled="searchLoading || !searchQuery.trim()">
|
||||
<button class="btn-primary" @click="testSearch" :disabled="searchLoading || !searchQuery.trim()">
|
||||
{{ searchLoading ? "Searching..." : "Search" }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -1891,7 +1891,7 @@ function formatUserDate(iso: string): string {
|
||||
/>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveBaseUrl" :disabled="savingBaseUrl">
|
||||
<button class="btn-primary" @click="saveBaseUrl" :disabled="savingBaseUrl">
|
||||
{{ savingBaseUrl ? "Saving..." : "Save" }}
|
||||
</button>
|
||||
<span v-if="baseUrlSaved" class="saved-msg">Saved!</span>
|
||||
@@ -1916,7 +1916,7 @@ function formatUserDate(iso: string): string {
|
||||
/>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveMarketplaceUrl" :disabled="savingMarketplaceUrl">
|
||||
<button class="btn-primary" @click="saveMarketplaceUrl" :disabled="savingMarketplaceUrl">
|
||||
{{ savingMarketplaceUrl ? "Saving..." : "Save" }}
|
||||
</button>
|
||||
<span v-if="marketplaceUrlSaved" class="saved-msg">Saved!</span>
|
||||
@@ -1946,10 +1946,10 @@ function formatUserDate(iso: string): string {
|
||||
</select>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-save" @click="saveDbMaintenance" :disabled="savingDbMaint">
|
||||
<button class="btn-primary" @click="saveDbMaintenance" :disabled="savingDbMaint">
|
||||
{{ savingDbMaint ? "Saving..." : "Save" }}
|
||||
</button>
|
||||
<button class="btn-save btn-secondary" @click="runDbMaintenanceNow" :disabled="runningDbMaint">
|
||||
<button class="btn-secondary" @click="runDbMaintenanceNow" :disabled="runningDbMaint">
|
||||
{{ runningDbMaint ? "Running..." : "Run now" }}
|
||||
</button>
|
||||
<span v-if="dbMaintSaved" class="saved-msg">Saved!</span>
|
||||
@@ -2040,7 +2040,7 @@ function formatUserDate(iso: string): string {
|
||||
<p class="field-hint">Recommended for port 587. Implicit TLS is used automatically for port 465.</p>
|
||||
</div>
|
||||
<div class="actions" style="margin-bottom: 1.25rem;">
|
||||
<button class="btn-save" @click="saveSmtp" :disabled="savingSmtp">
|
||||
<button class="btn-primary" @click="saveSmtp" :disabled="savingSmtp">
|
||||
{{ savingSmtp ? "Saving..." : "Save SMTP Settings" }}
|
||||
</button>
|
||||
<span v-if="smtpSaved" class="saved-msg">Saved!</span>
|
||||
@@ -2054,7 +2054,7 @@ function formatUserDate(iso: string): string {
|
||||
placeholder="test@example.com"
|
||||
class="input"
|
||||
/>
|
||||
<button class="btn-save" @click="sendTestEmail" :disabled="sendingTest || !testRecipient.trim()">
|
||||
<button class="btn-primary" @click="sendTestEmail" :disabled="sendingTest || !testRecipient.trim()">
|
||||
{{ sendingTest ? "Sending..." : "Send Test" }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -2079,7 +2079,7 @@ function formatUserDate(iso: string): string {
|
||||
<p class="field-hint">When closed, new users can only be added by an administrator.</p>
|
||||
</div>
|
||||
<button
|
||||
class="btn-toggle"
|
||||
class="btn-primary btn-toggle"
|
||||
:class="registrationOpen ? 'btn-toggle-close' : 'btn-toggle-open'"
|
||||
@click="toggleRegistration"
|
||||
:disabled="toggling"
|
||||
@@ -2100,7 +2100,7 @@ function formatUserDate(iso: string): string {
|
||||
required
|
||||
:disabled="sendingInvite"
|
||||
/>
|
||||
<button type="submit" class="btn-save" :disabled="sendingInvite || !inviteEmail.trim()">
|
||||
<button type="submit" class="btn-primary" :disabled="sendingInvite || !inviteEmail.trim()">
|
||||
{{ sendingInvite ? "Sending..." : "Send Invite" }}
|
||||
</button>
|
||||
</form>
|
||||
@@ -2122,7 +2122,7 @@ function formatUserDate(iso: string): string {
|
||||
<td class="hide-mobile cell-date">{{ formatUserDate(inv.created_at) }}</td>
|
||||
<td class="hide-mobile cell-date">{{ formatUserDate(inv.expires_at) }}</td>
|
||||
<td class="cell-actions">
|
||||
<button class="btn-delete" @click="revokeInvitation(inv.id)" :disabled="revokingId !== null">
|
||||
<button class="btn-ghost btn-compact" @click="revokeInvitation(inv.id)" :disabled="revokingId !== null">
|
||||
{{ revokingId === inv.id ? "Revoking..." : "Revoke" }}
|
||||
</button>
|
||||
</td>
|
||||
@@ -2161,13 +2161,13 @@ function formatUserDate(iso: string): string {
|
||||
<span class="you-label">You</span>
|
||||
</template>
|
||||
<template v-else-if="confirmDeleteId === u.id">
|
||||
<button class="btn-confirm-delete" @click="confirmDelete(u.id)" :disabled="deleting !== null">
|
||||
<button class="btn-danger btn-compact" @click="confirmDelete(u.id)" :disabled="deleting !== null">
|
||||
{{ deleting === u.id ? "Deleting..." : "Confirm" }}
|
||||
</button>
|
||||
<button class="btn-cancel-delete" @click="cancelDelete">Cancel</button>
|
||||
<button class="btn-ghost btn-compact" @click="cancelDelete">Cancel</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="btn-delete" @click="confirmDelete(u.id)" :disabled="deleting !== null">Delete</button>
|
||||
<button class="btn-ghost btn-compact" @click="confirmDelete(u.id)" :disabled="deleting !== null">Delete</button>
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -2305,10 +2305,10 @@ function formatUserDate(iso: string): string {
|
||||
<span v-if="g.description" class="group-desc">{{ g.description }}</span>
|
||||
</div>
|
||||
<div class="group-card-actions">
|
||||
<button class="btn-sm" @click="toggleGroupExpand(g)">
|
||||
<button class="btn-ghost btn-compact" @click="toggleGroupExpand(g)">
|
||||
{{ expandedGroupId === g.id ? 'Collapse' : 'Manage' }}
|
||||
</button>
|
||||
<button class="btn-sm btn-danger-sm" @click="deleteGroupConfirm(g)">Delete</button>
|
||||
<button class="btn-danger-outline btn-compact" @click="deleteGroupConfirm(g)">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2338,7 +2338,7 @@ function formatUserDate(iso: string): string {
|
||||
<li v-for="m in (groupMembers[g.id] || [])" :key="m.user_id" class="member-row">
|
||||
<span class="member-name">{{ m.username }}</span>
|
||||
<span class="member-role-badge" :class="`role-${m.role}`">{{ m.role }}</span>
|
||||
<button class="btn-sm btn-danger-sm" @click="removeMemberFromGroup(g.id, m.user_id)">Remove</button>
|
||||
<button class="btn-danger-outline btn-compact" @click="removeMemberFromGroup(g.id, m.user_id)">Remove</button>
|
||||
</li>
|
||||
<li v-if="!(groupMembers[g.id]?.length)" class="members-empty">No members yet.</li>
|
||||
</ul>
|
||||
@@ -2564,54 +2564,6 @@ function formatUserDate(iso: string): string {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
/* Save: Moss action-primary per Hybrid */
|
||||
.btn-save {
|
||||
padding: 0.4rem 0.9rem;
|
||||
background: var(--color-action-primary);
|
||||
color: var(--fs-text-on-action);
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
font-family: inherit;
|
||||
white-space: nowrap;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.btn-save:disabled { opacity: 0.6; cursor: default; }
|
||||
.btn-save:hover:not(:disabled) { background: var(--color-action-primary-hover); }
|
||||
|
||||
/* Danger outline (Invalidate sessions, Clear observations, etc.):
|
||||
Oxblood action-destructive ghost — fills on hover */
|
||||
.btn-danger-outline {
|
||||
padding: 0.4rem 0.9rem;
|
||||
background: none;
|
||||
color: var(--color-action-destructive);
|
||||
border: 1px solid var(--color-action-destructive);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
font-family: inherit;
|
||||
white-space: nowrap;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
}
|
||||
.btn-danger-outline:hover:not(:disabled) {
|
||||
background: var(--color-action-destructive);
|
||||
color: var(--fs-text-on-action);
|
||||
}
|
||||
.btn-danger-outline:disabled { opacity: 0.5; cursor: default; }
|
||||
|
||||
/* Filled destructive: Oxblood action-destructive */
|
||||
|
||||
/* Secondary: Bronze action-secondary — alternate paths (Detect, Test,
|
||||
Refresh, Add slot, etc.). Outline form for visual lightness. */
|
||||
|
||||
/* DB maintenance last-run summary */
|
||||
.db-maint-last { margin-top: 1rem; }
|
||||
.db-maint-last-label {
|
||||
display: block;
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-text-muted);
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.db-maint-table-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
@@ -2957,68 +2909,6 @@ function formatUserDate(iso: string): string {
|
||||
}
|
||||
.you-label { font-size: 0.8rem; color: var(--color-text-muted); }
|
||||
/* Per-row delete (users / invitations / etc.): ghost → Oxblood on hover */
|
||||
.btn-delete {
|
||||
padding: 0.25rem 0.6rem;
|
||||
background: transparent;
|
||||
color: var(--color-text-muted);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.btn-delete:hover:not(:disabled) { border-color: var(--color-action-destructive); color: var(--color-action-destructive); }
|
||||
.btn-delete:disabled { opacity: 0.4; cursor: default; }
|
||||
/* Two-stage destructive: Confirm = Oxblood filled, Cancel = Bronze ghost */
|
||||
.btn-confirm-delete {
|
||||
padding: 0.25rem 0.6rem;
|
||||
background: var(--color-action-destructive);
|
||||
color: var(--fs-text-on-action);
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
margin-right: 0.25rem;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.btn-confirm-delete:hover:not(:disabled) { background: var(--color-action-destructive-hover); }
|
||||
.btn-confirm-delete:disabled { opacity: 0.6; cursor: default; }
|
||||
.btn-cancel-delete {
|
||||
padding: 0.25rem 0.6rem;
|
||||
background: transparent;
|
||||
color: var(--color-text-muted);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.btn-cancel-delete:hover { color: var(--color-text); border-color: var(--color-text-muted); }
|
||||
/* Toggle (Open/Close registration, etc.): Open = Moss, Close = Pewter ghost */
|
||||
.btn-toggle {
|
||||
padding: 0.45rem 1rem;
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.btn-toggle:disabled { opacity: 0.6; cursor: default; }
|
||||
.btn-toggle-open { background: var(--color-action-primary); color: var(--fs-text-on-action); }
|
||||
.btn-toggle-open:hover:not(:disabled) { background: var(--color-action-primary-hover); }
|
||||
.btn-toggle-close {
|
||||
background: var(--color-bg-secondary);
|
||||
color: var(--color-text);
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
.btn-toggle-close:hover:not(:disabled) { border-color: var(--color-warning); color: var(--color-warning); }
|
||||
.loading-msg, .empty-msg {
|
||||
text-align: center;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.9rem;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
/* Logs panel */
|
||||
.stats-section { padding: 1rem 1.25rem; }
|
||||
@@ -3202,32 +3092,6 @@ function formatUserDate(iso: string): string {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 0.25rem 0.6rem;
|
||||
background: none;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
font-size: 0.78rem;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.15s, color 0.15s;
|
||||
}
|
||||
.btn-sm:hover { border-color: var(--color-primary); color: var(--color-primary); }
|
||||
.btn-danger-sm:hover { border-color: var(--color-action-destructive); color: var(--color-action-destructive); }
|
||||
|
||||
.group-members-panel {
|
||||
padding: 0.75rem 1rem 1rem;
|
||||
border-top: 1px solid var(--color-border);
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.members-search {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.member-search-wrap {
|
||||
flex: 1;
|
||||
@@ -3740,21 +3604,6 @@ function formatUserDate(iso: string): string {
|
||||
text-align: right;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
.btn-remove-slot {
|
||||
background: none;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--color-text-muted);
|
||||
cursor: pointer;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.2rem 0.45rem;
|
||||
line-height: 1;
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
}
|
||||
.btn-remove-slot:hover {
|
||||
color: var(--color-danger, #e05555);
|
||||
border-color: var(--color-danger, #e05555);
|
||||
}
|
||||
.blend-actions {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
@@ -3808,24 +3657,4 @@ function formatUserDate(iso: string): string {
|
||||
color: var(--color-text-muted);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.btn-danger-outline {
|
||||
padding: 0.45rem 1rem;
|
||||
background: none;
|
||||
border: 1px solid var(--color-action-destructive);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--color-action-destructive);
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
}
|
||||
.btn-danger-outline:hover:not(:disabled) {
|
||||
background: var(--color-action-destructive);
|
||||
color: var(--fs-text-on-action);
|
||||
}
|
||||
.btn-danger-outline:disabled { opacity: 0.5; cursor: default; }
|
||||
@keyframes va-dot-bounce {
|
||||
0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; }
|
||||
40% { transform: scale(1); opacity: 1; }
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -167,7 +167,7 @@ function formatDate(iso: string): string {
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="btn-toggle"
|
||||
class="btn-primary btn-toggle"
|
||||
:class="registrationOpen ? 'btn-toggle-close' : 'btn-toggle-open'"
|
||||
@click="toggleRegistration"
|
||||
:disabled="toggling"
|
||||
@@ -190,7 +190,7 @@ function formatDate(iso: string): string {
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn-invite"
|
||||
class="btn-primary"
|
||||
:disabled="sendingInvite || !inviteEmail.trim()"
|
||||
>
|
||||
{{ sendingInvite ? "Sending..." : "Send Invite" }}
|
||||
@@ -216,7 +216,7 @@ function formatDate(iso: string): string {
|
||||
<td class="hide-mobile cell-date">{{ formatDate(inv.expires_at) }}</td>
|
||||
<td class="cell-actions">
|
||||
<button
|
||||
class="btn-delete"
|
||||
class="btn-ghost btn-compact"
|
||||
@click="revokeInvitation(inv.id)"
|
||||
:disabled="revokingId !== null"
|
||||
>
|
||||
@@ -262,17 +262,17 @@ function formatDate(iso: string): string {
|
||||
</template>
|
||||
<template v-else-if="confirmDeleteId === u.id">
|
||||
<button
|
||||
class="btn-confirm-delete"
|
||||
class="btn-danger btn-compact"
|
||||
@click="confirmDelete(u.id)"
|
||||
:disabled="deleting !== null"
|
||||
>
|
||||
{{ deleting === u.id ? "Deleting..." : "Confirm" }}
|
||||
</button>
|
||||
<button class="btn-cancel-delete" @click="cancelDelete">Cancel</button>
|
||||
<button class="btn-ghost btn-compact" @click="cancelDelete">Cancel</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button
|
||||
class="btn-delete"
|
||||
class="btn-ghost btn-compact"
|
||||
@click="confirmDelete(u.id)"
|
||||
:disabled="deleting !== null"
|
||||
>
|
||||
@@ -328,24 +328,6 @@ function formatDate(iso: string): string {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
.btn-invite {
|
||||
padding: 0.45rem 1rem;
|
||||
background: var(--color-action-primary);
|
||||
color: var(--fs-text-on-action);
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
font-weight: var(--fs-weight-medium);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.btn-invite:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
.btn-invite:hover:not(:disabled) {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.invite-list {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
@@ -380,26 +362,8 @@ function formatDate(iso: string): string {
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
.btn-toggle {
|
||||
padding: 0.45rem 1rem;
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
font-weight: var(--fs-weight-medium);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.btn-toggle:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
.btn-toggle-open {
|
||||
background: var(--color-action-primary);
|
||||
color: var(--fs-text-on-action);
|
||||
}
|
||||
.btn-toggle-open:hover:not(:disabled) {
|
||||
opacity: 0.9;
|
||||
}
|
||||
/* The one genuine override: 'close registration' must NOT read as the
|
||||
primary action it sits on. Scoped, so it beats the shared variant. */
|
||||
.btn-toggle-close {
|
||||
background: var(--color-bg-secondary);
|
||||
color: var(--color-text);
|
||||
@@ -478,54 +442,6 @@ function formatDate(iso: string): string {
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
.btn-delete {
|
||||
padding: 0.25rem 0.6rem;
|
||||
background: transparent;
|
||||
color: var(--color-text-muted);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.btn-delete:hover:not(:disabled) {
|
||||
border-color: var(--color-danger);
|
||||
color: var(--color-danger);
|
||||
}
|
||||
.btn-delete:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: default;
|
||||
}
|
||||
.btn-confirm-delete {
|
||||
padding: 0.25rem 0.6rem;
|
||||
background: var(--color-danger);
|
||||
color: var(--fs-text-on-action);
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
font-weight: var(--fs-weight-medium);
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
.btn-confirm-delete:hover:not(:disabled) {
|
||||
filter: brightness(0.9);
|
||||
}
|
||||
.btn-confirm-delete:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
.btn-cancel-delete {
|
||||
padding: 0.25rem 0.6rem;
|
||||
background: transparent;
|
||||
color: var(--color-text-muted);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.btn-cancel-delete:hover {
|
||||
color: var(--color-text);
|
||||
border-color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.registration-row {
|
||||
|
||||
Reference in New Issue
Block a user