Merge remote-tracking branch 'origin/master' into feat/jobs
This commit is contained in:
commit
0ca12cecdb
@ -59,7 +59,7 @@ colDescription = sortable Nothing (i18nCell MsgCourseDescription)
|
|||||||
$ \DBRow{ dbrOutput=(Entity cid Course{..}, _, _, _) } ->
|
$ \DBRow{ dbrOutput=(Entity cid Course{..}, _, _, _) } ->
|
||||||
case courseDescription of
|
case courseDescription of
|
||||||
Nothing -> mempty
|
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 :: IsDBTable m a => Colonnade _ CourseTableData (DBCell m a)
|
||||||
colCShort = sortable (Just "cshort") (i18nCell MsgCourseShort)
|
colCShort = sortable (Just "cshort") (i18nCell MsgCourseShort)
|
||||||
@ -73,7 +73,11 @@ colCShortDescr = sortable (Just "cshort") (i18nCell MsgCourseShort)
|
|||||||
( case courseDescription of
|
( case courseDescription of
|
||||||
Nothing -> mempty
|
Nothing -> mempty
|
||||||
(Just descr) -> cell
|
(Just descr) -> cell
|
||||||
[whamlet|<span style="float:right"> ^{modalStatic descr} |]
|
[whamlet|
|
||||||
|
$newline never
|
||||||
|
<span style="float:right">
|
||||||
|
^{modal "Beschreibung" (Right $ toWidget descr)}
|
||||||
|
|]
|
||||||
)
|
)
|
||||||
|
|
||||||
colTerm :: IsDBTable m a => Colonnade _ CourseTableData (DBCell m a)
|
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 :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
||||||
getCHiWisR tid ssh csh = undefined -- TODO
|
getCHiWisR tid ssh csh = undefined -- TODO
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -176,14 +176,15 @@ getProfileDataR = do
|
|||||||
-- TODO: move this into a Message and/or Widget-File
|
-- TODO: move this into a Message and/or Widget-File
|
||||||
let delWdgt = [whamlet|
|
let delWdgt = [whamlet|
|
||||||
<form .form-inline method=post action=@{ProfileDataR} enctype=#{btnEnctype}>
|
<form .form-inline method=post action=@{ProfileDataR} enctype=#{btnEnctype}>
|
||||||
<div>Sind Sie sich absolut sicher, alle gespeicherten Daten zu löschen?
|
<h2>Sind Sie sich absolut sicher, alle gespeicherten Daten zu löschen?
|
||||||
|
<div .container>
|
||||||
Abgegebene Hausaufgaben werden dadurch rückwirkend gelöscht,
|
Abgegebene Hausaufgaben werden dadurch rückwirkend gelöscht,
|
||||||
wodurch eventuell ein Klausurbonus nicht mehr anerkannt wird.
|
wodurch eventuell ein Klausurbonus nicht mehr anerkannt wird.
|
||||||
<div>
|
<div .container>
|
||||||
<em>Gilt nicht in der Testphase von Uni2work:
|
<em>Gilt nicht in der Testphase von Uni2work:
|
||||||
Klausurnoten können Sie hiermit nicht löschen.
|
Klausurnoten können Sie hiermit nicht löschen.
|
||||||
Da diese 5 Jahre bis nach Ihrer Exmatrikulation aufbewahrt werden müssen.
|
Da diese 5 Jahre bis nach Ihrer Exmatrikulation aufbewahrt werden müssen.
|
||||||
<div>^{btnWdgt}
|
<div .container>^{btnWdgt}
|
||||||
|]
|
|]
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
$(widgetFile "profileData")
|
$(widgetFile "profileData")
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import Handler.Utils.Table.Cells
|
|||||||
-- import Colonnade hiding (fromMaybe, singleton, bool)
|
-- import Colonnade hiding (fromMaybe, singleton, bool)
|
||||||
import qualified Yesod.Colonnade as Yesod
|
import qualified Yesod.Colonnade as Yesod
|
||||||
import Text.Blaze (text)
|
import Text.Blaze (text)
|
||||||
--
|
--
|
||||||
-- import qualified Data.UUID.Cryptographic as UUID
|
-- import qualified Data.UUID.Cryptographic as UUID
|
||||||
import qualified Data.Conduit.List as C
|
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 sfSolutionF $ insertSheetFile' sid SheetSolution
|
||||||
whenIsJust sfMarkingF $ insertSheetFile' sid SheetMarking
|
whenIsJust sfMarkingF $ insertSheetFile' sid SheetMarking
|
||||||
insert_ $ SheetEdit aid actTime sid
|
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!
|
-- Sanity checks generating warnings only, but not errors!
|
||||||
warnTermDays tid [sfVisibleFrom, Just sfActiveFrom, Just sfActiveTo, sfHintFrom, sfSolutionFrom]
|
warnTermDays tid [sfVisibleFrom, Just sfActiveFrom, Just sfActiveTo, sfHintFrom, sfSolutionFrom]
|
||||||
return True
|
return True
|
||||||
@ -522,7 +522,7 @@ insertSheetFile' sid ftype fs = do
|
|||||||
fid <- insert file
|
fid <- insert file
|
||||||
void . insert $ SheetFile sid fid ftype -- cannot fail due to uniqueness, since we generated a fresh FileId in the previous step
|
void . insert $ SheetFile sid fid ftype -- cannot fail due to uniqueness, since we generated a fresh FileId in the previous step
|
||||||
|
|
||||||
|
|
||||||
data CorrectorForm = CorrectorForm
|
data CorrectorForm = CorrectorForm
|
||||||
{ cfUserId :: UserId
|
{ cfUserId :: UserId
|
||||||
, cfUserName :: Text
|
, cfUserName :: Text
|
||||||
@ -547,9 +547,9 @@ defaultLoads shid = do
|
|||||||
return . E.min_ $ sheetEdit E.^. SheetEditTime
|
return . E.min_ $ sheetEdit E.^. SheetEditTime
|
||||||
|
|
||||||
E.where_ $ sheet E.^. SheetCourse E.==. E.val cId
|
E.where_ $ sheet E.^. SheetCourse E.==. E.val cId
|
||||||
|
|
||||||
E.orderBy [E.desc creationTime]
|
E.orderBy [E.desc creationTime]
|
||||||
|
|
||||||
return (sheetCorrector E.^. SheetCorrectorUser, sheetCorrector E.^. SheetCorrectorLoad, sheetCorrector E.^. SheetCorrectorState)
|
return (sheetCorrector E.^. SheetCorrectorUser, sheetCorrector E.^. SheetCorrectorLoad, sheetCorrector E.^. SheetCorrectorState)
|
||||||
where
|
where
|
||||||
toMap :: [(E.Value UserId, E.Value Load, E.Value CorrectorState)] -> Loads
|
toMap :: [(E.Value UserId, E.Value Load, E.Value CorrectorState)] -> Loads
|
||||||
@ -616,11 +616,11 @@ correctorForm shid = do
|
|||||||
_ -> return loads''
|
_ -> return loads''
|
||||||
|
|
||||||
let deletions' = deletions `Set.difference` Map.keysSet 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
|
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)
|
E.where_ $ user E.^. UserId `E.in_` E.valList (Map.keys loads)
|
||||||
return $ (user E.^. UserId, user E.^. UserDisplayName)
|
return $ (user E.^. UserId, user E.^. UserDisplayName)
|
||||||
|
|
||||||
let
|
let
|
||||||
constructFields :: (UserId, Text, (CorrectorState, Load)) -> MForm Handler CorrectorForm
|
constructFields :: (UserId, Text, (CorrectorState, Load)) -> MForm Handler CorrectorForm
|
||||||
constructFields (uid, uname, (state, Load{..})) = do
|
constructFields (uid, uname, (state, Load{..})) = do
|
||||||
@ -691,7 +691,7 @@ correctorForm shid = do
|
|||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
-- Eingabebox für Korrektor hinzufügen
|
-- Eingabebox für Korrektor hinzufügen
|
||||||
-- Eingabe für Korrekt ausgefüllt: FormMissing zurückschicken um dann Feld hinzuzufügen
|
-- Eingabe für Korrekt ausgefüllt: FormMissing zurückschicken um dann Feld hinzuzufügen
|
||||||
|
|
||||||
|
|||||||
@ -76,7 +76,11 @@ courseCell (Course {..}) = anchorCell link name `mappend` desc
|
|||||||
name = citext2widget courseName
|
name = citext2widget courseName
|
||||||
desc = case courseDescription of
|
desc = case courseDescription of
|
||||||
Nothing -> mempty
|
Nothing -> mempty
|
||||||
(Just descr) -> cell [whamlet| <span style="float:right"> ^{modalStatic descr} |]
|
(Just descr) -> cell [whamlet|
|
||||||
|
$newline never
|
||||||
|
<span style="float:right">
|
||||||
|
^{modal "Beschreibung" (Right $ toWidget descr)}
|
||||||
|
|]
|
||||||
|
|
||||||
sheetCell :: IsDBTable m a => CourseLink -> SheetName -> DBCell m a
|
sheetCell :: IsDBTable m a => CourseLink -> SheetName -> DBCell m a
|
||||||
sheetCell crse shn =
|
sheetCell crse shn =
|
||||||
|
|||||||
@ -2,39 +2,19 @@
|
|||||||
|
|
||||||
module Handler.Utils.Templates where
|
module Handler.Utils.Templates where
|
||||||
|
|
||||||
|
import Data.Either (isLeft)
|
||||||
|
|
||||||
import Import.NoFoundation
|
import Import.NoFoundation
|
||||||
|
|
||||||
lipsum :: WidgetT site IO ()
|
lipsum :: WidgetT site IO ()
|
||||||
lipsum = $(widgetFile "widgets/lipsum")
|
lipsum = $(widgetFile "widgets/lipsum")
|
||||||
|
|
||||||
modalStatic :: Html -> WidgetT site IO ()
|
modal :: WidgetT site IO () -> Either (Route site) (WidgetT site IO ()) -> WidgetT site IO ()
|
||||||
modalStatic modalContent = do
|
modal modalTrigger modalContent = do
|
||||||
uniqueId <- newIdent
|
let modalDynamic = isLeft modalContent
|
||||||
let modalTrigger = cons '#' uniqueId -- SJ: I am confused why this is needed here?
|
modalId <- newIdent
|
||||||
modalId :: Int32
|
triggerId <- newIdent
|
||||||
modalId = 13
|
|
||||||
$(widgetFile "widgets/modalStatic")
|
|
||||||
[whamlet|<div .tooltip__handle ##{uniqueId}>?|] -- 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|<div .btn ##{uniqueId}>#{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"
|
|
||||||
$(widgetFile "widgets/modal")
|
$(widgetFile "widgets/modal")
|
||||||
|
case modalContent of
|
||||||
|
Left route -> [whamlet|<a .btn ##{triggerId} href=@{route}>^{modalTrigger}|]
|
||||||
|
Right content -> [whamlet|<div .btn ##{triggerId}>^{modalTrigger}|]
|
||||||
|
|||||||
@ -22,7 +22,6 @@
|
|||||||
<li .list-group-item>
|
<li .list-group-item>
|
||||||
<a href=@{CourseNewR}>Kurse anlegen
|
<a href=@{CourseNewR}>Kurse anlegen
|
||||||
|
|
||||||
<hr>
|
|
||||||
<div .container>
|
<div .container>
|
||||||
<h2>Funktionen zum Testen
|
<h2>Funktionen zum Testen
|
||||||
|
|
||||||
@ -33,12 +32,8 @@
|
|||||||
^{btnWdgt}
|
^{btnWdgt}
|
||||||
<li><br>
|
<li><br>
|
||||||
Modals:
|
Modals:
|
||||||
^{modal ".toggler1" Nothing}
|
^{modal "Klick mich für Ajax-Test" (Left UsersR)}
|
||||||
<a href=@{UsersR} .btn.toggler1>Klick mich für Ajax-Test
|
^{modal "Klick mich für Content-Test" (Right "Test Inhalt für Modal")}
|
||||||
<noscript>(Für Modals bitte JS aktivieren)</noscript>
|
|
||||||
^{modal ".toggler2" (Just "Test Inhalt für Modal")}
|
|
||||||
<div .btn.toggler2>Klick mich für Content-Test
|
|
||||||
<noscript>(Für Modals bitte JS aktivieren)</noscript>
|
|
||||||
<li>
|
<li>
|
||||||
<form method=post action=@{AdminTestR} enctype=#{emailEnctype}>
|
<form method=post action=@{AdminTestR} enctype=#{emailEnctype}>
|
||||||
^{emailWidget}
|
^{emailWidget}
|
||||||
|
|||||||
@ -7,38 +7,11 @@ $newline never
|
|||||||
<html class="no-js" lang="en"> <!--<![endif]-->
|
<html class="no-js" lang="en"> <!--<![endif]-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
<title>#{pageTitle pc}
|
<title>#{pageTitle pc}
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="author" content="">
|
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
|
||||||
^{pageHead pc}
|
^{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>
|
<body .no-js .theme--#{toPathPiece currentTheme} :isAuth:.logged-in>
|
||||||
<!-- removes no-js class from body if client supports javascript -->
|
<!-- removes no-js class from body if client supports javascript -->
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@ -113,7 +113,7 @@ a:hover {
|
|||||||
|
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style-type: none;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3, h4, h5 {
|
h1, h2, h3, h4, h5 {
|
||||||
@ -424,8 +424,17 @@ input[type="button"].btn-info:hover,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* LIST MODIFIERS */
|
/* LIST MODIFIERS */
|
||||||
.list--inline li {
|
.list--iconless {
|
||||||
display: inline-block;
|
list-style-type: none;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list--inline {
|
||||||
|
margin-left: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.list--comma-separated li {
|
.list--comma-separated li {
|
||||||
|
|||||||
@ -16,5 +16,5 @@ $# new files
|
|||||||
<label for=#{fieldId}_zip>ZIPs automatisch entpacken
|
<label for=#{fieldId}_zip>ZIPs automatisch entpacken
|
||||||
<input type=checkbox id=#{fieldId}_zip name=#{fieldName} value=#{unpackZips}>
|
<input type=checkbox id=#{fieldId}_zip name=#{fieldName} value=#{unpackZips}>
|
||||||
<div class="js-tooltip">
|
<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.
|
<div class="tooltip__content">Entpackt hochgeladene Zip-Dateien (*.zip) automatisch und fügt den Inhalt dem Stamm-Verzeichnis der Abgabe hinzu.
|
||||||
|
|||||||
@ -51,7 +51,7 @@
|
|||||||
.
|
.
|
||||||
|
|
||||||
<h2>
|
<h2>
|
||||||
^{modalWidget "Alle Benutzerbezogenen Daten löschen" delWdgt}
|
^{modal "Alle Benutzerbezogenen Daten löschen" (Right delWdgt)}
|
||||||
<p>
|
<p>
|
||||||
<h4>Hinweise:
|
<h4>Hinweise:
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
@ -3,25 +3,75 @@
|
|||||||
|
|
||||||
window.utils = window.utils || {};
|
window.utils = window.utils || {};
|
||||||
|
|
||||||
window.utils.alert = function(alertEl) {
|
var ALERT_INVISIBLE_CLASS = 'alert--invisible';
|
||||||
var closeEl = document.createElement('DIV');
|
var TOGGLER_INVISIBLE_CLASS = 'alerts__toggler--visible';
|
||||||
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]);
|
|
||||||
|
|
||||||
// auto-hide info and success-alerts after 3 seconds
|
window.utils.alerts = function(alertsEl) {
|
||||||
if (autoDecay > 0 && !alertEl.matches('.alert-danger, .alert-warning')) {
|
|
||||||
window.setTimeout(function() {
|
var alerts = Array.from(alertsEl.querySelectorAll('.alert'));
|
||||||
alertEl.classList.add('alert--invisible');
|
var toggler;
|
||||||
}, autoDecay * 1000);
|
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() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
// setup alerts
|
// setup alerts
|
||||||
Array.from(document.querySelectorAll('.alert')).forEach(function(alertEl) {
|
window.utils.alerts(document.querySelector('.alerts'));
|
||||||
window.utils.alert(alertEl);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,100 +3,152 @@
|
|||||||
.alert
|
.alert
|
||||||
Regular Info Alert
|
Regular Info Alert
|
||||||
Disappears automatically after 30 seconds
|
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'
|
Can be told not to disappear with data-decay='0'
|
||||||
|
|
||||||
.alert-warning, .alert-error
|
.alert-success
|
||||||
Warning or Error alert
|
Disappears automatically after 30 seconds
|
||||||
These don't disappear, only difference is color
|
|
||||||
.alert-warning is orange regardless of user's selected theme
|
.alert-warning
|
||||||
.alert-error is red regardless of user's selected theme
|
Does not disappear
|
||||||
|
Orange regardless of user's selected theme
|
||||||
|
|
||||||
|
.alert-error
|
||||||
|
Does not disappear
|
||||||
|
Red regardless of user's selected theme
|
||||||
|
|
||||||
*/
|
*/
|
||||||
.alerts {
|
.alerts {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 5%;
|
bottom: 0;
|
||||||
right: 0;
|
right: 5%;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
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 {
|
.alert {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: block;
|
||||||
background-color: var(--color-dark);
|
background-color: var(--color-lightblack);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--color-lightwhite);
|
color: var(--color-lightwhite);
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
max-height: 200px;
|
padding: 0 50px;
|
||||||
transition: all .3s ease-in-out;
|
padding-right: 60px;
|
||||||
padding-left: 20px;
|
|
||||||
margin-left: 20px;
|
|
||||||
animation: slide-in-alert .2s ease-out forwards;
|
animation: slide-in-alert .2s ease-out forwards;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 10px;
|
||||||
|
transition: margin-bottom .2s ease-out;
|
||||||
&:hover {
|
|
||||||
|
|
||||||
.alert__content {
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slide-in-alert {
|
@keyframes slide-in-alert {
|
||||||
from {
|
from {
|
||||||
left: 120%;
|
transform: translateY(120%);
|
||||||
}
|
}
|
||||||
to {
|
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) {
|
@media (min-width: 425px) {
|
||||||
|
|
||||||
.alert {
|
.alert {
|
||||||
margin-left: 80px;
|
max-width: 400px;
|
||||||
max-width: 420px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
.alert--invisible {
|
||||||
|
animation: slide-out-alert .2s ease-out forwards;
|
||||||
.alert {
|
margin-bottom: 0;
|
||||||
padding-left: 30px;
|
|
||||||
margin-left: 40px;
|
|
||||||
min-width: 400px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
|
||||||
|
|
||||||
.alert {
|
|
||||||
min-width: 350px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert__content {
|
.alert__content {
|
||||||
padding: 8px 1.5em;
|
padding: 8px 0;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: left;
|
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 {
|
&::before {
|
||||||
padding: 4px 7px;
|
content: '\f05a';
|
||||||
padding-left: 25px;
|
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;
|
cursor: pointer;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0px;
|
right: 0px;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -145,18 +197,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
background-color: var(--color-success);
|
||||||
|
|
||||||
|
.alert__icon::before {
|
||||||
|
content: '\f058';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.alert-warning {
|
.alert-warning {
|
||||||
background-color: var(--color-warning);
|
background-color: var(--color-warning);
|
||||||
|
|
||||||
|
.alert__icon::before {
|
||||||
|
content: '\f06a';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-danger,
|
|
||||||
.alert-error {
|
.alert-error {
|
||||||
background-color: var(--color-error);
|
background-color: var(--color-error);
|
||||||
}
|
|
||||||
|
|
||||||
.alert--invisible {
|
.alert__icon::before {
|
||||||
max-height: 0;
|
content: '\f071';
|
||||||
transform: translateX(120%);
|
}
|
||||||
margin-bottom: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
.form-group--has-error {
|
||||||
background-color: rgba(255, 0, 0, 0.1);
|
background-color: rgba(255, 0, 0, 0.1);
|
||||||
|
|
||||||
@ -187,6 +197,7 @@ input[type="checkbox"]:checked::after {
|
|||||||
.checkbox,
|
.checkbox,
|
||||||
.radio {
|
.radio {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
[type="checkbox"],
|
[type="checkbox"],
|
||||||
[type="radio"] {
|
[type="radio"] {
|
||||||
|
|||||||
@ -6,12 +6,11 @@
|
|||||||
window.utils.modal = function(modal) {
|
window.utils.modal = function(modal) {
|
||||||
var overlay = document.createElement('div');
|
var overlay = document.createElement('div');
|
||||||
var closer = 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;
|
var origParent = modal.parentNode;
|
||||||
|
|
||||||
function open(event) {
|
function open(event) {
|
||||||
// disable modals for narrow screens
|
// disable modals for narrow screens
|
||||||
if (window.innerWidth < 768) return true;
|
|
||||||
if (event) {
|
if (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
@ -20,7 +19,6 @@
|
|||||||
document.body.insertBefore(modal, null);
|
document.body.insertBefore(modal, null);
|
||||||
document.body.insertBefore(overlay, modal);
|
document.body.insertBefore(overlay, modal);
|
||||||
overlay.classList.add('modal__overlay--open');
|
overlay.classList.add('modal__overlay--open');
|
||||||
toggleScroll(false);
|
|
||||||
|
|
||||||
if (modal.dataset.closeable === 'true') {
|
if (modal.dataset.closeable === 'true') {
|
||||||
closer.classList.add('modal__closer');
|
closer.classList.add('modal__closer');
|
||||||
@ -30,8 +28,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// open this modal with an event:
|
// you can open this modal via event
|
||||||
// document.dispatchEvent(new CustomEvent('modal-open', { dateils: {for: 'modal-13'}}))
|
// example: document.dispatchEvent(new CustomEvent('modal-open', { details: { for: 'modal-[id]' }}))
|
||||||
function openOnEvent(event) {
|
function openOnEvent(event) {
|
||||||
if (event.detail.for === modal.getAttribute('id')) {
|
if (event.detail.for === modal.getAttribute('id')) {
|
||||||
open();
|
open();
|
||||||
@ -43,7 +41,6 @@
|
|||||||
overlay.remove();
|
overlay.remove();
|
||||||
origParent.insertBefore(modal, null);
|
origParent.insertBefore(modal, null);
|
||||||
modal.classList.remove('modal--open');
|
modal.classList.remove('modal--open');
|
||||||
toggleScroll(true);
|
|
||||||
closer.removeEventListener('click', close, false);
|
closer.removeEventListener('click', close, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -56,27 +53,20 @@
|
|||||||
trigger.classList.add('modal__trigger');
|
trigger.classList.add('modal__trigger');
|
||||||
trigger.addEventListener('click', open, false);
|
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.
|
if (modal.dataset.dynamic === 'True') {
|
||||||
// so we check if the trigger has a href-attribute, fetch that page
|
var dynamicContentURL = trigger.getAttribute('href');
|
||||||
// and replace the modal content with the response
|
if (dynamicContentURL.length > 0) {
|
||||||
var replaceMe = modal.querySelector('.replace-me');
|
fetch(dynamicContentURL, {
|
||||||
var replaceWith = trigger ? trigger.getAttribute('href') : '';
|
credentials: 'same-origin',
|
||||||
if (replaceMe) {
|
|
||||||
replaceMe.classList.remove('replace-me');
|
|
||||||
replaceMe.innerText = '...loading';
|
|
||||||
if (replaceWith.length > 0) {
|
|
||||||
fetch(replaceWith, {
|
|
||||||
credentials: 'same-origin'
|
|
||||||
}).then(function(response) {
|
}).then(function(response) {
|
||||||
return response.text();
|
return response.text();
|
||||||
}).then(function(body) {
|
}).then(function(body) {
|
||||||
var modalContent = document.createElement('div');
|
var modalContent = document.createElement('div');
|
||||||
modalContent.innerHTML = body;
|
modalContent.innerHTML = body;
|
||||||
var main = modalContent.querySelector('.main__content');
|
var main = modalContent.querySelector('.main__content-body');
|
||||||
if (main) {
|
if (main) {
|
||||||
replaceMe.innerText = '';
|
modal.appendChild(main);
|
||||||
replaceMe.insertBefore(main, null);
|
|
||||||
} else {
|
} else {
|
||||||
replaceMe.innerHTML = body;
|
replaceMe.innerHTML = body;
|
||||||
}
|
}
|
||||||
@ -88,11 +78,6 @@
|
|||||||
}
|
}
|
||||||
setup();
|
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() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|||||||
@ -4,14 +4,15 @@
|
|||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(-50%, -50%) scale(0.8, 0.8);
|
transform: translate(-50%, -50%) scale(0.8, 0.8);
|
||||||
display: block;
|
display: block;
|
||||||
background-color: rgba(255, 255, 255, 0.9);
|
background-color: rgba(255, 255, 255, 0.99);
|
||||||
min-width: 60vw;
|
min-width: 60vw;
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
max-height: calc(100vh - 30px);
|
max-height: calc(100vh - 30px);
|
||||||
border-radius: 7px;
|
border-radius: 2px;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
color: var(--color-font);
|
color: var(--color-font);
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
padding-right: 65px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: all .15s ease;
|
transition: all .15s ease;
|
||||||
@ -81,7 +82,3 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-scroll {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -19,6 +19,23 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
cursor: default;
|
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 {
|
.tooltip__content {
|
||||||
|
|||||||
@ -9,13 +9,13 @@ $newline never
|
|||||||
_{MsgWinterTermShort year}
|
_{MsgWinterTermShort year}
|
||||||
$of Summer
|
$of Summer
|
||||||
_{MsgSummerTermShort year}
|
_{MsgSummerTermShort year}
|
||||||
<ul .asidenav__list.js-show-hide__target>
|
<ul .asidenav__list.js-show-hide__target.list--iconless>
|
||||||
$forall (Course{..}, courseRoute, pageActions) <- favouriteTerm tid
|
$forall (Course{..}, courseRoute, pageActions) <- favouriteTerm tid
|
||||||
<li .asidenav__list-item :highlight courseRoute:.asidenav__list-item--active>
|
<li .asidenav__list-item :highlight courseRoute:.asidenav__list-item--active>
|
||||||
<a .asidenav__link-wrapper href=@{courseRoute}>
|
<a .asidenav__link-wrapper href=@{courseRoute}>
|
||||||
<div .asidenav__link-shorthand>#{courseShorthand}
|
<div .asidenav__link-shorthand>#{courseShorthand}
|
||||||
<div .asidenav__link-label>#{courseName}
|
<div .asidenav__link-label>#{courseName}
|
||||||
<ul .asidenav__nested-list>
|
<ul .asidenav__nested-list.list--iconless>
|
||||||
$forall action <- pageActions
|
$forall action <- pageActions
|
||||||
$case action
|
$case action
|
||||||
$of PageActionPrime (MenuItem{..})
|
$of PageActionPrime (MenuItem{..})
|
||||||
|
|||||||
@ -3,6 +3,7 @@ $newline never
|
|||||||
$case formLayout
|
$case formLayout
|
||||||
$of FormStandard
|
$of FormStandard
|
||||||
$forall view <- views
|
$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>
|
<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)
|
$if not (Blaze.null $ fvLabel view)
|
||||||
<label .form-group__label for=#{fvId view}>#{fvLabel view}
|
<label .form-group__label for=#{fvId view}>#{fvLabel view}
|
||||||
@ -10,5 +11,5 @@ $case formLayout
|
|||||||
^{fvInput view}
|
^{fvInput view}
|
||||||
$maybe tooltip <- fvTooltip view
|
$maybe tooltip <- fvTooltip view
|
||||||
<div .js-tooltip>
|
<div .js-tooltip>
|
||||||
<div .tooltip__handle>?
|
<div .tooltip__handle>
|
||||||
<div .tooltip__content>^{tooltip}
|
<div .tooltip__content>^{tooltip}
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
<div .modal.js-modal #modal-#{modalId} data-trigger=#{modalTrigger} data-closeable=true>
|
<div .modal.js-modal #modal-#{modalId} data-trigger=#{triggerId} data-closeable=true data-dynamic=#{modalDynamic}>
|
||||||
$# primitive way of checking if this is supposed to be add a placeholder for async data.
|
$case modalContent
|
||||||
$# modalContent is 'placeholder' if there should be a placeholder only.
|
$of Right content
|
||||||
$# 'placeholder' has length 11.
|
^{content}
|
||||||
$if 11 == length modalContent
|
$of Left _
|
||||||
<div .replace-me>
|
|
||||||
$else
|
|
||||||
#{modalContent}
|
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
<div .modal.js-modal #modal-#{modalId} data-trigger=#{modalTrigger} data-closeable=true>
|
|
||||||
#{modalContent}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
<div .modal.js-modal #modal-#{modalId} data-trigger=#{modalTriggerId} data-closeable=true>
|
|
||||||
^{modalContent}
|
|
||||||
@ -41,7 +41,7 @@
|
|||||||
background: linear-gradient(to top, var(--color-dark) 0%,var(--color-darker) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
|
background: linear-gradient(to top, var(--color-dark) 0%,var(--color-darker) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
|
||||||
color: white;
|
color: white;
|
||||||
margin-right: 40px;
|
margin-right: 40px;
|
||||||
z-index: 10;
|
z-index: 20;
|
||||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
transition: all .2s cubic-bezier(0.03, 0.43, 0.58, 1);
|
transition: all .2s cubic-bezier(0.03, 0.43, 0.58, 1);
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
.pagenav__list {
|
.pagenav__list {
|
||||||
display: block;
|
display: block;
|
||||||
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagenav__list-item {
|
.pagenav__list-item {
|
||||||
|
|||||||
Reference in New Issue
Block a user