diff options
Diffstat (limited to 'app/assets/stylesheets/components')
-rw-r--r-- | app/assets/stylesheets/components/_accordion.scss | 116 | ||||
-rw-r--r-- | app/assets/stylesheets/components/_card.scss | 36 | ||||
-rw-r--r-- | app/assets/stylesheets/components/_dropdown.scss | 214 | ||||
-rw-r--r-- | app/assets/stylesheets/components/_modal.scss | 168 | ||||
-rw-r--r-- | app/assets/stylesheets/components/_nav.scss | 141 | ||||
-rw-r--r-- | app/assets/stylesheets/components/_progress.scss | 89 |
6 files changed, 764 insertions, 0 deletions
diff --git a/app/assets/stylesheets/components/_accordion.scss b/app/assets/stylesheets/components/_accordion.scss new file mode 100644 index 0000000..59b2c65 --- /dev/null +++ b/app/assets/stylesheets/components/_accordion.scss @@ -0,0 +1,116 @@ +/** + * Accordion (<details>) + */ + +details { + display: block; + margin-bottom: var(--spacing); + padding-bottom: var(--spacing); + border-bottom: var(--border-width) solid var(--accordion-border-color); + + summary { + line-height: 1rem; + list-style-type: none; + cursor: pointer; + + &:not([role]) { + color: var(--accordion-close-summary-color); + } + + @if $enable-transitions { + transition: color var(--transition); + } + + // Reset marker + &::-webkit-details-marker { + display: none; + } + + &::marker { + display: none; + } + + &::-moz-list-bullet { + list-style-type: none; + } + + // Marker + &::after { + display: block; + width: 1rem; + height: 1rem; + margin-inline-start: calc(var(--spacing, 1rem) * 0.5); + float: right; + transform: rotate(-90deg); + background-image: var(--icon-chevron); + background-position: right center; + background-size: 1rem auto; + background-repeat: no-repeat; + content: ""; + + @if $enable-transitions { + transition: transform var(--transition); + } + } + + &:focus { + outline: none; + + &:not([role="button"]) { + color: var(--accordion-active-summary-color); + } + } + + // Type button + &[role="button"] { + width: 100%; + text-align: left; + + // Marker + &::after { + height: calc(1rem * var(--line-height, 1.5)); + background-image: var(--icon-chevron-button); + } + + @if $enable-classes { + // .contrast + &:not(.outline).contrast { + // Marker + &::after { + background-image: var(--icon-chevron-button-inverse); + } + } + } + } + } + + // Open + &[open] { + > summary { + margin-bottom: calc(var(--spacing)); + + &:not([role]) { + &:not(:focus) { + color: var(--accordion-open-summary-color); + } + } + + &::after { + transform: rotate(0); + } + } + } +} + +[dir="rtl"] { + details { + summary { + text-align: right; + + &::after { + float: left; + background-position: left center; + } + } + } +} diff --git a/app/assets/stylesheets/components/_card.scss b/app/assets/stylesheets/components/_card.scss new file mode 100644 index 0000000..924415e --- /dev/null +++ b/app/assets/stylesheets/components/_card.scss @@ -0,0 +1,36 @@ +/** + * Card (<article>) + */ + +article { + margin: var(--block-spacing-vertical) 0; + padding: var(--block-spacing-vertical) var(--block-spacing-horizontal); + border-radius: var(--border-radius); + background: var(--card-background-color); + box-shadow: var(--card-box-shadow); + + > header, + > footer { + margin-right: calc(var(--block-spacing-horizontal) * -1); + margin-left: calc(var(--block-spacing-horizontal) * -1); + padding: calc(var(--block-spacing-vertical) * 0.66) + var(--block-spacing-horizontal); + background-color: var(--card-sectionning-background-color); + } + + > header { + margin-top: calc(var(--block-spacing-vertical) * -1); + margin-bottom: var(--block-spacing-vertical); + border-bottom: var(--border-width) solid var(--card-border-color); + border-top-right-radius: var(--border-radius); + border-top-left-radius: var(--border-radius); + } + + > footer { + margin-top: var(--block-spacing-vertical); + margin-bottom: calc(var(--block-spacing-vertical) * -1); + border-top: var(--border-width) solid var(--card-border-color); + border-bottom-right-radius: var(--border-radius); + border-bottom-left-radius: var(--border-radius); + } +} diff --git a/app/assets/stylesheets/components/_dropdown.scss b/app/assets/stylesheets/components/_dropdown.scss new file mode 100644 index 0000000..a16e6d2 --- /dev/null +++ b/app/assets/stylesheets/components/_dropdown.scss @@ -0,0 +1,214 @@ +/** + * Dropdown ([role="list"]) + */ + +// Menu +details[role="list"], +li[role="list"] { + position: relative; +} + +details[role="list"] summary + ul, +li[role="list"] > ul { + display: flex; + z-index: 99; + position: absolute; + top: auto; + right: 0; + left: 0; + flex-direction: column; + margin: 0; + padding: 0; + border: var(--border-width) solid var(--dropdown-border-color); + border-radius: var(--border-radius); + border-top-right-radius: 0; + border-top-left-radius: 0; + background-color: var(--dropdown-background-color); + box-shadow: var(--card-box-shadow); + color: var(--dropdown-color); + white-space: nowrap; + + li { + width: 100%; + margin-bottom: 0; + padding: calc(var(--form-element-spacing-vertical) * 0.5) + var(--form-element-spacing-horizontal); + list-style: none; + + &:first-of-type { + margin-top: calc(var(--form-element-spacing-vertical) * 0.5); + } + + &:last-of-type { + margin-bottom: calc(var(--form-element-spacing-vertical) * 0.5); + } + + a { + display: block; + margin: calc(var(--form-element-spacing-vertical) * -0.5) + calc(var(--form-element-spacing-horizontal) * -1); + padding: calc(var(--form-element-spacing-vertical) * 0.5) + var(--form-element-spacing-horizontal); + overflow: hidden; + color: var(--dropdown-color); + text-decoration: none; + text-overflow: ellipsis; + + &:hover { + background-color: var(--dropdown-hover-background-color); + } + } + } +} + +// Marker +details[role="list"] summary, +li[role="list"] > a { + &::after { + display: block; + width: 1rem; + height: calc(1rem * var(--line-height, 1.5)); + margin-inline-start: 0.5rem; + float: right; + transform: rotate(0deg); + background-image: var(--icon-chevron); + background-position: right center; + background-size: 1rem auto; + background-repeat: no-repeat; + content: ""; + } +} + +// Global dropdown only +details[role="list"] { + padding: 0; + border-bottom: none; + + // Style <summary> as <select> + summary { + margin-bottom: 0; + + &:not([role]) { + height: calc( + 1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + + var(--border-width) * 2 + ); + padding: var(--form-element-spacing-vertical) + var(--form-element-spacing-horizontal); + border: var(--border-width) solid var(--form-element-border-color); + border-radius: var(--border-radius); + background-color: var(--form-element-background-color); + color: var(--form-element-placeholder-color); + line-height: inherit; + cursor: pointer; + + @if $enable-transitions { + transition: background-color var(--transition), + border-color var(--transition), color var(--transition), + box-shadow var(--transition); + } + + &:active, + &:focus { + border-color: var(--form-element-active-border-color); + background-color: var(--form-element-active-background-color); + } + + &:focus { + box-shadow: 0 0 0 var(--outline-width) var(--form-element-focus-color); + } + } + } + + // Close for details[role="list"] + &[open] summary { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + + &::before { + display: block; + z-index: 1; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: none; + content: ""; + cursor: default; + } + } +} + +// All Dropdowns inside <nav> +nav details[role="list"] summary, +nav li[role="list"] a { + display: flex; + direction: ltr; +} + +nav details[role="list"] summary + ul, +nav li[role="list"] > ul { + min-width: fit-content; + border-radius: var(--border-radius); + + li a { + border-radius: 0; + } +} + +// Dropdowns inside <nav> as nested <details> +nav details[role="list"] { + summary, + summary:not([role]) { + height: auto; + padding: var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal); + } + + &[open] summary { + border-radius: var(--border-radius); + } + + summary + ul { + margin-top: var(--outline-width); + margin-inline-start: 0; + } + + summary[role="link"] { + margin-bottom: calc(var(--nav-link-spacing-vertical) * -1); + line-height: var(--line-height); + + + ul { + margin-top: calc(var(--nav-link-spacing-vertical) + var(--outline-width)); + margin-inline-start: calc(var(--nav-link-spacing-horizontal) * -1); + } + } +} + +// Dropdowns inside a <nav> without using <details> +li[role="list"] { + // Open on hover (for mobile) + // or on active/focus (for keyboard navigation) + &:hover > ul, + a:active ~ ul, + a:focus ~ ul { + display: flex; + } + + > ul { + display: none; + margin-top: calc(var(--nav-link-spacing-vertical) + var(--outline-width)); + margin-inline-start: calc( + var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal) + ); + } + + > a::after { + background-image: var(--icon-chevron); + } +} + +label > details[role="list"] { + margin-top: calc(var(--spacing) * .25); + margin-bottom: var(--spacing); +} diff --git a/app/assets/stylesheets/components/_modal.scss b/app/assets/stylesheets/components/_modal.scss new file mode 100644 index 0000000..af5cb16 --- /dev/null +++ b/app/assets/stylesheets/components/_modal.scss @@ -0,0 +1,168 @@ +/** + * Modal (<dialog>) + */ + +:root { + --scrollbar-width: 0px; +} + +dialog { + display: flex; + z-index: 999; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + align-items: center; + justify-content: center; + width: inherit; + min-width: 100%; + height: inherit; + min-height: 100%; + padding: var(--spacing); + border: 0; + backdrop-filter: var(--modal-overlay-backdrop-filter); + background-color: var(--modal-overlay-background-color); + color: var(--color); + + // Content + article { + $close-selector: if($enable-classes, ".close", "a[rel='prev']"); + max-height: calc(100vh - var(--spacing) * 2); + overflow: auto; + + @if map-get($breakpoints, "sm") { + @media (min-width: map-get($breakpoints, "sm")) { + max-width: map-get($viewports, "sm"); + } + } + + @if map-get($breakpoints, "md") { + @media (min-width: map-get($breakpoints, "md")) { + max-width: map-get($viewports, "md"); + } + } + + > header, + > footer { + padding: calc(var(--block-spacing-vertical) * 0.5) + var(--block-spacing-horizontal); + } + + > header { + #{$close-selector} { + margin: 0; + margin-left: var(--spacing); + float: right; + } + } + + > footer { + text-align: right; + + [role="button"] { + margin-bottom: 0; + + &:not(:first-of-type) { + margin-left: calc(var(--spacing) * 0.5); + } + } + } + + p { + &:last-of-type { + margin: 0; + } + } + + // Close icon + #{$close-selector} { + display: block; + width: 1rem; + height: 1rem; + margin-top: calc(var(--block-spacing-vertical) * -0.5); + margin-bottom: var(--typography-spacing-vertical); + margin-left: auto; + background-image: var(--icon-close); + background-position: center; + background-size: auto 1rem; + background-repeat: no-repeat; + opacity: 0.5; + + @if $enable-transitions { + transition: opacity var(--transition); + } + + &:is([aria-current], :hover, :active, :focus) { + opacity: 1; + } + } + } + + // Closed state + &:not([open]), + &[open="false"] { + display: none; + } +} + +// Utilities +@if $enable-classes { + .modal-is-open { + padding-right: var(--scrollbar-width, 0px); + overflow: hidden; + pointer-events: none; + touch-action: none; + + dialog { + pointer-events: auto; + } + } +} + +// Animations +@if ($enable-classes and $enable-transitions) { + $animation-duration: 0.2s; + + :where(.modal-is-opening, .modal-is-closing) { + dialog, + dialog > article { + animation-duration: $animation-duration; + animation-timing-function: ease-in-out; + animation-fill-mode: both; + } + + dialog { + animation-duration: ($animation-duration * 4); + animation-name: modal-overlay ; + + > article { + animation-delay: $animation-duration; + animation-name: modal; + } + } + } + + .modal-is-closing { + dialog, + dialog > article { + animation-delay: 0s; + animation-direction: reverse; + } + } + + @keyframes modal-overlay { + from { + backdrop-filter: none; + background-color: transparent; + } + } + + @keyframes modal { + from { + transform: translateY(-100%); + opacity: 0; + } + } +} diff --git a/app/assets/stylesheets/components/_nav.scss b/app/assets/stylesheets/components/_nav.scss new file mode 100644 index 0000000..06fdd22 --- /dev/null +++ b/app/assets/stylesheets/components/_nav.scss @@ -0,0 +1,141 @@ +/** + * Nav + */ + +// Reboot based on : +// - sanitize.css v13.0.0 | CC0 1.0 Universal | github.com/csstools/sanitize.css + +// Prevent VoiceOver from ignoring list semantics in Safari (opinionated) +:where(nav li)::before { + float: left; + content: "\200B"; +} + +// Pico +// –––––––––––––––––––– + +// Horizontal Nav +nav, +nav ul { + display: flex; +} + +nav { + justify-content: space-between; + + ol, + ul { + align-items: center; + margin-bottom: 0; + padding: 0; + list-style: none; + + &:first-of-type { + margin-left: calc(var(--nav-element-spacing-horizontal) * -1); + } + &:last-of-type { + margin-right: calc(var(--nav-element-spacing-horizontal) * -1); + } + } + + li { + display: inline-block; + margin: 0; + padding: var(--nav-element-spacing-vertical) + var(--nav-element-spacing-horizontal); + + // Minimal support for buttons and forms elements + > * { + --spacing: 0; + } + } + + :where(a, [role="link"]) { + display: inline-block; + margin: calc(var(--nav-link-spacing-vertical) * -1) + calc(var(--nav-link-spacing-horizontal) * -1); + padding: var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal); + border-radius: var(--border-radius); + text-decoration: none; + + &:is([aria-current], :hover, :active, :focus) { + text-decoration: none; + } + } + + // Breadcrumb + &[aria-label="breadcrumb"] { + align-items: center; + justify-content: start; + + & ul li { + &:not(:first-child) { + margin-inline-start: var(--nav-link-spacing-horizontal); + } + + &:not(:last-child) { + ::after { + position: absolute; + width: calc(var(--nav-link-spacing-horizontal) * 2); + margin-inline-start: calc(var(--nav-link-spacing-horizontal) / 2); + content: "/"; + color: var(--muted-color); + text-align: center; + } + } + } + + & a[aria-current] { + background-color: transparent; + color: inherit; + text-decoration: none; + pointer-events: none; + } + } + + // Minimal support for role="button" + [role="button"] { + margin-right: inherit; + margin-left: inherit; + padding: var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal); + } +} + +// Vertical Nav +aside { + nav, + ol, + ul, + li { + display: block; + } + + li { + padding: calc(var(--nav-element-spacing-vertical) * 0.5) + var(--nav-element-spacing-horizontal); + + a { + display: block; + } + + // Minimal support for links as buttons + [role="button"] { + margin: inherit; + } + } +} + +// Breadcrumb RTL +[dir="rtl"] { + nav { + &[aria-label="breadcrumb"] { + & ul li { + &:not(:last-child) { + ::after { + content: "\\"; + } + } + } + } + } +} diff --git a/app/assets/stylesheets/components/_progress.scss b/app/assets/stylesheets/components/_progress.scss new file mode 100644 index 0000000..d62ddc0 --- /dev/null +++ b/app/assets/stylesheets/components/_progress.scss @@ -0,0 +1,89 @@ +/** + * Progress + */ + +// Reboot based on : +// - normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css +// - sanitize.css v13.0.0 | CC0 1.0 Universal | github.com/csstools/sanitize.css +// –––––––––––––––––––– + +// 1. Add the correct display in Edge 18- and IE +// 2. Add the correct vertical alignment in Chrome, Edge, and Firefox +progress { + display: inline-block; // 1 + vertical-align: baseline; // 2 +} + +// Pico +// –––––––––––––––––––– + +progress { + // Reset the default appearance + -webkit-appearance: none; + -moz-appearance: none; + + // Styles + display: inline-block; + appearance: none; + width: 100%; + height: 0.5rem; + margin-bottom: calc(var(--spacing) * 0.5); + overflow: hidden; + + // Remove Firefox and Opera border + border: 0; + border-radius: var(--border-radius); + background-color: var(--progress-background-color); + + // IE10 uses `color` to set the bar background-color + color: var(--progress-color); + + &::-webkit-progress-bar { + border-radius: var(--border-radius); + background: none; + } + &[value]::-webkit-progress-value { + background-color: var(--progress-color); + } + &::-moz-progress-bar { + background-color: var(--progress-color); + } + + // Indeterminate state + @media (prefers-reduced-motion: no-preference) { + &:indeterminate { + background: var(--progress-background-color) + linear-gradient( + to right, + var(--progress-color) 30%, + var(--progress-background-color) 30% + ) + top left / 150% 150% no-repeat; + animation: progress-indeterminate 1s linear infinite; + + &[value]::-webkit-progress-value { + background-color: transparent; + } + &::-moz-progress-bar { + background-color: transparent; + } + } + } +} + +[dir="rtl"] { + @media (prefers-reduced-motion: no-preference) { + progress:indeterminate { + animation-direction: reverse; + } + } +} + +@keyframes progress-indeterminate { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} |