Private
Public Access
The 12 color pickers (Background, Sidebar background, Surface, Border, etc.) gave no indication of what each one actually affects without trial and error. Adds a miniature, self-contained mockup of the real chat UI above the picker grid -- a sidebar with room rows, a message with an avatar/mention/role badge, a composer, a danger button -- styled from inline styles bound to the draft colors (not the --ds-* custom properties, since those reflect whatever theme is currently active, not necessarily the one being edited). Hovering or focusing either a color input or its matching element in the mockup highlights both, using a fixed amber outline that stays visible regardless of the theme's own palette -- makes the mapping between the 12 fields and where they actually show up immediately obvious in either direction, without needing to activate the theme and go look around the rest of the app. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
435 lines
8.0 KiB
CSS
435 lines
8.0 KiB
CSS
.modal-scrim {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(7, 8, 15, 0.7);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 40;
|
|
padding: var(--sp-4);
|
|
}
|
|
|
|
.modal {
|
|
width: min(380px, 100%);
|
|
max-height: 80vh;
|
|
overflow-y: auto;
|
|
background: var(--ds-surface);
|
|
border: 1px solid var(--ds-border);
|
|
border-radius: var(--radius);
|
|
padding: var(--sp-6);
|
|
}
|
|
|
|
.modal-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: var(--sp-4);
|
|
}
|
|
|
|
.modal-header h2 {
|
|
font-weight: 700;
|
|
font-size: 1rem;
|
|
margin: 0;
|
|
}
|
|
|
|
.modal-close {
|
|
background: transparent;
|
|
border: none;
|
|
color: var(--ds-muted);
|
|
cursor: pointer;
|
|
font-size: 1.1rem;
|
|
line-height: 1;
|
|
}
|
|
|
|
.modal-field-label {
|
|
font-size: 0.78rem;
|
|
color: var(--ds-muted);
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.modal input[type='text'],
|
|
.modal input[type='password'],
|
|
.modal input[type='email'],
|
|
.modal textarea {
|
|
width: 100%;
|
|
background: var(--ds-surface-2);
|
|
border: 1px solid var(--ds-border);
|
|
border-radius: var(--radius);
|
|
padding: 9px 10px;
|
|
color: var(--ds-text);
|
|
font-family: var(--sans);
|
|
font-size: 0.88rem;
|
|
outline: none;
|
|
margin-bottom: var(--sp-4);
|
|
}
|
|
|
|
.modal input[type='text']:focus,
|
|
.modal input[type='password']:focus,
|
|
.modal input[type='email']:focus,
|
|
.modal textarea:focus {
|
|
border-color: var(--ds-accent);
|
|
}
|
|
|
|
.modal-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: var(--sp-2);
|
|
}
|
|
|
|
.modal-error {
|
|
color: var(--ds-danger);
|
|
font-size: 0.82rem;
|
|
margin: -8px 0 var(--sp-3);
|
|
}
|
|
|
|
.modal-success {
|
|
color: var(--ds-accent);
|
|
font-size: 0.82rem;
|
|
margin: -8px 0 var(--sp-3);
|
|
}
|
|
|
|
.modal-divider {
|
|
border: none;
|
|
border-top: 1px solid var(--ds-border);
|
|
margin: var(--sp-5) 0 var(--sp-4);
|
|
}
|
|
|
|
.theme-swatch-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: var(--sp-2);
|
|
margin-bottom: var(--sp-4);
|
|
}
|
|
|
|
.theme-swatch {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-2);
|
|
background: var(--ds-surface-2);
|
|
border: 1px solid var(--ds-border);
|
|
border-radius: var(--radius);
|
|
padding: 8px 10px;
|
|
cursor: pointer;
|
|
text-align: left;
|
|
}
|
|
|
|
.theme-swatch:hover {
|
|
border-color: var(--ds-accent);
|
|
}
|
|
|
|
.theme-swatch-selected {
|
|
border-color: var(--ds-accent);
|
|
box-shadow: 0 0 0 1px var(--ds-accent);
|
|
}
|
|
|
|
.theme-swatch-label {
|
|
font-size: 0.82rem;
|
|
font-weight: 600;
|
|
color: var(--ds-text);
|
|
}
|
|
|
|
/* Each swatch's preview always shows its OWN theme's colors, not whatever
|
|
theme is currently active -- literal per-theme values on purpose, so a
|
|
user can see what an option looks like before picking it. */
|
|
.theme-swatch-preview {
|
|
width: 22px;
|
|
height: 22px;
|
|
border-radius: 50%;
|
|
flex: none;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
.theme-swatch-accent {
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.theme-swatch-dark .theme-swatch-preview {
|
|
background: #101030;
|
|
}
|
|
.theme-swatch-dark .theme-swatch-accent {
|
|
background: #60d8fc;
|
|
}
|
|
|
|
.theme-swatch-light .theme-swatch-preview {
|
|
background: #ffffff;
|
|
}
|
|
.theme-swatch-light .theme-swatch-accent {
|
|
background: #0891b2;
|
|
}
|
|
|
|
.theme-swatch-midnight .theme-swatch-preview {
|
|
background: #000000;
|
|
}
|
|
.theme-swatch-midnight .theme-swatch-accent {
|
|
background: #00f0ff;
|
|
}
|
|
|
|
.theme-swatch-sunset .theme-swatch-preview {
|
|
background: #241408;
|
|
}
|
|
.theme-swatch-sunset .theme-swatch-accent {
|
|
background: #fca050;
|
|
}
|
|
|
|
.custom-theme-swatch {
|
|
display: flex;
|
|
align-items: stretch;
|
|
gap: 4px;
|
|
border-radius: var(--radius);
|
|
}
|
|
|
|
.custom-theme-swatch.theme-swatch-selected {
|
|
box-shadow: 0 0 0 1px var(--ds-accent);
|
|
border-radius: var(--radius);
|
|
}
|
|
|
|
.custom-theme-swatch-select {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.custom-theme-swatch-select .theme-swatch-label {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.custom-theme-swatch-actions {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
flex: none;
|
|
}
|
|
|
|
.custom-theme-swatch-icon-btn {
|
|
flex: 1;
|
|
width: 24px;
|
|
background: var(--ds-surface-2);
|
|
border: 1px solid var(--ds-border);
|
|
border-radius: 5px;
|
|
color: var(--ds-muted);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
padding: 0;
|
|
}
|
|
|
|
.custom-theme-swatch-icon-btn:hover {
|
|
color: var(--ds-text);
|
|
border-color: var(--ds-accent);
|
|
}
|
|
|
|
.custom-theme-new {
|
|
justify-content: center;
|
|
color: var(--ds-muted);
|
|
}
|
|
|
|
.theme-swatch-preview-new {
|
|
background: transparent;
|
|
border-style: dashed;
|
|
font-size: 1rem;
|
|
line-height: 1;
|
|
color: var(--ds-muted);
|
|
}
|
|
|
|
.custom-theme-name-input {
|
|
margin-bottom: var(--sp-3) !important;
|
|
}
|
|
|
|
.custom-theme-editor {
|
|
background: var(--ds-surface-2);
|
|
border: 1px solid var(--ds-border);
|
|
border-radius: var(--radius);
|
|
padding: var(--sp-3);
|
|
margin-bottom: var(--sp-4);
|
|
}
|
|
|
|
.custom-theme-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
|
gap: var(--sp-3);
|
|
}
|
|
|
|
.custom-theme-field {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-2);
|
|
font-size: 0.8rem;
|
|
color: var(--ds-text);
|
|
cursor: pointer;
|
|
border-radius: 6px;
|
|
padding: 3px 4px;
|
|
margin: -3px -4px;
|
|
transition: background 0.1s ease;
|
|
}
|
|
|
|
/* Mirrors CustomThemePreview.css's .ctp-highlighted -- same fixed, theme-
|
|
independent color so it stays visible regardless of what's actually
|
|
being edited. Set when either this field's input OR the matching swatch
|
|
in the live mockup above is hovered/focused, so the mapping works in
|
|
both directions. */
|
|
.custom-theme-field-highlighted {
|
|
background: rgba(251, 191, 36, 0.15);
|
|
box-shadow: 0 0 0 1px #fbbf24;
|
|
}
|
|
|
|
.custom-theme-field input[type='color'] {
|
|
flex: none;
|
|
width: 28px;
|
|
height: 28px;
|
|
padding: 0;
|
|
border: 1px solid var(--ds-border);
|
|
border-radius: 6px;
|
|
background: none;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.custom-theme-scheme {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--sp-3);
|
|
margin-top: var(--sp-4);
|
|
font-size: 0.8rem;
|
|
color: var(--ds-muted);
|
|
}
|
|
|
|
.custom-theme-scheme-toggle {
|
|
display: flex;
|
|
gap: var(--sp-2);
|
|
}
|
|
|
|
.custom-theme-scheme-active {
|
|
border-color: var(--ds-accent);
|
|
color: var(--ds-accent);
|
|
}
|
|
|
|
.toggle-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--sp-3);
|
|
margin-bottom: var(--sp-4);
|
|
}
|
|
|
|
.toggle-row .toggle-label {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.toggle-row .toggle-label .t {
|
|
font-size: 0.86rem;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.toggle-row .toggle-label .d {
|
|
font-size: 0.74rem;
|
|
color: var(--ds-muted);
|
|
}
|
|
|
|
.switch {
|
|
position: relative;
|
|
width: 38px;
|
|
height: 22px;
|
|
flex: none;
|
|
}
|
|
|
|
.switch input {
|
|
position: absolute;
|
|
inset: 0;
|
|
opacity: 0;
|
|
margin: 0;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.switch .track {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: var(--ds-border);
|
|
border-radius: var(--radius-pill);
|
|
transition: background 0.15s ease;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.switch .track::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 2px;
|
|
left: 2px;
|
|
width: 18px;
|
|
height: 18px;
|
|
border-radius: var(--radius-pill);
|
|
background: var(--ds-text);
|
|
transition: transform 0.15s ease;
|
|
}
|
|
|
|
.switch input:checked + .track {
|
|
background: var(--ds-accent);
|
|
}
|
|
|
|
.switch input:checked + .track::after {
|
|
transform: translateX(16px);
|
|
background: var(--ds-void);
|
|
}
|
|
|
|
.modal-empty {
|
|
color: var(--ds-muted);
|
|
font-size: 0.86rem;
|
|
padding: var(--sp-4) 0;
|
|
text-align: center;
|
|
}
|
|
|
|
.modal-list-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-3);
|
|
padding: var(--sp-2) 0;
|
|
border-bottom: 1px solid var(--ds-border);
|
|
}
|
|
|
|
.modal-list-row:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.modal-list-row-body {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.modal-list-row-title {
|
|
font-weight: 600;
|
|
font-size: 0.88rem;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.modal-list-row-sub {
|
|
font-size: 0.76rem;
|
|
color: var(--ds-muted);
|
|
}
|
|
|
|
.profile-modal-avatar-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-4);
|
|
margin-bottom: var(--sp-4);
|
|
}
|
|
|
|
.profile-modal-avatar-actions {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--sp-2);
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.modal-hidden-file-input {
|
|
display: none;
|
|
}
|