Nuevo trait `ColorName` para que cada tema aporte su propia paleta de colores; `CoreColors` es la paleta por defecto. Aprovecha para refactorizar `core/theme.rs` en submódulos por concepto.
520 lines
11 KiB
CSS
520 lines
11 KiB
CSS
:root {
|
||
/* Font families */
|
||
--val-font-sans: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif;
|
||
--val-font-serif: Georgia,"Times New Roman",serif;
|
||
--val-font-monospace: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
|
||
--val-font-family: var(--val-font-sans);
|
||
/* Font size */
|
||
--val-fs--base: 1rem;
|
||
/* Font weight */
|
||
--val-fw--base: 400;
|
||
/* Line height */
|
||
--val-lh--base: 1.5;
|
||
/* Core Colors */
|
||
--val-color--primary: #0d6efd;
|
||
--val-color--secondary: #6c757d;
|
||
--val-color--success: #198754;
|
||
--val-color--info: #0dcaf0;
|
||
--val-color--warning: #ffc107;
|
||
--val-color--danger: #dc3545;
|
||
/* Other Colors */
|
||
--val-color--bg: #fafafa;
|
||
--val-color--bg--muted: #dee2e6;
|
||
--val-color--text: #212529;
|
||
--val-color--text--muted: color-mix(in srgb, var(--val-color--text) 50%, var(--val-color--bg));
|
||
--val-color--switch-off: #adb5bd;
|
||
--val-color--border: #212529;
|
||
}
|
||
|
||
*, *::before, *::after {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
html {
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
body {
|
||
font-family: var(--val-font-family);
|
||
font-size: var(--val-fs--base);
|
||
font-weight: var(--val-fw--base);
|
||
line-height: var(--val-lh--base);
|
||
color: var(--val-color--text);
|
||
background-color: var(--val-color--bg);
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
/*
|
||
* Form components
|
||
*/
|
||
|
||
.form-required {
|
||
color: var(--val-color--danger);
|
||
margin-left: 0.25rem;
|
||
}
|
||
|
||
.form-label {
|
||
display: block;
|
||
margin-top: 1em;
|
||
}
|
||
|
||
.form-text {
|
||
font-size: 0.9375rem;
|
||
color: var(--val-color--text--muted);
|
||
}
|
||
|
||
.form-field > select.form-select,
|
||
.form-field > input.form-control,
|
||
.form-field > input.form-range,
|
||
.form-field > textarea.form-control {
|
||
display: block;
|
||
padding: 0.25rem 0.5rem;
|
||
width: 100%;
|
||
}
|
||
|
||
fieldset {
|
||
margin: 2rem 0 1rem;
|
||
background: var(--val-color--bg);
|
||
}
|
||
fieldset > legend {
|
||
background-color: var(--val-color--bg);
|
||
border: 2px groove threedface;
|
||
padding: 0 0.5em;
|
||
}
|
||
|
||
.form-check {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
min-height: 1.5rem;
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
.form-check-inline {
|
||
display: inline-flex;
|
||
margin-right: 1rem;
|
||
}
|
||
.form-check-reverse {
|
||
flex-direction: row-reverse;
|
||
justify-content: flex-start;
|
||
text-align: right;
|
||
}
|
||
.form-check-input {
|
||
flex-shrink: 0;
|
||
cursor: pointer;
|
||
}
|
||
.form-check-label {
|
||
cursor: pointer;
|
||
}
|
||
.form-switch .form-check-input {
|
||
appearance: none;
|
||
-webkit-appearance: none;
|
||
width: 2em;
|
||
height: 1em;
|
||
background-color: var(--val-color--switch-off);
|
||
border-radius: 1em;
|
||
position: relative;
|
||
cursor: pointer;
|
||
transition: background-color .15s ease-in-out;
|
||
}
|
||
.form-switch .form-check-input::after {
|
||
content: "";
|
||
position: absolute;
|
||
width: 1em;
|
||
height: 1em;
|
||
background-color: white;
|
||
border-radius: 50%;
|
||
top: 0;
|
||
left: 0;
|
||
transition: transform .15s ease-in-out;
|
||
box-shadow: 0 0 0 1px rgba(0, 0, 0, .25);
|
||
}
|
||
.form-switch .form-check-input:checked {
|
||
background-color: var(--val-color--primary);
|
||
}
|
||
.form-switch .form-check-input:checked::after {
|
||
transform: translateX(1em);
|
||
}
|
||
|
||
input:disabled,
|
||
input:disabled + label {
|
||
cursor: default !important;
|
||
}
|
||
input:disabled + label {
|
||
color: var(--val-color--text--muted);
|
||
}
|
||
|
||
/*
|
||
* Dropdown component
|
||
*/
|
||
|
||
.dropdown {
|
||
position: relative;
|
||
display: inline-block;
|
||
}
|
||
|
||
.dropdown-button,
|
||
.dropdown-toggle {
|
||
padding: 0.5rem 0.75rem;
|
||
font: inherit;
|
||
color: var(--val-color--text);
|
||
background-color: transparent;
|
||
border: 1px solid var(--val-color--border);
|
||
border-radius: 0.375rem;
|
||
cursor: pointer;
|
||
}
|
||
.dropdown-toggle::after {
|
||
content: "";
|
||
display: inline-block;
|
||
width: 0.4em;
|
||
height: 0.4em;
|
||
margin-left: 0.35em;
|
||
border-right: 0.125em solid currentColor;
|
||
border-bottom: 0.125em solid currentColor;
|
||
transform: rotate(45deg);
|
||
transition: transform .15s ease-in-out;
|
||
}
|
||
.dropdown:has(> .dropdown-menu.show) > .dropdown-toggle::after {
|
||
transform: rotate(-135deg);
|
||
}
|
||
|
||
.dropdown-menu {
|
||
position: absolute;
|
||
z-index: 1000;
|
||
top: 100%;
|
||
left: 0;
|
||
min-width: 12rem;
|
||
margin: 0.25rem 0 0;
|
||
padding: 0.5rem 0;
|
||
list-style: none;
|
||
background-color: var(--val-color--bg);
|
||
border: 1px solid color-mix(in srgb, var(--val-color--border) 15%, var(--val-color--bg));
|
||
border-radius: 0.375rem;
|
||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||
}
|
||
.dropdown-menu.hide {
|
||
display: none;
|
||
}
|
||
|
||
.dropdown-item {
|
||
display: block;
|
||
width: 100%;
|
||
padding: 0.375rem 1rem;
|
||
text-align: left;
|
||
color: var(--val-color--text);
|
||
text-decoration: none;
|
||
background-color: transparent;
|
||
border: none;
|
||
font: inherit;
|
||
cursor: pointer;
|
||
}
|
||
.dropdown-item:hover {
|
||
background-color: color-mix(in srgb, var(--val-color--text) 8%, transparent);
|
||
}
|
||
.dropdown-item.active {
|
||
color: var(--val-color--primary);
|
||
font-weight: 600;
|
||
}
|
||
.dropdown-item.disabled {
|
||
color: var(--val-color--text--muted);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.dropdown-item-text {
|
||
display: block;
|
||
padding: 0.375rem 1rem;
|
||
color: var(--val-color--text--muted);
|
||
}
|
||
|
||
.dropdown-header {
|
||
display: block;
|
||
padding: 0.5rem 1rem 0.25rem;
|
||
margin: 0;
|
||
font-size: 0.8125rem;
|
||
font-weight: 600;
|
||
color: var(--val-color--text--muted);
|
||
}
|
||
|
||
.dropdown-divider {
|
||
height: 0;
|
||
margin: 0.5rem 0;
|
||
border: none;
|
||
border-top: 1px solid var(--val-color--border);
|
||
}
|
||
|
||
/* Utility: visually hidden but still accessible to assistive technology */
|
||
.visually-hidden {
|
||
position: absolute;
|
||
width: 1px;
|
||
height: 1px;
|
||
padding: 0;
|
||
margin: -1px;
|
||
overflow: hidden;
|
||
clip: rect(0, 0, 0, 0);
|
||
white-space: nowrap;
|
||
border: 0;
|
||
}
|
||
|
||
/*
|
||
* Messages component
|
||
*/
|
||
|
||
.message {
|
||
padding: 0.75rem 1rem;
|
||
margin-bottom: 1rem;
|
||
border: 1px solid transparent;
|
||
border-radius: 0.375rem;
|
||
}
|
||
|
||
.message-info {
|
||
color: color-mix(in srgb, var(--val-color--info) 40%, black);
|
||
background-color: color-mix(in srgb, var(--val-color--info) 15%, var(--val-color--bg));
|
||
border-color: color-mix(in srgb, var(--val-color--info) 40%, var(--val-color--bg));
|
||
}
|
||
|
||
.message-warning {
|
||
color: color-mix(in srgb, var(--val-color--warning) 40%, black);
|
||
background-color: color-mix(in srgb, var(--val-color--warning) 15%, var(--val-color--bg));
|
||
border-color: color-mix(in srgb, var(--val-color--warning) 40%, var(--val-color--bg));
|
||
}
|
||
|
||
.message-error {
|
||
color: color-mix(in srgb, var(--val-color--danger) 40%, black);
|
||
background-color: color-mix(in srgb, var(--val-color--danger) 15%, var(--val-color--bg));
|
||
border-color: color-mix(in srgb, var(--val-color--danger) 40%, var(--val-color--bg));
|
||
}
|
||
|
||
/*
|
||
* Table component
|
||
*/
|
||
|
||
.table-responsive {
|
||
overflow-x: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
text-align: left;
|
||
}
|
||
|
||
.table th,
|
||
.table td {
|
||
padding: 0.5rem 0.75rem;
|
||
border-bottom: 1px solid color-mix(in srgb, var(--val-color--border) 15%, var(--val-color--bg));
|
||
}
|
||
|
||
.table thead th {
|
||
border-bottom-width: 2px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.table-sort {
|
||
color: inherit;
|
||
text-decoration: none;
|
||
}
|
||
.table-sort:hover {
|
||
text-decoration: underline;
|
||
}
|
||
.table-sort::after {
|
||
content: "\25BC";
|
||
margin-left: 0.25rem;
|
||
font-size: 0.8em;
|
||
opacity: 0.15;
|
||
}
|
||
.table-sort-asc::after {
|
||
content: "\25B2";
|
||
font-size: 0.8em;
|
||
opacity: 1;
|
||
}
|
||
.table-sort-desc::after {
|
||
content: "\25BC";
|
||
font-size: 0.8em;
|
||
opacity: 1;
|
||
}
|
||
|
||
.table-empty {
|
||
text-align: center;
|
||
font-style: italic;
|
||
color: var(--val-color--text--muted);
|
||
}
|
||
|
||
/*
|
||
* Pager component
|
||
*/
|
||
|
||
.pager {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
margin: 1rem 0;
|
||
padding: 0 1rem;
|
||
}
|
||
.pager-align-start {
|
||
justify-content: flex-start;
|
||
}
|
||
.pager-align-center {
|
||
justify-content: center;
|
||
}
|
||
.pager-align-end {
|
||
justify-content: flex-end;
|
||
}
|
||
.pager-summary {
|
||
color: var(--val-color--text--muted);
|
||
font-size: 0.8125rem;
|
||
align-self: flex-start;
|
||
margin-inline-end: auto;
|
||
}
|
||
.pager-align-start .pager-summary {
|
||
order: 1;
|
||
margin-inline-end: 0;
|
||
margin-inline-start: auto;
|
||
}
|
||
.pager-align-center .pager-summary {
|
||
order: 1;
|
||
flex-basis: 100%;
|
||
text-align: center;
|
||
margin-inline-end: 0;
|
||
}
|
||
|
||
.pagination {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.25rem;
|
||
list-style: none;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
.pagination a {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: 1.5rem;
|
||
padding: 0.375rem 0.625rem;
|
||
border-radius: 0.375rem;
|
||
color: var(--val-color--text);
|
||
text-decoration: none;
|
||
}
|
||
.pagination a:hover {
|
||
background-color: color-mix(in srgb, var(--val-color--text) 8%, transparent);
|
||
}
|
||
.pagination .active a {
|
||
color: #fff;
|
||
background-color: var(--val-color--primary);
|
||
}
|
||
.pagination .disabled a {
|
||
color: var(--val-color--text--muted);
|
||
pointer-events: none;
|
||
cursor: default;
|
||
}
|
||
|
||
.page-ellipsis {
|
||
padding: 0.375rem 0.25rem;
|
||
color: var(--val-color--text--muted);
|
||
}
|
||
|
||
/* .page-link-icon muestra el texto de navegación de los botones anterior/siguiente. El texto
|
||
accesible completo va aparte, en el aria-label del enlace. Por eso sustituir el texto visible por
|
||
otro contenido no afecta a la accesibilidad, p.ej. para usar "‹"/"›" se puede aplicar:
|
||
|
||
.page-link-icon {
|
||
display: inline-block;
|
||
font-size: 0;
|
||
}
|
||
.page-previous .page-link-icon::before {
|
||
content: "‹";
|
||
font-size: 1rem;
|
||
display: inline-block;
|
||
transform: translateY(-0.15em) scale(1.5);
|
||
}
|
||
.page-next .page-link-icon::before {
|
||
content: "›";
|
||
font-size: 1rem;
|
||
display: inline-block;
|
||
transform: translateY(-0.15em) scale(1.5);
|
||
}
|
||
*/
|
||
|
||
.pager-jump {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.pager-jump:focus-within {
|
||
border-radius: 0.375rem;
|
||
box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--val-color--primary) 25%, transparent);
|
||
}
|
||
.pager-jump-input > input.form-control:focus,
|
||
.pager-jump-button:focus {
|
||
outline: none;
|
||
box-shadow: none;
|
||
}
|
||
.pager-jump-input > input.form-control {
|
||
width: calc(var(--pager-jump-width, 1ch) + 2.5rem);
|
||
padding: 0.375rem 0.625rem;
|
||
line-height: var(--val-lh--base);
|
||
border: 0;
|
||
border-start-end-radius: 0;
|
||
border-end-end-radius: 0;
|
||
background-color: var(--val-color--light);
|
||
}
|
||
.pager-jump-input > input.form-control {
|
||
text-align: center;
|
||
appearance: textfield;
|
||
-moz-appearance: textfield;
|
||
}
|
||
.pager-jump-input > input.form-control::-webkit-outer-spin-button,
|
||
.pager-jump-input > input.form-control::-webkit-inner-spin-button {
|
||
-webkit-appearance: none;
|
||
margin: 0;
|
||
}
|
||
.pager-jump-button {
|
||
padding: 0.375rem 0.625rem;
|
||
border: 0;
|
||
border-start-start-radius: 0;
|
||
border-end-start-radius: 0;
|
||
}
|
||
.pager-jump-button:hover {
|
||
background-color: color-mix(in srgb, var(--val-color--primary) 85%, black);
|
||
}
|
||
|
||
/*
|
||
* Breadcrumb component
|
||
*/
|
||
|
||
.breadcrumb {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
list-style: none;
|
||
margin: 0 0 1rem;
|
||
padding: 0.75rem 1rem;
|
||
font-size: 0.875rem;
|
||
}
|
||
.breadcrumb-item + .breadcrumb-item {
|
||
padding-left: 0.5rem;
|
||
}
|
||
.breadcrumb-item + .breadcrumb-item::before {
|
||
float: left;
|
||
padding-right: 0.5rem;
|
||
color: var(--val-color--text--muted);
|
||
content: "/";
|
||
}
|
||
.breadcrumb-item.active {
|
||
color: var(--val-color--text--muted);
|
||
}
|
||
.breadcrumb-item a {
|
||
color: var(--val-color--text);
|
||
text-decoration: none;
|
||
}
|
||
.breadcrumb-item a:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/*
|
||
* Region Footer
|
||
*/
|
||
|
||
.region-footer {
|
||
padding: .75rem 0 3rem;
|
||
text-align: center;
|
||
}
|