From 25c5dac6310d20ec9d2f3bee8efd9af0199fb699 Mon Sep 17 00:00:00 2001 From: ivarlovlie Date: Sun, 2 Aug 2020 18:47:30 +0200 Subject: show loading state --- src/browser/src/components/Alert/Alert.js | 20 ++ src/browser/src/components/Alert/Alert.scss | 54 ++++ src/browser/src/components/Alert/Alert.vue | 65 ++++ .../src/components/FillLoader/FillLoader.scss | 347 +++++++++++++++++++++ .../src/components/FillLoader/FillLoader.vue | 15 + src/browser/src/components/Sidebar/Sidebar.vue | 82 ++--- src/browser/src/styles/_btn-states.scss | 51 +++ src/browser/src/styles/_forms.scss | 4 + src/browser/src/views/Login.vue | 48 ++- 9 files changed, 633 insertions(+), 53 deletions(-) create mode 100644 src/browser/src/components/Alert/Alert.js create mode 100644 src/browser/src/components/Alert/Alert.scss create mode 100644 src/browser/src/components/Alert/Alert.vue create mode 100644 src/browser/src/components/FillLoader/FillLoader.scss create mode 100644 src/browser/src/components/FillLoader/FillLoader.vue create mode 100644 src/browser/src/styles/_btn-states.scss (limited to 'src') diff --git a/src/browser/src/components/Alert/Alert.js b/src/browser/src/components/Alert/Alert.js new file mode 100644 index 0000000..b7647dd --- /dev/null +++ b/src/browser/src/components/Alert/Alert.js @@ -0,0 +1,20 @@ +// File#: _1_alert +// Usage: codyhouse.co/license +function initAlert() { + var alertClose = document.getElementsByClassName("js-alert__close-btn"); + if (alertClose.length > 0) { + for (var i = 0; i < alertClose.length; i++) { + (function(i) { + initAlertEvent(alertClose[i]); + })(i); + } + } + + function initAlertEvent(element) { + element.addEventListener("click", function(event) { + event.preventDefault(); + Util.removeClass(element.closest(".js-alert"), "alert--is-visible"); + }); + } +} +export default initAlert; diff --git a/src/browser/src/components/Alert/Alert.scss b/src/browser/src/components/Alert/Alert.scss new file mode 100644 index 0000000..1cdf3d2 --- /dev/null +++ b/src/browser/src/components/Alert/Alert.scss @@ -0,0 +1,54 @@ +/* -------------------------------- + +File#: _1_alert +Title: Alert +Descr: Feedback message +Usage: codyhouse.co/license + +-------------------------------- */ + +.alert { + padding: var(--space-xs) var(--space-sm); + background-color: alpha(var(--color-primary), 0.2); + border-radius: var(--radius-md); + color: var(--color-contrast-higher); + // hide element + position: absolute; + clip: rect(1px, 1px, 1px, 1px); + clip-path: inset(50%); +} + +.alert__link { + color: inherit; + text-decoration: underline; +} + +.alert__close-btn { + display: inline-block; // flex fallback + flex-shrink: 0; + margin-left: var(--space-sm); + + .icon { + display: block; + } +} + +// themes +.alert--success { + background-color: alpha(var(--color-success), 0.2); +} + +.alert--error { + background-color: alpha(var(--color-error), 0.2); +} + +.alert--warning { + background-color: alpha(var(--color-warning), 0.2); +} + +// toggle visibility +.alert--is-visible { + position: static; + clip: auto; + clip-path: none; +} diff --git a/src/browser/src/components/Alert/Alert.vue b/src/browser/src/components/Alert/Alert.vue new file mode 100644 index 0000000..ed00284 --- /dev/null +++ b/src/browser/src/components/Alert/Alert.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/src/browser/src/components/FillLoader/FillLoader.scss b/src/browser/src/components/FillLoader/FillLoader.scss new file mode 100644 index 0000000..5c6b0ca --- /dev/null +++ b/src/browser/src/components/FillLoader/FillLoader.scss @@ -0,0 +1,347 @@ +/* -------------------------------- + +File#: _1_fill-loader +Title: Loader +Descr: A collection of animated loaders with a filling effect +Usage: codyhouse.co/license + +-------------------------------- */ + +.fill-loader { + position: relative; + overflow: hidden; + display: inline-block; +} + +.fill-loader__fill { + position: absolute; +} + +@supports (animation-name: this) { + .fill-loader__label { + @include srHide; // show label only to screen readers if animations are supported + } +} + +// loader v1 + v2 +@supports (animation-name: this) { + .fill-loader--v1, + .fill-loader--v2 { + .fill-loader__base { + width: 64px; // loader width + height: 4px; // loader height + background-color: var(--color-contrast-low); + } + + .fill-loader__fill { + background-color: var(--color-primary); + top: 0; + left: 0; + height: 100%; + width: 100%; + will-change: transform; + } + } + + .fill-loader--v1 { + .fill-loader__fill { + animation: fill-loader-1 0.8s infinite var(--ease-in-out); + } + } + + .fill-loader--v2 { + .fill-loader__fill { + animation: fill-loader-2 0.8s infinite alternate var(--ease-in-out); + } + } +} + +@keyframes fill-loader-1 { + 0% { + transform-origin: 0 0; + transform: scaleX(0); + } + + 49% { + transform-origin: 0 0; + transform: scaleX(1); + } + + 51% { + transform: scaleX(1); + transform-origin: 100% 0; + } + + 100% { + transform: scaleX(0); + transform-origin: 100% 0; + } +} + +@keyframes fill-loader-2 { + 0% { + transform-origin: 0 0; + transform: scaleX(0.1); + } + + 49% { + transform-origin: 0 0; + transform: scaleX(1); + } + + 51% { + transform: scaleX(1); + transform-origin: 100% 0; + } + + 100% { + transform: scaleX(0.1); + transform-origin: 100% 0; + } +} + +// loader v3 +@supports (animation-name: this) { + .fill-loader--v3 { + .fill-loader__base { + width: 120px; // loader width + height: 10px; // loader height + background-color: var(--color-contrast-low); + } + + .fill-loader__fill { + top: 0; + left: 0; + height: 100%; + width: 100%; + transform: scaleX(0); + will-change: transform; + animation: fill-loader-1 1s infinite var(--ease-in-out); + } + + .fill-loader__fill--1st { + background-color: var(--color-contrast-medium); + } + + .fill-loader__fill--2nd { + background-color: var(--color-contrast-higher); + animation-delay: 0.1s; + } + + .fill-loader__fill--3rd { + background-color: var(--color-primary); + animation-delay: 0.2s; + } + } +} + +// loader v4 +@supports (animation-name: this) { + .fill-loader--v4 { + width: 90%; // loader width + max-width: 300px; + + .fill-loader__base { + height: 4px; // loader height + background-color: var(--color-contrast-low); + } + + .fill-loader__fill { + top: 0; + left: 0; + right: 0; + height: 100%; + background-color: var(--color-primary); + animation: fill-loader-4 1.6s infinite var(--ease-in-out); + will-change: left, right; + } + } +} + +@keyframes fill-loader-4 { + 0% { + left: 0; + right: 100%; + background-color: var(--color-primary); + } + + 10%, + 60% { + left: 0; + } + + 40%, + 90% { + right: 0; + } + + 50% { + left: 100%; + background-color: var(--color-primary); + } + + 51% { + left: 0; + right: 100%; + background-color: var(--color-accent); + } + + 100% { + left: 100%; + background-color: var(--color-accent); + } +} + +// loader v5 +@supports (animation-name: this) { + .fill-loader--v5 { + .fill-loader__base { + width: 48px; // loader width + height: 48px; // loader height + background-color: var(--color-contrast-low); + } + + .fill-loader__fill { + top: 0; + left: 0; + height: 100%; + width: 100%; + will-change: transform; + } + + .fill-loader__fill--1st { + background-color: var(--color-primary); + transform-origin: 0 50%; + animation: fill-loader-5-1st 2s infinite var(--ease-in-out); + } + + .fill-loader__fill--2nd { + background-color: var(--color-contrast-higher); + transform-origin: 50% 100%; + animation: fill-loader-5-2nd 2s infinite var(--ease-in-out); + } + + .fill-loader__fill--3rd { + background-color: var(--color-accent); + transform-origin: 100% 50%; + animation: fill-loader-5-3rd 2s infinite var(--ease-in-out); + } + + .fill-loader__fill--4th { + background-color: var(--color-contrast-low); + transform-origin: 50% 0%; + animation: fill-loader-5-4th 2s infinite var(--ease-in-out); + } + } +} + +@keyframes fill-loader-5-1st { + 0% { + transform: scaleX(0); + } + + 25%, + 100% { + transform: scaleX(1); + } +} + +@keyframes fill-loader-5-2nd { + 0%, + 25% { + transform: scaleY(0); + } + + 50%, + 100% { + transform: scaleY(1); + } +} + +@keyframes fill-loader-5-3rd { + 0%, + 50% { + transform: scaleX(0); + } + + 75%, + 100% { + transform: scaleX(1); + } +} + +@keyframes fill-loader-5-4th { + 0%, + 75% { + transform: scaleY(0); + } + + 100% { + transform: scaleY(1); + } +} + +// loader v6 +@supports (animation-name: this) { + .fill-loader--v6 { + .fill-loader__grid { + display: flex; + } + + .fill-loader__bar { + position: relative; + } + + .fill-loader__bar:nth-child(2) { + margin: 0 8px; + } + + .fill-loader__base { + width: 6px; + height: 30px; + background-color: var(--color-contrast-low); + } + + .fill-loader__fill { + top: 0; + left: 0; + height: 100%; + width: 100%; + will-change: transform; + transform: scaleY(0); + transform-origin: 50% 100%; + background-color: var(--color-primary); + animation: fill-loader-6 0.8s infinite; + } + + .fill-loader__fill--2nd { + animation-delay: 0.1s; + } + + .fill-loader__fill--3rd { + animation-delay: 0.2s; + } + } +} + +@keyframes fill-loader-6 { + 0% { + transform-origin: 0 100%; + transform: scaleY(0); + } + + 49% { + transform-origin: 0 100%; + transform: scaleY(1); + } + + 51% { + transform: scaleY(1); + transform-origin: 0 0; + } + + 100% { + transform: scaleY(0); + transform-origin: 0 0; + } +} diff --git a/src/browser/src/components/FillLoader/FillLoader.vue b/src/browser/src/components/FillLoader/FillLoader.vue new file mode 100644 index 0000000..73a986f --- /dev/null +++ b/src/browser/src/components/FillLoader/FillLoader.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/browser/src/components/Sidebar/Sidebar.vue b/src/browser/src/components/Sidebar/Sidebar.vue index e4e97b5..aa6efc3 100644 --- a/src/browser/src/components/Sidebar/Sidebar.vue +++ b/src/browser/src/components/Sidebar/Sidebar.vue @@ -1,62 +1,62 @@ - diff --git a/src/browser/src/styles/_btn-states.scss b/src/browser/src/styles/_btn-states.scss new file mode 100644 index 0000000..bc1498f --- /dev/null +++ b/src/browser/src/styles/_btn-states.scss @@ -0,0 +1,51 @@ +/* -------------------------------- + +File#: _1_btn-states +Title: Buttons states +Descr: Multi-state button elements +Usage: codyhouse.co/license + +-------------------------------- */ + +.btn .btn__content-a { + display: inline-flex; +} + + +.btn .btn__content-b { + display: none; +} + +.btn__content-a, .btn__content-b { + align-items: center; +} + +.btn--state-b { + .btn__content-a { + display: none; + } + + .btn__content-b { + display: inline-block; // fallback + display: inline-flex; + } +} + +/* preserve button width when switching from state A to state B */ +.btn--preserve-width { + .btn__content-b { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + justify-content: center; + } + + &.btn--state-b .btn__content-a { + display: inline-block; // fallback + display: inline-flex; + visibility: hidden; + } +} + diff --git a/src/browser/src/styles/_forms.scss b/src/browser/src/styles/_forms.scss index f4fcd8c..0c7d745 100644 --- a/src/browser/src/styles/_forms.scss +++ b/src/browser/src/styles/_forms.scss @@ -32,6 +32,10 @@ } } +.form-control[disabled] { + filter: opacity(0.8); +} + .form-control[disabled], .form-control[readonly] { cursor: not-allowed; diff --git a/src/browser/src/views/Login.vue b/src/browser/src/views/Login.vue index 9beca02..f1105dc 100644 --- a/src/browser/src/views/Login.vue +++ b/src/browser/src/views/Login.vue @@ -1,13 +1,9 @@ + + -- cgit v1.3