diff --git a/src/Handler/Course.hs b/src/Handler/Course.hs index 47240a3ed..5e09e2b7e 100644 --- a/src/Handler/Course.hs +++ b/src/Handler/Course.hs @@ -59,7 +59,7 @@ colDescription = sortable Nothing (i18nCell MsgCourseDescription) $ \DBRow{ dbrOutput=(Entity cid Course{..}, _, _, _) } -> case courseDescription of Nothing -> mempty - (Just descr) -> cell $ modalStatic descr + (Just descr) -> cell $ modal "Beschreibung" (Right $ toWidget descr) colCShort :: IsDBTable m a => Colonnade _ CourseTableData (DBCell m a) colCShort = sortable (Just "cshort") (i18nCell MsgCourseShort) @@ -73,7 +73,11 @@ colCShortDescr = sortable (Just "cshort") (i18nCell MsgCourseShort) ( case courseDescription of Nothing -> mempty (Just descr) -> cell - [whamlet| ^{modalStatic descr} |] + [whamlet| + $newline never + + ^{modal "Beschreibung" (Right $ toWidget descr)} + |] ) colTerm :: IsDBTable m a => Colonnade _ CourseTableData (DBCell m a) @@ -612,5 +616,3 @@ getCUserR tid ssh csh uuid = do getCHiWisR :: TermId -> SchoolId -> CourseShorthand -> Handler Html getCHiWisR tid ssh csh = undefined -- TODO - - diff --git a/src/Handler/Profile.hs b/src/Handler/Profile.hs index 1eec221fe..867e69149 100644 --- a/src/Handler/Profile.hs +++ b/src/Handler/Profile.hs @@ -185,17 +185,19 @@ getProfileDataR = do -- TODO: move this into a Message and/or Widget-File let delWdgt = [whamlet|
-
+

+ Sind Sie sich absolut sicher, alle Ihre in Uni2work gespeicherten Daten zu löschen? +
Während der Testphase von Uni2work können Sie hiermit Ihren Account bei Uni2work vollständig löschen. Mit Ihrem Campus-Account können Sie sich aber danach jederzeit erneut einloggen, wodurch wieder ein leerer Account erstellt wird. -
+
Hochgeladene Hausaufgaben-Dateien werden unabhhängig vom Urherber nur dann gelöscht, wenn die Dateien ausschließlich Ihnen zugeordnet sind. Dateien aus Gruppenabgaben werden also erst dann gelöscht, wenn alle Gruppenmitglieder Ihren Account gelöscht haben. -
+
Achtung: Auch abgegebene Hausübungen werden gelöscht! Falls ein Veranstalter Informationen darüber nicht anderweitig gespeichert hat, @@ -203,13 +205,12 @@ getProfileDataR = do (Verbuchte Noten sollten dadurch nicht betroffen sein, aber in einem etwaigen Streitfall konnen die per Uni2work verwalteten Hausaufgaben dann auch nicht mehr rekonstruiert/berücksichtigt werden.) -
+
Nach der Testphase von Uni2work wird das Löschen eines Accounts etwas eingeschränkt werden, da z.B. Klausurnoten 5 Jahre bis nach Exmatrikulation aufbewahrt werden müssen. -
- Sind Sie sich absolut sicher, alle Ihre in Uni2work gespeicherten Daten zu löschen? -
^{btnWdgt} +
+ ^{btnWdgt} |] defaultLayout $ do $(widgetFile "profileData") diff --git a/src/Handler/Sheet.hs b/src/Handler/Sheet.hs index 67d119c10..510e92117 100644 --- a/src/Handler/Sheet.hs +++ b/src/Handler/Sheet.hs @@ -31,7 +31,7 @@ import Handler.Utils.Table.Cells -- import Colonnade hiding (fromMaybe, singleton, bool) import qualified Yesod.Colonnade as Yesod import Text.Blaze (text) --- +-- -- import qualified Data.UUID.Cryptographic as UUID import qualified Data.Conduit.List as C @@ -451,7 +451,7 @@ handleSheetEdit tid ssh csh msId template dbAction = do whenIsJust sfSolutionF $ insertSheetFile' sid SheetSolution whenIsJust sfMarkingF $ insertSheetFile' sid SheetMarking insert_ $ SheetEdit aid actTime sid - addMessageI Info $ MsgSheetEditOk tid ssh csh sfName + addMessageI Success $ MsgSheetEditOk tid ssh csh sfName -- Sanity checks generating warnings only, but not errors! warnTermDays tid [sfVisibleFrom, Just sfActiveFrom, Just sfActiveTo, sfHintFrom, sfSolutionFrom] return True @@ -522,7 +522,7 @@ insertSheetFile' sid ftype fs = do fid <- insert file void . insert $ SheetFile sid fid ftype -- cannot fail due to uniqueness, since we generated a fresh FileId in the previous step - + data CorrectorForm = CorrectorForm { cfUserId :: UserId , cfUserName :: Text @@ -547,9 +547,9 @@ defaultLoads shid = do return . E.min_ $ sheetEdit E.^. SheetEditTime E.where_ $ sheet E.^. SheetCourse E.==. E.val cId - + E.orderBy [E.desc creationTime] - + return (sheetCorrector E.^. SheetCorrectorUser, sheetCorrector E.^. SheetCorrectorLoad, sheetCorrector E.^. SheetCorrectorState) where toMap :: [(E.Value UserId, E.Value Load, E.Value CorrectorState)] -> Loads @@ -616,11 +616,11 @@ correctorForm shid = do _ -> return loads'' let deletions' = deletions `Set.difference` Map.keysSet loads - + names <- fmap (Map.fromList . map (\(E.Value a, E.Value b) -> (a, b))) . lift . runDB . E.select . E.from $ \user -> do E.where_ $ user E.^. UserId `E.in_` E.valList (Map.keys loads) return $ (user E.^. UserId, user E.^. UserDisplayName) - + let constructFields :: (UserId, Text, (CorrectorState, Load)) -> MForm Handler CorrectorForm constructFields (uid, uname, (state, Load{..})) = do @@ -691,7 +691,7 @@ correctorForm shid = do |] } ]) - + -- Eingabebox für Korrektor hinzufügen -- Eingabe für Korrekt ausgefüllt: FormMissing zurückschicken um dann Feld hinzuzufügen diff --git a/src/Handler/Utils/Table/Cells.hs b/src/Handler/Utils/Table/Cells.hs index 0b74f7e01..65bc11452 100644 --- a/src/Handler/Utils/Table/Cells.hs +++ b/src/Handler/Utils/Table/Cells.hs @@ -76,7 +76,11 @@ courseCell (Course {..}) = anchorCell link name `mappend` desc name = citext2widget courseName desc = case courseDescription of Nothing -> mempty - (Just descr) -> cell [whamlet| ^{modalStatic descr} |] + (Just descr) -> cell [whamlet| + $newline never + + ^{modal "Beschreibung" (Right $ toWidget descr)} + |] sheetCell :: IsDBTable m a => CourseLink -> SheetName -> DBCell m a sheetCell crse shn = diff --git a/src/Handler/Utils/Templates.hs b/src/Handler/Utils/Templates.hs index 810ea8472..57ab0f1d6 100644 --- a/src/Handler/Utils/Templates.hs +++ b/src/Handler/Utils/Templates.hs @@ -2,39 +2,19 @@ module Handler.Utils.Templates where +import Data.Either (isLeft) + import Import.NoFoundation lipsum :: WidgetT site IO () lipsum = $(widgetFile "widgets/lipsum") -modalStatic :: Html -> WidgetT site IO () -modalStatic modalContent = do - uniqueId <- newIdent - let modalTrigger = cons '#' uniqueId -- SJ: I am confused why this is needed here? - modalId :: Int32 - modalId = 13 - $(widgetFile "widgets/modalStatic") - [whamlet|
?|] -- SJ: confused why ## is needed here either? - -modalWidget :: Html -> WidgetT site IO () -> WidgetT site IO () -modalWidget modalTrigger modalContent = do - uniqueId <- newIdent - let modalTriggerId = cons '#' uniqueId -- SJ: I am confused why this is needed here? - modalId :: Int32 - modalId = 13 - $(widgetFile "widgets/modalWidget") - [whamlet|
#{modalTrigger}|] -- SJ: confused why ## is needed here either? - -modal :: Text -> Maybe [Char] -> WidgetT site IO () -modal modalTrigger (Just modalContent) = do -- WARNING: ModalContent should not have length 11. SJ: This is possibly bad. See Template! - let - modalId :: Int32 - modalId = 13 - $(widgetFile "widgets/modal") -modal modalTrigger Nothing = do - let - modalId :: Int32 - modalId = 13 - modalContent :: [Char] - modalContent = "placeholder" +modal :: WidgetT site IO () -> Either (Route site) (WidgetT site IO ()) -> WidgetT site IO () +modal modalTrigger modalContent = do + let modalDynamic = isLeft modalContent + modalId <- newIdent + triggerId <- newIdent $(widgetFile "widgets/modal") + case modalContent of + Left route -> [whamlet|^{modalTrigger}|] + Right content -> [whamlet|
^{modalTrigger}|] diff --git a/src/Utils/PathPiece.hs b/src/Utils/PathPiece.hs index cff91d976..0aa1a364c 100644 --- a/src/Utils/PathPiece.hs +++ b/src/Utils/PathPiece.hs @@ -44,6 +44,8 @@ splitCamel = map fromList . reverse . helper (error "hasChange undefined at star | sameCategory w c , null ws' = helper (Char.isLower w) items (c:ws) cs | sameCategory w c = helper hadChange items (c:ws) cs + | Char.isLower w + , Char.isUpper c = helper True (reverse ws :items) [c] cs | null ws' = helper True items (c:ws) cs | not hadChange = helper True (reverse ws':items) [c,w] cs | otherwise = helper True (reverse ws :items) [c] cs diff --git a/templates/adminTest.hamlet b/templates/adminTest.hamlet index ea27a3906..651d6b6e0 100644 --- a/templates/adminTest.hamlet +++ b/templates/adminTest.hamlet @@ -22,7 +22,6 @@
  • Kurse anlegen -

    Funktionen zum Testen @@ -33,9 +32,5 @@ ^{btnWdgt}

  • Modals: - ^{modal ".toggler1" Nothing} -
    Klick mich für Ajax-Test - - ^{modal ".toggler2" (Just "Test Inhalt für Modal")} -
    Klick mich für Content-Test - + ^{modal "Klick mich für Ajax-Test" (Left UsersR)} + ^{modal "Klick mich für Content-Test" (Right "Test Inhalt für Modal")} diff --git a/templates/default-layout-wrapper.hamlet b/templates/default-layout-wrapper.hamlet index 3eba4f9f1..014edc30f 100644 --- a/templates/default-layout-wrapper.hamlet +++ b/templates/default-layout-wrapper.hamlet @@ -7,38 +7,11 @@ $newline never - #{pageTitle pc} - <meta name="description" content=""> - <meta name="author" content=""> - <meta name="viewport" content="width=device-width,initial-scale=1"> ^{pageHead pc} - \<!--[if lt IE 9]> - \<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> - \<![endif]--> - <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.0.3/js.cookie.min.js"> - <script> - /* The `defaultCsrfMiddleware` Middleware added in Foundation.hs adds a CSRF token to the request cookies. */ - /* AJAX requests should add that token to a header to be validated by the server. */ - /* See the CSRF documentation in the Yesod.Core.Handler module of the yesod-core package for details. */ - var csrfHeaderName = "#{TE.decodeUtf8 $ CI.foldedCase defaultCsrfHeaderName}"; - - var csrfCookieName = "#{TE.decodeUtf8 defaultCsrfCookieName}"; - var csrfToken = Cookies.get(csrfCookieName); - - - if (csrfToken) { - \ $.ajaxPrefilter(function( options, originalOptions, jqXHR ) { - \ if (!options.crossDomain) { - \ jqXHR.setRequestHeader(csrfHeaderName, csrfToken); - \ } - \ }); - } - - <body .no-js .theme--#{toPathPiece currentTheme} :isAuth:.logged-in> <!-- removes no-js class from body if client supports javascript --> <script> diff --git a/templates/default-layout.lucius b/templates/default-layout.lucius index 34285a821..97968130e 100644 --- a/templates/default-layout.lucius +++ b/templates/default-layout.lucius @@ -113,7 +113,7 @@ a:hover { ul { - list-style-type: none; + margin-left: 20px; } h1, h2, h3, h4, h5 { @@ -424,8 +424,17 @@ input[type="button"].btn-info:hover, } /* LIST MODIFIERS */ -.list--inline li { - display: inline-block; +.list--iconless { + list-style-type: none; + margin-left: 0; +} + +.list--inline { + margin-left: 0; + + li { + display: inline-block; + } } .list--comma-separated li { diff --git a/templates/multiFileField.hamlet b/templates/multiFileField.hamlet index 62123a11e..649a9b47e 100644 --- a/templates/multiFileField.hamlet +++ b/templates/multiFileField.hamlet @@ -16,5 +16,5 @@ $# new files <label for=#{fieldId}_zip>ZIPs automatisch entpacken <input type=checkbox id=#{fieldId}_zip name=#{fieldName} value=#{unpackZips}> <div class="js-tooltip"> - <div class="tooltip__handle">? + <div class="tooltip__handle"> <div class="tooltip__content">Entpackt hochgeladene Zip-Dateien (*.zip) automatisch und fügt den Inhalt dem Stamm-Verzeichnis der Abgabe hinzu. diff --git a/templates/profileData.hamlet b/templates/profileData.hamlet index 5b6726cf1..8d2b42a71 100644 --- a/templates/profileData.hamlet +++ b/templates/profileData.hamlet @@ -51,7 +51,7 @@ . <h2> - ^{modalWidget "Alle Benutzerbezogenen Daten löschen" delWdgt} + ^{modal "Alle Benutzerbezogenen Daten löschen" (Right delWdgt)} <p> <h4>Hinweise: <ul> diff --git a/templates/standalone/alerts.julius b/templates/standalone/alerts.julius index 28b3f7c29..a07a002e6 100644 --- a/templates/standalone/alerts.julius +++ b/templates/standalone/alerts.julius @@ -3,25 +3,75 @@ window.utils = window.utils || {}; - window.utils.alert = function(alertEl) { - var closeEl = document.createElement('DIV'); - var dataDecay = alertEl.dataset.decay; - var autoDecay = 30; - if (dataDecay) { - autoDecay = parseInt(dataDecay, 10); - } - closeEl.classList.add('alert__close'); - closeEl.addEventListener('click', function(event) { - alertEl.classList.add('alert--invisible'); - }); - alertEl.insertBefore(closeEl, alertEl.children[0]); + var ALERT_INVISIBLE_CLASS = 'alert--invisible'; + var TOGGLER_INVISIBLE_CLASS = 'alerts__toggler--visible'; - // auto-hide info and success-alerts after 3 seconds - if (autoDecay > 0 && !alertEl.matches('.alert-danger, .alert-warning')) { - window.setTimeout(function() { - alertEl.classList.add('alert--invisible'); - }, autoDecay * 1000); + window.utils.alerts = function(alertsEl) { + + var alerts = Array.from(alertsEl.querySelectorAll('.alert')); + var toggler; + var showingToggler = false; + + function makeToggler() { + toggler = document.createElement('DIV'); + toggler.classList.add('alerts__toggler'); + toggler.addEventListener('click', function() { + alerts.forEach(function(alert) { + alert.classList.remove(ALERT_INVISIBLE_CLASS); + toggler.classList.remove(TOGGLER_INVISIBLE_CLASS); + }); + checkToggler(); + }); + alertsEl.appendChild(toggler); } + + function makeAlert(alertEl) { + var iconEl = document.createElement('DIV'); + var closeEl = document.createElement('DIV'); + var dataDecay = alertEl.dataset.decay; + var autoDecay = 30; + 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); + } + } + + function closeAlert(alertEl) { + alertEl.classList.add(ALERT_INVISIBLE_CLASS); + checkToggler(); + } + + function checkToggler() { + var hidden = true; + alerts.forEach(function(alert) { + if (hidden && !alert.classList.contains(ALERT_INVISIBLE_CLASS)) { + hidden = false; + } + }); + if (!showingToggler) { + showingToggler = true; + window.setTimeout(function() { + toggler.classList.toggle(TOGGLER_INVISIBLE_CLASS, hidden); + showingToggler = false; + }, 120); + } + } + + makeToggler(); + alerts.map(makeAlert); } })(); @@ -29,7 +79,5 @@ document.addEventListener('DOMContentLoaded', function() { // setup alerts - Array.from(document.querySelectorAll('.alert')).forEach(function(alertEl) { - window.utils.alert(alertEl); - }); + window.utils.alerts(document.querySelector('.alerts')); }); diff --git a/templates/standalone/alerts.lucius b/templates/standalone/alerts.lucius index 9501f1329..c1660b903 100644 --- a/templates/standalone/alerts.lucius +++ b/templates/standalone/alerts.lucius @@ -3,100 +3,152 @@ .alert Regular Info Alert Disappears automatically after 30 seconds - Disappears after x seconds if explicitly specified via data-decay='x' on html element + Disappears after x seconds if explicitly specified via data-decay='x' Can be told not to disappear with data-decay='0' - .alert-warning, .alert-error - Warning or Error alert - These don't disappear, only difference is color - .alert-warning is orange regardless of user's selected theme - .alert-error is red regardless of user's selected theme + .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: 5%; - right: 0; + 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; + + &::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-lightblack); + font-size: 30px; + transform: translateX(-50%); + } +} + +.alerts__toggler--visible { + top: -40px; + opacity: 1; + transition: top .5s cubic-bezier(0.73, 1.25, 0.61, 1), + opacity .5s cubic-bezier(0.73, 1.25, 0.61, 1); +} + +@media (max-width: 425px) { + + .alerts { + left: 5%; + } +} + .alert { position: relative; - display: inline-block; - background-color: var(--color-dark); + display: block; + background-color: var(--color-lightblack); font-size: 1rem; color: var(--color-lightwhite); z-index: 0; - max-height: 200px; - transition: all .3s ease-in-out; - padding-left: 20px; - margin-left: 20px; + padding: 0 50px; + padding-right: 60px; animation: slide-in-alert .2s ease-out forwards; - margin-bottom: 20px; - - &:hover { - - .alert__content { - - &::after { - opacity: 1; - } - } - } + margin-bottom: 10px; + transition: margin-bottom .2s ease-out; } @keyframes slide-in-alert { from { - left: 120%; + transform: translateY(120%); } to { - left: 0; + 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 { - margin-left: 80px; - max-width: 420px; + max-width: 400px; } } -@media (min-width: 768px) { - - .alert { - padding-left: 30px; - margin-left: 40px; - min-width: 400px; - } -} - -@media (min-width: 1024px) { - - .alert { - min-width: 350px; - } +.alert--invisible { + animation: slide-out-alert .2s ease-out forwards; + margin-bottom: 0; } .alert__content { - padding: 8px 1.5em; + padding: 8px 0; min-height: 40px; position: relative; display: flex; font-weight: 600; - justify-content: flex-end; align-items: center; text-align: left; } -@media (max-width: 768px) { +.alert__icon { + text-align: right; + position: absolute; + left: 0px; + top: 0; + width: 50px; + height: 100%; + z-index: 40; - .alert__content { - padding: 4px 7px; - padding-left: 25px; + &::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; } } @@ -104,7 +156,7 @@ cursor: pointer; text-align: right; position: absolute; - left: 0px; + right: 0px; top: 0; width: 60px; height: 100%; @@ -145,18 +197,26 @@ } } +.alert-success { + background-color: var(--color-success); + + .alert__icon::before { + content: '\f058'; + } +} + .alert-warning { background-color: var(--color-warning); + + .alert__icon::before { + content: '\f06a'; + } } -.alert-danger, .alert-error { background-color: var(--color-error); -} -.alert--invisible { - max-height: 0; - transform: translateX(120%); - margin-bottom: 0; - overflow: hidden; + .alert__icon::before { + content: '\f071'; + } } diff --git a/templates/standalone/inputs.lucius b/templates/standalone/inputs.lucius index ad6771a38..470efdb1b 100644 --- a/templates/standalone/inputs.lucius +++ b/templates/standalone/inputs.lucius @@ -30,6 +30,16 @@ } } +.form-group--submit .form-group__input { + grid-column: 2; +} + +@media (max-width: 768px) { + .form-group--submit .form-group__input { + grid-column: 1; + } +} + .form-group--has-error { background-color: rgba(255, 0, 0, 0.1); @@ -187,6 +197,7 @@ input[type="checkbox"]:checked::after { .checkbox, .radio { position: relative; + display: inline-block; [type="checkbox"], [type="radio"] { diff --git a/templates/standalone/modal.julius b/templates/standalone/modal.julius index 01a564ca4..8bac72f12 100644 --- a/templates/standalone/modal.julius +++ b/templates/standalone/modal.julius @@ -6,12 +6,11 @@ window.utils.modal = function(modal) { var overlay = document.createElement('div'); var closer = document.createElement('div'); - var trigger = document.querySelector(modal.dataset.trigger); + var trigger = document.querySelector('#' + modal.dataset.trigger); var origParent = modal.parentNode; function open(event) { // disable modals for narrow screens - if (window.innerWidth < 768) return true; if (event) { event.preventDefault(); } @@ -20,7 +19,6 @@ document.body.insertBefore(modal, null); document.body.insertBefore(overlay, modal); overlay.classList.add('modal__overlay--open'); - toggleScroll(false); if (modal.dataset.closeable === 'true') { closer.classList.add('modal__closer'); @@ -30,8 +28,8 @@ } } - // open this modal with an event: - // document.dispatchEvent(new CustomEvent('modal-open', { dateils: {for: 'modal-13'}})) + // you can open this modal via event + // example: document.dispatchEvent(new CustomEvent('modal-open', { details: { for: 'modal-[id]' }})) function openOnEvent(event) { if (event.detail.for === modal.getAttribute('id')) { open(); @@ -43,7 +41,6 @@ overlay.remove(); origParent.insertBefore(modal, null); modal.classList.remove('modal--open'); - toggleScroll(true); closer.removeEventListener('click', close, false); } }; @@ -56,27 +53,20 @@ trigger.classList.add('modal__trigger'); trigger.addEventListener('click', open, false); } - // if there is no content specified for the modal we assume that - // the content is supposed to be the page the trigger links to. - // so we check if the trigger has a href-attribute, fetch that page - // and replace the modal content with the response - var replaceMe = modal.querySelector('.replace-me'); - var replaceWith = trigger ? trigger.getAttribute('href') : ''; - if (replaceMe) { - replaceMe.classList.remove('replace-me'); - replaceMe.innerText = '...loading'; - if (replaceWith.length > 0) { - fetch(replaceWith, { - credentials: 'same-origin' + + if (modal.dataset.dynamic === 'True') { + var dynamicContentURL = trigger.getAttribute('href'); + if (dynamicContentURL.length > 0) { + fetch(dynamicContentURL, { + credentials: 'same-origin', }).then(function(response) { return response.text(); }).then(function(body) { var modalContent = document.createElement('div'); modalContent.innerHTML = body; - var main = modalContent.querySelector('.main__content'); + var main = modalContent.querySelector('.main__content-body'); if (main) { - replaceMe.innerText = ''; - replaceMe.insertBefore(main, null); + modal.appendChild(main); } else { replaceMe.innerHTML = body; } @@ -88,11 +78,6 @@ } setup(); }; - - // make sure document doesn't scroll when modal is active - function toggleScroll(scrollable) { - document.body.classList.toggle('no-scroll', !scrollable); - } })(); document.addEventListener('DOMContentLoaded', function() { diff --git a/templates/standalone/modal.lucius b/templates/standalone/modal.lucius index 2ccec226b..589083ece 100644 --- a/templates/standalone/modal.lucius +++ b/templates/standalone/modal.lucius @@ -4,14 +4,15 @@ top: 50%; transform: translate(-50%, -50%) scale(0.8, 0.8); display: block; - background-color: rgba(255, 255, 255, 0.9); + background-color: rgba(255, 255, 255, 0.99); min-width: 60vw; min-height: 100px; max-height: calc(100vh - 30px); - border-radius: 7px; + border-radius: 2px; z-index: -1; color: var(--color-font); padding: 20px; + padding-right: 65px; overflow: auto; opacity: 0; transition: all .15s ease; @@ -81,7 +82,3 @@ color: white; } } - -.no-scroll { - overflow: hidden; -} diff --git a/templates/standalone/tooltip.lucius b/templates/standalone/tooltip.lucius index 27e85f270..d85415d97 100644 --- a/templates/standalone/tooltip.lucius +++ b/templates/standalone/tooltip.lucius @@ -19,6 +19,23 @@ text-align: center; margin: 0 10px; cursor: default; + position: relative; + + &::before { + content: '\f128'; + position: absolute; + top: 0; + left: 0; + font-family: "Font Awesome 5 Free"; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 15px; + } + + &:hover { + background-color: var(--color-light); + } } .tooltip__content { diff --git a/templates/widgets/asidenav.hamlet b/templates/widgets/asidenav.hamlet index 346b356f5..f75a8f162 100644 --- a/templates/widgets/asidenav.hamlet +++ b/templates/widgets/asidenav.hamlet @@ -9,13 +9,13 @@ $newline never _{MsgWinterTermShort year} $of Summer _{MsgSummerTermShort year} - <ul .asidenav__list.js-show-hide__target> + <ul .asidenav__list.js-show-hide__target.list--iconless> $forall (Course{..}, courseRoute, pageActions) <- favouriteTerm tid <li .asidenav__list-item :highlight courseRoute:.asidenav__list-item--active> <a .asidenav__link-wrapper href=@{courseRoute}> <div .asidenav__link-shorthand>#{courseShorthand} <div .asidenav__link-label>#{courseName} - <ul .asidenav__nested-list> + <ul .asidenav__nested-list.list--iconless> $forall action <- pageActions $case action $of PageActionPrime (MenuItem{..}) diff --git a/templates/widgets/form.hamlet b/templates/widgets/form.hamlet index a28adabf4..2c0cfc9b8 100644 --- a/templates/widgets/form.hamlet +++ b/templates/widgets/form.hamlet @@ -3,6 +3,7 @@ $newline never $case formLayout $of FormStandard $forall view <- views + $# TODO: add class 'form-group--submit' if this is the submit-button view <div .form-group :fvRequired view:.form-group--required :not $ fvRequired view:.form-group--optional :isJust $ fvErrors view:.form-group--has-error> $if not (Blaze.null $ fvLabel view) <label .form-group__label for=#{fvId view}>#{fvLabel view} @@ -10,5 +11,5 @@ $case formLayout ^{fvInput view} $maybe tooltip <- fvTooltip view <div .js-tooltip> - <div .tooltip__handle>? + <div .tooltip__handle> <div .tooltip__content>^{tooltip} diff --git a/templates/widgets/modal.hamlet b/templates/widgets/modal.hamlet index 9dc569101..a971aab83 100644 --- a/templates/widgets/modal.hamlet +++ b/templates/widgets/modal.hamlet @@ -1,8 +1,5 @@ -<div .modal.js-modal #modal-#{modalId} data-trigger=#{modalTrigger} data-closeable=true> - $# primitive way of checking if this is supposed to be add a placeholder for async data. - $# modalContent is 'placeholder' if there should be a placeholder only. - $# 'placeholder' has length 11. - $if 11 == length modalContent - <div .replace-me> - $else - #{modalContent} +<div .modal.js-modal #modal-#{modalId} data-trigger=#{triggerId} data-closeable=true data-dynamic=#{modalDynamic}> + $case modalContent + $of Right content + ^{content} + $of Left _ diff --git a/templates/widgets/modalStatic.hamlet b/templates/widgets/modalStatic.hamlet deleted file mode 100644 index a9b8e3587..000000000 --- a/templates/widgets/modalStatic.hamlet +++ /dev/null @@ -1,2 +0,0 @@ -<div .modal.js-modal #modal-#{modalId} data-trigger=#{modalTrigger} data-closeable=true> - #{modalContent} diff --git a/templates/widgets/modalWidget.hamlet b/templates/widgets/modalWidget.hamlet deleted file mode 100644 index e80516d1f..000000000 --- a/templates/widgets/modalWidget.hamlet +++ /dev/null @@ -1,2 +0,0 @@ -<div .modal.js-modal #modal-#{modalId} data-trigger=#{modalTriggerId} data-closeable=true> - ^{modalContent} diff --git a/templates/widgets/navbar.lucius b/templates/widgets/navbar.lucius index 43e895c40..81200d4e8 100644 --- a/templates/widgets/navbar.lucius +++ b/templates/widgets/navbar.lucius @@ -41,7 +41,7 @@ background: linear-gradient(to top, var(--color-dark) 0%,var(--color-darker) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ color: white; margin-right: 40px; - z-index: 10; + z-index: 20; box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); overflow: auto; transition: all .2s cubic-bezier(0.03, 0.43, 0.58, 1); diff --git a/templates/widgets/pageactionprime.lucius b/templates/widgets/pageactionprime.lucius index 7694e55d0..5dba2f4c4 100644 --- a/templates/widgets/pageactionprime.lucius +++ b/templates/widgets/pageactionprime.lucius @@ -6,6 +6,7 @@ .pagenav__list { display: block; + margin-left: 0; } .pagenav__list-item {