Initial commit

This commit is contained in:
ThePetrovich 2026-08-17 22:42:04 +08:00
commit 97e799fd52
61 changed files with 2252 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,326 @@
/* =============================================================================
YKSA UI kit. Ships with yksa-web-kit; see ecosystem/ui-kit.md.
Requires Bootstrap >= 5.3: the state pills below are built on the
--bs-*-bg-subtle / --bs-*-text-emphasis / --bs-*-border-subtle families, and
text-body-secondary is a 5.3 utility. On 5.2.3 every rule here still parses
and the page renders wrong -- muted text is not muted, tinted backgrounds are
transparent. The bundled bootstrap.min.css is the version this is written for;
do not point a service at its own older copy.
Two rules govern the whole kit:
1. Typography carries meaning through weight, colour and size only. No
small-caps, no thin/semibold, no letter-spacing, no .display-*. Weights
are 400 and 700.
2. Colour is never the only signal. Every state renders an icon and a word
alongside its hue.
Anything Bootstrap already provides is used as-is. The classes below exist
only where it has no equivalent.
============================================================================= */
:root {
--navbar-height: 44px;
}
/* -----------------------------------------------------------------------------
Navbar and footer -- layout-identical across every service
-------------------------------------------------------------------------- */
.custom-navbar {
height: var(--navbar-height);
padding-top: 0;
padding-bottom: 0;
z-index: 1002;
border: none;
background-color: var(--bs-body-bg) !important;
}
.navbar {
z-index: 1002;
}
.navbar-brand {
margin-right: 1em;
}
/* Nav links fill the bar's height and butt against one another, so the active
item reads as a selected tab rather than a highlighted word. */
.nav-full-height {
display: flex;
align-items: center;
height: 100%;
}
.nav-full-height.nav-link {
color: inherit;
padding-left: 1rem !important;
padding-right: 1rem !important;
padding-top: 12px;
background-color: var(--bs-body-bg);
margin-right: -1px;
}
.nav-full-height.nav-link:hover,
.nav-full-height.nav-link.active {
color: #fff !important;
background-color: var(--bs-primary);
}
/* -----------------------------------------------------------------------------
State -- the sanctioned rendering of status (ui/_state.html)
-------------------------------------------------------------------------- */
.yksa-state {
display: inline-flex;
align-items: center;
gap: .25rem;
font-size: .75rem;
font-weight: 700;
padding: .05rem .4rem;
white-space: nowrap;
border: 1px solid transparent;
}
/* health */
.yksa-state-ok,
.yksa-state-complete {
color: var(--bs-success-text-emphasis);
background: var(--bs-success-bg-subtle);
border-color: var(--bs-success-border-subtle);
}
.yksa-state-warning,
.yksa-state-forced {
color: var(--bs-warning-text-emphasis);
background: var(--bs-warning-bg-subtle);
border-color: var(--bs-warning-border-subtle);
}
.yksa-state-failed {
color: var(--bs-danger-text-emphasis);
background: var(--bs-danger-bg-subtle);
border-color: var(--bs-danger-border-subtle);
}
.yksa-state-running,
.yksa-state-in-progress {
color: var(--bs-primary-text-emphasis);
background: var(--bs-primary-bg-subtle);
border-color: var(--bs-primary-border-subtle);
}
.yksa-state-skipped,
.yksa-state-unknown,
.yksa-state-not-started {
color: var(--bs-secondary-color);
background: var(--bs-secondary-bg-subtle);
border-color: var(--bs-border-color);
}
/* Neutral metadata chip. Not a coloured badge, because it carries no status. */
.yksa-chip {
display: inline-flex;
align-items: center;
gap: .25rem;
font-size: .75rem;
padding: 0 .35rem;
white-space: nowrap;
color: var(--bs-secondary-color);
background: var(--bs-tertiary-bg);
border: 1px solid var(--bs-border-color);
}
/* -----------------------------------------------------------------------------
Typography helpers
-------------------------------------------------------------------------- */
.yksa-label {
font-size: .75rem;
font-weight: 700;
color: var(--bs-secondary-color);
}
.yksa-hint {
font-size: .75rem;
font-weight: 400;
color: var(--bs-secondary-color);
}
/* Tabular numerals in the body face. Monospace is reserved for verbatim machine
text -- hex dumps, TLE lines, command mnemonics. */
.yksa-num {
font-variant-numeric: tabular-nums;
}
.yksa-readout {
font-variant-numeric: tabular-nums;
font-weight: 700;
line-height: 1;
}
.yksa-utc {
font-variant-numeric: tabular-nums;
}
.yksa-utc .yksa-local {
color: var(--bs-secondary-color);
font-size: .8em;
}
/* -----------------------------------------------------------------------------
Layout
-------------------------------------------------------------------------- */
/* A record in a list is a row with a left status marker, not a card. */
.yksa-row {
display: flex;
align-items: center;
gap: .75rem;
padding: .5rem;
border-left: 4px solid var(--bs-border-color);
}
.yksa-row:hover {
background: var(--bs-tertiary-bg);
}
.yksa-row.is-in-progress { border-left-color: var(--bs-primary); }
.yksa-row.is-complete { border-left-color: var(--bs-success); }
.yksa-row.is-pending { border-left-color: var(--bs-warning); }
.yksa-row.is-failed { border-left-color: var(--bs-danger); }
/* The one saturated element allowed on a surface: the active shift, the pass in
contact, the source currently polling. Two on a page means one is wrong. */
.yksa-row.is-active {
border-left-color: var(--bs-success);
background: var(--bs-success-bg-subtle);
}
/* Empty state: a sentence plus, where there is one, the action that resolves
it -- beside the sentence, not under it. Never a blank card. */
.yksa-empty {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .75rem;
padding: 1.25rem;
color: var(--bs-secondary-color);
}
/* Reading column for forms and reference pages that are worse for being wide. */
.yksa-narrow {
max-width: 920px;
}
/* Save bar pinned to the viewport bottom, plus a spacer so it never covers the
last row of the form it belongs to. */
.yksa-actionbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 1030;
}
.yksa-actionbar-spacer {
height: 5rem;
}
.form-error-bar ul {
margin-bottom: 0;
}
/* -----------------------------------------------------------------------------
Cookie banner
-------------------------------------------------------------------------- */
.cookie-banner {
position: sticky;
bottom: 0;
left: 0;
right: 0;
z-index: 1030;
background-color: #1f2937;
color: #f8fafc;
}
.cookie-banner a {
color: #bfdbfe;
}
/* -----------------------------------------------------------------------------
Responsive
-------------------------------------------------------------------------- */
@media (max-width: 991px) {
/* Collapsed, the nav is a stacked list; the full-height tab treatment would
put a border around every row. */
.nav-full-height.nav-link {
padding: var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);
margin-right: 0;
border: none !important;
}
.custom-navbar {
height: auto;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
}
/* -----------------------------------------------------------------------------
Chip filters (yksa/includes/chip_filters.html + src/chip-filters.js)
-------------------------------------------------------------------------- */
.filter-chip {
cursor: pointer;
user-select: none;
transition: background-color 0.12s ease;
}
.filter-chip:hover {
filter: brightness(110%);
}
.filter-chip.active {
background-color: var(--bs-primary) !important;
color: #fff;
}
/* -----------------------------------------------------------------------------
Prose and tables
Long-form text rendered from the database (policies, descriptions) and the
table cells that hold it. Everything else that used to live in main.css was
qsl-only and did not come across.
-------------------------------------------------------------------------- */
.text-content {
overflow: auto;
hyphens: auto;
}
.text-content img {
max-width: 100%;
height: auto !important;
}
.text-content p:last-child,
.text-content ul:last-child,
.text-content ol:last-child,
td p:last-child,
td ul:last-child {
margin-bottom: 0 !important;
}
/* Django's messages framework emits `error`; Bootstrap only ships `danger`. */
.alert-error {
--bs-alert-color: #fff;
--bs-alert-bg: #c42526;
--bs-alert-border-color: #c42526;
}
.btn-outline-bordered {
border-color: rgba(0, 0, 0, 0.066);
}