From 18c5de4b865ae30a2dc91081bde253b9f24fe33b Mon Sep 17 00:00:00 2001 From: Felix Hamann Date: Tue, 12 Feb 2019 22:17:03 +0100 Subject: [PATCH 1/6] move standalone alerts to static and prepare alerts widget --- src/Foundation.hs | 3 +- start.sh | 2 + static/css/utils/alerts.css | 182 ++++++++++++++++++ static/js/utils/alerts.js | 86 +++++++++ .../scss/utils/alerts.scss | 4 +- templates/default-layout.hamlet | 14 +- templates/standalone/alerts.hamlet | 1 - templates/standalone/alerts.julius | 101 ---------- templates/widgets/alerts/alerts.hamlet | 9 + templates/widgets/alerts/alerts.julius | 18 ++ 10 files changed, 310 insertions(+), 110 deletions(-) create mode 100644 static/css/utils/alerts.css create mode 100644 static/js/utils/alerts.js rename templates/standalone/alerts.lucius => static/scss/utils/alerts.scss (99%) delete mode 100644 templates/standalone/alerts.hamlet delete mode 100644 templates/standalone/alerts.julius create mode 100644 templates/widgets/alerts/alerts.hamlet create mode 100644 templates/widgets/alerts/alerts.julius diff --git a/src/Foundation.hs b/src/Foundation.hs index 6cb21a242..0e48f4823 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -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") diff --git a/start.sh b/start.sh index 24abcd36c..bc9a04a6a 100755 --- a/start.sh +++ b/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 $@ diff --git a/static/css/utils/alerts.css b/static/css/utils/alerts.css new file mode 100644 index 000000000..670e28696 --- /dev/null +++ b/static/css/utils/alerts.css @@ -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'; } diff --git a/static/js/utils/alerts.js b/static/js/utils/alerts.js new file mode 100644 index 000000000..980cb955c --- /dev/null +++ b/static/js/utils/alerts.js @@ -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); + }; +})(); diff --git a/templates/standalone/alerts.lucius b/static/scss/utils/alerts.scss similarity index 99% rename from templates/standalone/alerts.lucius rename to static/scss/utils/alerts.scss index bc5603220..3256eef96 100644 --- a/templates/standalone/alerts.lucius +++ b/static/scss/utils/alerts.scss @@ -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; } } diff --git a/templates/default-layout.hamlet b/templates/default-layout.hamlet index bf936affd..c01ab4e45 100644 --- a/templates/default-layout.hamlet +++ b/templates/default-layout.hamlet @@ -30,12 +30,16 @@ $if not isModal ^{widget} +
- $forall (status, msg) <- mmsgs - $with status2 <- bool status "info" (status == "") -
-
- #{msg} +
+ $forall (status, msg) <- mmsgs + $with status2 <- bool status "info" (status == "") +
+
+
+
+ #{msg} $if not isModal diff --git a/templates/standalone/alerts.hamlet b/templates/standalone/alerts.hamlet deleted file mode 100644 index 163f415b4..000000000 --- a/templates/standalone/alerts.hamlet +++ /dev/null @@ -1 +0,0 @@ - diff --git a/templates/standalone/alerts.julius b/templates/standalone/alerts.julius deleted file mode 100644 index c8c04dc14..000000000 --- a/templates/standalone/alerts.julius +++ /dev/null @@ -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 })) -}); diff --git a/templates/widgets/alerts/alerts.hamlet b/templates/widgets/alerts/alerts.hamlet new file mode 100644 index 000000000..aa7169ca1 --- /dev/null +++ b/templates/widgets/alerts/alerts.hamlet @@ -0,0 +1,9 @@ +
+
+ $forall (status, msg) <- mmsgs + $with status2 <- bool status "info" (status == "") +
+
+
+
+ #{msg} diff --git a/templates/widgets/alerts/alerts.julius b/templates/widgets/alerts/alerts.julius new file mode 100644 index 000000000..14e679f61 --- /dev/null +++ b/templates/widgets/alerts/alerts.julius @@ -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 })) +}); From 5c5a080f0f0fea643bdd6af1f6e40d89d8b5b4d9 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Wed, 13 Feb 2019 16:32:45 +0100 Subject: [PATCH 2/6] Compile Sass --- package.yaml | 1 + src/Settings/StaticFiles.hs | 3 +- src/Settings/StaticFiles/Generator.hs | 64 +++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/Settings/StaticFiles/Generator.hs diff --git a/package.yaml b/package.yaml index 46af6eab8..0aadd7a3f 100644 --- a/package.yaml +++ b/package.yaml @@ -114,6 +114,7 @@ dependencies: - memcached-binary - directory-tree - lifted-base + - hsass other-extensions: - GeneralizedNewtypeDeriving diff --git a/src/Settings/StaticFiles.hs b/src/Settings/StaticFiles.hs index c7bd88255..d2375a8e5 100644 --- a/src/Settings/StaticFiles.hs +++ b/src/Settings/StaticFiles.hs @@ -6,6 +6,7 @@ module Settings.StaticFiles import ClassyPrelude import Settings (appStaticDir, compileTimeAppSettings) +import Settings.StaticFiles.Generator import Yesod.EmbeddedStatic -- This generates easy references to files in the static directory at compile time, @@ -23,4 +24,4 @@ import Yesod.EmbeddedStatic #define DEV_BOOL False #endif -mkEmbeddedStatic DEV_BOOL "embeddedStatic" [embedDir $ appStaticDir compileTimeAppSettings] +mkEmbeddedStatic DEV_BOOL "embeddedStatic" . pure . staticGenerator $ appStaticDir compileTimeAppSettings diff --git a/src/Settings/StaticFiles/Generator.hs b/src/Settings/StaticFiles/Generator.hs new file mode 100644 index 000000000..e59e944ed --- /dev/null +++ b/src/Settings/StaticFiles/Generator.hs @@ -0,0 +1,64 @@ +module Settings.StaticFiles.Generator + ( staticGenerator + ) where + +import ClassyPrelude +import Yesod.EmbeddedStatic.Types +import Yesod.EmbeddedStatic + +import System.FilePath +import System.Directory.Tree +import Network.Mime + +import Language.Haskell.TH +import Language.Haskell.TH.Syntax + +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as LBS + +import qualified Data.Map as Map + +import qualified Text.Sass.Compilation as Sass + +import Data.Default + +import qualified Data.Foldable as Fold + + +staticGenerator :: FilePath -> Generator +staticGenerator staticDir = do + dirTree' <- runIO $ readDirectoryWith toEntries staticDir + Fold.forM_ (fst <$> zipPaths dirTree') addDependentFile + return . Fold.fold $ dirTree dirTree' + where + toEntries :: FilePath -- ^ Absolute path + -> IO [Entry] + toEntries loc = compile (mimeByExt mimeMap defaultMimeType $ pack loc) (makeRelative staticDir loc) loc + + mimeMap = defaultMimeMap `mappend` Map.fromList + [ ("sass", "text/x-sass") + , ("scss", "text/x-scss") + ] + +compile :: MimeType + -> Location -- ^ Relative location + -> FilePath -- ^ Absolute filepath + -> IO [Entry] +compile sassMime sassLoc fp + | sassMime `elem` [ "text/x-sass", "text/x-scss" ] + = return . pure $ def + { ebHaskellName = Just $ pathToName ebLocation + , ebLocation + , ebMimeType = "text/css" + , ebProductionContent = either (fail <=< Sass.errorMessage) (return . LBS.fromStrict) =<< Sass.compileFile fp def + , ebDevelReload = [| either (fail <=< Sass.errorMessage) (return . LBS.fromStrict) =<< Sass.compileFile $(litE $ stringL fp) def |] + } + where + ebLocation = sassLoc -<.> "css" +compile ebMimeType ebLocation fp = return . pure $ def + { ebHaskellName = Just $ pathToName ebLocation + , ebLocation + , ebMimeType + , ebProductionContent = LBS.fromStrict <$> BS.readFile fp + , ebDevelReload = [| LBS.fromStrict <$> BS.readFile $(litE $ stringL fp) |] + } From 800d063fa7de2acd5bc20c03c415279b64197848 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Wed, 13 Feb 2019 17:07:03 +0100 Subject: [PATCH 3/6] Use haskell-based sass-compilation for alerts.scss --- src/Foundation.hs | 2 +- src/Settings/StaticFiles/Generator.hs | 2 +- start.sh | 2 - static/css/utils/alerts.css | 182 ------------------------- static/{scss => css}/utils/alerts.scss | 0 5 files changed, 2 insertions(+), 186 deletions(-) delete mode 100644 static/css/utils/alerts.css rename static/{scss => css}/utils/alerts.scss (100%) diff --git a/src/Foundation.hs b/src/Foundation.hs index 0e48f4823..0bb653360 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -985,7 +985,7 @@ siteLayout headingOverride widget = do addStylesheet $ StaticR css_vendor_fontawesome_css addStylesheet $ StaticR css_fonts_css addStylesheet $ StaticR css_utils_tabber_css - addStylesheet $ StaticR css_utils_alerts_css + addStylesheet $ StaticR css_utils_alerts_scss $(widgetFile "default-layout") $(widgetFile "standalone/modal") $(widgetFile "standalone/showHide") diff --git a/src/Settings/StaticFiles/Generator.hs b/src/Settings/StaticFiles/Generator.hs index e59e944ed..6b4573631 100644 --- a/src/Settings/StaticFiles/Generator.hs +++ b/src/Settings/StaticFiles/Generator.hs @@ -47,7 +47,7 @@ compile :: MimeType compile sassMime sassLoc fp | sassMime `elem` [ "text/x-sass", "text/x-scss" ] = return . pure $ def - { ebHaskellName = Just $ pathToName ebLocation + { ebHaskellName = Just $ pathToName sassLoc , ebLocation , ebMimeType = "text/css" , ebProductionContent = either (fail <=< Sass.errorMessage) (return . LBS.fromStrict) =<< Sass.compileFile fp def diff --git a/start.sh b/start.sh index bc9a04a6a..24abcd36c 100755 --- a/start.sh +++ b/start.sh @@ -19,6 +19,4 @@ if [[ -d .stack-work-run ]]; then trap move-back EXIT fi -node-sass ./static/scss -o ./static/css - stack exec -- yesod devel $@ diff --git a/static/css/utils/alerts.css b/static/css/utils/alerts.css deleted file mode 100644 index 670e28696..000000000 --- a/static/css/utils/alerts.css +++ /dev/null @@ -1,182 +0,0 @@ -/* 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'; } diff --git a/static/scss/utils/alerts.scss b/static/css/utils/alerts.scss similarity index 100% rename from static/scss/utils/alerts.scss rename to static/css/utils/alerts.scss From ec3ec2a88294a80d1917c605804df25d02d425af Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Wed, 13 Feb 2019 19:45:39 +0100 Subject: [PATCH 4/6] Move alerts to separate widget --- src/Foundation.hs | 2 ++ templates/default-layout.hamlet | 11 +---------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/Foundation.hs b/src/Foundation.hs index 0bb653360..eb0816fd6 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -961,6 +961,8 @@ siteLayout headingOverride widget = do asidenav = $(widgetFile "widgets/asidenav") footer :: Widget footer = $(widgetFile "widgets/footer") + alerts :: Widget + alerts = $(widgetFile "widgets/alerts/alerts") contentHeadline :: Maybe Widget contentHeadline = (toWidget <$> headingOverride) <|> (pageHeading =<< mcurrentRoute) breadcrumbsWgt :: Widget diff --git a/templates/default-layout.hamlet b/templates/default-layout.hamlet index c01ab4e45..87870650b 100644 --- a/templates/default-layout.hamlet +++ b/templates/default-layout.hamlet @@ -30,16 +30,7 @@ $if not isModal ^{widget} - -
-
- $forall (status, msg) <- mmsgs - $with status2 <- bool status "info" (status == "") -
-
-
-
- #{msg} + ^{alerts} $if not isModal From fb52b2024b78ade470f79919b6cbfba31d06a589 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Wed, 13 Feb 2019 19:58:35 +0100 Subject: [PATCH 5/6] Handle sass properly (as opposed to scss) --- src/Settings/StaticFiles/Generator.hs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Settings/StaticFiles/Generator.hs b/src/Settings/StaticFiles/Generator.hs index 6b4573631..b60bcef2c 100644 --- a/src/Settings/StaticFiles/Generator.hs +++ b/src/Settings/StaticFiles/Generator.hs @@ -19,6 +19,7 @@ import qualified Data.ByteString.Lazy as LBS import qualified Data.Map as Map import qualified Text.Sass.Compilation as Sass +import Text.Sass.Options import Data.Default @@ -44,15 +45,22 @@ compile :: MimeType -> Location -- ^ Relative location -> FilePath -- ^ Absolute filepath -> IO [Entry] -compile sassMime sassLoc fp - | sassMime `elem` [ "text/x-sass", "text/x-scss" ] - = return . pure $ def - { ebHaskellName = Just $ pathToName sassLoc - , ebLocation - , ebMimeType = "text/css" - , ebProductionContent = either (fail <=< Sass.errorMessage) (return . LBS.fromStrict) =<< Sass.compileFile fp def - , ebDevelReload = [| either (fail <=< Sass.errorMessage) (return . LBS.fromStrict) =<< Sass.compileFile $(litE $ stringL fp) def |] - } +compile "text/x-scss" sassLoc fp = return . pure $ def + { ebHaskellName = Just $ pathToName sassLoc + , ebLocation + , ebMimeType = "text/css" + , ebProductionContent = either (fail <=< Sass.errorMessage) (return . LBS.fromStrict) =<< Sass.compileFile fp def + , ebDevelReload = [| either (fail <=< Sass.errorMessage) (return . LBS.fromStrict) =<< Sass.compileFile $(litE $ stringL fp) def |] + } + where + ebLocation = sassLoc -<.> "css" +compile "text/x-sass" sassLoc fp = return . pure $ def + { ebHaskellName = Just $ pathToName sassLoc + , ebLocation + , ebMimeType = "text/css" + , ebProductionContent = either (fail <=< Sass.errorMessage) (return . LBS.fromStrict) =<< Sass.compileFile fp (def { sassIsIndentedSyntax = True }) + , ebDevelReload = [| either (fail <=< Sass.errorMessage) (return . LBS.fromStrict) =<< Sass.compileFile $(litE $ stringL fp) (def { sassIsIndentedSyntax = True }) |] + } where ebLocation = sassLoc -<.> "css" compile ebMimeType ebLocation fp = return . pure $ def From effcd0454f8f9561ab104086624bfa37ff64f088 Mon Sep 17 00:00:00 2001 From: Felix Hamann Date: Wed, 13 Feb 2019 20:47:33 +0100 Subject: [PATCH 6/6] fix errors in alerts.js --- static/js/utils/alerts.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/static/js/utils/alerts.js b/static/js/utils/alerts.js index 980cb955c..eec2fb73a 100644 --- a/static/js/utils/alerts.js +++ b/static/js/utils/alerts.js @@ -11,7 +11,7 @@ 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 ALERT_AUTOCLOSING_MATCHER = '.alert-info, .alert-success'; var JS_INITIALIZED_CLASS = 'js-initialized'; @@ -71,11 +71,11 @@ } var alertsHidden = alertElements.reduce(function(acc, alert) { - return acc || alert.classList.contains(ALERT_INVISIBLE_CLASS); - }, false); + return acc && alert.classList.contains(ALERT_INVISIBLE_CLASS); + }, true); window.setTimeout(function() { - toggler.classList.toggle(ALERTS_TOGGLER_VISIBLE_CLASS, alertsHidden); + togglerEl.classList.toggle(ALERTS_TOGGLER_VISIBLE_CLASS, alertsHidden); togglerCheckRequested = false; }, ALERTS_TOGGLER_APPEAR_DELAY); }