move standalone alerts to static and prepare alerts widget
This commit is contained in:
parent
8efcd6f093
commit
18c5de4b86
@ -980,17 +980,18 @@ siteLayout headingOverride widget = do
|
||||
addScript $ StaticR js_polyfills_urlPolyfill_js
|
||||
addScript $ StaticR js_utils_featureChecker_js
|
||||
addScript $ StaticR js_utils_tabber_js
|
||||
addScript $ StaticR js_utils_alerts_js
|
||||
addStylesheet $ StaticR css_vendor_flatpickr_css
|
||||
addStylesheet $ StaticR css_vendor_fontawesome_css
|
||||
addStylesheet $ StaticR css_fonts_css
|
||||
addStylesheet $ StaticR css_utils_tabber_css
|
||||
addStylesheet $ StaticR css_utils_alerts_css
|
||||
$(widgetFile "default-layout")
|
||||
$(widgetFile "standalone/modal")
|
||||
$(widgetFile "standalone/showHide")
|
||||
$(widgetFile "standalone/inputs")
|
||||
$(widgetFile "standalone/tooltip")
|
||||
$(widgetFile "standalone/tabber")
|
||||
$(widgetFile "standalone/alerts")
|
||||
$(widgetFile "standalone/datepicker")
|
||||
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
|
||||
|
||||
|
||||
2
start.sh
2
start.sh
@ -19,4 +19,6 @@ if [[ -d .stack-work-run ]]; then
|
||||
trap move-back EXIT
|
||||
fi
|
||||
|
||||
node-sass ./static/scss -o ./static/css
|
||||
|
||||
stack exec -- yesod devel $@
|
||||
|
||||
182
static/css/utils/alerts.css
Normal file
182
static/css/utils/alerts.css
Normal file
@ -0,0 +1,182 @@
|
||||
/* ALERTS */
|
||||
/**
|
||||
.alert
|
||||
Regular Info Alert
|
||||
Disappears automatically after 30 seconds
|
||||
Disappears after x seconds if explicitly specified via data-decay='x'
|
||||
Can be told not to disappear with data-decay='0'
|
||||
|
||||
.alert-success
|
||||
Disappears automatically after 30 seconds
|
||||
|
||||
.alert-warning
|
||||
Does not disappear
|
||||
Orange regardless of user's selected theme
|
||||
|
||||
.alert-error
|
||||
Does not disappear
|
||||
Red regardless of user's selected theme
|
||||
|
||||
*/
|
||||
.alerts {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 5%;
|
||||
z-index: 20;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
flex-direction: column; }
|
||||
|
||||
.alerts__toggler {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
top: 400px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
cursor: pointer; }
|
||||
.alerts__toggler::before {
|
||||
content: '\f077';
|
||||
position: absolute;
|
||||
font-family: "Font Awesome 5 Free";
|
||||
left: 50%;
|
||||
top: 0;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
color: var(--color-grey);
|
||||
font-size: 30px;
|
||||
transform: translateX(-50%); }
|
||||
|
||||
.alerts__toggler--visible {
|
||||
top: -40px;
|
||||
opacity: 1;
|
||||
transition: top 0.5s cubic-bezier(0.73, 1.25, 0.61, 1), opacity 0.5s cubic-bezier(0.73, 1.25, 0.61, 1); }
|
||||
|
||||
@media (max-width: 425px) {
|
||||
.alerts {
|
||||
left: 5%; } }
|
||||
|
||||
.alert {
|
||||
position: relative;
|
||||
display: block;
|
||||
background-color: var(--color-lightblack);
|
||||
font-size: 1rem;
|
||||
color: var(--color-lightwhite);
|
||||
z-index: 0;
|
||||
padding: 0 50px;
|
||||
padding-right: 60px;
|
||||
animation: slide-in-alert .2s ease-out forwards;
|
||||
margin-bottom: 10px;
|
||||
transition: margin-bottom .2s ease-out; }
|
||||
|
||||
.alert a {
|
||||
color: var(--color-lightwhite); }
|
||||
|
||||
@keyframes slide-in-alert {
|
||||
from {
|
||||
transform: translateY(120%); }
|
||||
to {
|
||||
transform: translateY(0); } }
|
||||
|
||||
@keyframes slide-out-alert {
|
||||
from {
|
||||
transform: translateY(0);
|
||||
max-height: 200px; }
|
||||
to {
|
||||
transform: translateY(250%);
|
||||
opacity: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden; } }
|
||||
|
||||
@media (min-width: 425px) {
|
||||
.alert {
|
||||
max-width: 400px; } }
|
||||
|
||||
.alert--invisible {
|
||||
animation: slide-out-alert .2s ease-out forwards;
|
||||
margin-bottom: 0; }
|
||||
|
||||
.alert__content {
|
||||
padding: 8px 0;
|
||||
min-height: 40px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
font-weight: 600;
|
||||
align-items: center;
|
||||
text-align: left; }
|
||||
|
||||
.alert__icon {
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0;
|
||||
width: 50px;
|
||||
height: 100%;
|
||||
z-index: 40; }
|
||||
.alert__icon::before {
|
||||
content: '\f05a';
|
||||
position: absolute;
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-size: 24px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 50%;
|
||||
width: 30px;
|
||||
height: 30px; }
|
||||
|
||||
.alert__closer {
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 0;
|
||||
width: 60px;
|
||||
height: 100%;
|
||||
transition: all .3s ease;
|
||||
z-index: 40; }
|
||||
.alert__closer:hover {
|
||||
transform: scale(1.05, 1.05); }
|
||||
.alert__closer:hover::before {
|
||||
box-shadow: 0 0 4px white;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: white; }
|
||||
.alert__closer::before {
|
||||
content: '\f00d';
|
||||
position: absolute;
|
||||
font-family: "Font Awesome 5 Free";
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
transition: all .15s ease; }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.alert__closer {
|
||||
width: 40px; } }
|
||||
|
||||
.alert-success {
|
||||
background-color: var(--color-success); }
|
||||
.alert-success .alert__icon::before {
|
||||
content: '\f058'; }
|
||||
|
||||
.alert-warning {
|
||||
background-color: var(--color-warning); }
|
||||
.alert-warning .alert__icon::before {
|
||||
content: '\f06a'; }
|
||||
|
||||
.alert-error {
|
||||
background-color: var(--color-error); }
|
||||
.alert-error .alert__icon::before {
|
||||
content: '\f071'; }
|
||||
86
static/js/utils/alerts.js
Normal file
86
static/js/utils/alerts.js
Normal file
@ -0,0 +1,86 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.utils = window.utils || {};
|
||||
|
||||
var ALERTS_TOGGLER_CLASS = 'alerts__toggler';
|
||||
var ALERTS_TOGGLER_VISIBLE_CLASS = 'alerts__toggler--visible';
|
||||
var ALERTS_TOGGLER_APPEAR_DELAY = 120;
|
||||
|
||||
var ALERT_CLASS = 'alert';
|
||||
var ALERT_CLOSER_CLASS = 'alert__closer';
|
||||
var ALERT_INVISIBLE_CLASS = 'alert--invisible';
|
||||
var ALERT_AUTO_HIDE_DELAY = 10;
|
||||
var ALERT_AUTOCLOSING_MATCHER = 'alert-info';
|
||||
|
||||
var JS_INITIALIZED_CLASS = 'js-initialized';
|
||||
|
||||
window.utils.alerts = function(alertsEl) {
|
||||
|
||||
if (alertsEl.classList.contains(JS_INITIALIZED_CLASS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var togglerCheckRequested = false;
|
||||
|
||||
var togglerEl = alertsEl.querySelector('.' + ALERTS_TOGGLER_CLASS);
|
||||
|
||||
var alertElements = Array.from(alertsEl.querySelectorAll('.' + ALERT_CLASS))
|
||||
.filter(function(alert) {
|
||||
return !alert.classList.contains(JS_INITIALIZED_CLASS);
|
||||
});
|
||||
|
||||
function initToggler() {
|
||||
togglerEl.addEventListener('click', function() {
|
||||
alertElements.forEach(function(alertEl) {
|
||||
toggleAlert(alertEl, true);
|
||||
});
|
||||
togglerEl.classList.remove(ALERTS_TOGGLER_VISIBLE_CLASS);
|
||||
});
|
||||
alertsEl.classList.add(JS_INITIALIZED_CLASS);
|
||||
}
|
||||
|
||||
function initAlert(alertEl) {
|
||||
var autoHideDelay = ALERT_AUTO_HIDE_DELAY;
|
||||
if (alertEl.dataset.decay) {
|
||||
autoHideDelay = parseInt(alertEl.dataset.decay, 10);
|
||||
}
|
||||
|
||||
var closeEl = alertEl.querySelector('.' + ALERT_CLOSER_CLASS);
|
||||
closeEl.addEventListener('click', function() {
|
||||
toggleAlert(alertEl);
|
||||
});
|
||||
|
||||
if (autoHideDelay > 0 && alertEl.matches(ALERT_AUTOCLOSING_MATCHER)) {
|
||||
window.setTimeout(function() {
|
||||
toggleAlert(alertEl);
|
||||
}, autoHideDelay * 1000);
|
||||
}
|
||||
|
||||
alertEl.classList.add(JS_INITIALIZED_CLASS);
|
||||
}
|
||||
|
||||
function toggleAlert(alertEl, visible) {
|
||||
alertEl.classList.toggle(ALERT_INVISIBLE_CLASS, !visible);
|
||||
checkToggler();
|
||||
}
|
||||
|
||||
function checkToggler() {
|
||||
if (togglerCheckRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
var alertsHidden = alertElements.reduce(function(acc, alert) {
|
||||
return acc || alert.classList.contains(ALERT_INVISIBLE_CLASS);
|
||||
}, false);
|
||||
|
||||
window.setTimeout(function() {
|
||||
toggler.classList.toggle(ALERTS_TOGGLER_VISIBLE_CLASS, alertsHidden);
|
||||
togglerCheckRequested = false;
|
||||
}, ALERTS_TOGGLER_APPEAR_DELAY);
|
||||
}
|
||||
|
||||
initToggler();
|
||||
alertElements.forEach(initAlert);
|
||||
};
|
||||
})();
|
||||
@ -156,7 +156,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.alert__close {
|
||||
.alert__closer {
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
@ -196,7 +196,7 @@
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
.alert__close {
|
||||
.alert__closer {
|
||||
width: 40px;
|
||||
}
|
||||
}
|
||||
@ -30,12 +30,16 @@ $if not isModal
|
||||
^{widget}
|
||||
|
||||
<!-- alerts -->
|
||||
<!-- ^{alerts mmsgs} -->
|
||||
<div #alerts .alerts>
|
||||
$forall (status, msg) <- mmsgs
|
||||
$with status2 <- bool status "info" (status == "")
|
||||
<div class="alert alert-#{status2}">
|
||||
<div .alert__content>
|
||||
#{msg}
|
||||
<div .alerts__toggler>
|
||||
$forall (status, msg) <- mmsgs
|
||||
$with status2 <- bool status "info" (status == "")
|
||||
<div class="alert alert-#{status2}">
|
||||
<div .alert__closer>
|
||||
<div .alert__icon>
|
||||
<div .alert__content>
|
||||
#{msg}
|
||||
|
||||
<!-- footer -->
|
||||
$if not isModal
|
||||
|
||||
@ -1 +0,0 @@
|
||||
<!-- only here to be able to include alerts using `toWidget` -->
|
||||
@ -1,101 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.utils = window.utils || {};
|
||||
|
||||
var ALERT_INVISIBLE_CLASS = 'alert--invisible';
|
||||
var TOGGLER_INVISIBLE_CLASS = 'alerts__toggler--visible';
|
||||
var ALERT_AUTO_DISAPPEAR_DELAY = 10;
|
||||
|
||||
var alertsShowingToggler = false;
|
||||
|
||||
window.utils.alerts = function(alertsEl) {
|
||||
|
||||
var toggler = alertsEl.querySelector('.alerts__toggler');
|
||||
|
||||
function makeToggler() {
|
||||
toggler = document.createElement('DIV');
|
||||
toggler.classList.add('alerts__toggler');
|
||||
toggler.addEventListener('click', function() {
|
||||
Array.from(alertsEl.querySelectorAll('.alert')).forEach(function(alert) {
|
||||
alert.classList.remove(ALERT_INVISIBLE_CLASS);
|
||||
toggler.classList.remove(TOGGLER_INVISIBLE_CLASS);
|
||||
});
|
||||
checkToggler();
|
||||
});
|
||||
alertsEl.appendChild(toggler);
|
||||
alertsEl.classList.add('js-initialized');
|
||||
}
|
||||
|
||||
function makeAlert(alertEl) {
|
||||
var iconEl = document.createElement('DIV');
|
||||
var closeEl = document.createElement('DIV');
|
||||
var dataDecay = alertEl.dataset.decay;
|
||||
var autoDecay = ALERT_AUTO_DISAPPEAR_DELAY;
|
||||
if (dataDecay) {
|
||||
autoDecay = parseInt(dataDecay, 10);
|
||||
}
|
||||
iconEl.classList.add('alert__icon');
|
||||
closeEl.classList.add('alert__close');
|
||||
closeEl.addEventListener('click', function(event) {
|
||||
closeAlert(alertEl);
|
||||
});
|
||||
alertEl.insertBefore(iconEl, alertEl.children[0]);
|
||||
alertEl.insertBefore(closeEl, alertEl.children[0]);
|
||||
|
||||
// auto-hide info and success-alerts after 3 seconds
|
||||
if (autoDecay > 0 && !alertEl.matches('.alert-warning, .alert-error')) {
|
||||
window.setTimeout(function() {
|
||||
closeAlert(alertEl);
|
||||
}, autoDecay * 1000);
|
||||
}
|
||||
|
||||
alertEl.classList.add('js-initialized');
|
||||
}
|
||||
|
||||
function closeAlert(alertEl) {
|
||||
alertEl.classList.add(ALERT_INVISIBLE_CLASS);
|
||||
checkToggler();
|
||||
}
|
||||
|
||||
function checkToggler() {
|
||||
var hidden = true;
|
||||
Array.from(alertsEl.querySelectorAll('.alert')).forEach(function(alert) {
|
||||
if (hidden && !alert.classList.contains(ALERT_INVISIBLE_CLASS)) {
|
||||
hidden = false;
|
||||
}
|
||||
});
|
||||
if (!alertsShowingToggler) {
|
||||
alertsShowingToggler = true;
|
||||
window.setTimeout(function() {
|
||||
toggler.classList.toggle(TOGGLER_INVISIBLE_CLASS, hidden);
|
||||
alertsShowingToggler = false;
|
||||
}, 120);
|
||||
}
|
||||
}
|
||||
|
||||
if (!alertsEl.classList.contains('js-initialized') || !toggler)
|
||||
makeToggler();
|
||||
Array.from(alertsEl.querySelectorAll('.alert:not(.js-initialized)')).map(makeAlert);
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
document.addEventListener('setup', function(e) {
|
||||
if (e.detail.module && e.detail.module !== 'alerts')
|
||||
return;
|
||||
|
||||
|
||||
// setup alerts
|
||||
if (e.detail.scope.classList.contains('alerts')) {
|
||||
window.utils.alerts(e.detail.scope);
|
||||
} else {
|
||||
var alertsEl = e.detail.scope.querySelector('.alerts');
|
||||
if (alertsEl)
|
||||
window.utils.alerts(alertsEl);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.dispatchEvent(new CustomEvent('setup', { detail: { scope: document.body, module: 'alerts' }, bubbles: true, cancelable: true }))
|
||||
});
|
||||
9
templates/widgets/alerts/alerts.hamlet
Normal file
9
templates/widgets/alerts/alerts.hamlet
Normal file
@ -0,0 +1,9 @@
|
||||
<div #alerts .alerts>
|
||||
<div .alerts__toggler>
|
||||
$forall (status, msg) <- mmsgs
|
||||
$with status2 <- bool status "info" (status == "")
|
||||
<div class="alert alert-#{status2}">
|
||||
<div .alert__closer>
|
||||
<div .alert__icon>
|
||||
<div .alert__content>
|
||||
#{msg}
|
||||
18
templates/widgets/alerts/alerts.julius
Normal file
18
templates/widgets/alerts/alerts.julius
Normal file
@ -0,0 +1,18 @@
|
||||
document.addEventListener('setup', function(e) {
|
||||
if (!e.detail.module || e.detail.module !== 'alerts') {
|
||||
return;
|
||||
}
|
||||
|
||||
// setup alerts
|
||||
if (e.detail.scope.classList.contains('alerts')) {
|
||||
window.utils.alerts(e.detail.scope);
|
||||
} else {
|
||||
var alertsEl = e.detail.scope.querySelector('.alerts');
|
||||
if (alertsEl)
|
||||
window.utils.alerts(alertsEl);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.dispatchEvent(new CustomEvent('setup', { detail: { scope: document.body, module: 'alerts' }, bubbles: true, cancelable: true }))
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user