├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── bug.md
│ └── enhancement.md
├── .gitignore
├── .stylelintrc
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── examples
├── demo.webp
├── ratata.html
└── styles.css
├── package-lock.json
├── package.json
└── src
├── css
├── _icons.css
├── _print.css
├── _reset.css
├── _utilities.css
├── _variables.css
├── components
│ ├── _accordion.css
│ ├── _alert.css
│ ├── _breadcrumb.css
│ ├── _card.css
│ ├── _textmedia.css
│ └── _theme-switcher.css
├── content
│ ├── _base.css
│ ├── _buttons.css
│ ├── _code.css
│ ├── _forms.css
│ ├── _images.css
│ ├── _lists.css
│ ├── _quotes.css
│ ├── _table.css
│ ├── _typography.css
│ └── forms
│ │ ├── _form-check.css
│ │ ├── _form-input.css
│ │ ├── _form-radio.css
│ │ ├── _form-select.css
│ │ └── _form-textarea.css
├── layout
│ ├── _container.css
│ ├── _document.css
│ └── _grid.css
├── ratata.css
└── themes
│ ├── _default.css
│ └── default
│ ├── _colors.css
│ └── _light-dark.css
├── icons
├── check.svg
├── chevron-down.svg
├── error.svg
└── minus.svg
├── index.html
└── js
├── helpers
└── set-color-scheme.js
├── libs
├── _accordion.js
└── _toggle-color-scheme.js
└── ratata.js
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [deoostfrees]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug
3 | about: A problem with the boilerplate.
4 | title: 'Bug: [Title]'
5 | labels: 'type: bug'
6 | assignees: ''
7 | ---
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/enhancement.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Enhancement
3 | about: Propose an idea for this boilerplate.
4 | title: 'Enhancement: [Title]'
5 | labels: 'type: enhancement'
6 | assignees: ''
7 | ---
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .vscode/
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/.stylelintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "stylelint-config-standard"
4 | ],
5 | "plugins": [
6 | "stylelint-use-logical"
7 | ],
8 | "rules": {
9 | "property-no-vendor-prefix": null,
10 | "selector-no-vendor-prefix": null,
11 | "selector-not-notation": null,
12 | "color-hex-length": "long",
13 | "no-descending-specificity": null,
14 | "shorthand-property-no-redundant-values": [true, {"severity": "warning"}],
15 | "declaration-no-important": true,
16 | "no-duplicate-at-import-rules": true,
17 | "selector-max-id": 0,
18 | "declaration-block-no-duplicate-properties": true,
19 | "rule-empty-line-before": ["always-multi-line", {"ignore": ["after-comment"]}],
20 | "value-keyword-case": "lower",
21 | "selector-class-pattern": ["^([a-z][a-z0-9]*)(-[a-z0-9]+)*(_[a-z0-9]+)*(__[a-z]((_|-)?[a-z0-9])*)?(--[a-z0-9]((_|-)?[a-z0-9\\\\\\/])*)?$", { "resolveNestedSelectors": true }],
22 | "declaration-block-no-redundant-longhand-properties": null,
23 | "csstools/use-logical": true
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [Unreleased]
4 |
5 | - Grid system
6 |
7 | ## [0.8.0] - 2024-10-27
8 |
9 | ### Added
10 |
11 | - Code styles (keyboard input, sample output)
12 | - Description list
13 | - Image related styles (WIP)
14 | - Form validation styles
15 | - Textmedia component (WIP)
16 |
17 | ### Changed
18 |
19 | - **Breaking:** Use light-dark() color function instead media feature query
20 |
21 | ### Removed
22 |
23 | - **Breaking:** Share button
24 |
25 | ## [0.7.0] - 2024-05-29
26 |
27 | ### Added
28 |
29 | - CSS cascade layers
30 | - List styles
31 |
32 | ### Changed
33 |
34 | - Use CSS `min` instead of `padding` on the `.container` class
35 |
36 | ## [0.6.0] - 2024-05-14
37 |
38 | ### Added
39 |
40 | - Button with icon style
41 | - Share button
42 |
43 | ### Changed
44 |
45 | - **Breaking:** Use `details` and `summary` instead of JavaScript for accordions
46 |
47 | ## [0.5.0] - 2024-04-21
48 |
49 | ### Changed
50 |
51 | - Inline/ block quotation
52 |
53 | ### Added
54 |
55 | - Theme switcher
56 |
57 | ### Removed
58 |
59 | In this release, some additional styles have been removed to keep the boilerplate small.
60 |
61 | - **Breaking:** Zepra striped table style
62 | - **Breaking:** Vertically aligned card
63 | - **Breaking:** Card with an icon
64 |
65 | ## [0.4.0] - 2024-03-20
66 |
67 | ### Changed
68 |
69 | - File input button color
70 |
71 | ### Added
72 |
73 | - Breadcrumb
74 |
75 | ### Fixed
76 |
77 | - Fix the print stylesheet to display the URL after links
78 |
79 | ## [0.3.0] - 2024-03-14
80 |
81 | ### Changed
82 |
83 | - **Breaking:** CSS custom properties for table
84 |
85 | ### Added
86 |
87 | - Narrow container width
88 | - Table style variant
89 | - Code styles
90 | - File input styles
91 |
92 | ## [0.2.1] - 2024-03-11
93 |
94 | ### Fixed
95 |
96 | - Add missing changes to the changelog
97 |
98 | ## [0.2.0] - 2024-03-10
99 |
100 | ### Changed
101 |
102 | - **Breaking:** CSS custom properties for colors
103 |
104 | ### Added
105 |
106 | - Container layout
107 | - Table styles
108 | - Card element
109 |
110 | ### Removed
111 |
112 | - Autoprefixer
113 |
114 | ## [0.1.0] - 2024-02-27
115 |
116 | _First release._
117 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | Copyright (c) 2023 Benjamin de Oostfrees
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ratata
2 |
3 | More web standards, less bullshit.
4 |
5 | Ratata is a HTML, CSS and JavaScript boilerplate using just HTML, CSS and JavaScript. It's main focus is on web standards, accessibility and performance. [Check it out on CodePen](https://codepen.io/deoostfrees/pen/XWGWbEy).
6 |
7 | ## Table of contents
8 |
9 | - [Getting Started](#getting-started)
10 | - [Credits, Attribution and Inspiration](#credits-attribution-and-inspiration)
11 | - [Browser Support](#browser-support)
12 |
13 | ## Getting Started
14 |
15 | - [Download the latest release](https://github.com/deoostfrees/Ratata/releases). You may need to copy and paste the contents of the unzipped `Ratata-0.x.x/src` folder into your project directory.
16 | - Install Ratata from GitHub using [npm](https://www.npmjs.com): `npm install ratata`. You may need to copy and paste the contents of the `node_modules/ratata/src` folder into your project directory.
17 |
18 | ### Variables
19 |
20 | The file `_variables.css` in the `src` folder contains variables for all layout, spacing and typography used in Ratata.
21 |
22 | ```css
23 | :root {
24 | /**
25 | * Spacing
26 | *
27 | */
28 | --scroll-padding-top: calc((100 / 18) * 1rem);
29 | --scroll-padding-bottom: 0;
30 |
31 | /**
32 | * Layout
33 | *
34 | */
35 | --container-max-width: calc((1848 / 18) * 1rem);
36 | --container-small-max-width: calc((660 / 18) * 1rem);
37 | --container-padding-inline: calc((24 / 18) * 1rem);
38 |
39 | /**
40 | * Typography
41 | *
42 | */
43 | --base-font-family: -apple-system, blinkmacsystemfont, 'Segoe UI', helvetica, arial, sans-serif;
44 | --base-font-size: calc((18 / 16) * 1rem);
45 | --base-font-weight: 400;
46 | --base-line-height: calc((31 / 18));
47 |
48 | /* b, strong */
49 | --bold-font-weight: 700;
50 |
51 | /* small */
52 | --small-font-size: calc((16 / 18) * 1rem);
53 | --small-line-height: calc((27 / 16));
54 |
55 | /* Blockquote */
56 | --blockquote-font-size: calc((23 / 18) * 1rem);
57 | --blockquote-line-height: calc((38 / 23));
58 |
59 | /* Headings */
60 | --headings-font-family: var(--base-font-family);
61 | --headings-font-weight: 700;
62 |
63 | /* h1 */
64 | --h1-font-size: calc((47 / 18) * 1rem);
65 | --h1-line-height: calc((73 / 47));
66 |
67 | /* h2 */
68 | --h2-font-size: calc((37 / 18) * 1rem);
69 | --h2-line-height: calc((58 / 37));
70 |
71 | /* h3 */
72 | --h3-font-size: calc((29 / 18) * 1rem);
73 | --h3-line-height: calc((47 / 29));
74 |
75 | /* h4 */
76 | --h4-font-size: calc((23 / 18) * 1rem);
77 | --h4-line-height: calc((38 / 23));
78 | }
79 | ```
80 |
81 | A default color scheme for light and dark mode can be found in `src/themes/`.
82 |
83 | ## Credits, Attribution and Inspiration
84 |
85 | - [Stephanie Eckles](https://thinkdobecreate.com)' [Pure CSS Custom Checkbox Style](https://moderncss.dev/pure-css-custom-checkbox-style/)
86 | - [Stephanie Eckles](https://thinkdobecreate.com)' [Pure CSS Custom Styled Radio Buttons](https://moderncss.dev/pure-css-custom-styled-radio-buttons/)
87 | - [Manuel Matuzović](https://matuzo.at)'s [Removing list styles without affecting semantics](https://matuzo.at/blog/2023/removing-list-styles-without-affecting-semantics)
88 | - [David Bushell](https://dbushell.com)'s [CSS Button Styles You Might Not Know](https://dbushell.com/2024/03/10/css-button-styles-you-might-not-know/)
89 | - [Adrian Roselli](https://adrianroselli.com)'s [Progressively Enhanced HTML Accordion](https://adrianroselli.com/2023/08/progressively-enhanced-html-accordion.html)
90 |
91 | ## Browser Support
92 |
93 | Ratata supports the latest, stable releases of all major browsers.
94 |
--------------------------------------------------------------------------------
/examples/demo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deoostfrees/Ratata/97a87db38e206ee6c7cc917f096d23d386ec1469/examples/demo.webp
--------------------------------------------------------------------------------
/examples/ratata.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Ratata
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 | Ratata is a HTML, CSS and JavaScript boilerplate using just HTML, CSS and JavaScript. It's main focus is on web standards, accessibility and performance. Check it out on GitHub .
28 |
29 |
30 |
63 |
64 |
65 |
72 |
73 | Heading level 1
74 | Heading level 2
75 | Heading level 3
76 | Heading level 4
77 |
78 |
79 |
80 |
87 |
88 | Link
89 |
90 | Bold
91 |
92 | Italic
93 |
94 | Deleted
95 |
96 | Inserted
97 |
98 | Strikethrough
99 |
100 | Small
101 |
102 | Text Sub
103 |
104 | Text Sup
105 |
106 | Highlighted
107 |
108 |
109 | Man muss noch Chaos in sich haben, um einen tanzenden Stern gebären zu können.
110 |
111 | —Friedrich Nietzsche, Also sprach Zarathustra
112 |
113 |
114 |
115 |
116 |
123 |
124 | Description list
125 |
126 |
127 | Description term
128 | Description details
129 |
130 |
131 | Unordered list
132 |
133 |
134 | First item
135 | Second item
136 |
137 | First subitem of second item
138 | Second subitem of second item
139 |
140 |
141 |
142 |
143 | Ordered list
144 |
145 |
146 | First item
147 | Second item
148 |
149 | First subitem of second item
150 | Second subitem of second item
151 |
152 |
153 | Third item
154 | Fourth item
155 | Fifth item
156 |
157 |
158 |
159 |
160 |
167 |
168 | Keyboard input
169 |
170 | F2
171 |
172 | Inline code
173 |
174 | .class
175 |
176 | Sample output
177 |
178 | Press any key to continue.
179 |
180 | Preformatted text
181 |
182 | .class {
183 | background-color: var(--black);
184 | box-decoration-break: clone;
185 | color: var(--white);
186 | padding-block: calc((4 / 18) * 1rem);
187 | padding-inline: calc((8 / 18) * 1rem);
188 | }
189 |
190 |
191 |
202 |
203 |
204 |
211 |
212 |
213 |
214 | Superheroes information
215 |
216 |
217 |
218 | First Name
219 | Last Name
220 | Super Hero
221 |
222 |
223 |
224 |
225 | Peter
226 | Parker
227 | Spiderman
228 |
229 |
230 | Bruce
231 | Wayne
232 | Batman
233 |
234 |
235 | Clark
236 | Kent
237 | Superman
238 |
239 |
240 |
241 |
242 |
243 |
244 |
251 |
252 |
253 | Default
254 |
255 | Primary
256 |
257 | Secondary
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 | Button with icon
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 | Button with icon
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 | Button with icon
286 |
287 |
288 |
289 |
290 |
291 | Button with icon
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 | Button with icon
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 | Button with icon
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
400 |
401 |
402 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 | Select color scheme "system"
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 | Select color scheme "light"
426 |
427 |
428 |
429 |
430 |
431 |
432 | Select color scheme "dark"
433 |
434 |
435 |
436 |
437 |
454 |
455 |
456 |
463 |
464 |
465 |
466 | Title
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 | Content
476 |
477 |
478 |
479 |
480 |
481 | Title
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 | Content
491 |
492 |
493 |
494 |
495 |
496 |
503 |
504 |
507 |
508 |
511 |
512 |
515 |
516 |
519 |
520 |
521 |
522 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 | Test
537 |
538 |
539 |
540 |
541 |
542 |
Lorem ipsum odor amet, consectetuer adipiscing elit. Eget rhoncus duis massa curabitur tempus egestas.
543 |
544 |
Sodales taciti aptent porttitor dapibus nunc. Erat eros risus nibh sed, senectus vel ultricies facilisis orci.
545 |
546 |
547 |
548 |
549 |
550 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
Lorem ipsum odor amet, consectetuer adipiscing elit. Eget rhoncus duis massa curabitur tempus egestas.
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
--------------------------------------------------------------------------------
/examples/styles.css:
--------------------------------------------------------------------------------
1 | main {
2 | margin-block: calc((80 / 18) * 1rem);
3 |
4 | & > * + * {
5 | margin-block-start: calc((120 / 18) * 1rem);
6 | }
7 | }
8 |
9 | section,
10 | form {
11 |
12 |
13 |
14 | & > * + *:not(.accordion) {
15 | margin-block-start: 1rlh;
16 | }
17 | }
18 |
19 | header {
20 |
21 |
22 |
23 | &:has(.anchor) {
24 | align-items: baseline;
25 | display: flex;
26 | flex-wrap: wrap;
27 | }
28 |
29 | & + * {
30 | margin-block-start: calc((48 / 18) * 1rem);
31 | }
32 | }
33 |
34 | .anchor {
35 | font-size: calc((18 / 18) * 1rem);
36 | font-weight: var(--base-font-weight);
37 | margin-inline-start: calc((16 / 18) * 1rem);
38 | }
39 |
40 | .toc {
41 |
42 |
43 |
44 | & ol {
45 | display: flex;
46 | flex-flow: column;
47 | row-gap: calc((8 / 18) * 1rem);
48 | }
49 | }
50 |
51 | .card {
52 | max-inline-size: calc((350 / 18) * 1rem);
53 | }
54 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ratata",
3 | "version": "0.8.0",
4 | "description": "HTML, CSS and JavaScript boilerplate using just HTML, CSS and JavaScript.",
5 | "main": "src/css/ratata.css",
6 | "scripts": {
7 | "testJs": "standard src/js/*",
8 | "testCss": "stylelint src/css/*",
9 | "test": "npm run testJs && npm run testCss"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git://github.com/deoostfrees/ratata.git"
14 | },
15 | "keywords": [
16 | "html",
17 | "css",
18 | "javascript",
19 | "boilerplate"
20 | ],
21 | "author": "Benjamin de Oostfrees",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/deoostfrees/Ratata/issues"
25 | },
26 | "devDependencies": {
27 | "standard": "^17.1.2",
28 | "stylelint": "^16.10.0",
29 | "stylelint-config-standard": "^36.0.1",
30 | "stylelint-use-logical": "^2.1.2"
31 | },
32 | "standard": {
33 | "globals": [
34 | "localStorage",
35 | "Audio"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/css/_icons.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --check-icon: url('./../icons/check.svg');
3 | --chevron-down-icon: url('./../icons/chevron-down.svg');
4 | --error-icon: url('./../icons/error.svg');
5 | --minus-icon: url('./../icons/minus.svg');
6 | }
7 |
--------------------------------------------------------------------------------
/src/css/_print.css:
--------------------------------------------------------------------------------
1 | *,
2 | *::before,
3 | *::after {
4 | background-color: white;
5 | box-shadow: none;
6 | color: black;
7 | text-shadow: none;
8 | }
9 |
10 | a {
11 | text-decoration: none;
12 |
13 | &::after {
14 | content: ' ('attr(href)')';
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/css/_reset.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | *,
7 | *::before,
8 | *::after {
9 | box-sizing: border-box;
10 | }
11 |
12 | html {
13 | text-size-adjust: none;
14 | }
15 |
16 | a,
17 | button {
18 | touch-action: manipulation;
19 | }
20 |
21 | hr {
22 | border: 0;
23 | }
24 |
25 | address,
26 | button,
27 | input,
28 | select,
29 | textarea,
30 | ::file-selector-button {
31 | font: inherit;
32 | line-height: inherit;
33 | }
34 |
35 | ::placeholder {
36 | opacity: 1;
37 | }
38 |
39 | img,
40 | picture {
41 | display: block;
42 | }
43 |
44 | img {
45 | block-size: auto;
46 | max-inline-size: 100%;
47 | }
48 |
49 | h1,
50 | h2,
51 | h3,
52 | h4 {
53 | text-wrap: balance;
54 | }
55 |
--------------------------------------------------------------------------------
/src/css/_utilities.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Hide content visually
3 | *
4 | */
5 | .visually-hidden:not(:focus) {
6 | block-size: calc((1 / 18) * 1rem);
7 | clip-path: inset(50%);
8 | inline-size: calc((1 / 18) * 1rem);
9 | overflow: hidden;
10 | position: absolute;
11 | white-space: nowrap;
12 | }
13 |
--------------------------------------------------------------------------------
/src/css/_variables.css:
--------------------------------------------------------------------------------
1 | :root {
2 | /**
3 | * Spacing
4 | *
5 | */
6 | --scroll-padding-top: calc((100 / 18) * 1rem);
7 | --scroll-padding-bottom: 0;
8 |
9 | /**
10 | * Layout
11 | *
12 | */
13 | --container-max-width: calc((1848 / 18) * 1rem);
14 | --container-small-max-width: calc((660 / 18) * 1rem);
15 | --container-padding-inline: calc((24 / 18) * 1rem);
16 |
17 | /* Grid */
18 | --grid-gutter-vertical: calc((24 / 18) * 1rem);
19 | --grid-gutter-horizontal: calc((24 / 18) * 1rem);
20 |
21 | /**
22 | * Typography
23 | *
24 | */
25 | --base-font-family: -apple-system, blinkmacsystemfont, 'Segoe UI', helvetica, arial, sans-serif;
26 | --base-font-size: calc((18 / 16) * 1rem);
27 | --base-font-weight: 400;
28 | --base-line-height: calc((31 / 18));
29 |
30 | /* b, strong */
31 | --bold-font-weight: 700;
32 |
33 | /* small */
34 | --small-font-size: calc((16 / 18) * 1rem);
35 | --small-line-height: calc((27 / 16));
36 |
37 | /* Blockquote */
38 | --blockquote-font-size: calc((23 / 18) * 1rem);
39 | --blockquote-line-height: calc((38 / 23));
40 |
41 | /* Code */
42 | --code-font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
43 | --code-font-weight: 400;
44 |
45 | /* Headings */
46 | --headings-font-family: var(--base-font-family);
47 | --headings-font-weight: 700;
48 |
49 | /* h1 */
50 | --h1-font-size: calc((47 / 18) * 1rem);
51 | --h1-line-height: calc((73 / 47));
52 |
53 | /* h2 */
54 | --h2-font-size: calc((37 / 18) * 1rem);
55 | --h2-line-height: calc((58 / 37));
56 |
57 | /* h3 */
58 | --h3-font-size: calc((29 / 18) * 1rem);
59 | --h3-line-height: calc((47 / 29));
60 |
61 | /* h4 */
62 | --h4-font-size: calc((23 / 18) * 1rem);
63 | --h4-line-height: calc((38 / 23));
64 | }
65 |
--------------------------------------------------------------------------------
/src/css/components/_accordion.css:
--------------------------------------------------------------------------------
1 | .accordion {
2 | border-block-end: calc((1 / 18) * 1rem) solid var(--accordion-button-border-color);
3 | padding-block-end: calc((4 / 18) * 1rem);
4 |
5 |
6 | & + & {
7 | margin-block-start: calc((4 / 18) * 1rem);
8 | }
9 | }
10 |
11 | .accordion__title {
12 | align-items: center;
13 | background-color: var(--accordion-button-background-color);
14 | color: var(--accordion-button-color);
15 | column-gap: calc((8 / 18) * 1rem);
16 | display: flex;
17 | inline-size: 100%;
18 | justify-content: space-between;
19 |
20 | /* Remove list style without affecting semantics. */
21 | list-style-type: '';
22 |
23 | &::-webkit-details-marker {
24 | display: none;
25 | }
26 |
27 |
28 | & svg {
29 | flex-shrink: 0;
30 | transition: transform 0.3s linear;
31 |
32 | [open] & {
33 | transform: rotate(-45deg);
34 | }
35 | }
36 | }
37 |
38 | .accordion__content {
39 | background-color: var(--accordion-content-background-color);
40 | color: var(--accordion-content-color);
41 | padding-block: calc((18 / 18) * 1rem) 0;
42 | }
43 |
--------------------------------------------------------------------------------
/src/css/components/_alert.css:
--------------------------------------------------------------------------------
1 | .alert {
2 | --link-color: currentcolor;
3 | --link-decoration-line: underline;
4 | --link-hover-color: currentcolor;
5 | --link-hover-decoration-line: none;
6 |
7 | border: calc((1 / 18) * 1rem) solid transparent;
8 | padding-block: calc((16 / 18) * 1rem);
9 | padding-inline: calc((16 / 18) * 1rem);
10 | }
11 |
12 | /**
13 | * Alert types
14 | *
15 | */
16 | .alert--info {
17 | background-color: var(--alert-info-background-color);
18 | border-color: var(--alert-info-border-color);
19 | color: var(--alert-info-color);
20 | }
21 |
22 | .alert--success {
23 | background-color: var(--alert-success-background-color);
24 | border-color: var(--alert-success-border-color);
25 | color: var(--alert-success-color);
26 | }
27 |
28 | .alert--danger {
29 | background-color: var(--alert-danger-background-color);
30 | border-color: var(--alert-danger-border-color);
31 | color: var(--alert-danger-color);
32 | }
33 |
34 | .alert--warning {
35 | background-color: var(--alert-warning-background-color);
36 | border-color: var(--alert-warning-border-color);
37 | color: var(--alert-warning-color);
38 | }
39 |
--------------------------------------------------------------------------------
/src/css/components/_breadcrumb.css:
--------------------------------------------------------------------------------
1 | .breadcrumb {
2 | display: flex;
3 | flex-wrap: wrap;
4 | font-size: calc((16 / 18) * 1rem);
5 | margin-inline-start: 0;
6 |
7 | /* Remove list style without affecting semantics. */
8 | list-style-type: '';
9 | }
10 |
11 | .breadcrumb__item {
12 | /* Style the visual separators between links with CSS to prevent screen readers from announcing them. */
13 | &:not(:last-child)::after {
14 | block-size: calc((14 / 18) * 1rem);
15 | border-inline-end: calc((1 / 18) * 1rem) solid currentcolor;
16 | content: '';
17 | display: inline-block;
18 | inline-size: calc((1 / 18) * 1rem);
19 | margin-inline-end: calc((8 / 18) * 1rem);
20 | padding-inline-start: calc((8 / 18) * 1rem);
21 | transform: rotate(15deg);
22 | }
23 | }
24 |
25 | .breadcrumb__item--active {
26 | --link-color: currentcolor;
27 | --link-decoration-line: none;
28 | --link-hover-color: currentcolor;
29 | --link-hover-decoration-line: none;
30 | }
31 |
--------------------------------------------------------------------------------
/src/css/components/_card.css:
--------------------------------------------------------------------------------
1 | .card {
2 | --link-color: var(--card-link-color);
3 | --link-decoration-line: var(--card-link-decoration-line);
4 | --link-hover-color: var(--card-link-hover-color);
5 | --link-hover-decoration-line: var(--card-link-hover-decoration-line);
6 |
7 | background-color: var(--card-background-color);
8 | border-radius: calc((8 / 18) * 1rem);
9 | border: calc((1 / 18) * 1rem) solid var(--card-border-color);
10 | color: var(--card-color);
11 | display: flex;
12 | flex-direction: column;
13 | overflow: hidden;
14 | position: relative;
15 | }
16 |
17 | .card__image {
18 | background-color: var(--card-image-background-color);
19 | color: var(--card-image-color);
20 |
21 |
22 | & img {
23 | aspect-ratio: 16 / 9;
24 | block-size: 100%;
25 | inline-size: 100%;
26 | min-block-size: calc((150 / 18) * 1rem);
27 | object-fit: cover;
28 | }
29 | }
30 |
31 | .card__body {
32 | background-color: var(--card-body-background-color);
33 | color: var(--card-body-color);
34 | flex: 1;
35 | padding: calc((16 / 18) * 1rem);
36 |
37 |
38 | & a {
39 |
40 |
41 | &::after {
42 | content: '';
43 | inset: 0;
44 | position: absolute;
45 | }
46 | }
47 |
48 | & > * + * {
49 | margin-block-start: 1lh;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/css/components/_textmedia.css:
--------------------------------------------------------------------------------
1 | *:has(> .textmedia) {
2 | container-type: inline-size;
3 | container-name: textmedia;
4 | }
5 |
6 | .textmedia {
7 | display: flex;
8 | flex-direction: column;
9 | gap: calc((24 / 18) * 1rem);
10 |
11 | @container textmedia (min-width: 600px) {
12 | flex-direction: row;
13 | }
14 | }
15 |
16 | .textmedia__media {
17 | flex: 1;
18 | }
19 |
20 | .textmedia__text {
21 | flex: 1;
22 |
23 |
24 | & > * + * {
25 | margin-block-start: 1rlh;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/css/components/_theme-switcher.css:
--------------------------------------------------------------------------------
1 | .theme-switcher {
2 | --button-background-color: transparent;
3 | --button-color: currentcolor;
4 | --button-border-color: transparent;
5 | --button-hover-background-color: transparent;
6 | --button-hover-border-color: transparent;
7 | --button-hover-color: currentcolor;
8 |
9 | background-color: var(--theme-switcher-background-color);
10 | border-color: var(--theme-switcher-border-color);
11 | border-radius: calc((360 / 18) * 1rem);
12 | color: var(--theme-switcher-color);
13 | column-gap: calc((4 / 18) * 1rem);
14 | display: flex;
15 | inline-size: fit-content;
16 | padding: calc((4 / 18) * 1rem);
17 |
18 |
19 | & [data-color-scheme] {
20 | border-radius: 100%;
21 | padding: calc((4 / 18) * 1rem);
22 | }
23 |
24 | & [aria-pressed='true'] {
25 | background-color: var(--theme-switcher-active-background-color);
26 | color: var(--theme-switcher-active-color);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/css/content/_base.css:
--------------------------------------------------------------------------------
1 | ::selection {
2 | background-color: var(--focus-background-color);
3 | color: var(--focus-color);
4 | }
5 |
6 | ::target-text {
7 | background-color: var(--focus-background-color);
8 | color: var(--focus-color);
9 | }
10 |
11 | html {
12 | scroll-padding-block: var(--scroll-padding-top) var(--scroll-padding-bottom);
13 |
14 | @media screen and (prefers-reduced-motion: no-preference) {
15 | scroll-behavior: smooth;
16 | }
17 | }
18 |
19 | body {
20 | background-color: var(--body-background-color);
21 | color: var(--body-color);
22 | }
23 |
24 | hr {
25 | border-block-start: calc((1 / 18) * 1rem) solid var(--hr-border-color);
26 | }
27 |
--------------------------------------------------------------------------------
/src/css/content/_buttons.css:
--------------------------------------------------------------------------------
1 | .btn {
2 | appearance: none;
3 | background-color: var(--button-background-color);
4 | background-image: none;
5 | border-radius: 0;
6 | border: calc((1 / 18) * 1rem) solid var(--button-border-color);
7 | color: var(--button-color);
8 | display: flex;
9 | inline-size: fit-content;
10 | text-decoration: none;
11 |
12 | &:hover,
13 | &:focus-visible {
14 | background-color: var(--button-hover-background-color);
15 | border-color: var(--button-hover-border-color);
16 | color: var(--button-hover-color);
17 | }
18 | }
19 |
20 | /**
21 | * Primary Button
22 | *
23 | */
24 | .btn--primary {
25 | background-color: var(--button-primary-background-color);
26 | border-color: var(--button-primary-border-color);
27 | border-radius: 0;
28 | color: var(--button-primary-color);
29 | padding-block: calc((4 / 18) * 1rem);
30 | padding-inline: calc((12 / 18) * 1rem);
31 |
32 | &:hover,
33 | &:focus-visible {
34 | background-color: var(--button-primary-hover-background-color);
35 | border-color: var(--button-primary-hover-border-color);
36 | color: var(--button-primary-hover-color);
37 | }
38 | }
39 |
40 | /**
41 | * Secondary button
42 | *
43 | */
44 | .btn--secondary {
45 | background-color: var(--button-secondary-background-color);
46 | border-color: var(--button-secondary-border-color);
47 | border-radius: 0;
48 | color: var(--button-secondary-color);
49 | padding-block: calc((4 / 18) * 1rem);
50 | padding-inline: calc((12 / 18) * 1rem);
51 |
52 | &:hover,
53 | &:focus-visible {
54 | background-color: var(--button-secondary-hover-background-color);
55 | border-color: var(--button-secondary-hover-border-color);
56 | color: var(--button-secondary-hover-color);
57 | }
58 | }
59 |
60 | /**
61 | * Button with icon
62 | *
63 | */
64 | .btn--icon {
65 | align-items: center;
66 | column-gap: calc((8 / 18) * 1rem);
67 | display: flex;
68 | inline-size: fit-content;
69 | }
70 |
--------------------------------------------------------------------------------
/src/css/content/_code.css:
--------------------------------------------------------------------------------
1 | kbd,
2 | code,
3 | samp,
4 | pre {
5 | font-family: var(--code-font-family);
6 | font-weight: var(--code-font-weight);
7 | }
8 |
9 | /**
10 | * Keyboard input
11 | *
12 | */
13 | kbd {
14 | background-color: var(--code-background-color);
15 | box-decoration-break: clone;
16 | color: var(--code-color);
17 | font-size: calc((16 / 18) * 1rem);
18 | padding-block: calc((4 / 18) * 1rem);
19 | padding-inline: calc((8 / 18) * 1rem);
20 | }
21 |
22 | /**
23 | * Inline code
24 | *
25 | */
26 | code {
27 | background-color: var(--code-background-color);
28 | box-decoration-break: clone;
29 | color: var(--code-color);
30 | font-size: calc((16 / 18) * 1rem);
31 | padding-block: calc((4 / 18) * 1rem);
32 | padding-inline: calc((8 / 18) * 1rem);
33 | }
34 |
35 | /**
36 | * Sample output
37 | *
38 | */
39 | samp {
40 | font-size: calc((16 / 18) * 1rem);
41 | }
42 |
43 | /**
44 | * Preformatted text
45 | *
46 | */
47 | pre {
48 | background-color: var(--code-background-color);
49 | color: var(--code-color);
50 | overflow-x: auto;
51 | padding: calc((8 / 18) * 1rem);
52 | tab-size: 4;
53 |
54 |
55 | & code {
56 | padding: 0;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/css/content/_forms.css:
--------------------------------------------------------------------------------
1 | @import url('./forms/_form-input.css');
2 | @import url('./forms/_form-check.css');
3 | @import url('./forms/_form-radio.css');
4 | @import url('./forms/_form-select.css');
5 | @import url('./forms/_form-textarea.css');
6 |
7 | fieldset {
8 | border: none;
9 | }
10 |
11 | legend {
12 | display: block;
13 |
14 |
15 | & + * {
16 | margin-block-start: calc((4 / 18) * 1rem);
17 | }
18 | }
19 |
20 | label {
21 |
22 |
23 |
24 | & + * {
25 | margin-block-start: calc((4 / 18) * 1rem);
26 | }
27 | }
28 |
29 | input,
30 | textarea {
31 |
32 |
33 |
34 | &:user-valid {
35 | background-color: var(--input-valid-background-color);
36 | border-color: var(--input-valid-border-color);
37 | color: var(--input-valid-color);
38 | }
39 |
40 | &:user-invalid {
41 | background-color: var(--input-invalid-background-color);
42 | border-color: var(--input-invalid-border-color);
43 | color: var(--input-invalid-color);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/css/content/_images.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Figure
3 | *
4 | */
5 | figure {
6 |
7 | }
8 |
9 | figcaption {
10 | font-size: calc((16 / 18) * 1rem);
11 | margin-block-start: calc((2 / 18) * 1rem);
12 | }
13 |
--------------------------------------------------------------------------------
/src/css/content/_lists.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Description list
3 | *
4 | */
5 | dt {
6 | font-weight: var(--bold-font-weight);
7 | }
8 |
9 | dd {
10 | margin-inline-start: 1rem;
11 |
12 |
13 | & + dt {
14 | margin-block-start: 1rem;
15 | }
16 | }
17 |
18 | /**
19 | * Unordered list
20 | *
21 | */
22 | ul {
23 | margin-inline-start: 1rem;
24 |
25 |
26 | & ul {
27 | margin-inline-start: 1rem;
28 | }
29 | }
30 |
31 | /**
32 | * Ordered list
33 | *
34 | */
35 | ol {
36 | margin-inline-start: 1rem;
37 |
38 |
39 | & ol {
40 | margin-inline-start: 1rem;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/css/content/_quotes.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Inline quotation
3 | *
4 | */
5 | q {
6 |
7 |
8 |
9 | &::before {
10 | content: open-quote;
11 | }
12 |
13 | &::after {
14 | content: close-quote;
15 | }
16 | }
17 |
18 | /**
19 | * Block quotation
20 | *
21 | */
22 | blockquote {
23 |
24 |
25 |
26 | & p {
27 | font-size: var(--blockquote-font-size);
28 | font-style: italic;
29 | line-height: var(--blockquote-line-height);
30 | text-indent: -0.5rem;
31 |
32 | @supports (hanging-punctuation: first) {
33 | text-indent: 0;
34 | hanging-punctuation: first;
35 | }
36 |
37 |
38 | &::before {
39 | content: open-quote;
40 | }
41 |
42 | &::after {
43 | content: close-quote;
44 | }
45 | }
46 |
47 | & footer {
48 | margin-block-start: 1rlh;
49 | }
50 | }
51 |
52 | cite {
53 | font-style: italic;
54 | }
55 |
--------------------------------------------------------------------------------
/src/css/content/_table.css:
--------------------------------------------------------------------------------
1 | table {
2 | border-collapse: separate;
3 | border-spacing: 0;
4 | inline-size: 100%;
5 | }
6 |
7 | thead {
8 |
9 |
10 |
11 | & tr {
12 | background-color: var(--table-thead-tr-background-color);
13 | color: var(--table-thead-tr-color);
14 | }
15 |
16 | & th {
17 | border-block-end: calc((1 / 18) * 1rem) solid var(--table-thead-th-border-color);
18 | }
19 | }
20 |
21 | th {
22 | font-weight: var(--bold-font-weight);
23 | padding: calc((8 / 18) * 1rem);
24 | text-align: start;
25 | }
26 |
27 | tbody {
28 |
29 |
30 |
31 | & tr {
32 | background-color: var(--table-tbody-tr-background-color);
33 | color: var(--table-tbody-tr-color);
34 | }
35 |
36 | & th {
37 | border-block-end: calc((1 / 18) * 1rem) solid var(--table-tbody-th-border-color);
38 | }
39 |
40 | & td {
41 | border-block-end: calc((1 / 18) * 1rem) solid var(--table-tbody-td-border-color);
42 | }
43 | }
44 |
45 | td {
46 | padding: calc((8 / 18) * 1rem);
47 | text-align: start;
48 | }
49 |
50 | caption {
51 | caption-side: bottom;
52 | font-size: calc((16 / 18) * 1rem);
53 | margin-block-start: calc((8 / 18) * 1rem);
54 | text-align: start;
55 | }
56 |
--------------------------------------------------------------------------------
/src/css/content/_typography.css:
--------------------------------------------------------------------------------
1 | html {
2 | font-family: var(--base-font-family);
3 | font-size: var(--base-font-size);
4 | font-weight: var(--base-font-weight);
5 | line-height: var(--base-line-height);
6 | }
7 |
8 | h1,
9 | .h1,
10 | h2,
11 | .h2,
12 | h3,
13 | .h3,
14 | h4,
15 | .h4 {
16 | font-family: var(--headings-font-family);
17 | font-weight: var(--headings-font-weight);
18 | }
19 |
20 | h1,
21 | .h1 {
22 | font-size: var(--h1-font-size);
23 | line-height: var(--h1-line-height);
24 | }
25 |
26 | h2,
27 | .h2 {
28 | font-size: var(--h2-font-size);
29 | line-height: var(--h2-line-height);
30 | }
31 |
32 | h3,
33 | .h3 {
34 | font-size: var(--h3-font-size);
35 | line-height: var(--h3-line-height);
36 | }
37 |
38 | h4,
39 | .h4 {
40 | font-size: var(--h4-font-size);
41 | line-height: var(--h4-line-height);
42 | }
43 |
44 | a {
45 | color: var(--link-color);
46 | text-decoration-line: var(--link-decoration-line);
47 | text-decoration-skip-ink: auto;
48 |
49 |
50 | &:hover,
51 | &:focus-visible {
52 | color: var(--link-hover-color);
53 | text-decoration: var(--link-hover-decoration-line);
54 | }
55 | }
56 |
57 | b,
58 | strong {
59 | font-weight: var(--bold-font-weight);
60 | }
61 |
62 | i,
63 | em {
64 | font-style: italic;
65 | }
66 |
67 | small {
68 | font-size: var(--small-font-size);
69 | line-height: var(--small-line-height);
70 | }
71 |
72 | del,
73 | s {
74 | text-decoration-color: currentcolor;
75 | text-decoration-line: line-through;
76 | }
77 |
78 | ins {
79 | text-decoration: none;
80 | }
81 |
82 | sub,
83 | sup {
84 | font-size: var(--small-font-size);
85 | position: relative;
86 | user-select: none;
87 | vertical-align: unset;
88 | }
89 |
90 | sub {
91 | inset-block-end: calc((4 / 18) * -1rem);
92 | }
93 |
94 | sup {
95 | inset-block-start: calc((4 / 18) * -1rem);
96 | }
97 |
98 | mark {
99 | background-color: var(--focus-background-color);
100 | box-decoration-break: clone;
101 | color: var(--focus-color);
102 | padding-inline: calc((2 / 18) * 1rem);
103 | }
104 |
--------------------------------------------------------------------------------
/src/css/content/forms/_form-check.css:
--------------------------------------------------------------------------------
1 | .form-group--check {
2 | align-items: baseline;
3 | display: grid;
4 | gap: calc((8 / 18) * 1rem);
5 | grid-template-columns: calc((24 / 18) * 1rem) auto;
6 | justify-items: start;
7 | }
8 |
9 | /**
10 | * Input type checkbox
11 | *
12 | */
13 | input[type='checkbox'] {
14 | appearance: none;
15 | background-color: var(--check-background-color);
16 | block-size: calc((24 / 18) * 1rem);
17 | border-radius: 0;
18 | border: calc((1 / 18) * 1rem) solid var(--check-border-color);
19 | color: var(--check-color);
20 | display: grid;
21 | inline-size: calc((24 / 18) * 1rem);
22 | place-content: center;
23 | transform: translateY(calc((1 / 18) * 1rem));
24 |
25 | &::before {
26 | background-color: CanvasText;
27 | block-size: calc((16 / 18) * 1rem);
28 | box-shadow: inset 1em 1em var(--check-color);
29 | content: '';
30 | inline-size: calc((16 / 18) * 1rem);
31 | mask-image: url('./../../../icons/check.svg');
32 | mask-mode: auto;
33 | mask-position: center;
34 | mask-repeat: no-repeat;
35 | mask-size: contain;
36 | opacity: 0;
37 | }
38 |
39 | &:indeterminate::before,
40 | &[aria-checked='mixed']::before {
41 | mask-image: url('./../../../icons/minus.svg');
42 | }
43 |
44 | &:checked::before {
45 | opacity: 1;
46 | }
47 |
48 | &[disabled],
49 | &[aria-disabled='true'] {
50 | opacity: 0.4;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/css/content/forms/_form-input.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Input/ Textarea
3 | *
4 | */
5 | input:not([type='checkbox'], [type='radio'], [type='submit'], [type='reset'], [type='range']),
6 | textarea {
7 | background-color: var(--input-background-color);
8 | border-radius: 0;
9 | border: calc((1 / 18) * 1rem) solid var(--input-border-color);
10 | color: var(--input-color);
11 | inline-size: 100%;
12 | padding-block: calc((4 / 18) * 1rem);
13 | padding-inline: calc((8 / 18) * 1rem);
14 | }
15 |
16 | /**
17 | * File input
18 | *
19 | */
20 | ::file-selector-button {
21 | appearance: none;
22 | background-color: var(--button-file-input-background-color);
23 | border-radius: 0;
24 | border: calc((1 / 18) * 1rem) solid var(--button-file-input-border-color);
25 | color: var(--button-file-input-color);
26 | display: inline-flex;
27 | padding-block: calc((0 / 18) * 1rem);
28 | padding-inline: calc((4 / 18) * 1rem);
29 | text-decoration: none;
30 | }
31 |
--------------------------------------------------------------------------------
/src/css/content/forms/_form-radio.css:
--------------------------------------------------------------------------------
1 | .form-group--radio {
2 | align-items: baseline;
3 | display: grid;
4 | gap: calc((8 / 18) * 1rem);
5 | grid-template-columns: calc((24 / 18) * 1rem) auto;
6 | justify-items: start;
7 | }
8 |
9 | /**
10 | * Input type radio
11 | *
12 | */
13 | input[type='radio'] {
14 | appearance: none;
15 | background-color: var(--radio-background-color);
16 | block-size: calc((24 / 18) * 1rem);
17 | border-radius: 50%;
18 | border: calc((1 / 18) * 1rem) solid var(--radio-border-color);
19 | color: var(--radio-color);
20 | display: grid;
21 | inline-size: calc((24 / 18) * 1rem);
22 | place-content: center;
23 | transform: translateY(calc((-2 / 18) * 1rem));
24 |
25 | &::before {
26 | background-color: CanvasText;
27 | block-size: calc((8 / 18) * 1rem);
28 | border-radius: 50%;
29 | box-shadow: inset 1em 1em var(--radio-color);
30 | content: '';
31 | inline-size: calc((8 / 18) * 1rem);
32 | opacity: 0;
33 | }
34 |
35 | &:checked::before {
36 | opacity: 1;
37 | }
38 |
39 | &[disabled],
40 | &[aria-disabled='true'] {
41 | opacity: 0.4;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/css/content/forms/_form-select.css:
--------------------------------------------------------------------------------
1 | select {
2 | appearance: none;
3 | background-color: var(--select-background-color);
4 | background-image: url('./../../../icons/chevron-down.svg');
5 | background-position: calc(100% - ((8 / 18) * 1rem)) center;
6 | background-repeat: no-repeat;
7 | border-radius: 0;
8 | border: calc((1 / 18) * 1rem) solid var(--select-border-color);
9 | color: var(--select-color);
10 | inline-size: 100%;
11 | padding-block: calc((4 / 18) * 1rem);
12 | padding-inline: calc((8 / 18) * 1rem);
13 | }
14 |
--------------------------------------------------------------------------------
/src/css/content/forms/_form-textarea.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Textarea
3 | *
4 | */
5 | textarea {
6 | background-color: var(--input-background-color);
7 | border-radius: 0;
8 | border: calc((1 / 18) * 1rem) solid var(--input-border-color);
9 | color: var(--input-color);
10 | inline-size: 100%;
11 | padding-block: calc((4 / 18) * 1rem);
12 | padding-inline: calc((8 / 18) * 1rem);
13 | resize: block;
14 |
15 | &:not([rows]) {
16 | min-block-size: calc((200 / 18) * 1rem);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/css/layout/_container.css:
--------------------------------------------------------------------------------
1 | .container {
2 | inline-size: min(100% - var(--container-padding-inline) * 2, var(--container-max-width));
3 | margin-inline: auto;
4 |
5 |
6 | /* No padding for .container in .container */
7 | &:not(.container--full) & {
8 | inline-size: min(100%, (--container-max-width));
9 | }
10 | }
11 |
12 | .container--full {
13 | inline-size: 100%;
14 | }
15 |
16 | .container--small {
17 | inline-size: min(100% - var(--container-padding-inline) * 2, var(--container-small-max-width));
18 | }
19 |
--------------------------------------------------------------------------------
/src/css/layout/_document.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Skip to content link
3 | *
4 | */
5 | .skip-link {
6 |
7 |
8 | &:focus {
9 | inset-block-start: calc((24 / 18) * 1rem);
10 | inset-inline-start: calc((24 / 18) * 1rem);
11 | position: absolute;
12 | z-index: 1337;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/css/layout/_grid.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Prepare Gibki (grid system) integration: https://github.com/deoostfrees/Gibki
3 | * Waiting for CSS Functions & Mixins: https://github.com/w3c/csswg-drafts/issues/9350
4 | *
5 | */
6 | .flex {
7 | align-items: stretch;
8 | column-gap: var(--grid-gutter-horizontal);
9 | display: flex;
10 | flex-direction: row;
11 | flex-wrap: wrap;
12 | justify-content: flex-start;
13 | row-gap: var(--grid-gutter-vertical);
14 | }
15 |
16 | /**
17 | * Gutters
18 | *
19 | */
20 | .flex--no-gutters {
21 | --grid-gutter-horizontal: 0rem;
22 | --grid-gutter-vertical: 0rem;
23 | }
24 |
25 | .flex--no-horizontal-gutters {
26 | --grid-gutter-horizontal: 0rem;
27 | }
28 |
29 | .flex--no-vertical-gutters {
30 | --grid-gutter-vertical: 0rem;
31 | }
32 |
33 | /**
34 | * Directions
35 | *
36 | */
37 | .flex--row {
38 | flex-direction: row;
39 | }
40 |
41 | .flex--row-reverse {
42 | flex-direction: row-reverse;
43 | }
44 |
45 | .flex--column {
46 | flex-direction: column;
47 | }
48 |
49 | .flex--column-reverse {
50 | flex-direction: column-reverse;
51 | }
52 |
53 | /**
54 | * Wrapping
55 | *
56 | */
57 | .flex--wrap {
58 | flex-wrap: wrap;
59 | }
60 |
61 | .flex--wrap-reverse {
62 | flex-wrap: wrap-reverse;
63 | }
64 |
65 | .flex--nowrap {
66 | flex-wrap: nowrap;
67 | }
68 |
69 | /**
70 | * Horizontal alignment
71 | *
72 | */
73 | .flex--left {
74 | justify-content: flex-start;
75 | }
76 |
77 | .flex--center {
78 | justify-content: center;
79 | }
80 |
81 | .flex--right {
82 | justify-content: flex-end;
83 | }
84 |
85 | .flex--space-between {
86 | justify-content: space-between;
87 | }
88 |
89 | .flex--space-around {
90 | justify-content: space-around;
91 | }
92 |
93 | /**
94 | * Vertical alignment
95 | *
96 | */
97 | .flex--stretch {
98 | align-items: stretch;
99 |
100 | .flex > & {
101 | align-self: stretch;
102 | }
103 | }
104 |
105 | .flex--top {
106 | align-items: flex-start;
107 |
108 | .flex > & {
109 | align-self: flex-start;
110 | }
111 | }
112 |
113 | .flex--bottom {
114 | align-items: flex-end;
115 |
116 | .flex > & {
117 | align-self: flex-end;
118 | }
119 | }
120 |
121 | .flex--middle {
122 | align-items: center;
123 |
124 | .flex > & {
125 | align-self: center;
126 | }
127 | }
128 |
129 | .flex--baseline {
130 | align-items: baseline;
131 |
132 | .flex > & {
133 | align-self: baseline;
134 | }
135 | }
136 |
137 | /* flex__* */
138 | [class*='flex__'] {
139 | inline-size: 100%;
140 | }
141 |
142 | .flex__auto {
143 | flex: 1;
144 | }
145 |
146 | /**
147 | * TODO:
148 | * Add the rest of Gibki when CSS Functions & Mixins are available (https://github.com/w3c/csswg-drafts/issues/9350)
149 | *
150 | */
151 |
--------------------------------------------------------------------------------
/src/css/ratata.css:
--------------------------------------------------------------------------------
1 | @layer reset, vendor, config, content, layout, components, utilities, print;
2 |
3 | @import url('./_print.css') layer(print) print;
4 | @import url('./_reset.css') layer(reset);
5 | @import url('./_utilities.css') layer(utilities);
6 | @import url('./_icons.css') layer(config);
7 | @import url('./_variables.css') layer(config);
8 |
9 | /**
10 | * Theme
11 | *
12 | */
13 | @import url('./themes/_default.css') layer(config);
14 |
15 | /**
16 | * Layout
17 | *
18 | */
19 | @import url('./layout/_document.css') layer(layout);
20 | @import url('./layout/_container.css') layer(layout);
21 | @import url('./layout/_grid.css') layer(layout);
22 |
23 | /**
24 | * Content
25 | *
26 | */
27 | @import url('./content/_base.css') layer(content);
28 | @import url('./content/_typography.css') layer(content);
29 | @import url('./content/_buttons.css') layer(content);
30 | @import url('./content/_code.css') layer(content);
31 | @import url('./content/_quotes.css') layer(content);
32 | @import url('./content/_lists.css') layer(content);
33 | @import url('./content/_table.css') layer(content);
34 | @import url('./content/_forms.css') layer(content);
35 | @import url('./content/_images.css') layer(content);
36 |
37 | /**
38 | * Components
39 | *
40 | */
41 | @import url('./components/_accordion.css') layer(components);
42 | @import url('./components/_alert.css') layer(components);
43 | @import url('./components/_breadcrumb.css') layer(components);
44 | @import url('./components/_card.css') layer(components);
45 | @import url('./components/_textmedia.css') layer(components);
46 | @import url('./components/_theme-switcher.css') layer(components);
47 |
--------------------------------------------------------------------------------
/src/css/themes/_default.css:
--------------------------------------------------------------------------------
1 | @import url('./default/_colors.css');
2 | @import url('./default/_light-dark.css');
3 |
--------------------------------------------------------------------------------
/src/css/themes/default/_colors.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --black: #000000;
3 | --blue: #0000FF;
4 | --green: #008000;
5 | --orange: #FFA500;
6 | --red: #FF0000;
7 | --white: #FFFFFF;
8 | --yellow: #FFFF00;
9 |
10 | /**
11 | * Brand colors
12 | *
13 | */
14 | --primary-color: #0000FF;
15 |
16 | /**
17 | * Neutral colors
18 | *
19 | */
20 | --color-neutral-900: #292827; /* base color */
21 | --color-neutral-800: #545352;
22 | --color-neutral-700: #696968;
23 | --color-neutral-600: #7F7E7D;
24 | --color-neutral-500: #949493;
25 | --color-neutral-400: #A9A9A9;
26 | --color-neutral-300: #BFBFBE;
27 | --color-neutral-200: #D4D4D4;
28 | --color-neutral-100: #EAEAE9;
29 |
30 | /**
31 | * Blue colors
32 | *
33 | */
34 | --color-blue-900: color-mix(in srgb, var(--color-blue-500), black 90%);
35 | --color-blue-800: color-mix(in srgb, var(--color-blue-500), black 80%);
36 | --color-blue-700: color-mix(in srgb, var(--color-blue-500), black 70%);
37 | --color-blue-600: color-mix(in srgb, var(--color-blue-500), black 60%);
38 | --color-blue-500: var(--blue); /* base color */
39 | --color-blue-400: color-mix(in srgb, var(--color-blue-500), white 60%);
40 | --color-blue-300: color-mix(in srgb, var(--color-blue-500), white 70%);
41 | --color-blue-200: color-mix(in srgb, var(--color-blue-500), white 80%);
42 | --color-blue-100: color-mix(in srgb, var(--color-blue-500), white 90%);
43 |
44 | /**
45 | * Green colors
46 | *
47 | */
48 | --color-green-900: color-mix(in srgb, var(--color-green-500), black 90%);
49 | --color-green-800: color-mix(in srgb, var(--color-green-500), black 80%);
50 | --color-green-700: color-mix(in srgb, var(--color-green-500), black 70%);
51 | --color-green-600: color-mix(in srgb, var(--color-green-500), black 60%);
52 | --color-green-500: var(--green); /* base color */
53 | --color-green-400: color-mix(in srgb, var(--color-green-500), white 60%);
54 | --color-green-300: color-mix(in srgb, var(--color-green-500), white 70%);
55 | --color-green-200: color-mix(in srgb, var(--color-green-500), white 80%);
56 | --color-green-100: color-mix(in srgb, var(--color-green-500), white 90%);
57 |
58 | /**
59 | * Orange colors
60 | *
61 | */
62 | --color-orange-900: color-mix(in srgb, var(--color-orange-500), black 90%);
63 | --color-orange-800: color-mix(in srgb, var(--color-orange-500), black 80%);
64 | --color-orange-700: color-mix(in srgb, var(--color-orange-500), black 70%);
65 | --color-orange-600: color-mix(in srgb, var(--color-orange-500), black 60%);
66 | --color-orange-500: var(--orange); /* base color */
67 | --color-orange-400: color-mix(in srgb, var(--color-orange-500), white 60%);
68 | --color-orange-300: color-mix(in srgb, var(--color-orange-500), white 70%);
69 | --color-orange-200: color-mix(in srgb, var(--color-orange-500), white 80%);
70 | --color-orange-100: color-mix(in srgb, var(--color-orange-500), white 90%);
71 |
72 | /**
73 | * Red colors
74 | *
75 | */
76 | --color-red-900: color-mix(in srgb, var(--color-red-500), black 90%);
77 | --color-red-800: color-mix(in srgb, var(--color-red-500), black 80%);
78 | --color-red-700: color-mix(in srgb, var(--color-red-500), black 70%);
79 | --color-red-600: color-mix(in srgb, var(--color-red-500), black 60%);
80 | --color-red-500: var(--red); /* base color */
81 | --color-red-400: color-mix(in srgb, var(--color-red-500), white 60%);
82 | --color-red-300: color-mix(in srgb, var(--color-red-500), white 70%);
83 | --color-red-200: color-mix(in srgb, var(--color-red-500), white 80%);
84 | --color-red-100: color-mix(in srgb, var(--color-red-500), white 90%);
85 | }
86 |
--------------------------------------------------------------------------------
/src/css/themes/default/_light-dark.css:
--------------------------------------------------------------------------------
1 | html {
2 | color-scheme: light dark;
3 | }
4 |
5 | [data-color-scheme='light'] {
6 | color-scheme: light;
7 | }
8 |
9 | [data-color-scheme='dark'] {
10 | color-scheme: dark;
11 | }
12 |
13 | :root {
14 | /**
15 | * Body
16 | *
17 | */
18 | --body-background-color: light-dark(var(--white), var(--color-neutral-900));
19 | --body-color: light-dark(var(--color-neutral-900), var(--color-neutral-100));
20 |
21 | /**
22 | * Focus
23 | *
24 | */
25 | --focus-background-color: var(--yellow);
26 | --focus-color: var(--color-neutral-900);
27 |
28 | /**
29 | * Links
30 | *
31 | */
32 | --link-color: light-dark(var(--primary-color), var(--color-neutral-100));
33 | --link-decoration-line: underline;
34 | --link-hover-color: light-dark(var(--primary-color), var(--color-neutral-100));
35 | --link-hover-decoration-line: none;
36 |
37 | /**
38 | * hr
39 | *
40 | */
41 | --hr-border-color: var(--color-neutral-500);
42 |
43 | /**
44 | * Table
45 | *
46 | */
47 | --table-thead-tr-background-color: light-dark(var(--white), var(--color-neutral-900));
48 | --table-thead-tr-color: light-dark(var(--color-neutral-900), var(--color-neutral-100));
49 | --table-thead-th-border-color: light-dark(var(--color-neutral-500), var(--color-neutral-100));
50 |
51 | /* tbody */
52 | --table-tbody-tr-background-color: light-dark(var(--white), var(--color-neutral-900));
53 | --table-tbody-tr-color: light-dark(var(--color-neutral-900), var(--color-neutral-100));
54 | --table-tbody-th-border-color: light-dark(var(--color-neutral-100), var(--color-neutral-800));
55 | --table-tbody-td-border-color: light-dark(var(--color-neutral-100), var(--color-neutral-800));
56 |
57 | /**
58 | * Code
59 | *
60 | */
61 | --code-background-color: light-dark(var(--color-neutral-100), var(--color-neutral-800));
62 | --code-color: light-dark(var(--color-neutral-900), var(--color-neutral-100));
63 |
64 | /**
65 | * Buttons
66 | *
67 | */
68 | --button-background-color: transparent;
69 | --button-color: light-dark(var(--color-neutral-900), var(--color-neutral-100));
70 | --button-border-color: transparent;
71 | --button-hover-background-color: transparent;
72 | --button-hover-border-color: transparent;
73 | --button-hover-color: light-dark(var(--color-neutral-900), var(--color-neutral-100));
74 |
75 | /* Primary */
76 | --button-primary-background-color: light-dark(var(--primary-color), var(--color-neutral-100));
77 | --button-primary-border-color: light-dark(var(--primary-color), var(--color-neutral-100));
78 | --button-primary-color: light-dark(var(--white), var(--color-neutral-900));
79 | --button-primary-hover-background-color: light-dark(color-mix(in srgb, var(--primary-color) 80%, black), color-mix(in srgb, var(--color-neutral-100) 80%, black));
80 | --button-primary-hover-border-color: light-dark(color-mix(in srgb, var(--primary-color) 80%, black), color-mix(in srgb, var(--color-neutral-100) 80%, black));
81 | --button-primary-hover-color: light-dark(var(--white), var(--color-neutral-900));
82 |
83 | /* Secondary */
84 | --button-secondary-background-color: transparent;
85 | --button-secondary-border-color: light-dark(var(--primary-color), var(--color-neutral-100));
86 | --button-secondary-color: light-dark(var(--primary-color), var(--color-neutral-100));
87 | --button-secondary-hover-background-color: light-dark(var(--primary-color), var(--color-neutral-100));
88 | --button-secondary-hover-border-color: light-dark(var(--primary-color), var(--color-neutral-100));
89 | --button-secondary-hover-color: light-dark(var(--white), var(--color-neutral-900));
90 |
91 | /**
92 | * Forms
93 | *
94 | */
95 |
96 | /* Input */
97 | --input-background-color: light-dark(var(--white), var(--color-neutral-100));
98 | --input-border-color: var(--color-neutral-500);
99 | --input-color: var(--color-neutral-900);
100 | --input-valid-background-color: var(--input-background-color);
101 | --input-valid-border-color: var(--input-border-color);
102 | --input-valid-color: var(--input-color);
103 | --input-invalid-background-color: var(--color-red-100);
104 | --input-invalid-border-color: var(--color-red-200);
105 | --input-invalid-color: var(--color-red-600);
106 |
107 | /* Checkbox */
108 | --check-background-color: light-dark(var(--white), var(--color-neutral-100));
109 | --check-border-color: var(--color-neutral-500);
110 | --check-color: light-dark(var(--primary-color), var(--color-neutral-900));
111 |
112 | /* Radio */
113 | --radio-background-color: light-dark(var(--white), var(--color-neutral-100));
114 | --radio-border-color: var(--color-neutral-500);
115 | --radio-color: light-dark(var(--primary-color), var(--color-neutral-900));
116 |
117 | /* Select */
118 | --select-background-color: light-dark(var(--white), var(--color-neutral-100));
119 | --select-border-color: var(--color-neutral-500);
120 | --select-color: var(--color-neutral-900);
121 |
122 | /* File input */
123 | --button-file-input-background-color: light-dark(var(--primary-color), var(--color-neutral-900));
124 | --button-file-input-border-color: light-dark(var(--primary-color), var(--color-neutral-900));
125 | --button-file-input-color: light-dark(var(--white), var(--color-neutral-100));
126 |
127 | /**
128 | * Accordion
129 | *
130 | */
131 | --accordion-button-background-color: transparent;
132 | --accordion-button-color: light-dark(var(--color-neutral-900), var(--color-neutral-100));
133 | --accordion-button-border-color: var(--color-neutral-500);
134 | --accordion-content-background-color: transparent;
135 | --accordion-content-color: light-dark(var(--color-neutral-900), var(--color-neutral-100));
136 |
137 | /**
138 | * Alert
139 | *
140 | */
141 |
142 | /* Info */
143 | --alert-info-background-color: var(--color-blue-100);
144 | --alert-info-border-color: var(--color-blue-200);
145 | --alert-info-color: var(--color-blue-600);
146 |
147 | /* Success */
148 | --alert-success-background-color: var(--color-green-100);
149 | --alert-success-border-color: var(--color-green-200);
150 | --alert-success-color: var(--color-green-600);
151 |
152 | /* Warning */
153 | --alert-warning-background-color: var(--color-orange-100);
154 | --alert-warning-border-color: var(--color-orange-200);
155 | --alert-warning-color: var(--color-orange-600);
156 |
157 | /* Danger */
158 | --alert-danger-background-color: var(--color-red-100);
159 | --alert-danger-border-color: var(--color-red-200);
160 | --alert-danger-color: var(--color-red-600);
161 |
162 | /**
163 | * Theme switcher
164 | *
165 | */
166 | --theme-switcher-background-color: light-dark(var(--primary-color), var(--color-neutral-100));
167 | --theme-switcher-border-color: transparent;
168 | --theme-switcher-color: light-dark(var(--white), var(--color-neutral-900));
169 | --theme-switcher-active-background-color: light-dark(var(--white), var(--color-neutral-900));
170 | --theme-switcher-active-color: light-dark(var(--primary-color), var(--color-neutral-100));
171 |
172 | /**
173 | * Card
174 | *
175 | */
176 | --card-background-color: transparent;
177 | --card-border-color: light-dark(var(--color-neutral-500), var(--color-neutral-800));
178 | --card-color: var(--color-neutral-900);
179 | --card-image-background-color: light-dark(var(--primary-color), var(--color-neutral-800));
180 | --card-image-color: light-dark(var(--white), var(--color-neutral-100));
181 | --card-body-background-color: light-dark(var(--white), var(--color-neutral-100));
182 | --card-body-color: var(--color-neutral-900);
183 | --card-link-color: light-dark(var(--primary-color), var(--color-neutral-900));
184 | --card-link-decoration-line: underline;
185 | --card-link-hover-color: light-dark(var(--primary-color), var(--color-neutral-900));
186 | --card-link-hover-decoration-line: none;
187 | }
188 |
--------------------------------------------------------------------------------
/src/icons/check.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/icons/chevron-down.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/icons/error.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/icons/minus.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/js/helpers/set-color-scheme.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Load this file in the to avoid FART (Flash of inAccurate coloR Theme)
3 | *
4 | */
5 | if (localStorage.getItem('color-scheme')) {
6 | document.documentElement.setAttribute('data-color-scheme', localStorage.getItem('color-scheme'))
7 | }
8 |
--------------------------------------------------------------------------------
/src/js/libs/_accordion.js:
--------------------------------------------------------------------------------
1 | export default function accordion () {
2 | const BROWSER_WINDOW = window
3 |
4 | const closeAllAccordions = () => {
5 | const OPEN_ACCORDION_ELS = document.querySelectorAll('details[open]')
6 |
7 | OPEN_ACCORDION_ELS.forEach((openAccordionEl) => {
8 | openAccordionEl.removeAttribute('open')
9 | })
10 | }
11 |
12 | const openAllAccordions = () => {
13 | const OPEN_ACCORDION_ELS = document.querySelectorAll('details')
14 |
15 | OPEN_ACCORDION_ELS.forEach((openAccordionEl) => {
16 | openAccordionEl.setAttribute('open', '')
17 | })
18 | }
19 |
20 | /**
21 | * Expand all accordions for printing, restore previously opened accordions
22 | * after printing
23 | *
24 | */
25 | let openAccordionEls
26 |
27 | BROWSER_WINDOW.addEventListener('beforeprint', () => {
28 | openAccordionEls = document.querySelectorAll('details[open]')
29 |
30 | openAllAccordions()
31 | })
32 |
33 | BROWSER_WINDOW.addEventListener('afterprint', () => {
34 | closeAllAccordions()
35 |
36 | openAccordionEls.forEach((openAccordionEl) => {
37 | openAccordionEl.setAttribute('open', '')
38 | })
39 | })
40 | }
41 |
--------------------------------------------------------------------------------
/src/js/libs/_toggle-color-scheme.js:
--------------------------------------------------------------------------------
1 | export default function toggleColorScheme () {
2 | const DOCUMENT_EL = document.documentElement
3 | const BROWSER_WINDOW = window
4 | const COLOR_SCHEME_TOGGLE = document.querySelectorAll('.btn--color-scheme-switch')
5 |
6 | let currentColorScheme = 'system'
7 |
8 | /**
9 | * Set active button
10 | *
11 | */
12 | const setActiveButton = (colorScheme) => {
13 | COLOR_SCHEME_TOGGLE.forEach((colorSchemeToggle) => {
14 | if (colorSchemeToggle.getAttribute('data-color-scheme') === colorScheme) {
15 | colorSchemeToggle.setAttribute('aria-pressed', 'true')
16 | } else {
17 | colorSchemeToggle.setAttribute('aria-pressed', 'false')
18 | }
19 | })
20 | }
21 |
22 | /**
23 | * Set color-scheme
24 | *
25 | * @param {string} colorScheme - Color-scheme
26 | */
27 | const setColorScheme = (colorScheme) => {
28 | DOCUMENT_EL.setAttribute('data-color-scheme', colorScheme)
29 |
30 | localStorage.setItem('color-scheme', colorScheme)
31 | }
32 |
33 | COLOR_SCHEME_TOGGLE.forEach((colorSchemeToggle) => {
34 | colorSchemeToggle.addEventListener('click', () => {
35 | if (colorSchemeToggle.getAttribute('aria-pressed') !== 'true') {
36 | currentColorScheme = colorSchemeToggle.getAttribute('data-color-scheme')
37 |
38 | setColorScheme(currentColorScheme)
39 | setActiveButton(currentColorScheme)
40 | }
41 | })
42 | })
43 |
44 | /**
45 | * Check prefers color scheme
46 | *
47 | */
48 | const COLOR_QUERY = BROWSER_WINDOW.matchMedia('(prefers-color-scheme: dark)')
49 |
50 | const prefersColorCheck = () => {
51 | if (localStorage.getItem('color-scheme')) {
52 | currentColorScheme = localStorage.getItem('color-scheme')
53 |
54 | setColorScheme(currentColorScheme)
55 | } else {
56 | currentColorScheme = 'system'
57 | }
58 |
59 | setActiveButton(currentColorScheme)
60 | }
61 |
62 | prefersColorCheck()
63 |
64 | // Check for any OS level changes to the preference
65 | COLOR_QUERY.addEventListener('change', prefersColorCheck)
66 |
67 | /**
68 | * Check for any storage changes
69 | * It fires on a page every time another page from the same domain has modified a value
70 | *
71 | */
72 | BROWSER_WINDOW.addEventListener('storage', (event) => {
73 | if (event.key === 'color-scheme') {
74 | setColorScheme(event.newValue, true)
75 | }
76 | })
77 | }
78 |
--------------------------------------------------------------------------------
/src/js/ratata.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Toggle color scheme
3 | *
4 | */
5 | if (document.querySelector('.btn--color-scheme-switch') !== null) {
6 | import('./libs/_toggle-color-scheme.js')
7 | .then(({ default: toggleColorScheme }) => {
8 | toggleColorScheme()
9 | })
10 | }
11 |
12 | /**
13 | * Accordion
14 | *
15 | */
16 | if (document.querySelector('.accordion') !== null) {
17 | import('./libs/_accordion.js')
18 | .then(({ default: accordion }) => {
19 | accordion()
20 | })
21 | }
22 |
--------------------------------------------------------------------------------