From c848b97450b55c32ea6667016db1d7c6a2aa6dba Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sat, 3 Oct 2026 11:15:10 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20(basic):=20Organiza=20estilos=20?= =?UTF-8?q?de=20Basic=20e=20Intro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Divide `basic.css` en parciales SCSS bajo `assets/scss/basic/`, integra `normalize.css` en `basic.min.css` y compila `intro.scss` por separado a `intro.min.css`. --- assets/css/basic.css | 1267 ----------------- assets/css/intro.css | 525 ------- assets/scss/basic.scss | 41 + assets/scss/basic/_badge.scss | 21 + assets/scss/basic/_base.scss | 23 + assets/scss/basic/_brand.scss | 12 + assets/scss/basic/_breadcrumb.scss | 27 + assets/scss/basic/_breakpoints.scss | 25 + assets/scss/basic/_buttons.scss | 120 ++ assets/scss/basic/_container.scss | 32 + assets/scss/basic/_dialog.scss | 57 + assets/scss/basic/_dropdown.scss | 93 ++ assets/scss/basic/_form.scss | 110 ++ assets/scss/basic/_image.scss | 15 + assets/scss/basic/_messages.scss | 24 + assets/scss/basic/_nav.scss | 61 + assets/scss/basic/_navbar.scss | 118 ++ .../basic/_normalize.scss} | 0 assets/scss/basic/_pager.scss | 133 ++ assets/scss/basic/_regions.scss | 4 + assets/scss/basic/_root.scss | 27 + assets/scss/basic/_table.scss | 51 + assets/scss/basic/_user.scss | 68 + assets/scss/basic/_utilities.scss | 12 + assets/scss/intro.scss | 522 +++++++ build.rs | 15 +- extensions/pagetop-aliner/src/lib.rs | 7 +- src/base/component/intro/component.rs | 4 +- src/base/theme/basic.rs | 5 - src/lib.rs | 5 +- 30 files changed, 1612 insertions(+), 1812 deletions(-) delete mode 100644 assets/css/basic.css delete mode 100644 assets/css/intro.css create mode 100644 assets/scss/basic.scss create mode 100644 assets/scss/basic/_badge.scss create mode 100644 assets/scss/basic/_base.scss create mode 100644 assets/scss/basic/_brand.scss create mode 100644 assets/scss/basic/_breadcrumb.scss create mode 100644 assets/scss/basic/_breakpoints.scss create mode 100644 assets/scss/basic/_buttons.scss create mode 100644 assets/scss/basic/_container.scss create mode 100644 assets/scss/basic/_dialog.scss create mode 100644 assets/scss/basic/_dropdown.scss create mode 100644 assets/scss/basic/_form.scss create mode 100644 assets/scss/basic/_image.scss create mode 100644 assets/scss/basic/_messages.scss create mode 100644 assets/scss/basic/_nav.scss create mode 100644 assets/scss/basic/_navbar.scss rename assets/{css/normalize.css => scss/basic/_normalize.scss} (100%) create mode 100644 assets/scss/basic/_pager.scss create mode 100644 assets/scss/basic/_regions.scss create mode 100644 assets/scss/basic/_root.scss create mode 100644 assets/scss/basic/_table.scss create mode 100644 assets/scss/basic/_user.scss create mode 100644 assets/scss/basic/_utilities.scss create mode 100644 assets/scss/intro.scss diff --git a/assets/css/basic.css b/assets/css/basic.css deleted file mode 100644 index 3a4b71c8..00000000 --- a/assets/css/basic.css +++ /dev/null @@ -1,1267 +0,0 @@ -: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; -} - -/* Header, Aside, Content and Footer are stacked in that order, using the full available width. */ -.wrapper { - display: flex; - flex-direction: column; -} - -/* - * Badge component - */ - -.badge { - display: inline-block; - padding: 0.3em 0.6em; - font-size: 0.8125rem; - font-weight: 600; - line-height: 1; - color: #fff; - background-color: var(--val-color--secondary); - border-radius: 0.375rem; - white-space: nowrap; -} -.badge-info, -.badge-warning { - color: #000; -} -.badge-primary { background-color: var(--val-color--primary); } -.badge-neutral { background-color: var(--val-color--secondary); } -.badge-success { background-color: var(--val-color--success); } -.badge-info { background-color: var(--val-color--info); } -.badge-warning { background-color: var(--val-color--warning); } -.badge-severe { background-color: var(--val-color--danger); } - -/* - * Brand component - */ - -.brand { - display: inline-flex; - align-items: center; - gap: 0.5rem; - color: var(--val-color--text); - font-size: 1.75rem; - font-weight: 600; - text-decoration: none; -} -.brand .image { - display: flex; -} - -/* - * 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; -} - -/* Base geometry of .dropdown-button/.dropdown-toggle (see "Dropdown component" below). It is - * declared here, before "Buttons", so that the .button-sm/.button-lg/.button-* classes win the - * specificity tie against it when combined on the same element (CSS resolves a tie by order of - * appearance in the file, not by the order of the classes in the HTML). */ -.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; -} - -/* - * Buttons - */ - -.button { - display: inline-block; - padding: 0.5rem 1.25rem; - font-size: var(--val-fs--base); - font-weight: 600; - line-height: var(--val-lh--base); - color: #fff; - background-color: var(--val-color--primary); - border: 1px solid var(--val-color--primary); - border-radius: 0.375rem; - text-decoration: none; - cursor: pointer; - transition: background-color .15s ease-in-out, border-color .15s ease-in-out; -} -.button:hover { - background-color: color-mix(in srgb, var(--val-color--primary) 85%, black); - border-color: color-mix(in srgb, var(--val-color--primary) 85%, black); -} -.button:disabled, -.button.disabled { - opacity: 0.65; - cursor: default; - pointer-events: none; -} -.button::-moz-focus-inner { - border: 0; -} - -.button-sm { - padding: 0.25rem 0.75rem; - font-size: 0.875rem; -} -.button-lg { - padding: 0.75rem 1.5rem; - font-size: 1.25rem; -} - -.button-primary, -.button-neutral, -.button-success, -.button-severe { - color: #fff; -} -.button-info, -.button-warning { - color: #000; -} -.button-primary { background-color: var(--val-color--primary); border-color: var(--val-color--primary); } -.button-neutral { background-color: var(--val-color--secondary); border-color: var(--val-color--secondary); } -.button-success { background-color: var(--val-color--success); border-color: var(--val-color--success); } -.button-info { background-color: var(--val-color--info); border-color: var(--val-color--info); } -.button-warning { background-color: var(--val-color--warning); border-color: var(--val-color--warning); } -.button-severe { background-color: var(--val-color--danger); border-color: var(--val-color--danger); } - -.button-primary:hover { background-color: color-mix(in srgb, var(--val-color--primary) 85%, black); border-color: color-mix(in srgb, var(--val-color--primary) 85%, black); } -.button-neutral:hover { background-color: color-mix(in srgb, var(--val-color--secondary) 85%, black); border-color: color-mix(in srgb, var(--val-color--secondary) 85%, black); } -.button-success:hover { background-color: color-mix(in srgb, var(--val-color--success) 85%, black); border-color: color-mix(in srgb, var(--val-color--success) 85%, black); } -.button-info:hover { background-color: color-mix(in srgb, var(--val-color--info) 85%, black); border-color: color-mix(in srgb, var(--val-color--info) 85%, black); } -.button-warning:hover { background-color: color-mix(in srgb, var(--val-color--warning) 85%, black); border-color: color-mix(in srgb, var(--val-color--warning) 85%, black); } -.button-severe:hover { background-color: color-mix(in srgb, var(--val-color--danger) 85%, black); border-color: color-mix(in srgb, var(--val-color--danger) 85%, black); } - -.button-outline-primary, -.button-outline-neutral, -.button-outline-success, -.button-outline-info, -.button-outline-warning, -.button-outline-severe { - background-color: transparent; -} -.button-outline-primary { border-color: var(--val-color--primary); color: var(--val-color--primary); } -.button-outline-neutral { border-color: var(--val-color--secondary); color: var(--val-color--secondary); } -.button-outline-success { border-color: var(--val-color--success); color: var(--val-color--success); } -.button-outline-info { border-color: var(--val-color--info); color: var(--val-color--info); } -.button-outline-warning { border-color: var(--val-color--warning); color: var(--val-color--warning); } -.button-outline-severe { border-color: var(--val-color--danger); color: var(--val-color--danger); } - -.button-outline-primary:hover { background-color: var(--val-color--primary); border-color: var(--val-color--primary); color: #fff; } -.button-outline-neutral:hover { background-color: var(--val-color--secondary); border-color: var(--val-color--secondary); color: #fff; } -.button-outline-success:hover { background-color: var(--val-color--success); border-color: var(--val-color--success); color: #fff; } -.button-outline-info:hover { background-color: var(--val-color--info); border-color: var(--val-color--info); color: #000; } -.button-outline-warning:hover { background-color: var(--val-color--warning); border-color: var(--val-color--warning); color: #000; } -.button-outline-severe:hover { background-color: var(--val-color--danger); border-color: var(--val-color--danger); color: #fff; } - -.button-link { - font-weight: 400; - color: var(--val-color--primary); - background-color: transparent; - border-color: transparent; - text-decoration: underline; -} -.button-link:hover { - color: color-mix(in srgb, var(--val-color--primary) 85%, black); - background-color: transparent; - border-color: transparent; -} -.button-link:disabled, -.button-link.disabled { - color: var(--val-color--text--muted); -} - -.button-set { - display: flex; - flex-wrap: wrap; - gap: 0.5rem; -} - -/* - * Container component - */ - -/* Classes added by the `Container` component from `Width`. All of them are centered and fill the - * available width; `.container` and `.container-{name}` also get a maximum width from the - * breakpoint they name (`.container` from the first one). The minimum widths match the default - * `Theme::breakpoint_entry()` table, so a child theme that renames or resizes the breakpoints must - * also redefine these classes. */ -.container, -.container-fluid, -.container-sm, -.container-md, -.container-lg, -.container-xl, -.container-xxl, -.container-xxxl { - width: 100%; - margin-inline: auto; - padding-inline: 1rem; -} -@media (width >= 576px) { - .container, - .container-sm { - max-width: 540px; - } -} -@media (width >= 768px) { - .container, - .container-sm, - .container-md { - max-width: 720px; - } -} -@media (width >= 992px) { - .container, - .container-sm, - .container-md, - .container-lg { - max-width: 960px; - } -} -@media (width >= 1200px) { - .container, - .container-sm, - .container-md, - .container-lg, - .container-xl { - max-width: 1140px; - } -} -@media (width >= 1400px) { - .container, - .container-sm, - .container-md, - .container-lg, - .container-xl, - .container-xxl { - max-width: 1320px; - } -} -@media (width >= 1920px) { - .container, - .container-sm, - .container-md, - .container-lg, - .container-xl, - .container-xxl, - .container-xxxl { - max-width: 1800px; - } -} - -/* - * Dialog component - */ - -.dialog { - padding: 0; - width: 100%; - max-width: 32rem; - color: var(--val-color--text); - background-color: var(--val-color--bg); - border: none; - border-radius: 0.5rem; - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); -} -.dialog::backdrop { - background-color: rgba(0, 0, 0, 0.5); -} - -.dialog-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 1rem; - padding: 1rem 1.25rem; - border-bottom: 1px solid color-mix(in srgb, var(--val-color--border) 15%, var(--val-color--bg)); -} - -.dialog-title { - margin: 0; - font-size: 1.125rem; - font-weight: 600; -} - -.dialog-close { - width: 1.5rem; - height: 1.5rem; - padding: 0; - line-height: 1; - color: var(--val-color--text--muted); - background-color: transparent; - border: none; - cursor: pointer; -} -.dialog-close::before { - content: "\2715"; -} -.dialog-close:hover { - color: var(--val-color--text); -} - -.dialog-body { - padding: 1.25rem; -} - -.dialog-footer { - display: flex; - justify-content: flex-end; - gap: 0.5rem; - padding: 1rem 1.25rem; - border-top: 1px solid color-mix(in srgb, var(--val-color--border) 15%, var(--val-color--bg)); -} - -/* - * Dropdown component - */ - -.dropdown { - position: relative; - display: inline-block; -} - -/* The base geometry of .dropdown-button/.dropdown-toggle lives next to "Buttons" (before this - * section), so that the .button-sm/.button-lg/.button-* classes win the specificity tie against it - * (CSS resolves a tie by order of appearance in the file, not by the order of the classes in the - * HTML). */ -.dropdown-toggle::after { - content: "\25BC"; - display: inline-block; - margin-left: 0.35em; - font-size: 0.8em; - transition: transform .15s ease-in-out; -} -.dropdown:has(> .dropdown-menu.show) > .dropdown-toggle::after { - transform: rotate(180deg); -} - -.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); - /* Closed by default */ - display: none; -} -.dropdown-menu.show { - display: block; -} -/* Anchors the menu's right edge to the button's right edge, so it opens inwards. */ -.dropdown-menu-end { - left: auto; - right: 0; -} - -/* Options and headers stay on one line, so the menu grows to fit the longest one. */ -.dropdown-item { - display: block; - width: 100%; - padding: 0.375rem 1rem; - text-align: left; - white-space: nowrap; - 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; - white-space: nowrap; - 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; -} - -/* - * 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); -} - -.form-field > select.form-select, -.form-field > input.form-control, -.form-field > textarea.form-control { - border: 1px solid var(--val-color--border); - border-radius: 0.375rem; - background-color: #fff; - transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; -} -.form-field > select.form-select:focus, -.form-field > input.form-control:focus, -.form-field > textarea.form-control:focus { - outline: none; - border-color: var(--val-color--primary); - box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--val-color--primary) 25%, transparent); -} - -/* - * Image component - */ - -.image { - vertical-align: middle; -} -.image-fluid { - max-width: 100%; - height: auto; -} -.image-thumbnail { - max-width: 100%; - height: auto; - padding: 0.25rem; - background-color: var(--val-color--bg); - border: 1px solid var(--val-color--border); - border-radius: 0.375rem; -} - -/* - * 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)); -} - -/* - * Nav component - */ - -.nav { - display: flex; - align-items: center; - gap: 0.25rem; - list-style: none; - margin: 0; - padding: 0; -} - -.nav-item { - position: relative; -} - -.nav-link { - display: block; - padding: 0.5rem 0.75rem; - color: var(--val-color--text); - text-decoration: none; - border-radius: 0.375rem; -} -.nav-link:hover { - background-color: color-mix(in srgb, var(--val-color--text) 8%, transparent); -} -.nav-link.active { - color: var(--val-color--primary); - font-weight: 600; -} -.nav-link.disabled { - color: var(--val-color--text--muted); - pointer-events: none; -} -/* The toggle of a dropdown inside a `Nav` looks like the other links: it drops the border that a - * standalone `Dropdown` toggle has (see "Dropdown component"). */ -.nav-link.dropdown-toggle { - width: 100%; - text-align: start; - border: 0; -} - -.nav-start { - justify-content: flex-start; -} -.nav-center { - justify-content: center; -} -.nav-end { - justify-content: flex-end; -} -.nav-vertical { - flex-direction: column; - align-items: stretch; -} -.nav-fill > .nav-item { - flex: 1 1 auto; - text-align: center; -} -.nav-justified > .nav-item { - flex-basis: 0; - flex-grow: 1; - text-align: center; -} - -/* - * Navbar component - */ - -.navbar { - display: flex; - align-items: center; - gap: 1rem; - padding: 0.5rem 1rem; -} - -.navbar-toggle { - display: none; - padding: 0.25rem 0.5rem; - font-size: 1.25rem; - line-height: 1; - color: inherit; - background-color: transparent; - border: 1px solid var(--val-color--border); - border-radius: 0.375rem; - cursor: pointer; -} -.navbar-toggle::before { - content: "\2630"; -} - -/* Pushes the toggle (`BrandLeft`) or the brand (`BrandRight`) to the far end of the bar. */ -.brand ~ .navbar-toggle, -.navbar-toggle ~ .brand { - margin-inline-start: auto; -} - -.navbar-content { - display: flex; - align-items: center; - gap: 1rem; - flex: 1 1 auto; -} -/* A bar without a toggle button never stacks its `.nav` items in a column, so they wrap onto - * another line when they don't fit instead of overflowing the bar. */ -.navbar-content .nav { - flex-wrap: wrap; -} - -.navbar-text { - color: var(--val-color--text--muted); -} - -/* - * Navbar position, from the `navbar::Position` classes. `.navbar` has no background of its own, so - * a bar taken out of the flow (fixed) or pinned while scrolling (sticky) gets one, or the content - * passing underneath would show through. - */ -.navbar.fixed-top, -.navbar.fixed-bottom, -.navbar.sticky-top, -.navbar.sticky-bottom { - background-color: var(--val-color--bg); -} -.navbar.fixed-top, -.navbar.fixed-bottom { - position: fixed; - right: 0; - left: 0; - z-index: 1030; -} -.navbar.fixed-top { - top: 0; -} -.navbar.fixed-bottom { - bottom: 0; -} -.navbar.sticky-top, -.navbar.sticky-bottom { - position: sticky; - z-index: 1020; -} -.navbar.sticky-top { - top: 0; -} -.navbar.sticky-bottom { - bottom: 0; -} - -/* - * A navbar with a toggle button collapses below the breakpoint set by its `navbar-expand-{name}` - * class, added by the `Navbar` component. `navbar-expand` alone (a breakpoint with no minimum - * width) never collapses and needs no rules, since the base rules above are the expanded layout. - * The widths below match the default `Theme::breakpoint_entry()` table, so a child theme that - * renames or resizes the breakpoints must also redefine these classes. - * - * While collapsed, the `.nav` items are stacked in a column, so a dropdown menu inside it is laid - * out in the flow (`position: static`) to push down the following items instead of covering them. - * A navbar without a toggle button has nothing to collapse: its `.nav` items stay in a row. - */ -@media (width < 576px) { - .navbar-expand-sm { - flex-wrap: wrap; - } - .navbar-expand-sm:has(.navbar-toggle) .navbar-toggle { - display: inline-block; - } - .navbar-expand-sm:has(.navbar-toggle) .navbar-content { - order: 1; - display: none; - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-sm:has(.navbar-toggle) .navbar-content.show { - display: flex; - } - .navbar-expand-sm:has(.navbar-toggle) .nav { - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-sm:has(.navbar-toggle) .nav .dropdown-menu { - position: static; - box-shadow: none; - } -} - -@media (width < 768px) { - .navbar-expand-md { - flex-wrap: wrap; - } - .navbar-expand-md:has(.navbar-toggle) .navbar-toggle { - display: inline-block; - } - .navbar-expand-md:has(.navbar-toggle) .navbar-content { - order: 1; - display: none; - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-md:has(.navbar-toggle) .navbar-content.show { - display: flex; - } - .navbar-expand-md:has(.navbar-toggle) .nav { - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-md:has(.navbar-toggle) .nav .dropdown-menu { - position: static; - box-shadow: none; - } -} - -@media (width < 992px) { - .navbar-expand-lg { - flex-wrap: wrap; - } - .navbar-expand-lg:has(.navbar-toggle) .navbar-toggle { - display: inline-block; - } - .navbar-expand-lg:has(.navbar-toggle) .navbar-content { - order: 1; - display: none; - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-lg:has(.navbar-toggle) .navbar-content.show { - display: flex; - } - .navbar-expand-lg:has(.navbar-toggle) .nav { - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-lg:has(.navbar-toggle) .nav .dropdown-menu { - position: static; - box-shadow: none; - } -} - -@media (width < 1200px) { - .navbar-expand-xl { - flex-wrap: wrap; - } - .navbar-expand-xl:has(.navbar-toggle) .navbar-toggle { - display: inline-block; - } - .navbar-expand-xl:has(.navbar-toggle) .navbar-content { - order: 1; - display: none; - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-xl:has(.navbar-toggle) .navbar-content.show { - display: flex; - } - .navbar-expand-xl:has(.navbar-toggle) .nav { - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-xl:has(.navbar-toggle) .nav .dropdown-menu { - position: static; - box-shadow: none; - } -} - -@media (width < 1400px) { - .navbar-expand-xxl { - flex-wrap: wrap; - } - .navbar-expand-xxl:has(.navbar-toggle) .navbar-toggle { - display: inline-block; - } - .navbar-expand-xxl:has(.navbar-toggle) .navbar-content { - order: 1; - display: none; - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-xxl:has(.navbar-toggle) .navbar-content.show { - display: flex; - } - .navbar-expand-xxl:has(.navbar-toggle) .nav { - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-xxl:has(.navbar-toggle) .nav .dropdown-menu { - position: static; - box-shadow: none; - } -} - -@media (width < 1920px) { - .navbar-expand-xxxl { - flex-wrap: wrap; - } - .navbar-expand-xxxl:has(.navbar-toggle) .navbar-toggle { - display: inline-block; - } - .navbar-expand-xxxl:has(.navbar-toggle) .navbar-content { - order: 1; - display: none; - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-xxxl:has(.navbar-toggle) .navbar-content.show { - display: flex; - } - .navbar-expand-xxxl:has(.navbar-toggle) .nav { - flex-direction: column; - align-items: stretch; - width: 100%; - } - .navbar-expand-xxxl:has(.navbar-toggle) .nav .dropdown-menu { - position: static; - box-shadow: none; - } -} - -/* - * 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 shows the navigation text of the previous/next buttons. The full accessible text - goes separately, in the link's aria-label. So replacing the visible text with other content does - not affect accessibility, e.g. to use "‹"/"›" you can apply: - -.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--bg--muted); -} -.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); -} - -/* - * 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); -} - -/* - * Region Footer - */ - -.region-footer { - padding: .75rem 0 3rem; - text-align: center; -} - -/* - * pagetop-user: login page - */ - -.user-login-page { - display: flex; - align-items: center; - justify-content: center; - min-height: 70vh; - padding: 2rem 1rem; - background: radial-gradient( - ellipse 120% 60% at 50% -10%, - color-mix(in srgb, var(--val-color--primary) 18%, var(--val-color--bg)) 0%, - var(--val-color--bg) 70% - ); -} - -.user-login-card { - width: 100%; - max-width: 24rem; - padding: 2rem; - background-color: #fff; - border-radius: 0.75rem; - box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.15); -} - -.user-login-card .form-label { - margin-top: 1.25rem; -} - -.user-login-card .button { - display: block; - width: 100%; - margin-top: 1.5rem; -} - -.user-admin-table-wrapper { - margin: 1.5rem 0; -} - -.user-admin-table { - font-size: 0.9375rem; -} - -.user-admin-permission-list { - list-style: none; - padding-left: 0; -} - -.user-admin-permission-granted { - font-weight: 600; -} - -.user-admin-permission-missing { - color: var(--val-color--text--muted); -} - -.user-form-error { - padding: 0.625rem 0.875rem; - margin-bottom: 1rem; - color: #fff; - background-color: var(--val-color--danger); - border-radius: 0.375rem; - font-size: 0.9375rem; -} - -.user-register-link, -.user-reset-link { - margin-top: 1rem; - text-align: center; - font-size: 0.9375rem; -} diff --git a/assets/css/intro.css b/assets/css/intro.css deleted file mode 100644 index b7679c3e..00000000 --- a/assets/css/intro.css +++ /dev/null @@ -1,525 +0,0 @@ -:root { - --intro-bg-img: url('/pagetop/img/intro-header.jpg'); - --intro-bg-img-set: image-set(url('/pagetop/img/intro-header.avif') type('image/avif'), url('/pagetop/img/intro-header.webp') type('image/webp'), var(--intro-bg-img) type('image/jpeg')); - --intro-bg-img-sm: url('/pagetop/img/intro-header-sm.jpg'); - --intro-bg-img-sm-set: image-set(url('/pagetop/img/intro-header-sm.avif') type('image/avif'), url('/pagetop/img/intro-header-sm.webp') type('image/webp'), var(--intro-bg-img-sm) type('image/jpeg')); - --intro-bg-color: #7a430e; - --intro-bg-block-1: #ffb84b; - --intro-bg-block-2: #ffc66f; - --intro-bg-block-3: #ffd493; - --intro-bg-block-4: #ffe3b7; - --intro-bg-block-5: #fff1db; - --intro-bg-block-6: #ffffff; - --intro-color: #1a202c; - --intro-color-gray: #e8e3da; - --intro-color-link: #8b2500; - --intro-focus-outline: 2px solid var(--intro-color-link); - --intro-focus-outline-offset: 2px; - --intro-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); -} - -body { - overflow-x: clip; -} - -/* - * Media queries: 768px and 992px match the default `Md` and `Lg` breakpoints of the core. - */ - -.intro { - position: relative; - color: var(--intro-color); - background-color: var(--intro-bg-color); - - left: 50%; - right: 50%; - margin-left: -50vw; - margin-right: -50vw; - width: 100vw; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -} - -.intro section { - position: relative; - text-align: center; -} - -/* - * Intro Header - */ - -.intro-header { - display: flex; - flex-direction: column-reverse; - width: 100%; - max-width: 80rem; - margin: 0 auto; - padding-bottom: 4rem; - background-image: var(--intro-bg-img-sm); - background-image: var(--intro-bg-img-sm-set); - background-position: top center; - background-position-y: -1rem; - background-size: contain; - background-repeat: no-repeat; -} -.intro-header-body { - padding: 0; - background: none; -} -.intro-header-title { - margin: 0 0 0 1.5rem; - text-align: left; - display: flex; - flex-direction: column; - box-sizing: border-box; - color: #dceefb; - padding: clamp(0rem, -5.4892rem + 23.4206vw, 9.5rem) 1rem 1rem; - font-size: clamp(1.5rem, 0.7231rem + 3.3149vw, 3.375rem); - font-style: italic; - font-weight: 600; - line-height: 110%; - text-shadow: 0 0.125rem 0.1875rem rgba(0, 0, 0, 0.3); -} -.intro-header-title > span { - background: linear-gradient(180deg, #ddff95 30%, #ffb84b 100%); - background-clip: text; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - font-size: clamp(2.25rem, 1.3177rem + 3.9779vw, 6.5rem); - font-style: normal; - font-weight: 700; - line-height: 135%; - text-shadow: none; -} -.intro-header-img { - display: flex; - justify-content: flex-start; - text-align: right; - width: 100%; -} -.intro-header-mascot { - margin: 2rem; - flex-shrink: 1; - width: 280px; - height: 280px; -} -@media (width >= 992px) { - .intro-header { - background-image: var(--intro-bg-img); - background-image: var(--intro-bg-img-set); - } - .intro-header-title { - padding: 0 2rem 2.6rem 2rem; - } - .intro-header-img { - justify-content: flex-end; - } - .intro-header-mascot { - margin-right: 12rem; - } -} - -/* - * Intro Content - */ - -.intro-content { - height: auto; - margin-top: 1.6rem; - width: 100%; -} -.intro-content-body { - box-sizing: border-box; - max-width: 80rem; - margin-left: auto; - margin-right: auto; -} -.intro-content-body:before, -.intro-content-body:after { - content: ''; - position: absolute; - left: 0; - right: 0; - background: linear-gradient(130deg, rgba(13, 44, 91, 0) 0%, #ddff95 77.4%); - margin: 0 -1.2rem; - filter: blur(2.75rem); - opacity: 0.8; - inset: unset; -} -.intro-content-body:before { - top: -1rem; -} -.intro-content-body:after { - bottom: -1rem; -} -@media (width < 768px) { - .intro-content-body { - margin-top: -9.8rem; - } -} -@media (width >= 992px) { - .intro-content { - margin-top: 0; - } - .intro-content-body { - margin-top: -5.7rem; - } - .intro-content-body:before, - .intro-content-body:after { - inset: 11.75rem; - } -} - -.intro-button { - width: 100%; - margin: 0 auto; -} -.intro-button-link { - background: #7f1d1d; - background-image: linear-gradient(to bottom, rgba(255,0,0,0.8), rgba(255,255,255,0)); - background-position: top left, center; - background-size: contain; - background-repeat: no-repeat; - border-radius: 0.75rem; - display: flex; - flex-wrap: wrap; - justify-content: space-between; - font-size: 1.5rem; - line-height: 1.3; - text-decoration: none !important; - transition: transform 0.3s ease-in-out !important; - position: relative; - overflow: hidden; - min-width: 28.875rem; - min-height: 7.6875rem; - outline: none; -} -.intro-button-link:focus-visible { - outline: var(--intro-focus-outline); - outline-offset: var(--intro-focus-outline-offset); -} -.intro-button-link::before { - content: ''; - position: absolute; - top: -13.125rem; - left: -10rem; - height: 26.25rem; - width: 26.25rem; - background: linear-gradient(135deg, #ec7bae 50.41%, #9600b8 70.41%); - transform: rotate(45deg); - transition: transform 0.3s ease-in-out; - z-index: 5; -} -.intro-button-text { - display: flex; - flex-direction: column; - flex: 1; - transition: all 0.5s ease-in-out; - position: relative; - z-index: 10; - padding: 1rem 1.5rem; - text-align: left; - color: white; - font-size: 1.65rem; - font-style: normal; - font-weight: 600; - line-height: 130.023%; - letter-spacing: 0.0075rem; -} -.intro-button-text strong { - font-size: 2.625rem; - font-weight: 600; - line-height: 130.023%; - letter-spacing: 0.013125rem; -} -.intro-button-link span { - position: absolute; - display: block; - pointer-events: none; -} -.intro-button-link span:nth-child(1) { - height: 8px; - width: 100%; - top: 0; - left: 0; - background: linear-gradient(to right, rgba(0, 0, 0, 0), #f6e58d); - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - transform: translateX(-100%); - animation: span1 8s linear infinite; - animation-delay: 1s; -} -@keyframes span1 { - 0% { - transform: translateX(-100%); - } - 100% { - transform: translateX(100%); - } -} -.intro-button-link span:nth-child(2) { - width: 8px; - height: 100%; - top: 0; - right: 0; - background: linear-gradient(to bottom, rgba(0, 0, 0, 0), #f6e58d); - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; - transform: translateY(100%); - animation: span2 4s linear infinite; - animation-delay: 5s; -} -@keyframes span2 { - 0% { - transform: translateY(-100%); - } - 100% { - transform: translateY(100%); - } -} -.intro-button-link span:nth-child(3) { - height: 8px; - width: 100%; - bottom: 0; - right: 0; - background: linear-gradient(to left, rgba(0, 0, 0, 0), #f6e58d); - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - transform: translateX(100%); - animation: span3 8s linear infinite; - animation-delay: 7s; -} -@keyframes span3 { - 0% { - transform: translateX(100%); - } - 100% { - transform: translateX(-100%); - } -} -.intro-button-link:hover span { - animation-play-state: paused; -} -@media (width < 768px) { - .intro-header { - padding-bottom: 9rem;; - } - .intro-button-link { - height: 6.25rem; - min-width: auto; - border-radius: 0; - } - .intro-button-text { - display: inline; - padding-top: .5rem; - } -} -@media (width >= 768px) { - .intro-button { - position: absolute; - top: 0; - left: 50%; - transform: translate(-50%, -50%); - max-width: 29.375rem; - margin-bottom: 0; - } - .intro-button-link:hover { - transition: all .5s; - transform: rotate(-3deg) scale(1.125); - } -} - -.intro-text { - z-index: 1; - width: 100%; - display: flex; - flex-direction: column; - box-sizing: border-box; - align-items: center; - text-align: left; - margin-bottom: 0; - background: #fff; - position: relative; -} -.intro-text-body { - padding: 2.5rem 1.063rem 0.75rem; - overflow: hidden; - width: 100%; -} -.intro-text-lead { - width: 100%; - font-size: 1.5rem; - margin: 0 0 1.5rem; -} -@media (width >= 768px) { - .intro-button + .intro-text-body { - padding-top: 7rem; - } -} -@media (width >= 992px) { - .intro-header { - padding-bottom: 9rem;; - } - .intro-text, - .intro-text-body { - border-radius: 0.75rem; - } - .intro-text { - box-shadow: var(--intro-shadow); - max-width: min(60rem, 100vw - 4rem); - margin: 0 auto 6rem; - } - .intro-text-narrow { - max-width: min(50rem, 100vw - 4rem); - } - .intro-text-wide { - max-width: min(67rem, 100vw - 4rem); - } - .intro-text-full { - max-width: min(74rem, 100vw - 4rem); - } - .intro-text-body { - padding-left: 4.5rem; - padding-right: 4.5rem; - } -} - -.intro-text-body .block { - position: relative; -} -.intro-text-body .block-title { - margin: 1em 0 .8em; -} -.intro-text-body .block-title span { - display: inline-block; - padding: 10px 30px 14px; - margin: 30px 20px 0; - background: white; - border: 5px solid; - border-radius: 30px; - box-shadow: 0 0 0 5px white, inset 0 0 0 5px white; - border-color: orangered; - transform: rotate(-3deg) translateY(-25%); -} -.intro-text-body .block-title:before { - content: ""; - height: 5px; - position: absolute; - top: 50px; - left: -15%; - width: 130%; - z-index: -5; - background: orangered; - box-shadow: 0 0 0 5px white, 0 -10px 0 5px white; - transform: rotate(2deg) translateY(-50%); - transform-origin: top left; -} -.intro-text-body .block-title:after { - content: ""; - height: 120%; - position: absolute; - top: 42px; - left: -25%; - width: 150%; - z-index: -10; - background: var(--intro-bg-block-1); - transform: rotate(2deg); -} -.intro-text-body .block:nth-of-type(6n+1) .block-title:after { - background: var(--intro-bg-block-1); -} -.intro-text-body .block:nth-of-type(6n+2) .block-title:after { - background: var(--intro-bg-block-2); -} -.intro-text-body .block:nth-of-type(6n+3) .block-title:after { - background: var(--intro-bg-block-3); -} -.intro-text-body .block:nth-of-type(6n+4) .block-title:after { - background: var(--intro-bg-block-4); -} -.intro-text-body .block:nth-of-type(6n+5) .block-title:after { - background: var(--intro-bg-block-5); -} -.intro-text-body .block:nth-of-type(6n+6) .block-title:after { - background: var(--intro-bg-block-6); -} - -#intro-badges { - min-height: 3.2rem; - text-align: center; - visibility: hidden; -} -#intro-badges img { - margin-bottom: 0.25rem; -} -#intro-release:not([src]) { - display: none; -} - -/* - * Intro Footer - */ - -.intro-footer { - width: 100%; - background-color: black; - color: var(--intro-color-gray); - padding-bottom: 2rem; -} - -.intro-footer-body { - display: flex; - justify-content: center; - flex-direction: column; - margin: 0 auto; - padding: 0 10.625rem; - max-width: 80rem; -} -.intro-footer-body a:visited { - color: var(--intro-color-gray); -} -/* The footer has its own dark surface, so its links don't inherit the theme's link colors. */ -.intro-footer-links a { - color: currentColor; - text-decoration: underline; - transition: font-size 0.2s, text-decoration-color 0.2s; -} -.intro-footer-links a:focus-visible { - outline: var(--intro-focus-outline); - outline-offset: var(--intro-focus-outline-offset); -} -.intro-footer-links a:hover, -.intro-footer-links a:hover:visited { - text-decoration-color: var(--intro-color-link); -} -.intro-footer-logo, -.intro-footer-links { - display: flex; - justify-content: center; - width: 100%; -} -.intro-footer-logo { - max-height: 12.625rem; -} -.intro-footer-logo svg { - width: 100%; -} -.intro-footer-links { - gap: 1.875rem; - flex-wrap: wrap; - margin-top: 2rem; -} -@media (width < 768px) { - .intro-footer-logo { - display: none; - } -} -@media (width < 992px) { - .intro-footer-body { - padding: 0 1rem; - } -} diff --git a/assets/scss/basic.scss b/assets/scss/basic.scss new file mode 100644 index 00000000..8165962b --- /dev/null +++ b/assets/scss/basic.scss @@ -0,0 +1,41 @@ +// PageTop Basic theme styles. +// +// Compiled by `build.rs` into `static/css/basic.min.css`. Comments written with `//` never reach +// the compiled file, so they can be as long as needed. +// +// The partials are emitted in the order they are loaded here, which matters when two rules tie on +// specificity: the later one wins. + +// Third-party reset (normalize.css v8.0.1, MIT), copied verbatim. It goes first so that every +// rule of the theme can override it. +@use "basic/normalize"; + +// Custom properties and base styles. +@use "basic/root"; +@use "basic/base"; + +// Components, in alphabetical order. `buttons` must go before `dropdown` and `nav`, see the notes +// in `basic/_buttons.scss`. +@use "basic/badge"; +@use "basic/brand"; +@use "basic/breadcrumb"; +@use "basic/buttons"; +@use "basic/container"; +@use "basic/dialog"; +@use "basic/dropdown"; +@use "basic/form"; +@use "basic/image"; +@use "basic/messages"; +@use "basic/nav"; +@use "basic/navbar"; +@use "basic/pager"; +@use "basic/table"; + +// Theme regions. +@use "basic/regions"; + +// Styles for the pages of the `pagetop-user` extension. +@use "basic/user"; + +// Utilities go last so they win over any component rule they are combined with. +@use "basic/utilities"; diff --git a/assets/scss/basic/_badge.scss b/assets/scss/basic/_badge.scss new file mode 100644 index 00000000..3b0ba3ce --- /dev/null +++ b/assets/scss/basic/_badge.scss @@ -0,0 +1,21 @@ +.badge { + display: inline-block; + padding: 0.3em 0.6em; + font-size: 0.8125rem; + font-weight: 600; + line-height: 1; + color: #fff; + background-color: var(--val-color--secondary); + border-radius: 0.375rem; + white-space: nowrap; +} +.badge-info, +.badge-warning { + color: #000; +} +.badge-primary { background-color: var(--val-color--primary); } +.badge-neutral { background-color: var(--val-color--secondary); } +.badge-success { background-color: var(--val-color--success); } +.badge-info { background-color: var(--val-color--info); } +.badge-warning { background-color: var(--val-color--warning); } +.badge-severe { background-color: var(--val-color--danger); } diff --git a/assets/scss/basic/_base.scss b/assets/scss/basic/_base.scss new file mode 100644 index 00000000..203b656d --- /dev/null +++ b/assets/scss/basic/_base.scss @@ -0,0 +1,23 @@ +*, *::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; +} + +// Header, Aside, Content and Footer are stacked in that order, using the full available width. +.wrapper { + display: flex; + flex-direction: column; +} diff --git a/assets/scss/basic/_brand.scss b/assets/scss/basic/_brand.scss new file mode 100644 index 00000000..89132ea5 --- /dev/null +++ b/assets/scss/basic/_brand.scss @@ -0,0 +1,12 @@ +.brand { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--val-color--text); + font-size: 1.75rem; + font-weight: 600; + text-decoration: none; +} +.brand .image { + display: flex; +} diff --git a/assets/scss/basic/_breadcrumb.scss b/assets/scss/basic/_breadcrumb.scss new file mode 100644 index 00000000..eefc005f --- /dev/null +++ b/assets/scss/basic/_breadcrumb.scss @@ -0,0 +1,27 @@ +.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; +} diff --git a/assets/scss/basic/_breakpoints.scss b/assets/scss/basic/_breakpoints.scss new file mode 100644 index 00000000..542c349c --- /dev/null +++ b/assets/scss/basic/_breakpoints.scss @@ -0,0 +1,25 @@ +// Breakpoints of the Basic theme, used to generate the responsive classes of `Container` and +// `Navbar`. They match the default `Theme::breakpoint_entry()` table (`xs` has no minimum width, so +// it is left out), so a child theme that renames or resizes the breakpoints must also redefine the +// classes generated from them. +// +// This partial emits no CSS on its own. + +$breakpoints: ( + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px, + xxl: 1400px, + xxxl: 1920px, +); + +// Maximum width of `.container` and `.container-{name}` from each breakpoint on. +$container-max-widths: ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px, + xxl: 1320px, + xxxl: 1800px, +); diff --git a/assets/scss/basic/_buttons.scss b/assets/scss/basic/_buttons.scss new file mode 100644 index 00000000..726ee12b --- /dev/null +++ b/assets/scss/basic/_buttons.scss @@ -0,0 +1,120 @@ +// Base geometry of .dropdown-button/.dropdown-toggle (the rest is in `_dropdown.scss`). It is +// declared here, before the button classes, so that .button-sm/.button-lg/.button-* win the +// specificity tie against it when combined on the same element (CSS resolves a tie by order of +// appearance in the file, not by the order of the classes in the HTML). +.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; +} + +.button { + display: inline-block; + padding: 0.5rem 1.25rem; + font-size: var(--val-fs--base); + font-weight: 600; + line-height: var(--val-lh--base); + color: #fff; + background-color: var(--val-color--primary); + border: 1px solid var(--val-color--primary); + border-radius: 0.375rem; + text-decoration: none; + cursor: pointer; + transition: background-color .15s ease-in-out, border-color .15s ease-in-out; +} +.button:hover { + background-color: color-mix(in srgb, var(--val-color--primary) 85%, black); + border-color: color-mix(in srgb, var(--val-color--primary) 85%, black); +} +.button:disabled, +.button.disabled { + opacity: 0.65; + cursor: default; + pointer-events: none; +} +.button::-moz-focus-inner { + border: 0; +} + +.button-sm { + padding: 0.25rem 0.75rem; + font-size: 0.875rem; +} +.button-lg { + padding: 0.75rem 1.5rem; + font-size: 1.25rem; +} + +.button-primary, +.button-neutral, +.button-success, +.button-severe { + color: #fff; +} +.button-info, +.button-warning { + color: #000; +} +.button-primary { background-color: var(--val-color--primary); border-color: var(--val-color--primary); } +.button-neutral { background-color: var(--val-color--secondary); border-color: var(--val-color--secondary); } +.button-success { background-color: var(--val-color--success); border-color: var(--val-color--success); } +.button-info { background-color: var(--val-color--info); border-color: var(--val-color--info); } +.button-warning { background-color: var(--val-color--warning); border-color: var(--val-color--warning); } +.button-severe { background-color: var(--val-color--danger); border-color: var(--val-color--danger); } + +.button-primary:hover { background-color: color-mix(in srgb, var(--val-color--primary) 85%, black); border-color: color-mix(in srgb, var(--val-color--primary) 85%, black); } +.button-neutral:hover { background-color: color-mix(in srgb, var(--val-color--secondary) 85%, black); border-color: color-mix(in srgb, var(--val-color--secondary) 85%, black); } +.button-success:hover { background-color: color-mix(in srgb, var(--val-color--success) 85%, black); border-color: color-mix(in srgb, var(--val-color--success) 85%, black); } +.button-info:hover { background-color: color-mix(in srgb, var(--val-color--info) 85%, black); border-color: color-mix(in srgb, var(--val-color--info) 85%, black); } +.button-warning:hover { background-color: color-mix(in srgb, var(--val-color--warning) 85%, black); border-color: color-mix(in srgb, var(--val-color--warning) 85%, black); } +.button-severe:hover { background-color: color-mix(in srgb, var(--val-color--danger) 85%, black); border-color: color-mix(in srgb, var(--val-color--danger) 85%, black); } + +.button-outline-primary, +.button-outline-neutral, +.button-outline-success, +.button-outline-info, +.button-outline-warning, +.button-outline-severe { + background-color: transparent; +} +.button-outline-primary { border-color: var(--val-color--primary); color: var(--val-color--primary); } +.button-outline-neutral { border-color: var(--val-color--secondary); color: var(--val-color--secondary); } +.button-outline-success { border-color: var(--val-color--success); color: var(--val-color--success); } +.button-outline-info { border-color: var(--val-color--info); color: var(--val-color--info); } +.button-outline-warning { border-color: var(--val-color--warning); color: var(--val-color--warning); } +.button-outline-severe { border-color: var(--val-color--danger); color: var(--val-color--danger); } + +.button-outline-primary:hover { background-color: var(--val-color--primary); border-color: var(--val-color--primary); color: #fff; } +.button-outline-neutral:hover { background-color: var(--val-color--secondary); border-color: var(--val-color--secondary); color: #fff; } +.button-outline-success:hover { background-color: var(--val-color--success); border-color: var(--val-color--success); color: #fff; } +.button-outline-info:hover { background-color: var(--val-color--info); border-color: var(--val-color--info); color: #000; } +.button-outline-warning:hover { background-color: var(--val-color--warning); border-color: var(--val-color--warning); color: #000; } +.button-outline-severe:hover { background-color: var(--val-color--danger); border-color: var(--val-color--danger); color: #fff; } + +.button-link { + font-weight: 400; + color: var(--val-color--primary); + background-color: transparent; + border-color: transparent; + text-decoration: underline; +} +.button-link:hover { + color: color-mix(in srgb, var(--val-color--primary) 85%, black); + background-color: transparent; + border-color: transparent; +} +.button-link:disabled, +.button-link.disabled { + color: var(--val-color--text--muted); +} + +.button-set { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; +} diff --git a/assets/scss/basic/_container.scss b/assets/scss/basic/_container.scss new file mode 100644 index 00000000..44db9f2a --- /dev/null +++ b/assets/scss/basic/_container.scss @@ -0,0 +1,32 @@ +@use "sass:list"; +@use "sass:map"; +@use "breakpoints" as bp; + +// Classes added by the `Container` component from `Width`. All of them are centered and fill the +// available width; `.container` and `.container-{name}` also get a maximum width from the +// breakpoint they name (`.container` from the first one). + +$named: (); +@each $name in map.keys(bp.$breakpoints) { + $named: list.append($named, ".container-#{$name}", comma); +} + +.container, +.container-fluid, +#{$named} { + width: 100%; + margin-inline: auto; + padding-inline: 1rem; +} + +// From each breakpoint on, `.container` and every `.container-{name}` up to that breakpoint take +// its maximum width, while the larger ones stay fluid until their own breakpoint is reached. +$sized: (".container"); +@each $name, $width in bp.$breakpoints { + $sized: list.append($sized, ".container-#{$name}", comma); + @media (width >= $width) { + #{$sized} { + max-width: map.get(bp.$container-max-widths, $name); + } + } +} diff --git a/assets/scss/basic/_dialog.scss b/assets/scss/basic/_dialog.scss new file mode 100644 index 00000000..efbab797 --- /dev/null +++ b/assets/scss/basic/_dialog.scss @@ -0,0 +1,57 @@ +.dialog { + padding: 0; + width: 100%; + max-width: 32rem; + color: var(--val-color--text); + background-color: var(--val-color--bg); + border: none; + border-radius: 0.5rem; + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); +} +.dialog::backdrop { + background-color: rgba(0, 0, 0, 0.5); +} + +.dialog-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 1rem 1.25rem; + border-bottom: 1px solid color-mix(in srgb, var(--val-color--border) 15%, var(--val-color--bg)); +} + +.dialog-title { + margin: 0; + font-size: 1.125rem; + font-weight: 600; +} + +.dialog-close { + width: 1.5rem; + height: 1.5rem; + padding: 0; + line-height: 1; + color: var(--val-color--text--muted); + background-color: transparent; + border: none; + cursor: pointer; +} +.dialog-close::before { + content: "\2715"; +} +.dialog-close:hover { + color: var(--val-color--text); +} + +.dialog-body { + padding: 1.25rem; +} + +.dialog-footer { + display: flex; + justify-content: flex-end; + gap: 0.5rem; + padding: 1rem 1.25rem; + border-top: 1px solid color-mix(in srgb, var(--val-color--border) 15%, var(--val-color--bg)); +} diff --git a/assets/scss/basic/_dropdown.scss b/assets/scss/basic/_dropdown.scss new file mode 100644 index 00000000..1a93d54c --- /dev/null +++ b/assets/scss/basic/_dropdown.scss @@ -0,0 +1,93 @@ +.dropdown { + position: relative; + display: inline-block; +} + +// The base geometry of .dropdown-button/.dropdown-toggle lives at the top of `_buttons.scss`, which +// is loaded before this partial, so that .button-sm/.button-lg/.button-* win the specificity tie +// against it (CSS resolves a tie by order of appearance in the file, not by the order of the +// classes in the HTML). +.dropdown-toggle::after { + content: "\25BC"; + display: inline-block; + margin-left: 0.35em; + font-size: 0.8em; + transition: transform .15s ease-in-out; +} +.dropdown:has(> .dropdown-menu.show) > .dropdown-toggle::after { + transform: rotate(180deg); +} + +.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); + // Closed by default + display: none; +} +.dropdown-menu.show { + display: block; +} +// Anchors the menu's right edge to the button's right edge, so it opens inwards. +.dropdown-menu-end { + left: auto; + right: 0; +} + +// Options and headers stay on one line, so the menu grows to fit the longest one. +.dropdown-item { + display: block; + width: 100%; + padding: 0.375rem 1rem; + text-align: left; + white-space: nowrap; + 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; + white-space: nowrap; + 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); +} diff --git a/assets/scss/basic/_form.scss b/assets/scss/basic/_form.scss new file mode 100644 index 00000000..7d8550cf --- /dev/null +++ b/assets/scss/basic/_form.scss @@ -0,0 +1,110 @@ +.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); +} + +.form-field > select.form-select, +.form-field > input.form-control, +.form-field > textarea.form-control { + border: 1px solid var(--val-color--border); + border-radius: 0.375rem; + background-color: #fff; + transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; +} +.form-field > select.form-select:focus, +.form-field > input.form-control:focus, +.form-field > textarea.form-control:focus { + outline: none; + border-color: var(--val-color--primary); + box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--val-color--primary) 25%, transparent); +} diff --git a/assets/scss/basic/_image.scss b/assets/scss/basic/_image.scss new file mode 100644 index 00000000..661e7983 --- /dev/null +++ b/assets/scss/basic/_image.scss @@ -0,0 +1,15 @@ +.image { + vertical-align: middle; +} +.image-fluid { + max-width: 100%; + height: auto; +} +.image-thumbnail { + max-width: 100%; + height: auto; + padding: 0.25rem; + background-color: var(--val-color--bg); + border: 1px solid var(--val-color--border); + border-radius: 0.375rem; +} diff --git a/assets/scss/basic/_messages.scss b/assets/scss/basic/_messages.scss new file mode 100644 index 00000000..44d34cfb --- /dev/null +++ b/assets/scss/basic/_messages.scss @@ -0,0 +1,24 @@ +.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)); +} diff --git a/assets/scss/basic/_nav.scss b/assets/scss/basic/_nav.scss new file mode 100644 index 00000000..e91f17f4 --- /dev/null +++ b/assets/scss/basic/_nav.scss @@ -0,0 +1,61 @@ +.nav { + display: flex; + align-items: center; + gap: 0.25rem; + list-style: none; + margin: 0; + padding: 0; +} + +.nav-item { + position: relative; +} + +.nav-link { + display: block; + padding: 0.5rem 0.75rem; + color: var(--val-color--text); + text-decoration: none; + border-radius: 0.375rem; +} +.nav-link:hover { + background-color: color-mix(in srgb, var(--val-color--text) 8%, transparent); +} +.nav-link.active { + color: var(--val-color--primary); + font-weight: 600; +} +.nav-link.disabled { + color: var(--val-color--text--muted); + pointer-events: none; +} +// The toggle of a dropdown inside a `Nav` looks like the other links: it drops the border that a +// standalone `Dropdown` toggle has (see `_buttons.scss`). +.nav-link.dropdown-toggle { + width: 100%; + text-align: start; + border: 0; +} + +.nav-start { + justify-content: flex-start; +} +.nav-center { + justify-content: center; +} +.nav-end { + justify-content: flex-end; +} +.nav-vertical { + flex-direction: column; + align-items: stretch; +} +.nav-fill > .nav-item { + flex: 1 1 auto; + text-align: center; +} +.nav-justified > .nav-item { + flex-basis: 0; + flex-grow: 1; + text-align: center; +} diff --git a/assets/scss/basic/_navbar.scss b/assets/scss/basic/_navbar.scss new file mode 100644 index 00000000..fb393727 --- /dev/null +++ b/assets/scss/basic/_navbar.scss @@ -0,0 +1,118 @@ +@use "breakpoints" as bp; + +.navbar { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.5rem 1rem; +} + +.navbar-toggle { + display: none; + padding: 0.25rem 0.5rem; + font-size: 1.25rem; + line-height: 1; + color: inherit; + background-color: transparent; + border: 1px solid var(--val-color--border); + border-radius: 0.375rem; + cursor: pointer; +} +.navbar-toggle::before { + content: "\2630"; +} + +// Pushes the toggle (`BrandLeft`) or the brand (`BrandRight`) to the far end of the bar. +.brand ~ .navbar-toggle, +.navbar-toggle ~ .brand { + margin-inline-start: auto; +} + +.navbar-content { + display: flex; + align-items: center; + gap: 1rem; + flex: 1 1 auto; +} +// A bar without a toggle button never stacks its `.nav` items in a column, so they wrap onto +// another line when they don't fit instead of overflowing the bar. +.navbar-content .nav { + flex-wrap: wrap; +} + +.navbar-text { + color: var(--val-color--text--muted); +} + +// Navbar position, from the `navbar::Position` classes. `.navbar` has no background of its own, so +// a bar taken out of the flow (fixed) or pinned while scrolling (sticky) gets one, or the content +// passing underneath would show through. +.navbar.fixed-top, +.navbar.fixed-bottom, +.navbar.sticky-top, +.navbar.sticky-bottom { + background-color: var(--val-color--bg); +} +.navbar.fixed-top, +.navbar.fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +.navbar.fixed-top { + top: 0; +} +.navbar.fixed-bottom { + bottom: 0; +} +.navbar.sticky-top, +.navbar.sticky-bottom { + position: sticky; + z-index: 1020; +} +.navbar.sticky-top { + top: 0; +} +.navbar.sticky-bottom { + bottom: 0; +} + +// A navbar with a toggle button collapses below the breakpoint set by its `navbar-expand-{name}` +// class, added by the `Navbar` component. `navbar-expand` alone (a breakpoint with no minimum +// width) never collapses and needs no rules, since the base rules above are the expanded layout. +// +// While collapsed, the `.nav` items are stacked in a column, so a dropdown menu inside it is laid +// out in the flow (`position: static`) to push down the following items instead of covering them. +// A navbar without a toggle button has nothing to collapse: its `.nav` items stay in a row. +@each $name, $width in bp.$breakpoints { + @media (width < $width) { + .navbar-expand-#{$name} { + flex-wrap: wrap; + } + .navbar-expand-#{$name}:has(.navbar-toggle) { + .navbar-toggle { + display: inline-block; + } + .navbar-content { + order: 1; + display: none; + flex-direction: column; + align-items: stretch; + width: 100%; + } + .navbar-content.show { + display: flex; + } + .nav { + flex-direction: column; + align-items: stretch; + width: 100%; + } + .nav .dropdown-menu { + position: static; + box-shadow: none; + } + } + } +} diff --git a/assets/css/normalize.css b/assets/scss/basic/_normalize.scss similarity index 100% rename from assets/css/normalize.css rename to assets/scss/basic/_normalize.scss diff --git a/assets/scss/basic/_pager.scss b/assets/scss/basic/_pager.scss new file mode 100644 index 00000000..be2c7c6e --- /dev/null +++ b/assets/scss/basic/_pager.scss @@ -0,0 +1,133 @@ +.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 shows the navigation text of the previous/next buttons. The full accessible text +// goes separately, in the link's aria-label. So replacing the visible text with other content does +// not affect accessibility, e.g. to use "‹"/"›" you can apply: +// +// .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--bg--muted); +} +.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); +} diff --git a/assets/scss/basic/_regions.scss b/assets/scss/basic/_regions.scss new file mode 100644 index 00000000..3fb08467 --- /dev/null +++ b/assets/scss/basic/_regions.scss @@ -0,0 +1,4 @@ +.region-footer { + padding: .75rem 0 3rem; + text-align: center; +} diff --git a/assets/scss/basic/_root.scss b/assets/scss/basic/_root.scss new file mode 100644 index 00000000..c767a750 --- /dev/null +++ b/assets/scss/basic/_root.scss @@ -0,0 +1,27 @@ +: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; +} diff --git a/assets/scss/basic/_table.scss b/assets/scss/basic/_table.scss new file mode 100644 index 00000000..99cbf6e6 --- /dev/null +++ b/assets/scss/basic/_table.scss @@ -0,0 +1,51 @@ +.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); +} diff --git a/assets/scss/basic/_user.scss b/assets/scss/basic/_user.scss new file mode 100644 index 00000000..38e4d094 --- /dev/null +++ b/assets/scss/basic/_user.scss @@ -0,0 +1,68 @@ +.user-login-page { + display: flex; + align-items: center; + justify-content: center; + min-height: 70vh; + padding: 2rem 1rem; + background: radial-gradient( + ellipse 120% 60% at 50% -10%, + color-mix(in srgb, var(--val-color--primary) 18%, var(--val-color--bg)) 0%, + var(--val-color--bg) 70% + ); +} + +.user-login-card { + width: 100%; + max-width: 24rem; + padding: 2rem; + background-color: #fff; + border-radius: 0.75rem; + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.15); +} + +.user-login-card .form-label { + margin-top: 1.25rem; +} + +.user-login-card .button { + display: block; + width: 100%; + margin-top: 1.5rem; +} + +.user-admin-table-wrapper { + margin: 1.5rem 0; +} + +.user-admin-table { + font-size: 0.9375rem; +} + +.user-admin-permission-list { + list-style: none; + padding-left: 0; +} + +.user-admin-permission-granted { + font-weight: 600; +} + +.user-admin-permission-missing { + color: var(--val-color--text--muted); +} + +.user-form-error { + padding: 0.625rem 0.875rem; + margin-bottom: 1rem; + color: #fff; + background-color: var(--val-color--danger); + border-radius: 0.375rem; + font-size: 0.9375rem; +} + +.user-register-link, +.user-reset-link { + margin-top: 1rem; + text-align: center; + font-size: 0.9375rem; +} diff --git a/assets/scss/basic/_utilities.scss b/assets/scss/basic/_utilities.scss new file mode 100644 index 00000000..3c0ddcf3 --- /dev/null +++ b/assets/scss/basic/_utilities.scss @@ -0,0 +1,12 @@ +// 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; +} diff --git a/assets/scss/intro.scss b/assets/scss/intro.scss new file mode 100644 index 00000000..4cc40d0c --- /dev/null +++ b/assets/scss/intro.scss @@ -0,0 +1,522 @@ +// Styles of the `Intro` component. +// +// Compiled by `build.rs` into `static/css/intro.min.css`, apart from `basic.scss`: the component +// loads them on its own, whatever the active theme is. + +:root { + --intro-bg-img: url('/pagetop/img/intro-header.jpg'); + --intro-bg-img-set: image-set(url('/pagetop/img/intro-header.avif') type('image/avif'), url('/pagetop/img/intro-header.webp') type('image/webp'), var(--intro-bg-img) type('image/jpeg')); + --intro-bg-img-sm: url('/pagetop/img/intro-header-sm.jpg'); + --intro-bg-img-sm-set: image-set(url('/pagetop/img/intro-header-sm.avif') type('image/avif'), url('/pagetop/img/intro-header-sm.webp') type('image/webp'), var(--intro-bg-img-sm) type('image/jpeg')); + --intro-bg-color: #7a430e; + --intro-bg-block-1: #ffb84b; + --intro-bg-block-2: #ffc66f; + --intro-bg-block-3: #ffd493; + --intro-bg-block-4: #ffe3b7; + --intro-bg-block-5: #fff1db; + --intro-bg-block-6: #ffffff; + --intro-color: #1a202c; + --intro-color-gray: #e8e3da; + --intro-color-link: #8b2500; + --intro-focus-outline: 2px solid var(--intro-color-link); + --intro-focus-outline-offset: 2px; + --intro-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); +} + +body { + overflow-x: clip; +} + +// Media queries: 768px and 992px match the default `Md` and `Lg` breakpoints of the core. + +.intro { + position: relative; + color: var(--intro-color); + background-color: var(--intro-bg-color); + + left: 50%; + right: 50%; + margin-left: -50vw; + margin-right: -50vw; + width: 100vw; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.intro section { + position: relative; + text-align: center; +} + +// Intro Header + +.intro-header { + display: flex; + flex-direction: column-reverse; + width: 100%; + max-width: 80rem; + margin: 0 auto; + padding-bottom: 4rem; + background-image: var(--intro-bg-img-sm); + background-image: var(--intro-bg-img-sm-set); + background-position: top center; + background-position-y: -1rem; + background-size: contain; + background-repeat: no-repeat; +} +.intro-header-body { + padding: 0; + background: none; +} +.intro-header-title { + margin: 0 0 0 1.5rem; + text-align: left; + display: flex; + flex-direction: column; + box-sizing: border-box; + color: #dceefb; + padding: clamp(0rem, -5.4892rem + 23.4206vw, 9.5rem) 1rem 1rem; + font-size: clamp(1.5rem, 0.7231rem + 3.3149vw, 3.375rem); + font-style: italic; + font-weight: 600; + line-height: 110%; + text-shadow: 0 0.125rem 0.1875rem rgba(0, 0, 0, 0.3); +} +.intro-header-title > span { + background: linear-gradient(180deg, #ddff95 30%, #ffb84b 100%); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + font-size: clamp(2.25rem, 1.3177rem + 3.9779vw, 6.5rem); + font-style: normal; + font-weight: 700; + line-height: 135%; + text-shadow: none; +} +.intro-header-img { + display: flex; + justify-content: flex-start; + text-align: right; + width: 100%; +} +.intro-header-mascot { + margin: 2rem; + flex-shrink: 1; + width: 280px; + height: 280px; +} +@media (width >= 992px) { + .intro-header { + background-image: var(--intro-bg-img); + background-image: var(--intro-bg-img-set); + } + .intro-header-title { + padding: 0 2rem 2.6rem 2rem; + } + .intro-header-img { + justify-content: flex-end; + } + .intro-header-mascot { + margin-right: 12rem; + } +} + +// Intro Content + +.intro-content { + height: auto; + margin-top: 1.6rem; + width: 100%; +} +.intro-content-body { + box-sizing: border-box; + max-width: 80rem; + margin-left: auto; + margin-right: auto; +} +.intro-content-body:before, +.intro-content-body:after { + content: ''; + position: absolute; + left: 0; + right: 0; + background: linear-gradient(130deg, rgba(13, 44, 91, 0) 0%, #ddff95 77.4%); + margin: 0 -1.2rem; + filter: blur(2.75rem); + opacity: 0.8; + inset: unset; +} +.intro-content-body:before { + top: -1rem; +} +.intro-content-body:after { + bottom: -1rem; +} +@media (width < 768px) { + .intro-content-body { + margin-top: -9.8rem; + } +} +@media (width >= 992px) { + .intro-content { + margin-top: 0; + } + .intro-content-body { + margin-top: -5.7rem; + } + .intro-content-body:before, + .intro-content-body:after { + inset: 11.75rem; + } +} + +.intro-button { + width: 100%; + margin: 0 auto; +} +.intro-button-link { + background: #7f1d1d; + background-image: linear-gradient(to bottom, rgba(255,0,0,0.8), rgba(255,255,255,0)); + background-position: top left, center; + background-size: contain; + background-repeat: no-repeat; + border-radius: 0.75rem; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + font-size: 1.5rem; + line-height: 1.3; + text-decoration: none !important; + transition: transform 0.3s ease-in-out !important; + position: relative; + overflow: hidden; + min-width: 28.875rem; + min-height: 7.6875rem; + outline: none; +} +.intro-button-link:focus-visible { + outline: var(--intro-focus-outline); + outline-offset: var(--intro-focus-outline-offset); +} +.intro-button-link::before { + content: ''; + position: absolute; + top: -13.125rem; + left: -10rem; + height: 26.25rem; + width: 26.25rem; + background: linear-gradient(135deg, #ec7bae 50.41%, #9600b8 70.41%); + transform: rotate(45deg); + transition: transform 0.3s ease-in-out; + z-index: 5; +} +.intro-button-text { + display: flex; + flex-direction: column; + flex: 1; + transition: all 0.5s ease-in-out; + position: relative; + z-index: 10; + padding: 1rem 1.5rem; + text-align: left; + color: white; + font-size: 1.65rem; + font-style: normal; + font-weight: 600; + line-height: 130.023%; + letter-spacing: 0.0075rem; +} +.intro-button-text strong { + font-size: 2.625rem; + font-weight: 600; + line-height: 130.023%; + letter-spacing: 0.013125rem; +} +.intro-button-link span { + position: absolute; + display: block; + pointer-events: none; +} +.intro-button-link span:nth-child(1) { + height: 8px; + width: 100%; + top: 0; + left: 0; + background: linear-gradient(to right, rgba(0, 0, 0, 0), #f6e58d); + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + transform: translateX(-100%); + animation: span1 8s linear infinite; + animation-delay: 1s; +} +@keyframes span1 { + 0% { + transform: translateX(-100%); + } + 100% { + transform: translateX(100%); + } +} +.intro-button-link span:nth-child(2) { + width: 8px; + height: 100%; + top: 0; + right: 0; + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), #f6e58d); + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + transform: translateY(100%); + animation: span2 4s linear infinite; + animation-delay: 5s; +} +@keyframes span2 { + 0% { + transform: translateY(-100%); + } + 100% { + transform: translateY(100%); + } +} +.intro-button-link span:nth-child(3) { + height: 8px; + width: 100%; + bottom: 0; + right: 0; + background: linear-gradient(to left, rgba(0, 0, 0, 0), #f6e58d); + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + transform: translateX(100%); + animation: span3 8s linear infinite; + animation-delay: 7s; +} +@keyframes span3 { + 0% { + transform: translateX(100%); + } + 100% { + transform: translateX(-100%); + } +} +.intro-button-link:hover span { + animation-play-state: paused; +} +@media (width < 768px) { + .intro-header { + padding-bottom: 9rem;; + } + .intro-button-link { + height: 6.25rem; + min-width: auto; + border-radius: 0; + } + .intro-button-text { + display: inline; + padding-top: .5rem; + } +} +@media (width >= 768px) { + .intro-button { + position: absolute; + top: 0; + left: 50%; + transform: translate(-50%, -50%); + max-width: 29.375rem; + margin-bottom: 0; + } + .intro-button-link:hover { + transition: all .5s; + transform: rotate(-3deg) scale(1.125); + } +} + +.intro-text { + z-index: 1; + width: 100%; + display: flex; + flex-direction: column; + box-sizing: border-box; + align-items: center; + text-align: left; + margin-bottom: 0; + background: #fff; + position: relative; +} +.intro-text-body { + padding: 2.5rem 1.063rem 0.75rem; + overflow: hidden; + width: 100%; +} +.intro-text-lead { + width: 100%; + font-size: 1.5rem; + margin: 0 0 1.5rem; +} +@media (width >= 768px) { + .intro-button + .intro-text-body { + padding-top: 7rem; + } +} +@media (width >= 992px) { + .intro-header { + padding-bottom: 9rem;; + } + .intro-text, + .intro-text-body { + border-radius: 0.75rem; + } + .intro-text { + box-shadow: var(--intro-shadow); + max-width: min(60rem, 100vw - 4rem); + margin: 0 auto 6rem; + } + .intro-text-narrow { + max-width: min(50rem, 100vw - 4rem); + } + .intro-text-wide { + max-width: min(67rem, 100vw - 4rem); + } + .intro-text-full { + max-width: min(74rem, 100vw - 4rem); + } + .intro-text-body { + padding-left: 4.5rem; + padding-right: 4.5rem; + } +} + +.intro-text-body .block { + position: relative; +} +.intro-text-body .block-title { + margin: 1em 0 .8em; +} +.intro-text-body .block-title span { + display: inline-block; + padding: 10px 30px 14px; + margin: 30px 20px 0; + background: white; + border: 5px solid; + border-radius: 30px; + box-shadow: 0 0 0 5px white, inset 0 0 0 5px white; + border-color: orangered; + transform: rotate(-3deg) translateY(-25%); +} +.intro-text-body .block-title:before { + content: ""; + height: 5px; + position: absolute; + top: 50px; + left: -15%; + width: 130%; + z-index: -5; + background: orangered; + box-shadow: 0 0 0 5px white, 0 -10px 0 5px white; + transform: rotate(2deg) translateY(-50%); + transform-origin: top left; +} +.intro-text-body .block-title:after { + content: ""; + height: 120%; + position: absolute; + top: 42px; + left: -25%; + width: 150%; + z-index: -10; + background: var(--intro-bg-block-1); + transform: rotate(2deg); +} +.intro-text-body .block:nth-of-type(6n+1) .block-title:after { + background: var(--intro-bg-block-1); +} +.intro-text-body .block:nth-of-type(6n+2) .block-title:after { + background: var(--intro-bg-block-2); +} +.intro-text-body .block:nth-of-type(6n+3) .block-title:after { + background: var(--intro-bg-block-3); +} +.intro-text-body .block:nth-of-type(6n+4) .block-title:after { + background: var(--intro-bg-block-4); +} +.intro-text-body .block:nth-of-type(6n+5) .block-title:after { + background: var(--intro-bg-block-5); +} +.intro-text-body .block:nth-of-type(6n+6) .block-title:after { + background: var(--intro-bg-block-6); +} + +#intro-badges { + min-height: 3.2rem; + text-align: center; + visibility: hidden; +} +#intro-badges img { + margin-bottom: 0.25rem; +} +#intro-release:not([src]) { + display: none; +} + +// Intro Footer + +.intro-footer { + width: 100%; + background-color: black; + color: var(--intro-color-gray); + padding-bottom: 2rem; +} + +.intro-footer-body { + display: flex; + justify-content: center; + flex-direction: column; + margin: 0 auto; + padding: 0 10.625rem; + max-width: 80rem; +} +.intro-footer-body a:visited { + color: var(--intro-color-gray); +} +// The footer has its own dark surface, so its links don't inherit the theme's link colors. +.intro-footer-links a { + color: currentColor; + text-decoration: underline; + transition: font-size 0.2s, text-decoration-color 0.2s; +} +.intro-footer-links a:focus-visible { + outline: var(--intro-focus-outline); + outline-offset: var(--intro-focus-outline-offset); +} +.intro-footer-links a:hover, +.intro-footer-links a:hover:visited { + text-decoration-color: var(--intro-color-link); +} +.intro-footer-logo, +.intro-footer-links { + display: flex; + justify-content: center; + width: 100%; +} +.intro-footer-logo { + max-height: 12.625rem; +} +.intro-footer-logo svg { + width: 100%; +} +.intro-footer-links { + gap: 1.875rem; + flex-wrap: wrap; + margin-top: 2rem; +} +@media (width < 768px) { + .intro-footer-logo { + display: none; + } +} +@media (width < 992px) { + .intro-footer-body { + padding: 0 1rem; + } +} diff --git a/build.rs b/build.rs index 3a7a6554..0dcf973d 100644 --- a/build.rs +++ b/build.rs @@ -1,14 +1,21 @@ -use pagetop_build::{StaticFilesBundle, compile_scss, copy_dir, minify_js}; +use pagetop_build::{StaticFilesBundle, compile_scss, copy_dir, copy_file, minify_js}; fn main() -> std::io::Result<()> { // Regenera `static/` desde cero sólo si hay cambios en `assets/`. println!("cargo:rerun-if-changed=assets"); let _ = std::fs::remove_dir_all("static"); - copy_dir("assets", "static")?; + // Copia sin transformar. `assets/scss/` queda fuera porque sólo contiene fuentes SCSS. + copy_file("assets/banner.png", "static/banner.png")?; + copy_file("assets/favicon.ico", "static/favicon.ico")?; + copy_dir("assets/img", "static/img")?; + copy_dir("assets/js", "static/js")?; - // CSS: genera la variante minificada de `basic.css` del tema Basic. - compile_scss("assets/css/basic.css", "static/css/basic.min.css")?; + // CSS: compila los estilos del tema Basic. + compile_scss("assets/scss/basic.scss", "static/css/basic.min.css")?; + + // CSS: compila los estilos del componente `Intro`, independientes del tema. + compile_scss("assets/scss/intro.scss", "static/css/intro.min.css")?; // JS: minifica el manejo de `Dialog` del tema Basic. minify_js( diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs index fe7e1b19..aa41219a 100644 --- a/extensions/pagetop-aliner/src/lib.rs +++ b/extensions/pagetop-aliner/src/lib.rs @@ -114,12 +114,7 @@ impl Extension for Aliner { impl Theme for Aliner { fn before_render_page_body(&self, page: &mut Page) { page.alter_assets( - StyleSheet::from("/pagetop/css/normalize.css") - .with_version("8.0.1") - .with_weight(-99), - ) - .alter_assets( - StyleSheet::from("/pagetop/css/basic.css") + StyleSheet::from("/pagetop/css/basic.min.css") .with_version(PAGETOP_VERSION) .with_weight(-99), ) diff --git a/src/base/component/intro/component.rs b/src/base/component/intro/component.rs index 52a80439..b53e618a 100644 --- a/src/base/component/intro/component.rs +++ b/src/base/component/intro/component.rs @@ -107,7 +107,9 @@ impl Component for Intro { } async fn prepare(&self, cx: &mut Context) -> Result { - cx.alter_assets(StyleSheet::from("/pagetop/css/intro.css").with_version(PAGETOP_VERSION)); + cx.alter_assets( + StyleSheet::from("/pagetop/css/intro.min.css").with_version(PAGETOP_VERSION), + ); if *self.kind() == intro::Kind::PageTop { cx.alter_assets(JavaScript::on_load_async("intro-js", |cx| util::indoc!(r#" diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 7b1aa66d..9d53714b 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -15,11 +15,6 @@ impl Extension for Basic { impl Theme for Basic { fn before_render_page_body(&self, page: &mut Page) { page.alter_assets( - StyleSheet::from("/pagetop/css/normalize.css") - .with_version("8.0.1") - .with_weight(-99), - ) - .alter_assets( StyleSheet::from("/pagetop/css/basic.min.css") .with_version(PAGETOP_VERSION) .with_weight(-99), diff --git a/src/lib.rs b/src/lib.rs index dbcea9d2..d022eb37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,10 +110,7 @@ use std::ops::Deref; /// fn before_render_page_body(&self, page: &mut Page) { /// page /// .alter_assets( -/// StyleSheet::from("/pagetop/css/normalize.css").with_version("8.0.1") -/// ) -/// .alter_assets( -/// StyleSheet::from("/pagetop/css/basic.css").with_version(PAGETOP_VERSION), +/// StyleSheet::from("/pagetop/css/basic.min.css").with_version(PAGETOP_VERSION), /// ) /// .alter_assets( /// StyleSheet::from("/mytheme/styles.css").with_version(env!("CARGO_PKG_VERSION")),