mirror of
https://github.com/Steffo99/bluelib.git
synced 2024-12-23 03:54:21 +00:00
713 lines
16 KiB
Text
713 lines
16 KiB
Text
/// ===== Root =====
|
|
/// Every HTML document using Bluelib must define a root, an element where all bluelib styles can start being applied.
|
|
/// Elements outside the root won't be styled at all, allowing Bluelib's styling to be contained in components or modules of a website.
|
|
|
|
@{bluelib} {
|
|
|
|
// Set the background defined in the palette
|
|
background-color: @hex-background;
|
|
|
|
// Set the base color to the foreground defined in the palette
|
|
.bluelib-color(@hex-foreground);
|
|
|
|
// By default, text should use the main font
|
|
.font-text();
|
|
|
|
/// ===== All =====
|
|
/// By default, browsers style elements with some weird rules.
|
|
/// This is an attempt to correct them, and to implement some Bluelib magic.
|
|
|
|
&, @{all} {
|
|
|
|
// Globally set the box-sizing to border-box, as content-box is completely insane
|
|
&, &::before, &::after {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
// Bluelib magic!
|
|
// This rule sets the color of all text to be equal to the current .bluelib-color() at 100% opacity.
|
|
// Thanks, CSS variables!
|
|
color: @bA;
|
|
|
|
}
|
|
|
|
/// ===== Layouts =====
|
|
/// Layouts arrange the content displayed inside the root.
|
|
/// Layouts are the second element in the Bluelib hierarchy, immediately following the root.
|
|
/// Ideally, a single layout should be used per page.
|
|
|
|
// The base layout class.
|
|
@{layout} {
|
|
display: grid;
|
|
justify-content: stretch;
|
|
align-items: stretch;
|
|
|
|
width: 100%;
|
|
}
|
|
|
|
// A layout with a single container spanning the whole screen.
|
|
@{layout-fill} {
|
|
padding: 4px;
|
|
|
|
grid-template-areas:
|
|
"single";
|
|
grid-template-columns: 1fr;
|
|
grid-template-rows: 1fr;
|
|
}
|
|
|
|
@{layout-fill-single} {
|
|
grid-area: single;
|
|
}
|
|
|
|
// A layout with a centered 1024px wide main container and two symmetric containers at the sides.
|
|
@{layout-threecol} {
|
|
padding: 4px;
|
|
|
|
@media screen and (min-width: 1281px) {
|
|
grid-template-areas:
|
|
"left center right";
|
|
grid-template-columns: 1fr auto 1fr;
|
|
grid-template-rows: 1fr;
|
|
}
|
|
|
|
// If the side containers would be smaller than 128px (if the screen is narrower than 1280px), the smaller containers are moved below the main one.
|
|
@media screen and (max-width: 1280px) {
|
|
grid-template-areas:
|
|
"center center"
|
|
"left right";
|
|
grid-template-columns: 1fr 1fr;
|
|
grid-template-rows: auto auto;
|
|
|
|
// Keep the container limited to 1024px and centered
|
|
max-width: 1024px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
}
|
|
}
|
|
|
|
@{layout-threecol-left} {
|
|
grid-area: left;
|
|
|
|
@media screen and (min-width: 1281px) {
|
|
justify-self: end;
|
|
}
|
|
|
|
@media screen and (max-width: 1280px) {
|
|
justify-self: stretch;
|
|
}
|
|
}
|
|
|
|
@{layout-threecol-center} {
|
|
grid-area: center;
|
|
|
|
// Ensure the container doesn't eat up all the space
|
|
max-width: 1024px;
|
|
}
|
|
|
|
@{layout-threecol-right} {
|
|
grid-area: right;
|
|
|
|
@media screen and (min-width: 1281px) {
|
|
justify-self: start;
|
|
}
|
|
|
|
@media screen and (max-width: 1280px) {
|
|
justify-self: stretch;
|
|
}
|
|
}
|
|
|
|
/// ===== Panels =====
|
|
/// Panels are the main sectioning elements available in Bluelib.
|
|
/// Many instance of them should be present on the page!
|
|
/// They should group small amounts of tightly related content, which can be understood more or less separately from the rest of the page.
|
|
|
|
// The base panel class.
|
|
@{panel} {
|
|
// Panels have a margin to separate them from other elements
|
|
margin: 8px 0;
|
|
// And a padding to separate them from their contents
|
|
padding: 8px;
|
|
|
|
// Panels should try to fill the most space possible
|
|
width: 100%;
|
|
|
|
background-color: @b0;
|
|
border-color: @b1;
|
|
|
|
// The first and last elements of a panel should not have a margin
|
|
> @{all} {
|
|
&:first-child {
|
|
margin-top: 0;
|
|
}
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// A panel which encloses its contents with a border.
|
|
@{panel-box} {
|
|
border-radius: 4px;
|
|
border-width: 2px;
|
|
border-style: solid;
|
|
}
|
|
|
|
// A panel which encloses its contents with a quote-like border.
|
|
@{panel-blockquote} {
|
|
border-radius: 4px;
|
|
border-width: 0 0 0 2px;
|
|
border-style: solid;
|
|
}
|
|
|
|
// A panel with no border whose contents are made smaller.
|
|
@{panel-aside} {
|
|
border-width: 0;
|
|
font-size: smaller;
|
|
}
|
|
|
|
/// ===== Split =====
|
|
/// A split is an element which splits everything contained inside in multiple columns of equal width.
|
|
|
|
@{split} {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 4px 8px;
|
|
justify-content: center;
|
|
|
|
> @{panel} {
|
|
// Add a horizontal margin to panels
|
|
margin: 0;
|
|
}
|
|
|
|
// Allow contained elements to grow
|
|
> @{all} {
|
|
flex-grow: 1;
|
|
flex-shrink: 0;
|
|
flex-basis: 0;
|
|
}
|
|
}
|
|
|
|
// Force a split to wrap
|
|
@{split-forcewrap} {
|
|
flex-grow: 0;
|
|
flex-shrink: 0;
|
|
flex-basis: 100%;
|
|
}
|
|
|
|
/// ===== Separators =====
|
|
/// Separators are horizontal lines separating elements.
|
|
|
|
@{separator} {
|
|
border-width: 1px;
|
|
border-style: solid;
|
|
border-color: @b5;
|
|
}
|
|
|
|
@{separator-light} {
|
|
border-color: @b1;
|
|
}
|
|
|
|
@{separator-heavy} {
|
|
border-color: @bA;
|
|
}
|
|
|
|
/// ===== Images =====
|
|
/// Images are changed to block elements and are automatically centered.
|
|
|
|
@{image} {
|
|
display: block;
|
|
|
|
max-width: 100%;
|
|
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
|
|
object-fit: contain;
|
|
}
|
|
|
|
@{image-limit-half} {
|
|
max-height: max(28.2vw, 50vh);
|
|
}
|
|
|
|
@{image-limit-quarter} {
|
|
max-height: max(14.1vw, 25vh);
|
|
}
|
|
|
|
/// ===== Status =====
|
|
/// Statuses are classes that can be applied to elements to indicate that special interactions are available.
|
|
|
|
@{status-disabled} {
|
|
opacity: 50%;
|
|
|
|
// All sub-elements of a disabled element should have a not-allowed cursor
|
|
&, @{all} {
|
|
cursor: not-allowed !important;
|
|
}
|
|
}
|
|
|
|
/// ===== Forms =====
|
|
/// Forms are containers where interactable elements are contained.
|
|
/// Every interactable is split in two parts: a label on the left and the control on the right
|
|
///
|
|
/// Example:
|
|
///
|
|
/// Username | Steffo
|
|
/// Email | ste.pigozzi@gmail.com
|
|
/// Password | ············
|
|
/// Country | Italy ↓
|
|
///
|
|
/// [Submit]
|
|
|
|
@{form} {
|
|
display: grid;
|
|
|
|
align-items: center;
|
|
row-gap: 4px;
|
|
column-gap: 8px;
|
|
|
|
// Labels should have the greater width between the one they require and 1/6 of the form width.
|
|
grid-template-columns: minmax(auto, 1fr) 5fr;
|
|
}
|
|
|
|
@{form-label} {
|
|
// Labels are on the left column of the grid
|
|
grid-column: 1;
|
|
// They should be right-aligned
|
|
justify-self: end;
|
|
text-align: right;
|
|
}
|
|
|
|
@{form-input} {
|
|
// Inputs are on the right column of the grid
|
|
grid-column: 2;
|
|
// They should occupy all the available space
|
|
justify-self: stretch;
|
|
width: 100%;
|
|
}
|
|
|
|
// An element filling a whole row of a form
|
|
// Useful for adding buttons or similar flow interruptions
|
|
@{form-row} {
|
|
grid-column-start: 1;
|
|
grid-column-end: 3;
|
|
|
|
display: flex;
|
|
gap: 8px;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 100%;
|
|
|
|
margin-top: 8px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
/// ===== Buttons =====
|
|
/// Buttons are clickable elements which should trigger an action when clicked.
|
|
/// Their contents are elements containing either an icon or text, or possibly both.
|
|
|
|
@{button} {
|
|
// Buttons are rendered as inline elements, but should arrange their contents as if they were flex
|
|
display: inline-flex;
|
|
|
|
// Center the button contents both vertically and horizontally
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
// Disable the operating system appearance for the button
|
|
appearance: none;
|
|
|
|
// Button properties should be set explicitly, as otherwise every browser will display them in a different manner
|
|
background-color: @bA;
|
|
color: @hex-away;
|
|
border: none;
|
|
padding: 6px 16px;
|
|
border-radius: 4px;
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
|
|
// Buttons should display a pointer cursor
|
|
cursor: pointer;
|
|
|
|
&:hover {
|
|
// Hovered buttons should provide feedback
|
|
background-color: @bC;
|
|
}
|
|
|
|
&:active {
|
|
// Activated buttons should provide greater feedback
|
|
background-color: @bF;
|
|
}
|
|
|
|
// Disabled buttons shouldn't do anything
|
|
&@{status-disabled} {
|
|
&:hover {
|
|
background-color: @bA;
|
|
}
|
|
|
|
&:active {
|
|
background-color: @bA;
|
|
}
|
|
}
|
|
|
|
// If using keyboard navigation, display an outline to make the focused button more evident
|
|
&:focus-visible {
|
|
outline: 4px solid @b7 !important;
|
|
}
|
|
}
|
|
|
|
@{button-fill-width} {
|
|
width: 100%;
|
|
}
|
|
|
|
@{button-toggle} {
|
|
padding: 4px 14px;
|
|
border-width: 2px;
|
|
border-style: solid;
|
|
|
|
&@{status-disabled} {
|
|
border-style: dashed;
|
|
}
|
|
}
|
|
|
|
@{button-toggle-off} {
|
|
border-color: @bA;
|
|
color: @bA;
|
|
background-color: @b0;
|
|
|
|
&:hover {
|
|
border-color: @bC;
|
|
color: @bC;
|
|
background-color: @b1;
|
|
}
|
|
|
|
&:active {
|
|
border-color: @bF;
|
|
color: @bF;
|
|
background-color: @b2;
|
|
}
|
|
|
|
&@{status-disabled} {
|
|
border-style: dashed;
|
|
|
|
&:hover {
|
|
border-color: @bA;
|
|
color: @bA;
|
|
background-color: @b0;
|
|
}
|
|
|
|
&:active {
|
|
border-color: @bA;
|
|
color: @bA;
|
|
background-color: @b0;
|
|
}
|
|
}
|
|
}
|
|
|
|
@{button-toggle-on} {
|
|
border-color: @bF;
|
|
color: @bF;
|
|
background-color: @b2;
|
|
|
|
&:hover {
|
|
border-color: @bC;
|
|
color: @bC;
|
|
background-color: @b1;
|
|
}
|
|
|
|
&:active {
|
|
border-color: @bA;
|
|
color: @bA;
|
|
background-color: @b0;
|
|
}
|
|
|
|
&@{status-disabled} {
|
|
border-style: dashed;
|
|
|
|
&:hover {
|
|
border-color: @bF;
|
|
color: @bF;
|
|
background-color: @b2;
|
|
}
|
|
|
|
&:active {
|
|
border-color: @bF;
|
|
color: @bF;
|
|
background-color: @b2;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Inputs ---
|
|
|
|
@{input} {
|
|
border-style: solid;
|
|
border-color: @b3;
|
|
color: @bA;
|
|
background-color: @b0;
|
|
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
|
|
&::placeholder {
|
|
color: @b4;
|
|
opacity: 1;
|
|
}
|
|
|
|
&:optional, &:optional::placeholder {
|
|
font-style: italic;
|
|
}
|
|
|
|
// &:valid:not(:placeholder-shown) {
|
|
// .bluelib-color(@hex-lime);
|
|
// }
|
|
|
|
&:invalid:not(:placeholder-shown) {
|
|
.bluelib-color(@hex-red);
|
|
}
|
|
|
|
&:hover, &:focus {
|
|
border-color: @b6;
|
|
color: @bF;
|
|
background-color: @b1;
|
|
|
|
&::placeholder {
|
|
color: @b7;
|
|
}
|
|
}
|
|
|
|
&@{status-disabled} {
|
|
border-style: dashed;
|
|
|
|
&:hover, &:focus {
|
|
border-color: @b3;
|
|
color: @bA;
|
|
background-color: @b0;
|
|
|
|
&::placeholder {
|
|
color: @b4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@{input-field} {
|
|
cursor: text;
|
|
|
|
border-width: 0 0 2px 0;
|
|
border-radius: 4px 4px 0 0;
|
|
padding: 4px 6px;
|
|
}
|
|
|
|
@{input-select}, @{input-multiselect} {
|
|
// Browsers add 4px of unremovable horizontal padding to options for some reason
|
|
padding: 4px 2px;
|
|
}
|
|
|
|
@{input-select-option}, @{input-multiselect-option} {
|
|
font-weight: normal;
|
|
color: @bA;
|
|
|
|
padding: 4px 4px;
|
|
|
|
// TODO: style checked elements, when it will be possible
|
|
}
|
|
|
|
@{input-select-optgroup}, @{input-multiselect-optgroup} {
|
|
font-weight: bold;
|
|
color: @hex-accent;
|
|
|
|
padding: 4px 4px;
|
|
|
|
@{input-select-option}, @{input-multiselect-option} {
|
|
padding: 4px 20px;
|
|
|
|
&::before {
|
|
content: "";
|
|
}
|
|
}
|
|
}
|
|
|
|
@{input-select-optgroup}, @{input-select-option}, @{input-multiselect-optgroup}, @{input-multiselect-option} {
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
font-style: inherit;
|
|
}
|
|
|
|
@{input-select} {
|
|
cursor: context-menu;
|
|
|
|
border-width: 0 0 2px 0;
|
|
border-radius: 4px 4px 0 0;
|
|
|
|
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
|
@{input-select-option}, @{input-select-optgroup} {
|
|
background-color: @hex-background;
|
|
}
|
|
}
|
|
}
|
|
|
|
@{input-multiselect} {
|
|
cursor: vertical-text;
|
|
|
|
border-width: 0 0 0 2px;
|
|
border-radius: 0 4px 4px 0;
|
|
}
|
|
|
|
// --- Elements ---
|
|
|
|
@{element-title} {
|
|
text-align: center;
|
|
.bluelib-color(@hex-accent);
|
|
.font-title();
|
|
}
|
|
|
|
@{element-paragraph} {
|
|
|
|
}
|
|
|
|
@{element-list-item} {
|
|
margin: 10px 0;
|
|
}
|
|
|
|
@{element-anchor} {
|
|
.bluelib-color(@hex-link);
|
|
text-decoration-line: underline;
|
|
text-decoration-style: solid;
|
|
text-decoration-color: currentColor;
|
|
text-decoration-thickness: 1px;
|
|
|
|
&:hover, &:focus {
|
|
.bluelib-color(@hex-link-hover);
|
|
}
|
|
|
|
&:focus-visible {
|
|
text-decoration-thickness: 2px;
|
|
}
|
|
|
|
&:active {
|
|
.bluelib-color(@hex-link-active);
|
|
}
|
|
|
|
&@{status-disabled} {
|
|
text-decoration-style: dashed;
|
|
|
|
&:hover, &:focus {
|
|
.bluelib-color(@hex-link);
|
|
}
|
|
|
|
&:active {
|
|
.bluelib-color(@hex-link);
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Alignment ---
|
|
|
|
@{align-left} {
|
|
text-align: left;
|
|
}
|
|
|
|
@{align-center} {
|
|
text-align: center;
|
|
}
|
|
|
|
@{align-right} {
|
|
text-align: right;
|
|
}
|
|
|
|
// --- Sizes ---
|
|
|
|
@{size-xxl} {
|
|
font-size: xx-large;
|
|
}
|
|
|
|
@{size-xl} {
|
|
font-size: x-large;
|
|
}
|
|
|
|
@{size-l} {
|
|
font-size: large;
|
|
}
|
|
|
|
@{size-m} {
|
|
font-size: medium;
|
|
}
|
|
|
|
@{size-s} {
|
|
font-size: small;
|
|
}
|
|
|
|
@{size-xs} {
|
|
font-size: x-small;
|
|
}
|
|
|
|
@{size-xxs} {
|
|
font-size: xx-small;
|
|
}
|
|
|
|
// --- Styles ---
|
|
|
|
@{style-bold} {
|
|
font-weight: bold;
|
|
.bluelib-color(@hex-accent);
|
|
}
|
|
|
|
@{style-italic} {
|
|
font-style: italic;
|
|
}
|
|
|
|
@{style-underline} {
|
|
text-decoration-line: underline;
|
|
}
|
|
|
|
@{style-strike} {
|
|
text-decoration-line: line-through;
|
|
}
|
|
|
|
@{style-monospace} {
|
|
.font-code();
|
|
}
|
|
|
|
@{style-keyboard} {
|
|
.font-code();
|
|
padding: 2px 4px;
|
|
border: 2px outset;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
// --- Colors ---
|
|
|
|
@{color-red} {
|
|
.bluelib-color(@hex-red)
|
|
}
|
|
|
|
@{color-orange} {
|
|
.bluelib-color(@hex-orange)
|
|
}
|
|
|
|
@{color-yellow} {
|
|
.bluelib-color(@hex-yellow)
|
|
}
|
|
|
|
@{color-lime} {
|
|
.bluelib-color(@hex-lime)
|
|
}
|
|
|
|
@{color-cyan} {
|
|
.bluelib-color(@hex-cyan)
|
|
}
|
|
|
|
@{color-blue} {
|
|
.bluelib-color(@hex-blue)
|
|
}
|
|
|
|
@{color-magenta} {
|
|
.bluelib-color(@hex-magenta)
|
|
}
|
|
|
|
@{color-gray} {
|
|
.bluelib-color(@hex-gray)
|
|
}
|
|
}
|
|
|