summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.stylelintrc.json2
-rw-r--r--package.json8
-rw-r--r--src/_general.scss82
-rw-r--r--src/_vars.scss85
-rw-r--r--src/index.scss47
-rw-r--r--src/layouts/_card.scss38
-rw-r--r--src/layouts/_container.scss91
-rw-r--r--src/mixins/_grid.scss88
-rw-r--r--src/mixins/_typography.scss63
-rw-r--r--src/objects/_heading.scss68
-rw-r--r--src/objects/_rule.scss120
-rw-r--r--static/script.js26
-rw-r--r--tpl/index.pug281
-rw-r--r--tpl/layouts/container.pug14
-rw-r--r--tpl/objects/heading.pug34
-rw-r--r--tpl/objects/rule.pug12
16 files changed, 724 insertions, 335 deletions
diff --git a/.stylelintrc.json b/.stylelintrc.json
index 63040f7..864ce42 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -58,7 +58,7 @@
58 }, 58 },
59 "overrides": [ 59 "overrides": [
60 { 60 {
61 "files": ["src/style/**/*.scss"], 61 "files": ["src/**/*.scss"],
62 "customSyntax": "postcss-scss" 62 "customSyntax": "postcss-scss"
63 } 63 }
64 ] 64 ]
diff --git a/package.json b/package.json
index 2ee3eb8..2d6bba6 100644
--- a/package.json
+++ b/package.json
@@ -10,10 +10,10 @@
10 "scripts": { 10 "scripts": {
11 "build": "npm run build:app && npm run build:style && npm run build:assets", 11 "build": "npm run build:app && npm run build:style && npm run build:assets",
12 "build:assets": "cp -r static/* public/", 12 "build:assets": "cp -r static/* public/",
13 "build:app": "pug tpl -p tpl --out public/", 13 "build:app": "pug tpl/index.pug -p tpl --out public/",
14 "build:style": "sass --load-path=node_modules src/index.scss >> public/style.css", 14 "build:style": "sass --load-path=node_modules src/index.scss public/style.css",
15 "lint:style": "stylelint \"src/style/**/*.scss\"", 15 "lint:style": "stylelint \"src/**/*.scss\"",
16 "fix:style": "stylelint \"src/style/**/*.scss\" --fix" 16 "fix:style": "stylelint \"src/**/*.scss\" --fix"
17 }, 17 },
18 "dependencies": { 18 "dependencies": {
19 "include-media": "^1.4.9", 19 "include-media": "^1.4.9",
diff --git a/src/_general.scss b/src/_general.scss
new file mode 100644
index 0000000..82b9467
--- /dev/null
+++ b/src/_general.scss
@@ -0,0 +1,82 @@
1@use 'iro-sass/src/index' as iro;
2@use 'mixins/typography';
3@use 'vars';
4
5html,
6body {
7 height: 100%;
8}
9
10body {
11 @include typography.set-font(vars.$font--main, (size: iro.props-get(--dims --font-size --md)));
12
13 margin: 0;
14 padding: 0;
15 background-color: iro.props-get(--colors --bg);
16 color: iro.props-get(--colors --fg);
17}
18
19h1,
20h2,
21h3,
22h4,
23h5,
24h6 {
25 @include typography.set-font(vars.$font--main, (size: iro.props-get(--dims --font-size --md), weight: 400));
26
27 margin: 0;
28}
29
30p {
31 margin-top: iro.props-get(--dims --paragraph --margin-top);
32 margin-bottom: 0;
33
34 &:empty {
35 display: none;
36 }
37}
38
39ul,
40ol {
41 margin: iro.props-get(--dims --paragraph --margin-top) 0 0;
42 padding-left: iro.props-get(--dims --list --indent);
43}
44
45:focus {
46 outline: 0;
47}
48
49:link,
50:visited {
51 color: currentColor;
52 text-decoration: none;
53}
54
55button {
56 box-sizing: content-box;
57 margin: 0;
58 padding: 0;
59 border: 0;
60 background-color: transparent;
61 color: currentColor;
62 font: inherit;
63 letter-spacing: inherit;
64 text-align: left;
65 text-transform: inherit;
66 appearance: none;
67
68 &::-moz-focus-inner {
69 border: 0;
70 }
71}
72
73::selection {
74 background: iro.props-get(--colors --selection --bg);
75 color: iro.props-get(--colors --selection --fg);
76}
77
78img {
79 &::selection {
80 background: iro.props-get(--colors --selection --bg-img);
81 }
82}
diff --git a/src/_vars.scss b/src/_vars.scss
index 5a6c1d0..d2bdf38 100644
--- a/src/_vars.scss
+++ b/src/_vars.scss
@@ -1,13 +1,14 @@
1@use 'iro-sass/src/index' as iro; 1@use 'iro-sass/src/index' as iro;
2@use 'include-media/dist/include-media' as media;
2 3
3iro.$vars-root-size: 16px; 4iro.$vars-root-size: 16px;
4 5
5$breakpoints: ( 6media.$breakpoints: (
6 md: 40rem, 7 md: 40rem,
7 sm: 28rem 8 sm: 28rem
8); 9);
9 10
10$unit-intervals: ( 11media.$unit-intervals: (
11 'px': 1, 12 'px': 1,
12 'em': .01, 13 'em': .01,
13 'rem': .01, 14 'rem': .01,
@@ -22,45 +23,15 @@ $font--main: (
22); 23);
23 24
24$font--headline: ( 25$font--headline: (
25 family: ('IBM Plex Sans', 'Open Sans', 'Segoe UI', 'Droid Sans', Roboto, Oxygen, 'Helvetica Neue', Helvetica, Tahoma, Arial, sans-serif), 26 family: ('IBM Plex Sans', 'Open Sans', 'Segoe UI', 'Droid Sans', Roboto, Oxygen, 'Helvetica Neue', Helvetica, Tahoma, Arial, sans-serif),
26 line-height: 1.2, 27 line-height: 1.2,
27 weight: 700, 28 weight: 700,
28); 29);
29 30
30$line-height: map-get($font--main, line-height); 31$line-height: map-get($font--main, line-height);
31 32
32// 33//
33 34
34$theme-light: (
35 --gray1: hsl(210, 0%, 100%), // 1.11
36 --gray2: hsl(210, 0%, 98%), // 1.07
37 --gray3: hsl(210, 0%, 95%), // 1
38 --gray4: hsl(210, 0%, 90%), // 1.11
39 --gray5: hsl(210, 0%, 87%), // 1.2
40 --gray6: hsl(210, 0%, 78%), // 1.51
41 --gray7: hsl(210, 0%, 69%), // 1.93
42 --gray8: hsl(210, 0%, 55%), // 3
43 --gray9: hsl(210, 0%, 38%), // 5.53
44 --gray10: hsl(210, 0%, 19%), // 11.78
45 --gray11: hsl(210, 0%, 0%), // 18.75
46);
47
48$theme-lighter: (
49 --gray1: hsl(210, 0%, 100%), // 1
50 --gray2: hsl(210, 0%, 100%), // 1
51 --gray3: hsl(210, 0%, 100%), // 1
52 --gray4: hsl(210, 0%, 95%), // 1.11
53 --gray5: hsl(210, 0%, 92%), // 1.19
54 --gray6: hsl(210, 0%, 82%), // 1.52
55 --gray7: hsl(210, 0%, 73%), // 1.94
56 --gray8: hsl(210, 0%, 58%), // 3.03
57 --gray9: hsl(210, 0%, 41%), // 5.48
58 --gray10: hsl(210, 0%, 22%), // 11.72
59 --gray11: hsl(210, 0%, 0%), // 21
60);
61
62//
63
64@include iro.fn-execute { 35@include iro.fn-execute {
65 $primary-accent-base: hsl(222, 49.8%, 52.4%); 36 $primary-accent-base: hsl(222, 49.8%, 52.4%);
66 $error-accent-base: hsl(352, 49.8%, 52.4%); 37 $error-accent-base: hsl(352, 49.8%, 52.4%);
@@ -119,6 +90,18 @@ $theme-lighter: (
119 ), 90 ),
120 91
121 --colors: ( 92 --colors: (
93 --gray1: hsl(210, 0%, 100%), // 1.11
94 --gray2: hsl(210, 0%, 98%), // 1.07
95 --gray3: hsl(210, 0%, 95%), // 1
96 --gray4: hsl(210, 0%, 90%), // 1.11
97 --gray5: hsl(210, 0%, 87%), // 1.2
98 --gray6: hsl(210, 0%, 78%), // 1.51
99 --gray7: hsl(210, 0%, 69%), // 1.93
100 --gray8: hsl(210, 0%, 55%), // 3
101 --gray9: hsl(210, 0%, 38%), // 5.53
102 --gray10: hsl(210, 0%, 19%), // 11.78
103 --gray11: hsl(210, 0%, 0%), // 18.75
104
122 --bg-hi2: iro.props-get(--colors --gray1, null), // Lightest background 105 --bg-hi2: iro.props-get(--colors --gray1, null), // Lightest background
123 --bg-hi: iro.props-get(--colors --gray2, null), // Lighter background 106 --bg-hi: iro.props-get(--colors --gray2, null), // Lighter background
124 --bg: iro.props-get(--colors --gray3, null), // Background 107 --bg: iro.props-get(--colors --gray3, null), // Background
@@ -183,18 +166,44 @@ $theme-lighter: (
183 ), 166 ),
184 ), 167 ),
185 )); 168 ));
169
170 @include iro.props-store((
171 --colors: (
172 --gray1: hsl(210, 0%, 100%), // 1
173 --gray2: hsl(210, 0%, 100%), // 1
174 --gray3: hsl(210, 0%, 100%), // 1
175 --gray4: hsl(210, 0%, 95%), // 1.11
176 --gray5: hsl(210, 0%, 92%), // 1.19
177 --gray6: hsl(210, 0%, 82%), // 1.52
178 --gray7: hsl(210, 0%, 73%), // 1.94
179 --gray8: hsl(210, 0%, 58%), // 3.03
180 --gray9: hsl(210, 0%, 41%), // 5.48
181 --gray10: hsl(210, 0%, 22%), // 11.72
182 --gray11: hsl(210, 0%, 0%), // 21
183 )
184 ), 'light-raised');
186} 185}
187 186
188// 187//
189 188
190@include iro.fn-execute { 189@include iro.fn-execute {
191 @include iro.props-store((), 'dark'); 190 @include iro.fn-execute {
191 @include iro.props-store((
192 --colors: ()
193 ), 'dark');
194 }
195
196 @include iro.fn-execute {
197 @include iro.props-store((
198 --colors: ()
199 ), 'dark-raised');
200 }
192} 201}
193 202
194// 203//
195 204
196@each $breakpoint in map-keys($breakpoints) { 205@each $breakpoint in map-keys(media.$breakpoints) {
197 @include media('<=#{$breakpoint}') { 206 @include media.media('<=#{$breakpoint}') {
198 @include iro.props-store(( 207 @include iro.props-store((
199 --colors: () 208 --colors: ()
200 ), $breakpoint); 209 ), $breakpoint);
diff --git a/src/index.scss b/src/index.scss
index dc71caa..292785d 100644
--- a/src/index.scss
+++ b/src/index.scss
@@ -1,19 +1,48 @@
1@use 'iro-sass/src/props'; 1@use 'iro-sass/src/index' as iro;
2 2@use 'include-media/dist/include-media' as media;
3@import 'include-media/dist/include-media';
4 3
5@import 'vars'; 4@import 'vars';
5@import 'general';
6
7@import 'layouts/container';
8
9@import 'objects/heading';
10@import 'objects/rule';
6 11
7:root { 12:root {
8 @include props.assign; 13 @include iro.props-assign;
9 14
10 @each $breakpoint in map-keys($breakpoints) { 15 @each $breakpoint in map-keys(media.$breakpoints) {
11 @include media('<=#{$breakpoint}') { 16 @include media.media('<=#{$breakpoint}') {
12 @include props.assign($breakpoint); 17 @include iro.props-assign($breakpoint);
13 } 18 }
14 } 19 }
20}
21
22@include iro.bem-theme('grayscale') {
23 @include iro.props-assign($root: --colors --grayscale-accent, $prefix: --colors --accent);
24}
25
26@include iro.bem-theme('raised') {
27 @include iro.props-assign('light-raised');
15 28
16 @media (prefers-color-scheme: dark) { 29 @include iro.bem-multi('at-theme' 'grayscale', 'theme' 'grayscale') {
17 @include props.assign('dark'); 30 @include iro.props-assign($root: --colors --grayscale-accent, $prefix: --colors --accent);
18 } 31 }
19} 32}
33
34/*@media (prefers-color-scheme: dark) {
35 @include iro.props-assign('dark');
36
37 @include iro.bem-theme('grayscale') {
38 @include iro.props-assign('dark', $root: --colors --grayscale-accent, $prefix: --colors --accent);
39 }
40
41 @include iro.bem-theme('raised') {
42 @include iro.props-assign('dark-raised');
43
44 @include iro.bem-multi('at-theme' 'grayscale', 'theme' 'grayscale') {
45 @include iro.props-assign('dark', $root: --colors --grayscale-accent, $prefix: --colors --accent);
46 }
47 }
48}*/
diff --git a/src/layouts/_card.scss b/src/layouts/_card.scss
new file mode 100644
index 0000000..f6b6b03
--- /dev/null
+++ b/src/layouts/_card.scss
@@ -0,0 +1,38 @@
1@include namespace('card') {
2 @include store((
3 --dims: (
4 --pad-x: iro-px-to-rem(11px),
5 --pad-y: iro-px-to-rem(8px),
6 --lg: (
7 --pad-x: iro-px-to-rem(14px),
8 --pad-y: iro-px-to-rem(11px),
9 )
10 )
11 ));
12
13 @include layout(namespace()) {
14 display: flex;
15 align-items: center;
16 padding: prop(--dims --pad-y) prop(--dims --pad-x);
17 gap: prop(--dims --pad-x);
18 line-height: 1.4;
19
20 @include modifier('lg') {
21 padding: prop(--dims --lg --pad-y) prop(--dims --lg --pad-x);
22 gap: prop(--dims --lg --pad-x);
23 }
24
25 @include modifier('flush') {
26 padding: 0;
27 }
28
29 @include element('block') {
30 flex: 0 0 auto;
31
32 @include modifier('main') {
33 flex-shrink: 1;
34 width: 100%;
35 }
36 }
37 }
38}
diff --git a/src/layouts/_container.scss b/src/layouts/_container.scss
new file mode 100644
index 0000000..efe5203
--- /dev/null
+++ b/src/layouts/_container.scss
@@ -0,0 +1,91 @@
1@use 'iro-sass/src/index' as iro;
2@use 'include-media/dist/include-media' as media;
3
4@include iro.props-namespace('container') {
5 @include iro.props-store((
6 --dims: (
7 --content-width: iro.fn-px-to-rem(700px),
8 --sm-content-width: iro.fn-px-to-rem(360px),
9 --padding-x: 3rem,
10 --padding-y: 3rem,
11 --in-page-spacing-y: iro.props-get(--dims --spacing --y --xl, $global: true),
12 )
13 ));
14
15 @include iro.bem-layout(iro.props-namespace()) {
16 overflow: hidden;
17
18 @include iro.bem-elem('inner') {
19 margin-top: calc(-1 * iro.props-get(--dims --spacing --y --xl, $global: true));
20 margin-bottom: calc(-1 * iro.props-get(--dims --spacing --y --xl, $global: true));
21
22 &::before,
23 &::after {
24 content: '';
25 display: block;
26 width: 0;
27 height: 0;
28 }
29
30 &::before {
31 margin-bottom: iro.props-get(--dims --spacing --y --xl, $global: true);
32 }
33
34 &::after {
35 margin-top: iro.props-get(--dims --spacing --y --xl, $global: true);
36 }
37 }
38
39 @include iro.bem-modifier('pad-x') {
40 padding-right: iro.props-get(--dims --padding-x);
41 padding-left: iro.props-get(--dims --padding-x);
42 }
43
44 @include iro.bem-modifier('pad-y') {
45 padding-top: iro.props-get(--dims --padding-y);
46 padding-bottom: iro.props-get(--dims --padding-y);
47 }
48
49 @include iro.bem-modifier('narrow') {
50 max-width: iro.props-get(--dims --content-width);
51 margin-right: auto;
52 margin-left: auto;
53
54 @each $breakpoint in map-keys(media.$breakpoints) {
55 @include media.media('<=#{$breakpoint}') {
56 @include iro.bem-suffix('#{$breakpoint}-down') {
57 max-width: iro.props-get(--dims --content-width);
58 margin-right: auto;
59 margin-left: auto;
60 }
61 }
62 }
63 }
64
65 @include iro.bem-modifier('sm-narrow') {
66 max-width: iro.props-get(--dims --sm-content-width);
67 margin-right: auto;
68 margin-left: auto;
69
70 @each $breakpoint in map-keys(media.$breakpoints) {
71 @include media.media('<=#{$breakpoint}') {
72 @include iro.bem-suffix('#{$breakpoint}-down') {
73 max-width: iro.props-get(--dims --sm-content-width);
74 margin-right: auto;
75 margin-left: auto;
76 }
77 }
78 }
79 }
80
81 @include iro.bem-modifier('themed') {
82 background-color: iro.props-get(--colors --bg, $global: true);
83 color: iro.props-get(--colors --fg, $global: true);
84 }
85
86 @include iro.bem-modifier('in-page') {
87 margin-top: iro.props-get(--dims --in-page-spacing-y);
88 margin-bottom: iro.props-get(--dims --in-page-spacing-y);
89 }
90 }
91}
diff --git a/src/mixins/_grid.scss b/src/mixins/_grid.scss
new file mode 100644
index 0000000..e0a73d9
--- /dev/null
+++ b/src/mixins/_grid.scss
@@ -0,0 +1,88 @@
1$context-id: 'grid' !default;
2
3@include iro-context-stack-create($grid-context-id);
4
5@mixin native-grid {
6 @supports (display: grid) {
7 @content;
8 }
9}
10
11@mixin grid($columns: 12, $h-spacing: 0, $v-spacing: 0, $reverse: false) {
12 display: flex;
13 flex-flow: row wrap;
14 align-items: stretch;
15 justify-content: flex-start;
16 margin: (-.5 * $v-spacing) (-.5 * $h-spacing);
17
18 @if $reverse {
19 flex-direction: row-reverse;
20 }
21
22 @include iro-context-push($grid-context-id, 'grid', (
23 --h-spacing: $h-spacing,
24 --v-spacing: $v-spacing,
25 --columns: $columns,
26 --reverse: $reverse
27 ));
28
29 @content;
30
31 @include iro-context-pop($grid-context-id);
32}
33
34@mixin grid-col {
35 @include iro-context-assert-stack-must-contain($grid-context-id, 'grid');
36
37 $data: nth(iro-context-get($grid-context-id, 'grid'), 2);
38 $v-spacing: map-get($data, --v-spacing);
39 $h-spacing: map-get($data, --h-spacing);
40
41 box-sizing: border-box;
42 flex: 0 0 auto;
43 margin: .5 * $v-spacing .5 * $h-spacing;
44
45 @include iro-context-push($grid-context-id, 'grid__col');
46
47 @content;
48
49 @include iro-context-pop($grid-context-id);
50}
51
52@mixin grid-col-span($i) {
53 @include iro-context-assert-stack-must-contain($grid-context-id, 'grid');
54
55 $data: nth(iro-context-get($grid-context-id, 'grid'), 2);
56 $columns: map-get($data, --columns);
57 $h-spacing: map-get($data, --h-spacing);
58
59 @if $h-spacing != 0 {
60 width: calc((100% - #{$columns * $h-spacing}) * #{floor($i / $columns * 10000 - 1) / 10000} + #{($i - 1) * $h-spacing});
61 // ^^^^^^^^^^ Bugfix for Firefox ^^^^^^^^^^
62 } @else {
63 width: calc(100% * #{floor($i / $columns * 10000 - 1) / 10000});
64 }
65}
66
67@mixin grid-col-shift($i) {
68 @include iro-context-assert-stack-must-contain($grid-context-id, 'grid');
69
70 $data: nth(iro-context-get($grid-context-id, 'grid'), 2);
71 $columns: map-get($data, --columns);
72 $h-spacing: map-get($data, --h-spacing);
73 $reverse: map-get($data, --reverse);
74
75 $prop: if($reverse, margin-right, margin-left);
76
77 @if $i == 0 {
78 #{$prop}: 0;
79 } @else {
80 @if $h-spacing != 0 {
81 #{$prop}: calc((100% - #{$columns * $h-spacing}) * #{floor($i / $columns * 10000 - 1) / 10000} + #{$i * $h-spacing + $h-spacing / 2});
82 // ^^^^^^^^^^ Bugfix for Firefox ^^^^^^^^^^
83 } @else {
84 #{$prop}: calc(100% * #{floor($i / $columns * 10000 - 1) / 10000});
85 // ^^^^^^^^^^ Bugfix for Firefox ^^^^^^^^^^
86 }
87 }
88}
diff --git a/src/mixins/_typography.scss b/src/mixins/_typography.scss
new file mode 100644
index 0000000..31e39f0
--- /dev/null
+++ b/src/mixins/_typography.scss
@@ -0,0 +1,63 @@
1@function set-font($basis, $values: ()) {
2 $font: map-merge($basis, $values);
3
4 $map: (font-family: map-get($font, 'family'));
5
6 @if (map-has-key($font, 'size')) {
7 $map: map-merge(
8 $map, (
9 font-size: map-get($font, 'size')
10 )
11 );
12 }
13
14 @if (map-has-key($font, 'weight')) {
15 $map: map-merge(
16 $map, (
17 font-weight: map-get($font, 'weight')
18 )
19 );
20 }
21
22 @if (map-has-key($font, 'style')) {
23 $map: map-merge(
24 $map, (
25 font-style: map-get($font, 'style')
26 )
27 );
28 }
29
30 @if (map-has-key($font, 'line-height')) {
31 $map: map-merge(
32 $map, (
33 line-height: map-get($font, 'line-height')
34 )
35 );
36 }
37
38 @if (map-has-key($font, 'transform')) {
39 $map: map-merge(
40 $map, (
41 text-transform: map-get($font, 'transform')
42 )
43 );
44 }
45
46 @if (map-has-key($font, 'variant-alternates')) {
47 $map: map-merge(
48 $map, (
49 font-variant-alternates: map-get($font, 'variant-alternates')
50 )
51 );
52 }
53
54 @return $map;
55}
56
57@mixin set-font($basis, $values: ()) {
58 $values: set-font($basis, $values);
59
60 @each $prop, $value in $values {
61 #{$prop}: $value;
62 }
63}
diff --git a/src/objects/_heading.scss b/src/objects/_heading.scss
new file mode 100644
index 0000000..a0ce052
--- /dev/null
+++ b/src/objects/_heading.scss
@@ -0,0 +1,68 @@
1@use 'iro-sass/src/index' as iro;
2@use '../vars';
3@use '../mixins/typography';
4
5@include iro.props-namespace('heading') {
6 @include iro.props-store((
7 --dims: (
8 --in-page-margin: (
9 --top: iro.props-get(--dims --spacing --y --lg, $global: true),
10 --top-sibling: iro.props-get(--dims --spacing --y --md, $global: true),
11 --bottom: iro.props-get(--dims --spacing --y --sm, $global: true),
12 ),
13 ),
14 --colors: (
15 --light: iro.props-get(--colors --fg-hi, $global: true),
16 --strong: iro.props-get(--colors --fg-lo, $global: true),
17 ),
18 ));
19
20 @include iro.bem-object(iro.props-namespace()) {
21 @include typography.set-font(vars.$font--headline);
22
23 display: block;
24 margin-top: iro.props-get(--dims --in-page-margin --top);
25 margin-bottom: 0;
26
27 & + & {
28 margin-top: iro.props-get(--dims --in-page-margin --top-sibling);
29 }
30
31 @include iro.bem-modifier('xxl') {
32 color: iro.props-get(--colors --strong);
33 font-size: iro.props-get(--dims --font-size --xxxl, $global: true);
34 }
35
36 @include iro.bem-modifier('xl') {
37 color: iro.props-get(--colors --strong);
38 font-size: iro.props-get(--dims --font-size --xxl, $global: true);
39 }
40
41 @include iro.bem-modifier('lg') {
42 color: iro.props-get(--colors --strong);
43 font-size: iro.props-get(--dims --font-size --xl, $global: true);
44 }
45
46 @include iro.bem-modifier('md') {
47 color: iro.props-get(--colors --strong);
48 font-size: iro.props-get(--dims --font-size --lg, $global: true);
49 }
50
51 @include iro.bem-modifier('sm') {
52 @include typography.set-font($font--main, (line-height: map-get(vars.$font--headline, line-height)));
53
54 color: iro.props-get(--colors --strong);
55 font-size: iro.props-get(--dims --font-size --md, $global: true);
56 font-weight: 500;
57 }
58
59 @include iro.bem-modifier('xs') {
60 @include typography.set-font($font--main, (line-height: map-get(vars.$font--headline, line-height)));
61
62 color: iro.props-get(--colors --light);
63 font-size: iro.props-get(--dims --font-size --xs, $global: true);
64 font-weight: 500;
65 text-transform: uppercase;
66 }
67 }
68}
diff --git a/src/objects/_rule.scss b/src/objects/_rule.scss
new file mode 100644
index 0000000..74987da
--- /dev/null
+++ b/src/objects/_rule.scss
@@ -0,0 +1,120 @@
1@use 'iro-sass/src/index' as iro;
2@use '../vars';
3@use '../mixins/typography';
4
5@include iro.props-namespace('rule') {
6 @include iro.props-store((
7 --dims: (
8 --margin-y: iro.props-get(--dims --spacing --y --xs, $global: true),
9
10 --strong: (
11 --border-width: iro.props-get(--dims --border-width --thick, $global: true),
12 --label-font-size: iro.props-get(--dims --font-size --md, $global: true),
13 ),
14 --medium: (
15 --border-width: iro.props-get(--dims --border-width --medium, $global: true),
16 --label-font-size: iro.props-get(--dims --font-size --sm, $global: true),
17 ),
18 --faint: (
19 --border-width: iro.props-get(--dims --border-width --thin, $global: true),
20 --label-font-size: iro.props-get(--dims --font-size --xs, $global: true),
21 ),
22 ),
23 --colors: (
24 --strong: (
25 --bg: iro.props-get(--colors --fg, $global: true),
26 --label: iro.props-get(--colors --fg, $global: true),
27 ),
28 --medium: (
29 --bg: iro.props-get(--colors --obj, $global: true),
30 --label: iro.props-get(--colors --fg-hi, $global: true),
31 ),
32 --faint: (
33 --bg: iro.props-get(--colors --obj, $global: true),
34 --label: iro.props-get(--colors --fg-hi2, $global: true),
35 ),
36 ),
37 ));
38
39 @include iro.bem-object(iro.props-namespace()) {
40 display: block;
41 height: iro.props-get(--dims --strong --border-width);
42 margin-top: iro.props-get(--dims --margin-y);
43 margin-bottom: iro.props-get(--dims --margin-y);
44 background-color: iro.props-get(--colors --strong --bg);
45
46 @include iro.bem-modifier('medium') {
47 height: iro.props-get(--dims --medium --border-width);
48 background-color: iro.props-get(--colors --medium --bg);
49 }
50
51 @include iro.bem-modifier('faint') {
52 height: iro.props-get(--dims --faint --border-width);
53 background-color: iro.props-get(--colors --faint --bg);
54 }
55
56 @include iro.bem-modifier('labelled') {
57 display: flex;
58 flex-direction: row;
59 align-items: center;
60 height: auto;
61 border-radius: 0;
62 background-color: transparent;
63
64 &::before,
65 &::after {
66 content: '';
67 display: block;
68 flex: 1 1 auto;
69 width: 100%;
70 height: 3px;
71 background-color: iro.props-get(--colors --strong --bg);
72 }
73
74 &::before {
75 margin-right: 1em;
76 }
77
78 &::after {
79 margin-left: 1em;
80 }
81
82 @include iro.bem-elem('label') {
83 flex: 0 0 auto;
84 color: iro.props-get(--colors --strong --label);
85 font-size: iro.props-get(--dims --strong --label-font-size);
86 font-weight: 700;
87 letter-spacing: .5px;
88 text-transform: uppercase;
89 }
90
91 @include iro.bem-modifier('medium') {
92 &::before,
93 &::after {
94 height: 2px;
95 background-color: iro.props-get(--colors --medium --bg);
96 }
97
98 @include iro.bem-elem('label') {
99 color: iro.props-get(--colors --medium --label);
100 font-size: iro.props-get(--dims --medium --label-font-size);
101 font-weight: 500;
102 }
103 }
104
105 @include iro.bem-modifier('faint') {
106 &::before,
107 &::after {
108 height: 1px;
109 background-color: iro.props-get(--colors --faint --bg);
110 }
111
112 @include iro.bem-elem('label') {
113 color: iro.props-get(--colors --faint --label);
114 font-size: iro.props-get(--dims --faint --label-font-size);
115 font-weight: 500;
116 }
117 }
118 }
119 }
120}
diff --git a/static/script.js b/static/script.js
new file mode 100644
index 0000000..ece93e8
--- /dev/null
+++ b/static/script.js
@@ -0,0 +1,26 @@
1'use strict';
2
3//
4
5document.querySelectorAll('.is-indeterminate').forEach(el => el.indeterminate = true);
6
7//
8
9const enableFocusIndicator = e => {
10 if (e.key !== 'Tab') {
11 return;
12 }
13
14 document.body.classList.add('t-keyboard');
15 document.removeEventListener('keydown', enableFocusIndicator);
16 document.addEventListener('mousedown', disableFocusIndicator);
17}
18
19const disableFocusIndicator = e => {
20 document.body.classList.remove('t-keyboard');
21
22 document.removeEventListener('mousedown', disableFocusIndicator);
23 document.addEventListener('keydown', enableFocusIndicator);
24}
25
26document.addEventListener('keydown', enableFocusIndicator);
diff --git a/tpl/index.pug b/tpl/index.pug
index 2fb865d..c63e9f1 100644
--- a/tpl/index.pug
+++ b/tpl/index.pug
@@ -4,19 +4,11 @@
4include layouts/container.pug 4include layouts/container.pug
5include objects/heading.pug 5include objects/heading.pug
6include objects/rule.pug 6include objects/rule.pug
7include objects/button.pug
8include objects/icon.pug
9include objects/text-input.pug
10include objects/field-label.pug
11include objects/radio.pug
12include objects/checkbox.pug
13include objects/switch.pug
14include objects/form.pug
15include objects/action-button.pug
16 7
17mixin box 8mixin box
18 +container(padH=true padV=true theme='box' inPage=true) 9 .t-raised
19 block 10 +container(padH=true padV=true inPage=true themed=true)
11 block
20 12
21 13
22doctype html 14doctype html
@@ -25,6 +17,8 @@ html
25 meta(charset='utf-8') 17 meta(charset='utf-8')
26 meta(name='viewport' content='width=device-width, initial-scale=1') 18 meta(name='viewport' content='width=device-width, initial-scale=1')
27 title iro-design 19 title iro-design
20 link(rel="stylesheet", href="style.css")
21 script(src="script.js")
28 22
29 body(class='t-lighter') 23 body(class='t-lighter')
30 +container(padH=true padV=true narrow=true) 24 +container(padH=true padV=true narrow=true)
@@ -64,268 +58,3 @@ html
64 +rule(level='strong')= 'Strong' 58 +rule(level='strong')= 'Strong'
65 +rule(level='medium')= 'Medium' 59 +rule(level='medium')= 'Medium'
66 +rule(level='faint')= 'Faint' 60 +rule(level='faint')= 'Faint'
67
68 //-----------------------------------------
69
70 +h1-heading(level='xl')= 'Button'
71 +rule(level='medium')
72
73 +box
74 +a-button(variant='primary')= 'Button'
75 = ' '
76 +a-button(variant='primary' disabled=true)= 'Button'
77 br
78 br
79 +a-button(variant='secondary')= 'Button'
80 = ' '
81 +a-button(variant='secondary' disabled=true)= 'Button'
82
83 +box
84 +a-button(variant='primary' quiet=true)= 'Button'
85 = ' '
86 +a-button(variant='primary' quiet=true disabled=true)= 'Button'
87 br
88 br
89 +a-button(variant='secondary' quiet=true)= 'Button'
90 = ' '
91 +a-button(variant='secondary' quiet=true disabled=true)= 'Button'
92
93 //-----------------------------------------
94
95 +h1-heading(level='xl')= 'Text input'
96 +rule(level='medium')
97
98 +box
99 +text-input(placeholder='Placeholder')
100 br
101 br
102 +text-input(value='Just landed in L.A.')
103 br
104 br
105 +text-input(value='Readonly' readonly=true)
106 br
107 br
108 +text-input(value='Incorrect input' pattern='a+' required=true)
109 br
110 br
111 +text-input(placeholder='Placeholder' disabled=true)
112 br
113 br
114 +text-input(value='Just landed in L.A.' disabled=true)
115 br
116 br
117 +text-input(value='Readonly' readonly=true disabled=true)
118 br
119 br
120 +text-input(value='Incorrect input' pattern='a+' required=true disabled=true)
121
122 //-----------------------------------------
123
124 +h1-heading(level='xl')= 'Field label'
125 +rule(level='medium')
126
127 +box
128 +field-label('First name')
129 +text-input(placeholder='Placeholder')
130 br
131 br
132 +field-label('Password', 'At least 6 characters required')
133 +text-input(placeholder='Placeholder' type='password')
134 br
135 br
136 +field-label('Password', 'At least 6 characters required')(invalid=true)
137 +text-input(placeholder='Placeholder' type='password' invalid=true)
138 br
139 br
140 +field-label('First name')(disabled=true)
141 +text-input(placeholder='Placeholder' disabled=true)
142 br
143 br
144 +field-label('Password', 'At least 6 characters required')(disabled=true)
145 +text-input(placeholder='Placeholder' type='password' disabled=true)
146 br
147 br
148 +field-label('Password', 'At least 6 characters required')(invalid=true disabled=true)
149 +text-input(placeholder='Placeholder' type='password' invalid=true disabled=true)
150
151 +box
152 +field-label('First name')(align='left' labelWidth='100px')
153 +text-input(placeholder='Placeholder')
154 br
155 br
156 +field-label('Password', 'At least 6 characters required')(align='left' labelWidth='100px')
157 +text-input(placeholder='Placeholder' type='password')
158 br
159 br
160 +field-label('Password', 'At least 6 characters required')(align='left' labelWidth='100px' invalid=true)
161 +text-input(placeholder='Placeholder' type='password' invalid=true)
162 br
163 br
164 +field-label('First name')(align='left' labelWidth='100px' disabled=true)
165 +text-input(placeholder='Placeholder' disabled=true)
166 br
167 br
168 +field-label('Password', 'At least 6 characters required')(align='left' labelWidth='100px' disabled=true)
169 +text-input(placeholder='Placeholder' type='password' disabled=true)
170 br
171 br
172 +field-label('Password', 'At least 6 characters required')(align='left' labelWidth='100px' invalid=true disabled=true)
173 +text-input(placeholder='Placeholder' type='password' invalid=true disabled=true)
174
175 +box
176 +field-label('First name')(align='right' labelWidth='100px')
177 +text-input(placeholder='Placeholder')
178 br
179 br
180 +field-label('Password', 'At least 6 characters required')(align='right' labelWidth='100px')
181 +text-input(placeholder='Placeholder' type='password')
182 br
183 br
184 +field-label('Password', 'At least 6 characters required')(align='right' labelWidth='100px' invalid=true)
185 +text-input(placeholder='Placeholder' type='password' invalid=true)
186 br
187 br
188 +field-label('First name')(align='right' labelWidth='100px' disabled=true)
189 +text-input(placeholder='Placeholder' disabled=true)
190 br
191 br
192 +field-label('Password', 'At least 6 characters required')(align='right' labelWidth='100px' disabled=true)
193 +text-input(placeholder='Placeholder' type='password' disabled=true)
194 br
195 br
196 +field-label('Password', 'At least 6 characters required')(align='right' labelWidth='100px' invalid=true disabled=true)
197 +text-input(placeholder='Placeholder' type='password' invalid=true disabled=true)
198
199 //-----------------------------------------
200
201 +h1-heading(level='xl')= 'Radio'
202 +rule(level='medium')
203
204 +box
205 +radio(name="radio-demo-1")= 'Cats'
206 +radio(name="radio-demo-1")= 'Dogs'
207 +radio(name="radio-demo-1" checked=true)= 'Foxes'
208 br
209 +radio(name="radio-demo-2" disabled=true)= 'Cats'
210 +radio(name="radio-demo-2" disabled=true)= 'Dogs'
211 +radio(name="radio-demo-2" checked=true disabled=true)= 'Foxes'
212
213 //-----------------------------------------
214
215 +h1-heading(level='xl')= 'Checkbox'
216 +rule(level='medium')
217
218 +box
219 +checkbox(indeterminate=true)= 'Cats'
220 +checkbox= 'Dogs'
221 +checkbox(checked=true)= 'Foxes'
222 br
223 +checkbox(indeterminate=true disabled=true)= 'Cats'
224 +checkbox(disabled=true)= 'Dogs'
225 +checkbox(checked=true disabled=true)= 'Foxes'
226
227 //-----------------------------------------
228
229 +h1-heading(level='xl')= 'Switch'
230 +rule(level='medium')
231
232 +box
233 +switch= 'Cats'
234 +switch= 'Dogs'
235 +switch(checked=true)= 'Foxes'
236 br
237 +switch(disabled=true)= 'Cats'
238 +switch(disabled=true)= 'Dogs'
239 +switch(checked=true disabled=true)= 'Foxes'
240
241 //-----------------------------------------
242
243 +h1-heading(level='xl')= 'Form'
244 +rule(level='medium')
245
246 +box
247 +form
248 +form-item('Username')
249 +text-input(placeholder='Example: Feuerfuchs')
250
251 +form-item('Password', 'At least 6 characters, all characters allowed')
252 +text-input(placeholder='Example: hunter2' type='password')
253
254 +form-item('Bio')
255 +text-input(placeholder='Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam...')
256
257 +form-item('Favorite animal')
258 +radio(name="form-demo-1" checked=true)= 'Foxes'
259 +radio(name="form-demo-1")= 'Other'
260
261 +form-item('Notification settings')
262 +switch= 'In-app notifications'
263 br
264 +switch= 'Desktop notifications'
265 br
266 +switch= 'Email notifications'
267
268 +form-item('')
269 +checkbox= 'I\'ve read and accept the terms and conditions'
270
271 +form-item('')
272 +a-button(variant='primary')= 'Register'
273
274 //-----------------------------------------
275
276 +h1-heading(level='xl')= 'Action button'
277 +rule(level='medium')
278
279 +box
280 +a-action-button= 'Idle'
281 = ' '
282 +a-action-button(selected=true)= 'Selected'
283 = ' '
284 +a-action-button(disabled=true)= 'Disabled'
285 = ' '
286 +a-action-button(selected=true disabled=true)= 'Selected + disabled'
287 br
288 br
289 +a-action-button(icon='trash')= 'Idle'
290 = ' '
291 +a-action-button(icon='trash' selected=true)= 'Selected'
292 = ' '
293 +a-action-button(icon='trash' disabled=true)= 'Disabled'
294 = ' '
295 +a-action-button(icon='trash' selected=true disabled=true)= 'Selected + disabled'
296 br
297 br
298 +a-action-button(icon='trash')
299 = ' '
300 +a-action-button(icon='trash' selected=true)
301 = ' '
302 +a-action-button(icon='trash' disabled=true)
303 = ' '
304 +a-action-button(icon='trash' selected=true disabled=true)
305
306 +box
307 +a-action-button(quiet=true )= 'Idle'
308 = ' '
309 +a-action-button(quiet=true selected=true)= 'Selected'
310 = ' '
311 +a-action-button(quiet=true disabled=true)= 'Disabled'
312 = ' '
313 +a-action-button(quiet=true selected=true disabled=true)= 'Selected + disabled'
314 br
315 br
316 +a-action-button(quiet=true icon='trash')= 'Idle'
317 = ' '
318 +a-action-button(quiet=true icon='trash' selected=true)= 'Selected'
319 = ' '
320 +a-action-button(quiet=true icon='trash' disabled=true)= 'Disabled'
321 = ' '
322 +a-action-button(quiet=true icon='trash' selected=true disabled=true)= 'Selected + disabled'
323 br
324 br
325 +a-action-button(quiet=true icon='trash')
326 = ' '
327 +a-action-button(quiet=true icon='trash' selected=true)
328 = ' '
329 +a-action-button(quiet=true icon='trash' disabled=true)
330 = ' '
331 +a-action-button(quiet=true icon='trash' selected=true disabled=true)
diff --git a/tpl/layouts/container.pug b/tpl/layouts/container.pug
index 75e3b36..9dde2d6 100644
--- a/tpl/layouts/container.pug
+++ b/tpl/layouts/container.pug
@@ -1,13 +1,13 @@
1mixin container 1mixin container
2 - 2 -
3 let classes = { 3 let classes = {
4 'l-container': true, 4 'l-container': true,
5 'l-container--padH': attributes.padH, 5 'l-container--pad-h': attributes.padH,
6 'l-container--padV': attributes.padV, 6 'l-container--pad-v': attributes.padV,
7 'l-container--narrow': attributes.narrow, 7 'l-container--narrow': attributes.narrow,
8 'l-container--smNarrow': attributes.smNarrow, 8 'l-container--sm-narrow': attributes.smNarrow,
9 'l-container--inPage': attributes.inPage, 9 'l-container--in-page': attributes.inPage,
10 'l-container--themed': !!attributes.theme 10 'l-container--themed': attributes.themed
11 } 11 }
12 if (!!attributes.theme) { 12 if (!!attributes.theme) {
13 classes['t-' + attributes.theme] = true 13 classes['t-' + attributes.theme] = true
diff --git a/tpl/objects/heading.pug b/tpl/objects/heading.pug
new file mode 100644
index 0000000..546df43
--- /dev/null
+++ b/tpl/objects/heading.pug
@@ -0,0 +1,34 @@
1mixin h1-heading
2 - let classes = ['o-heading', 'o-heading--' + attributes.level]
3 h1(class=classes)
4 block
5
6mixin h2-heading
7 - let classes = ['o-heading', 'o-heading--' + attributes.level]
8 h2(class=classes)
9 block
10
11mixin h3-heading
12 - let classes = ['o-heading', 'o-heading--' + attributes.level]
13 h3(class=classes)
14 block
15
16mixin h4-heading
17 - let classes = ['o-heading', 'o-heading--' + attributes.level]
18 h4(class=classes)
19 block
20
21mixin h5-heading
22 - let classes = ['o-heading', 'o-heading--' + attributes.level]
23 h5(class=classes)
24 block
25
26mixin h6-heading
27 - let classes = ['o-heading', 'o-heading--' + attributes.level]
28 h6(class=classes)
29 block
30
31mixin div-heading
32 - let classes = ['o-heading', 'o-heading--' + attributes.level]
33 div(class=classes)
34 block
diff --git a/tpl/objects/rule.pug b/tpl/objects/rule.pug
new file mode 100644
index 0000000..958ff18
--- /dev/null
+++ b/tpl/objects/rule.pug
@@ -0,0 +1,12 @@
1mixin rule
2 -
3 let classes = {
4 'o-rule': true,
5 'o-rule--labelled': !!block
6 }
7 classes['o-rule--' + attributes.level] = true
8
9 div(class=classes)
10 if block
11 .o-rule__label
12 block