mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-10-08 13:35:25 +00:00
* build: move frontend assets to Bootstrap 5.3 and Tom Select * feat: migrate templates and scripts to Bootstrap 5, dropping jQuery Templates - Rename Bootstrap 4 classes and data attributes (data-bs-*, ms-/me-/ps-/pe-, text-start/end, form-group -> mb-3, input-group wrappers removed, badges, custom controls -> form-check/form-select, media -> d-flex, btn-close, ...) - Dark mode now uses Bootstrap 5.3 colour modes (data-bs-theme on <html>), set from <head> to avoid a flash of the light theme - Remove the Bootstrap 4 /bootstrap/ demo page - Contextual table classes (table-success etc.) still work as plain backgrounds for the rigboard key JavaScript - Remove jQuery: src.js/interaction.js and every inline template script are rewritten in plain JS on top of small helpers (helpers.js, bundled with Bootstrap into jpop.js so inline scripts can use them) - Replace bootstrap-select/ajax-bootstrap-select with Tom Select. The remote search now sends the `q` parameter and reads `text`, which is what the API actually uses (the old picker sent `term` and read `label`) - HTML fragments are fetched with an X-Requested-With header so views keep rendering their modal variants, and fetched scripts are re-executed - Remove the Bootstrap 4 plugin script includes * fix: stop rigboard header buttons stretching to full width under Bootstrap 5 * fix: restore dark-mode brand colours and contextual table colours under Bootstrap 5 * fix: brighten dark-mode links and make coloured card outlines visible * fix: calendar layout and grid borders, navbar search button width, guard missing modal links * fix: readable text in dark-mode Tom Select inputs and placeholders, restore form-control column widths * build: split the Dockerfile into cached stages with prod and dev targets * deploy: make compose.yml development-only with live reload, and document it * fix: keep badge text colour for links inside badges * fix: restore table-bordered grid lines in dark mode * fix: include Bootstrap's progress styles and keep progress labels readable
548 lines
13 KiB
SCSS
548 lines
13 KiB
SCSS
// Bootstrap 5 is consumed via @import (the Sass module system is not yet supported by Bootstrap's own build)
|
|
@import "custom-variables";
|
|
//Required
|
|
@import "node_modules/bootstrap/scss/functions";
|
|
@import "node_modules/bootstrap/scss/variables";
|
|
@import "node_modules/bootstrap/scss/variables-dark";
|
|
@import "node_modules/bootstrap/scss/maps";
|
|
@import "node_modules/bootstrap/scss/mixins";
|
|
@import "node_modules/bootstrap/scss/utilities";
|
|
//Optional
|
|
@import "node_modules/bootstrap/scss/root";
|
|
@import "node_modules/bootstrap/scss/reboot";
|
|
@import "node_modules/bootstrap/scss/type";
|
|
@import "node_modules/bootstrap/scss/images";
|
|
@import "node_modules/bootstrap/scss/containers";
|
|
@import "node_modules/bootstrap/scss/grid";
|
|
@import "node_modules/bootstrap/scss/tables";
|
|
@import "node_modules/bootstrap/scss/forms";
|
|
@import "node_modules/bootstrap/scss/buttons";
|
|
@import "node_modules/bootstrap/scss/transitions";
|
|
@import "node_modules/bootstrap/scss/dropdown";
|
|
@import "node_modules/bootstrap/scss/button-group";
|
|
@import "node_modules/bootstrap/scss/nav";
|
|
@import "node_modules/bootstrap/scss/navbar";
|
|
@import "node_modules/bootstrap/scss/card";
|
|
@import "node_modules/bootstrap/scss/pagination";
|
|
@import "node_modules/bootstrap/scss/badge";
|
|
@import "node_modules/bootstrap/scss/alert";
|
|
@import "node_modules/bootstrap/scss/list-group";
|
|
@import "node_modules/bootstrap/scss/close";
|
|
@import "node_modules/bootstrap/scss/modal";
|
|
@import "node_modules/bootstrap/scss/tooltip";
|
|
@import "node_modules/bootstrap/scss/popover";
|
|
@import "node_modules/bootstrap/scss/progress";
|
|
@import "node_modules/bootstrap/scss/spinners";
|
|
@import "node_modules/bootstrap/scss/helpers";
|
|
@import "node_modules/bootstrap/scss/utilities/api";
|
|
//FontAwesome
|
|
$fa-font-path: '/static/fonts';
|
|
@import "node_modules/@fortawesome/fontawesome-free/scss/fontawesome";
|
|
@import "node_modules/@fortawesome/fontawesome-free/scss/solid";
|
|
|
|
html {
|
|
--brand: #3F58AA;
|
|
scrollbar-color: #3F58AA Canvas !important;
|
|
}
|
|
|
|
:root { accent-color: var(--brand); }
|
|
:focus-visible { outline-color: var(--brand); }
|
|
::selection { background-color: var(--brand); }
|
|
::marker { color: var(--brand); }
|
|
|
|
:is(
|
|
::-webkit-calendar-picker-indicator,
|
|
::-webkit-clear-button,
|
|
::-webkit-inner-spin-button,
|
|
::-webkit-outer-spin-button
|
|
) {
|
|
color: var(--brand);
|
|
}
|
|
|
|
@media screen and
|
|
(prefers-reduced-motion: reduce),
|
|
(update: slow) {
|
|
* {
|
|
animation-duration: 0.001ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.001ms !important;
|
|
}
|
|
}
|
|
|
|
.fc-event-main {
|
|
color: black !important;
|
|
}
|
|
|
|
.fc-daygrid-dot-event {
|
|
color: black !important;
|
|
}
|
|
|
|
.fc-timeGridDay-view {
|
|
.fc-event-main {
|
|
font-size: large !important;
|
|
}
|
|
}
|
|
|
|
.fc-timeGridWeek-view {
|
|
.fc-event-main {
|
|
font-size: 0.9rem;
|
|
}
|
|
}
|
|
|
|
#content {
|
|
padding: 40px 15px;
|
|
}
|
|
|
|
#userdropdown > li {
|
|
padding: 0 0.3em;
|
|
}
|
|
|
|
#userdropdown > li, #activity {
|
|
.media-object {
|
|
max-width: 3em;
|
|
}
|
|
}
|
|
|
|
// Bootstrap 4's contextual table classes also worked as background colours on non-table elements
|
|
@each $color, $value in $table-variants {
|
|
.table-#{$color}:not(table):not(tr):not(td):not(th) {
|
|
background-color: var(--bs-table-bg);
|
|
}
|
|
}
|
|
|
|
// Bootstrap 4 columns used max-width, so `.form-control.col-sm-6` stayed narrow; Bootstrap 5's
|
|
// `.form-control { width: 100% }` now wins over the column width
|
|
@each $breakpoint, $_min in $grid-breakpoints {
|
|
@include media-breakpoint-up($breakpoint) {
|
|
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
|
|
@for $i from 1 through $grid-columns {
|
|
.form-control.col#{$infix}-#{$i},
|
|
.form-select.col#{$infix}-#{$i} {
|
|
width: calc(#{$i} / #{$grid-columns} * 100%);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Links inside badges (e.g. "Reviewed by ...") sit on a coloured background, so keep the badge's text colour
|
|
.badge a {
|
|
color: inherit;
|
|
text-decoration: underline;
|
|
}
|
|
|
|
// Bootstrap 4 gave labels a bottom margin, Bootstrap 5 expects .form-label
|
|
label {
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.table tbody > tr > td.vert-align {
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.align-right {
|
|
text-align: right;
|
|
}
|
|
|
|
textarea {
|
|
width: 100%;
|
|
resize: vertical;
|
|
}
|
|
|
|
.custom-combobox {
|
|
display: block;
|
|
}
|
|
|
|
.event-mic-photo {
|
|
max-width: 2em;
|
|
border-radius: 0.25em;
|
|
}
|
|
|
|
.item-description {
|
|
margin-left: 1em;
|
|
}
|
|
|
|
.overflow-ellipsis {
|
|
text-overflow: ellipsis;
|
|
display: inline-block;
|
|
max-width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.dont-break-out {
|
|
overflow-wrap: break-word;
|
|
word-wrap: break-word;
|
|
hyphens: auto;
|
|
}
|
|
|
|
del {
|
|
background-color: #f2dede;
|
|
border-radius: 3px;
|
|
padding: 0.1em;
|
|
}
|
|
|
|
ins {
|
|
background-color: #dff0d8;
|
|
border-radius: 3px;
|
|
padding: 0.1em;
|
|
}
|
|
|
|
.nav-link {
|
|
color: $gray-400 !important;
|
|
}
|
|
|
|
.btn-light {
|
|
--bs-btn-bg: #{$gray-200};
|
|
}
|
|
|
|
.skip-link {
|
|
background: $dark;
|
|
outline: unset;
|
|
height: 30px;
|
|
left: 50%;
|
|
padding: 8px;
|
|
position: absolute;
|
|
transform: translateY(-100%);
|
|
transition: transform 0.3s;
|
|
}
|
|
|
|
.skip-link:focus {
|
|
transform: translateY(45px); /* TODO Remove absolute positioning */
|
|
}
|
|
|
|
.errorlist > li {
|
|
list-style-type: none;
|
|
}
|
|
|
|
pre {
|
|
page-break-inside: avoid;
|
|
font-family: monospace;
|
|
font-size: 15px;
|
|
line-height: 1.6;
|
|
margin-bottom: 1.6em;
|
|
max-width: 100%;
|
|
overflow: auto;
|
|
padding: 1em 1.5em;
|
|
display: block;
|
|
word-wrap: break-word;
|
|
}
|
|
|
|
svg {
|
|
display: inline;
|
|
white-space: no-wrap;
|
|
}
|
|
|
|
span.fas {
|
|
padding-left: 0.1em !important;
|
|
padding-right: 0.3em !important;
|
|
}
|
|
|
|
html.embedded {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
height: 100%;
|
|
max-height: 100%;
|
|
overflow: hidden;
|
|
justify-content: center;
|
|
|
|
body{
|
|
padding:0;
|
|
width:100%;
|
|
background:none;
|
|
overflow: auto;
|
|
}
|
|
|
|
.embed_container{
|
|
border:5px solid #e9e9e9;
|
|
padding:12px 0px;
|
|
min-height:100%;
|
|
width:100%;
|
|
}
|
|
|
|
.source{
|
|
background: url('/static/imgs/pyrigs-avatar.png') no-repeat;
|
|
background-size: 16px 16px;
|
|
padding-left: 20px;
|
|
color: #000;
|
|
}
|
|
|
|
h3{
|
|
margin-top:10px;
|
|
margin-bottom:5px;
|
|
}
|
|
|
|
p{
|
|
margin-bottom:2px;
|
|
font-size: 11px;
|
|
}
|
|
|
|
.event-mic-photo{
|
|
max-width: 3em;
|
|
}
|
|
}
|
|
|
|
.markdown {
|
|
h1 {
|
|
font-size: $h1-font-size * 0.75;
|
|
}
|
|
h2 {
|
|
font-size: $h2-font-size * 0.8;
|
|
}
|
|
h3 {
|
|
font-size: $h3-font-size * 0.85;
|
|
}
|
|
h4 {
|
|
font-size: $h4-font-size * 0.9;
|
|
}
|
|
h5 {
|
|
font-size: $h5-font-size * 0.95;
|
|
}
|
|
|
|
img {
|
|
max-width: 100%;
|
|
}
|
|
}
|
|
|
|
#rigboard {
|
|
.markdown {
|
|
img {
|
|
max-width: 30rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
.CodeMirror, .editor-toolbar {
|
|
border-radius: 0 !important;
|
|
}
|
|
|
|
.ts-wrapper.form-select, .ts-wrapper.form-control {
|
|
padding: 0;
|
|
}
|
|
// New implementation of class dropped in Bootstrap 3
|
|
.dl-horizontal {
|
|
display: grid;
|
|
grid-template-columns: auto 1fr;
|
|
gap: 0.7rem 0;
|
|
}
|
|
.dl-horizontal > dd, .dl-horizontal .markdown > p {
|
|
margin-bottom: 0 !important;
|
|
}
|
|
|
|
// Dark mode: Bootstrap 5.3 colour modes (set via data-bs-theme on <html>), with a few project-specific tweaks
|
|
$darktheme: #121416;
|
|
|
|
// Brighter brand colours for dark mode (the light-mode ones are pastel tints on a dark background)
|
|
$dark-theme-colors: (
|
|
"success": #3AB54A,
|
|
"warning": #FFE89B,
|
|
"danger": #BF1E2E,
|
|
"info": #25AAE2,
|
|
"primary": #3A52A2,
|
|
"secondary": $secondary,
|
|
"light": $light,
|
|
"dark": $dark
|
|
);
|
|
|
|
[data-bs-theme="dark"] {
|
|
@each $name, $value in $dark-theme-colors {
|
|
--bs-#{$name}: #{$value};
|
|
--bs-#{$name}-rgb: #{to-rgb($value)};
|
|
|
|
.btn-#{$name} {
|
|
@include button-variant($value, $value);
|
|
}
|
|
.btn-outline-#{$name} {
|
|
@include button-outline-variant($value);
|
|
}
|
|
.text-bg-#{$name} {
|
|
color: color-contrast($value) !important;
|
|
background-color: RGBA(to-rgb($value), var(--bs-bg-opacity, 1)) !important;
|
|
}
|
|
// Contextual table classes (tables, rows, cells and the plain-element variant used for the rigboard key)
|
|
.table-#{$name} {
|
|
--bs-table-color: #{color-contrast(shade-color($value, 55%))};
|
|
--bs-table-bg: #{shade-color($value, 55%)};
|
|
--bs-table-border-color: #{shade-color($value, 35%)};
|
|
--bs-table-striped-bg: #{shade-color($value, 50%)};
|
|
--bs-table-hover-bg: #{shade-color($value, 45%)};
|
|
color: var(--bs-table-color);
|
|
border-color: var(--bs-table-border-color);
|
|
}
|
|
}
|
|
--bs-body-bg: #222;
|
|
--bs-body-color: #{$gray-100};
|
|
// Bootstrap derives these from $primary, which is too dim on the dark background
|
|
--bs-link-color: #6ea8fe;
|
|
--bs-link-color-rgb: #{to-rgb(#6ea8fe)};
|
|
--bs-link-hover-color: #8bb9fe;
|
|
--bs-link-hover-color-rgb: #{to-rgb(#8bb9fe)};
|
|
--bs-secondary-color: #c9c9c9;
|
|
--bs-tertiary-bg: #{$darktheme};
|
|
|
|
.navbar {
|
|
background-color: #111111 !important;
|
|
}
|
|
// Coloured card outlines (training levels): make them visible, including the "dark" and "light" ones
|
|
.card[class*="border-"] {
|
|
--bs-card-border-width: 2px;
|
|
}
|
|
.border-dark {
|
|
border-color: $gray-500 !important;
|
|
}
|
|
.dropdown-menu, .popover {
|
|
box-shadow: 0 0.5rem 1rem black;
|
|
--bs-dropdown-bg: #{$darktheme};
|
|
--bs-popover-bg: #{$darktheme};
|
|
}
|
|
.form-control:not(.btn), .form-select, .ts-control, .ts-dropdown {
|
|
background-color: $darktheme;
|
|
color: $gray-100;
|
|
}
|
|
// Tom Select hard-codes dark text colours
|
|
.ts-wrapper .ts-control,
|
|
.ts-wrapper .ts-control input,
|
|
.ts-dropdown,
|
|
.ts-dropdown .option,
|
|
.ts-dropdown .optgroup-header,
|
|
.ts-dropdown .no-results,
|
|
.ts-dropdown .create {
|
|
color: $gray-100;
|
|
}
|
|
.ts-wrapper .ts-control input::placeholder {
|
|
color: $gray-500;
|
|
}
|
|
.ts-wrapper.multi .ts-control > div {
|
|
background: $gray-700;
|
|
color: $gray-100;
|
|
border-color: $gray-600;
|
|
}
|
|
.ts-wrapper.multi .ts-control > div.active {
|
|
background: $primary;
|
|
color: #fff;
|
|
}
|
|
.ts-dropdown .active {
|
|
background-color: $gray-800;
|
|
color: $gray-100;
|
|
}
|
|
.ts-dropdown .active.create {
|
|
color: $gray-100;
|
|
}
|
|
.ts-dropdown .optgroup-header {
|
|
background: $darktheme;
|
|
}
|
|
::placeholder {
|
|
color: $gray-500;
|
|
opacity: 1;
|
|
}
|
|
.btn-light, .status {
|
|
--bs-btn-bg: #{$darktheme};
|
|
--bs-btn-color: #{$gray-100};
|
|
--bs-btn-border-color: #{$darktheme};
|
|
--bs-btn-hover-bg: #{tint-color($darktheme, 8%)};
|
|
--bs-btn-hover-color: #{$gray-100};
|
|
--bs-btn-hover-border-color: #{$darktheme};
|
|
background-color: $darktheme !important;
|
|
color: $gray-100 !important;
|
|
border-color: $darktheme;
|
|
}
|
|
.btn-link {
|
|
color: white;
|
|
}
|
|
.input-group-text {
|
|
border-color: $darktheme;
|
|
}
|
|
.page-item.disabled {
|
|
opacity: 0.5;
|
|
}
|
|
.bg-light {
|
|
color: black;
|
|
background-color: $gray-200 !important;
|
|
border-radius: 0.2em;
|
|
}
|
|
.fc-day-today {
|
|
background-color: transparent !important;
|
|
border: 0.2em solid $info !important;
|
|
}
|
|
.fc-daygrid-dot-event {
|
|
color: white !important;
|
|
}
|
|
@each $color, $value in $dark-theme-colors {
|
|
#event_row.table-#{$color} {
|
|
border: 0.3em solid shade-color($value, 60%) !important;
|
|
background-color: #222 !important;
|
|
color: white !important;
|
|
}
|
|
}
|
|
del {
|
|
color: black;
|
|
background-color: $danger;
|
|
border-radius: 3px;
|
|
}
|
|
ins {
|
|
color: black;
|
|
background-color: $success;
|
|
border-radius: 3px;
|
|
}
|
|
pre {
|
|
background: $gray-600;
|
|
color: white;
|
|
}
|
|
.source {
|
|
color: white !important;
|
|
}
|
|
.embed_container {
|
|
border-color: #3853a4 !important;
|
|
background: #222;
|
|
color: $gray-100;
|
|
}
|
|
input:-webkit-autofill,
|
|
input:-webkit-autofill:hover,
|
|
input:-webkit-autofill:focus,
|
|
textarea:-webkit-autofill,
|
|
textarea:-webkit-autofill:hover,
|
|
textarea:-webkit-autofill:focus,
|
|
select:-webkit-autofill,
|
|
select:-webkit-autofill:hover,
|
|
select:-webkit-autofill:focus {
|
|
border: 1px solid $info;
|
|
-webkit-text-fill-color: white;
|
|
-webkit-box-shadow: 0 0 0px 1000px rgba($info, .3) inset;
|
|
transition: background-color 5000s ease-in-out 0s;
|
|
}
|
|
.editor-toolbar > a {
|
|
color: white !important;
|
|
}
|
|
.editor-toolbar > a:hover {
|
|
background: transparent !important;
|
|
}
|
|
.editor-toolbar > a.active {
|
|
background: $info !important;
|
|
}
|
|
.cm-s-easymde {
|
|
color: white;
|
|
background-color: $darktheme;
|
|
border-color: #bbb;
|
|
}
|
|
.CodeMirror-cursor {
|
|
border-color: white !important;
|
|
}
|
|
}
|
|
|
|
.ts-wrapper.has-items .ts-control > input::placeholder {
|
|
color: transparent;
|
|
}
|
|
|
|
// FullCalendar (standard theme) colours, matching the site's light/dark modes
|
|
.fc {
|
|
--fc-border-color: var(--bs-border-color);
|
|
--fc-page-bg-color: var(--bs-body-bg);
|
|
--fc-neutral-bg-color: var(--bs-tertiary-bg);
|
|
--fc-today-bg-color: rgba(var(--bs-warning-rgb), 0.15);
|
|
--fc-list-event-hover-bg-color: var(--bs-tertiary-bg);
|
|
}
|
|
|
|
.fc a {
|
|
color: inherit;
|
|
text-decoration: none;
|
|
}
|