From 9691ccf48f64dd0fac669ae51943907cc8da9b78 Mon Sep 17 00:00:00 2001 From: Volpeon Date: Sun, 6 Feb 2022 20:23:11 +0100 Subject: Added status indicator and avatar --- src/_functions.scss | 20 +++++++-- src/index.scss | 3 ++ src/layouts/_card.scss | 12 ++--- src/layouts/_container.scss | 12 ++--- src/objects/_action-button.scss | 8 ++-- src/objects/_avatar.scss | 89 +++++++++++++++++++++++++++++++++++++ src/objects/_button.scss | 8 ++-- src/objects/_checkbox.scss | 10 ++--- src/objects/_radio.scss | 10 ++--- src/objects/_status-indicator.scss | 33 ++++++++++++++ src/objects/_switch.scss | 10 ++--- src/objects/_text-field.scss | 8 ++-- static/avatar.png | Bin 0 -> 61956 bytes tpl/index.pug | 72 ++++++++++++++++++++++++++++++ tpl/objects/avatar.pug | 26 +++++++++++ tpl/objects/status-indicator.pug | 8 ++++ 16 files changed, 286 insertions(+), 43 deletions(-) create mode 100644 src/objects/_avatar.scss create mode 100644 src/objects/_status-indicator.scss create mode 100755 static/avatar.png create mode 100644 tpl/objects/avatar.pug create mode 100644 tpl/objects/status-indicator.pug diff --git a/src/_functions.scss b/src/_functions.scss index a649cc2..a11d5f4 100644 --- a/src/_functions.scss +++ b/src/_functions.scss @@ -1,19 +1,31 @@ @use 'iro-sass/src/index' as iro; @function color($key, $tree: 'colors', $default: null, $global: false) { - $new-key: iro.fn-list-prepend($key, --colors); - @return iro.props-get($new-key, $tree, $default, $global); + $key: iro.fn-list-prepend($key, --colors); + @return iro.props-get($key, $tree, $default, $global); } @function global-color($key, $tree: 'colors', $default: null, $global: true) { @return color($key, $tree, $default, $global); } +@function foreign-color($foreign-key, $key, $tree: 'colors', $default: null, $global: true) { + $key: iro.fn-list-prepend($key, --colors); + $key: iro.fn-list-prepend($key, $foreign-key); + @return iro.props-get($key, $tree, $default, $global); +} + @function dim($key, $tree: 'dims', $default: null, $global: false) { - $new-key: iro.fn-list-prepend($key, --dims); - @return iro.props-get($new-key, $tree, $default, $global); + $key: iro.fn-list-prepend($key, --dims); + @return iro.props-get($key, $tree, $default, $global); } @function global-dim($key, $tree: 'dims', $default: null, $global: true) { @return dim($key, $tree, $default, $global); } + +@function foreign-dim($foreign-key, $key, $tree: 'dims', $default: null, $global: true) { + $key: iro.fn-list-prepend($key, --dims); + $key: iro.fn-list-prepend($key, $foreign-key); + @return iro.props-get($key, $tree, $default, $global); +} diff --git a/src/index.scss b/src/index.scss index 63124ed..813764c 100644 --- a/src/index.scss +++ b/src/index.scss @@ -4,6 +4,7 @@ @import 'vars'; @import 'general'; +@import 'layouts/card'; @import 'layouts/container'; @import 'objects/icon'; @@ -16,6 +17,8 @@ @import 'objects/checkbox'; @import 'objects/switch'; @import 'objects/action-button'; +@import 'objects/status-indicator'; +@import 'objects/avatar'; @import 'layouts/form'; diff --git a/src/layouts/_card.scss b/src/layouts/_card.scss index 5db1a6a..a5b9028 100644 --- a/src/layouts/_card.scss +++ b/src/layouts/_card.scss @@ -5,11 +5,11 @@ @include iro.props-namespace('card') { @include iro.props-store(( --dims: ( - --pad-x: iro.fn-px-to-rem(11px), - --pad-y: iro.fn-px-to-rem(8px), + --pad-x: .6rem, + --pad-y: .4rem, --lg: ( - --pad-x: iro.fn-px-to-rem(14px), - --pad-y: iro.fn-px-to-rem(11px), + --pad-x: .9rem, + --pad-y: .7rem, ) ) ), 'dims'); @@ -34,8 +34,8 @@ flex: 0 0 auto; @include iro.bem-modifier('main') { - flex-shrink: 1; - width: 100%; + width: 100%; + min-width: 0; } } } diff --git a/src/layouts/_container.scss b/src/layouts/_container.scss index 40e8ab6..7f13a8b 100644 --- a/src/layouts/_container.scss +++ b/src/layouts/_container.scss @@ -7,8 +7,8 @@ --dims: ( --content-width: iro.fn-px-to-rem(700px), --sm-content-width: iro.fn-px-to-rem(360px), - --padding-x: 3rem, - --padding-y: 3rem, + --pad-x: 3rem, + --pad-y: 3rem, --in-page-spacing-y: fn.global-dim(--spacing --y --xl), ) ), 'dims'); @@ -38,13 +38,13 @@ } @include iro.bem-modifier('pad-x') { - padding-right: fn.dim(--padding-x); - padding-left: fn.dim(--padding-x); + padding-right: fn.dim(--pad-x); + padding-left: fn.dim(--pad-x); } @include iro.bem-modifier('pad-y') { - padding-top: fn.dim(--padding-y); - padding-bottom: fn.dim(--padding-y); + padding-top: fn.dim(--pad-y); + padding-bottom: fn.dim(--pad-y); } @include iro.bem-modifier('narrow') { diff --git a/src/objects/_action-button.scss b/src/objects/_action-button.scss index dd5cea7..86c7089 100644 --- a/src/objects/_action-button.scss +++ b/src/objects/_action-button.scss @@ -4,9 +4,9 @@ @include iro.props-namespace('action-button') { @include iro.props-store(( --dims: ( - --padding-x: .6rem, - --padding-y: .6rem, - --rounding: 3px, + --pad-x: .6rem, + --pad-y: .6rem, + --rounding: 3px, ), ), 'dims'); @@ -93,7 +93,7 @@ @include iro.bem-object(iro.props-namespace()) { display: inline-block; - padding: fn.dim(--padding-y) fn.dim(--padding-x); + padding: fn.dim(--pad-y) fn.dim(--pad-x); border: 1px solid fn.color(--border); border-radius: fn.dim(--rounding); background-color: fn.color(--bg); diff --git a/src/objects/_avatar.scss b/src/objects/_avatar.scss new file mode 100644 index 0000000..3bdfddc --- /dev/null +++ b/src/objects/_avatar.scss @@ -0,0 +1,89 @@ +@use 'iro-sass/src/index' as iro; +@use '../functions' as fn; + +@include iro.props-namespace('avatar') { + @include iro.props-store(( + --dims: ( + --size: iro.fn-px-to-rem(40px), + --size-sm: iro.fn-px-to-rem(30px), + --size-xs: iro.fn-px-to-rem(20px), + --indicator-size: fn.foreign-dim(--status-indicator, --size), + --indicator-spacing: iro.fn-px-to-rem(3px), + --rounding: 25%, + ), + ), 'dims'); + + @include iro.props-store(( + --colors: ( + --h: 354, + --s: 44%, + --l: 45%, + ), + ), 'colors'); + + @include iro.bem-object(iro.props-namespace()) { + display: inline-block; + position: relative; + font-size: 1rem; + font-style: normal; + + @include iro.bem-elem('status') { + position: absolute; + right: 0; + bottom: 0; + + @include iro.bem-next-elem('content') { + mask-image: radial-gradient( + circle calc(.5 * fn.dim(--indicator-size) + fn.dim(--indicator-spacing)) at + calc(100% - .5 * fn.dim(--indicator-size)) + calc(100% - .5 * fn.dim(--indicator-size)), + transparent 95%, + #fff + ); + } + } + + @include iro.bem-elem('content') { + display: block; + width: fn.dim(--size); + height: fn.dim(--size); + border-radius: fn.dim(--rounding); + background-color: hsl(fn.color(--h), fn.color(--s), fn.color(--l)); + color: #fff; + line-height: fn.dim(--size); + text-align: center; + } + + @include iro.bem-modifier('circle') { + @include iro.bem-elem('content') { + border-radius: 100%; + } + } + + @include iro.bem-modifier('placeholder') { + @include iro.bem-elem('content') { + background-color: hsl(0, 0%, fn.color(--l)); + } + } + + @include iro.bem-modifier('sm') { + font-size: iro.fn-px-to-rem(13px); + + @include iro.bem-elem('content') { + width: fn.dim(--size-sm); + height: fn.dim(--size-sm); + line-height: fn.dim(--size-sm); + } + } + + @include iro.bem-modifier('xs') { + font-size: iro.fn-px-to-rem(12px); + + @include iro.bem-elem('content') { + width: fn.dim(--size-xs); + height: fn.dim(--size-xs); + line-height: fn.dim(--size-xs); + } + } + } +} diff --git a/src/objects/_button.scss b/src/objects/_button.scss index 57c49e8..f158176 100644 --- a/src/objects/_button.scss +++ b/src/objects/_button.scss @@ -35,9 +35,9 @@ @include iro.props-namespace('button') { @include iro.props-store(( --dims: ( - --padding-x: 1.2rem, - --padding-y: .5rem, - --rounding: 10em, + --pad-x: 1.2rem, + --pad-y: .5rem, + --rounding: 10em, ), ), 'dims'); @@ -114,7 +114,7 @@ @include typography.set-font(vars.$font--main, (weight: 500)); display: inline-block; - padding: fn.dim(--padding-y) fn.dim(--padding-x); + padding: fn.dim(--pad-y) fn.dim(--pad-x); border: 2px solid transparent; border-radius: fn.dim(--rounding); line-height: 1; diff --git a/src/objects/_checkbox.scss b/src/objects/_checkbox.scss index 377b002..3bda5e7 100644 --- a/src/objects/_checkbox.scss +++ b/src/objects/_checkbox.scss @@ -7,8 +7,8 @@ --size: iro.fn-px-to-rem(14px), --label-gap: .6rem, --border-width: fn.global-dim(--border-width --medium), - --padding-x: .3rem, - --padding-y: .3rem, + --pad-x: .3rem, + --pad-y: .3rem, --margin-right: fn.global-dim(--spacing --x --md), ), ), 'dims'); @@ -46,9 +46,9 @@ display: inline-flex; position: relative; align-items: flex-start; - margin-right: calc(-1 * fn.dim(--padding-x) + fn.dim(--margin-right)); - margin-left: calc(-1 * fn.dim(--padding-x)); - padding: fn.dim(--padding-y) fn.dim(--padding-x); + margin-right: calc(-1 * fn.dim(--pad-x) + fn.dim(--margin-right)); + margin-left: calc(-1 * fn.dim(--pad-x)); + padding: fn.dim(--pad-y) fn.dim(--pad-x); @include iro.bem-elem('box') { display: block; diff --git a/src/objects/_radio.scss b/src/objects/_radio.scss index 51bfcd8..26e8c31 100644 --- a/src/objects/_radio.scss +++ b/src/objects/_radio.scss @@ -7,8 +7,8 @@ --diameter: iro.fn-px-to-rem(15px), --label-gap: .6rem, --border-width: fn.global-dim(--border-width --medium), - --padding-x: .3rem, - --padding-y: .3rem, + --pad-x: .3rem, + --pad-y: .3rem, --margin-right: fn.global-dim(--spacing --x --md), ), ), 'dims'); @@ -46,9 +46,9 @@ display: inline-flex; position: relative; align-items: flex-start; - margin-right: calc(-1 * fn.dim(--padding-x) + fn.dim(--margin-right)); - margin-left: calc(-1 * fn.dim(--padding-x)); - padding: fn.dim(--padding-y) fn.dim(--padding-x); + margin-right: calc(-1 * fn.dim(--pad-x) + fn.dim(--margin-right)); + margin-left: calc(-1 * fn.dim(--pad-x)); + padding: fn.dim(--pad-y) fn.dim(--pad-x); @include iro.bem-elem('circle') { display: block; diff --git a/src/objects/_status-indicator.scss b/src/objects/_status-indicator.scss new file mode 100644 index 0000000..18d6f81 --- /dev/null +++ b/src/objects/_status-indicator.scss @@ -0,0 +1,33 @@ +@use 'iro-sass/src/index' as iro; +@use '../functions' as fn; + +@include iro.props-namespace('status-indicator') { + @include iro.props-store(( + --dims: ( + --size: iro.fn-px-to-rem(10px), + ), + ), 'dims'); + + @include iro.props-store(( + --colors: ( + --default: fn.global-color(--obj-lo), + --green: scale-color(hsl(113, 49.8%, 49.6%), $lightness: 15%), + --yellow: scale-color(hsl(50, 59.8%, 58.4%), $lightness: 15%), + --red: scale-color(hsl(352, 69.8%, 58.4%), $lightness: 15%), + ), + ), 'colors'); + + @include iro.bem-object(iro.props-namespace()) { + display: inline-block; + width: fn.dim(--size); + height: fn.dim(--size); + border-radius: fn.dim(--size); + background-color: fn.color(--default); + + @each $color in 'green' 'yellow' 'red' { + @include iro.bem-is($color) { + background-color: fn.color(--#{$color}); + } + } + } +} diff --git a/src/objects/_switch.scss b/src/objects/_switch.scss index 85aa782..2d70844 100644 --- a/src/objects/_switch.scss +++ b/src/objects/_switch.scss @@ -8,8 +8,8 @@ --height: iro.fn-px-to-rem(15px), --label-gap: .6rem, --border-width: fn.global-dim(--border-width --medium), - --padding-x: .3rem, - --padding-y: .3rem, + --pad-x: .3rem, + --pad-y: .3rem, --margin-right: fn.global-dim(--spacing --x --md), ), ), 'dims'); @@ -50,9 +50,9 @@ display: inline-flex; position: relative; align-items: flex-start; - margin-right: calc(-1 * fn.dim(--padding-x) + fn.dim(--margin-right)); - margin-left: calc(-1 * fn.dim(--padding-x)); - padding: fn.dim(--padding-y) fn.dim(--padding-x); + margin-right: calc(-1 * fn.dim(--pad-x) + fn.dim(--margin-right)); + margin-left: calc(-1 * fn.dim(--pad-x)); + padding: fn.dim(--pad-y) fn.dim(--pad-x); @include iro.bem-elem('indicator') { display: block; diff --git a/src/objects/_text-field.scss b/src/objects/_text-field.scss index ca0eb5b..90d4b11 100644 --- a/src/objects/_text-field.scss +++ b/src/objects/_text-field.scss @@ -34,8 +34,8 @@ @include iro.props-namespace('text-field') { @include iro.props-store(( --dims: ( - --padding-x: .6rem, - --padding-y: .5rem, + --pad-x: .6rem, + --pad-y: .5rem, --border-width: fn.global-dim(--border-width --thin), --border-radius: 2px, @@ -91,7 +91,7 @@ @include iro.bem-object(iro.props-namespace()) { position: relative; min-width: 0; - padding: fn.dim(--padding-y) fn.dim(--padding-x); + padding: fn.dim(--pad-y) fn.dim(--pad-x); background-color: fn.color(--bg); @include iro.bem-elem('bg') { @@ -176,7 +176,7 @@ @include iro.bem-elem('native') { box-sizing: border-box; - padding: fn.dim(--padding-y) fn.dim(--padding-x); + padding: fn.dim(--pad-y) fn.dim(--pad-x); } } diff --git a/static/avatar.png b/static/avatar.png new file mode 100755 index 0000000..aa4345f Binary files /dev/null and b/static/avatar.png differ diff --git a/tpl/index.pug b/tpl/index.pug index 2980016..206e40b 100644 --- a/tpl/index.pug +++ b/tpl/index.pug @@ -13,6 +13,8 @@ include objects/checkbox.pug include objects/switch.pug include objects/form.pug include objects/action-button.pug +include objects/status-indicator.pug +include objects/avatar.pug mixin box +container(padX=true padY=true inPage=true theme="raised") @@ -363,3 +365,73 @@ html = ' ' +action-button(quiet=true icon='trash' selected=true disabled=true) + //----------------------------------------- + + +h1-heading(level='xl')= 'Status indicator' + +rule(level='medium') + + +box + +status-indicator + = ' ' + +status-indicator('green') + = ' ' + +status-indicator('yellow') + = ' ' + +status-indicator('red') + + //----------------------------------------- + + +h1-heading(level='xl')= 'Avatar' + +rule(level='medium') + + +box + div(style={ display: 'flex', gap: '.3em' }) + +avatar + = 'Vo' + +avatar(status='green' hue=45) + = 'lp' + +avatar(src='avatar.png') + +avatar(src='avatar.png' status='red') + br + br + div(style={ display: 'flex', gap: '.3em' }) + +avatar(size='sm' hue=90) + = 'eo' + +avatar(size='sm' status='green' hue=135) + = 'n' + +avatar(size='sm' src='avatar.png') + +avatar(size='sm' src='avatar.png' status='red') + br + br + div(style={ display: 'flex', gap: '.3em' }) + +avatar(size='xs' hue=180) + = 'V' + +avatar(size='xs' hue=225) + = 'o' + +avatar(size='xs' src='avatar.png') + + +box + div(style={ display: 'flex', gap: '.3em' }) + +avatar(circle=true) + = 'Vo' + +avatar(circle=true status='green' hue=45) + = 'lp' + +avatar(circle=true src='avatar.png') + +avatar(circle=true src='avatar.png' status='red') + br + br + div(style={ display: 'flex', gap: '.3em' }) + +avatar(circle=true size='sm' hue=90) + = 'eo' + +avatar(circle=true size='sm' status='green' hue=135) + = 'n' + +avatar(circle=true size='sm' src='avatar.png') + +avatar(circle=true size='sm' src='avatar.png' status='red') + br + br + div(style={ display: 'flex', gap: '.3em' }) + +avatar(circle=true size='xs' hue=180) + = 'V' + +avatar(circle=true size='xs' hue=225) + = 'o' + +avatar(circle=true size='xs' src='avatar.png') diff --git a/tpl/objects/avatar.pug b/tpl/objects/avatar.pug new file mode 100644 index 0000000..83c0f7c --- /dev/null +++ b/tpl/objects/avatar.pug @@ -0,0 +1,26 @@ +include ../objects/status-indicator.pug + +mixin avatar + - + let classes = { + 'o-avatar': true, + 'o-avatar--circle': attributes.circle + } + + if (attributes.size) { + classes['o-avatar--' + attributes.size] = true; + } + + let styles = {} + if (attributes.hue) { + styles['--avatar--colors--h'] = attributes.hue; + } + + div(class=classes style=styles) + if attributes.status + +status-indicator(attributes.status)(class='o-avatar__status') + if attributes.src + img.o-avatar__content(src=attributes.src) + else + .o-avatar__content + block diff --git a/tpl/objects/status-indicator.pug b/tpl/objects/status-indicator.pug new file mode 100644 index 0000000..9b240e1 --- /dev/null +++ b/tpl/objects/status-indicator.pug @@ -0,0 +1,8 @@ +mixin status-indicator(status) + - + let classes = { + 'o-status-indicator': true, + } + classes['is-' + status] = true + + div(class=classes)&attributes(attributes) -- cgit v1.2.3-54-g00ecf