localstorage for show-hides, sortable tables, more navigation
This commit is contained in:
parent
dd07a1307f
commit
475411bb4a
@ -90,6 +90,7 @@ data MenuTypes
|
||||
= NavbarLeft { menuItem :: MenuItem }
|
||||
| NavbarRight { menuItem :: MenuItem }
|
||||
| NavbarExtra { menuItem :: MenuItem }
|
||||
| NavbarSecondary { menuItem :: MenuItem }
|
||||
|
||||
-- | A convenient synonym for creating forms.
|
||||
type Form x = Html -> MForm (HandlerT UniWorX IO) (FormResult x, Widget)
|
||||
@ -277,7 +278,7 @@ instance YesodBreadcrumbs UniWorX where
|
||||
|
||||
defaultLinks :: [MenuTypes]
|
||||
defaultLinks = -- Define the menu items of the header.
|
||||
[ NavbarLeft $ MenuItem
|
||||
[ NavbarRight $ MenuItem
|
||||
{ menuItemLabel = "Home"
|
||||
, menuItemRoute = HomeR
|
||||
, menuItemAccessCallback = return True
|
||||
@ -287,7 +288,7 @@ defaultLinks = -- Define the menu items of the header.
|
||||
, menuItemRoute = CourseListR
|
||||
, menuItemAccessCallback = return True
|
||||
}
|
||||
, NavbarRight $ MenuItem
|
||||
, NavbarLeft $ MenuItem
|
||||
{ menuItemLabel = "Users"
|
||||
, menuItemRoute = UsersR
|
||||
, menuItemAccessCallback = return True -- Creates a LOOP: (Authorized ==) <$> isAuthorized UsersR False
|
||||
@ -297,12 +298,12 @@ defaultLinks = -- Define the menu items of the header.
|
||||
, menuItemRoute = ProfileR
|
||||
, menuItemAccessCallback = isJust <$> maybeAuthPair
|
||||
}
|
||||
, NavbarRight $ MenuItem
|
||||
, NavbarSecondary $ MenuItem
|
||||
{ menuItemLabel = "Login"
|
||||
, menuItemRoute = AuthR LoginR
|
||||
, menuItemAccessCallback = isNothing <$> maybeAuthPair
|
||||
}
|
||||
, NavbarRight $ MenuItem
|
||||
, NavbarSecondary $ MenuItem
|
||||
{ menuItemLabel = "Logout"
|
||||
, menuItemRoute = AuthR LogoutR
|
||||
, menuItemAccessCallback = isJust <$> maybeAuthPair
|
||||
|
||||
@ -70,11 +70,11 @@ getCourseListTermR tidini = do
|
||||
, menuItemAccessCallback = (== Authorized) <$> isAuthorized CourseEditR False
|
||||
}
|
||||
]
|
||||
let coursesTable = encodeWidgetTable tableSortable colonnadeTerms courses
|
||||
defaultLinkLayout pageLinks $ do
|
||||
-- defaultLayout $ do
|
||||
-- defaultLayout $ do
|
||||
setTitle "Semesterkurse"
|
||||
linkButton "Neuen Kurs anlegen" BCPrimary CourseEditR
|
||||
encodeWidgetTable tableDefault colonnadeTerms courses -- (map entityVal courses)
|
||||
$(widgetFile "courses")
|
||||
|
||||
getCourseShowR :: TermId -> Text -> Handler Html
|
||||
getCourseShowR tid csh = do
|
||||
@ -324,5 +324,3 @@ validateCourse (CourseForm{..}) =
|
||||
, "Anmeldungen aktivieren oder Anmeldezeitraum löschen"
|
||||
)
|
||||
] ]
|
||||
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ getTermShowR = do
|
||||
]
|
||||
defaultLayout $ do
|
||||
setTitle "Freigeschaltete Semester"
|
||||
encodeWidgetTable tableDefault colonnadeTerms termData
|
||||
encodeWidgetTable tableSortable colonnadeTerms termData
|
||||
|
||||
|
||||
getTermEditR :: Handler Html
|
||||
|
||||
@ -41,5 +41,5 @@ getUsersR = do
|
||||
-- ++ map (\school -> headed (text2widget $ schoolName $ entityVal school) (\u -> "xx")) schools
|
||||
defaultLayout $ do
|
||||
setTitle "Comprehensive User List"
|
||||
let userList = encodeWidgetTable tableDefault colonnadeUsers users
|
||||
let userList = encodeWidgetTable tableSortable colonnadeUsers users
|
||||
$(widgetFile "users")
|
||||
|
||||
@ -25,6 +25,9 @@ import Data.Either
|
||||
tableDefault :: Attribute
|
||||
tableDefault = customAttribute "class" "table table-striped table-hover"
|
||||
|
||||
tableSortable :: Attribute
|
||||
tableSortable = customAttribute "class" "js-sortable"
|
||||
|
||||
-- Colonnade Tools
|
||||
numberColonnade :: (IsString c) => Colonnade Headed Int c
|
||||
numberColonnade = headed "Nr" (fromString.show)
|
||||
|
||||
6
templates/courses.hamlet
Normal file
6
templates/courses.hamlet
Normal file
@ -0,0 +1,6 @@
|
||||
<div>
|
||||
<h1>Kursübersicht für Semester #{termToText $ unTermKey tidini}
|
||||
^{coursesTable}
|
||||
|
||||
<div>
|
||||
<a href=@{CourseEditR}>Neuen Kurs anlegen
|
||||
@ -19,7 +19,3 @@
|
||||
|
||||
<!-- actual content -->
|
||||
^{widget}
|
||||
|
||||
<!-- footer -->
|
||||
<footer>
|
||||
#{appCopyright $ appSettings master}
|
||||
|
||||
@ -28,12 +28,14 @@
|
||||
--blackbase: #1A2A36;
|
||||
--fontbase: #34303a;
|
||||
--fontsec: #5b5861;
|
||||
--primarybase: #4C7A9C;
|
||||
|
||||
|
||||
/* THEME INDEPENDENT COLORS */
|
||||
--errorbase: red;
|
||||
--warningbase: #fe7700;
|
||||
--validbase: #2dcc35;
|
||||
--infobase: var(--darkbase);
|
||||
|
||||
|
||||
/* FONTS */
|
||||
@ -100,12 +102,23 @@ h4 {
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 21px 0;
|
||||
/*width: 100%;*/
|
||||
}
|
||||
th, td {
|
||||
text-align: left;
|
||||
padding: 0 2px 0 4px;
|
||||
padding: 0 13px 0 7px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
th:first-child,
|
||||
td:first-child {
|
||||
padding-left: 0;
|
||||
border-left: 0;
|
||||
}
|
||||
th {
|
||||
border-left: 2px solid var(--greybase);
|
||||
}
|
||||
|
||||
/* LAYOUT */
|
||||
.main {
|
||||
display: flex;
|
||||
@ -115,6 +128,7 @@ th, td {
|
||||
|
||||
.main__aside {
|
||||
width: 300px;
|
||||
flex-shrink: 0;
|
||||
padding-right: 20px;
|
||||
padding-left: 4vw;
|
||||
background-color: var(--darkbase);
|
||||
@ -144,3 +158,57 @@ th, td {
|
||||
outline: 5px auto var(--lightbase);
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
/* GENERAL BUTTON STYLES */
|
||||
input[type="submit"],
|
||||
input[type="button"],
|
||||
button,
|
||||
.btn {
|
||||
outline: 0;
|
||||
border: 0;
|
||||
box-shadow: 0;
|
||||
background-color: var(--lightbase);
|
||||
color: white;
|
||||
padding: 10px 17px;
|
||||
min-width: 100px;
|
||||
transition: all .1s;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
input.btn-primary,
|
||||
button.btn-primary,
|
||||
.btn.btn-primary {
|
||||
background-color: var(--primarybase);
|
||||
}
|
||||
|
||||
input.btn-info,
|
||||
button.btn-info,
|
||||
.btn.btn-info {
|
||||
background-color: var(--infobase)
|
||||
}
|
||||
|
||||
input[type="submit"][disabled],
|
||||
input[type="button"][disabled],
|
||||
button[disabled],
|
||||
.btn[disabled] {
|
||||
opacity: 0.3;
|
||||
background-color: var(--greybase);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
input[type="submit"]:not([disabled]):hover,
|
||||
input[type="button"]:not([disabled]):hover,
|
||||
button:not([disabled]):hover,
|
||||
.btn:not([disabled]):hover {
|
||||
background-color: var(--lighterbase);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
input[type="submit"].btn-info:hover,
|
||||
input[type="button"].btn-info:hover,
|
||||
button.btn-info:hover,
|
||||
.btn.btn-info:hover {
|
||||
background-color: var(--greybase)
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
<a href=@{SubmissionListR}>Dateien hochladen und abrufen
|
||||
|
||||
<hr>
|
||||
<div .js-show-hide.js-show-hide--collapsed>
|
||||
<div .js-show-hide data-collapsed=true>
|
||||
<h2 .js-show-hide__toggle>Tabellen
|
||||
<table .js-sortable>
|
||||
<thead>
|
||||
|
||||
@ -16,12 +16,31 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
var toggle = toggles[el.dataset.index];
|
||||
toggle.collapsed = !toggle.collapsed;
|
||||
toggle.parent.classList.toggle('js-show-hide--collapsed', toggle.collapsed);
|
||||
updateLocalStorage();
|
||||
});
|
||||
}
|
||||
|
||||
function updateLocalStorage(id) {
|
||||
let jsonToggles = JSON.stringify(toggles.map(t => {
|
||||
return {id: t.index, collapsed: t.collapsed};
|
||||
}));
|
||||
window.localStorage.setItem('showHidesToggles', jsonToggles);
|
||||
}
|
||||
|
||||
function collapsedStateInLocalStorage(id, fallBack) {
|
||||
let lsData = JSON.parse(window.localStorage.getItem('showHidesToggles'));
|
||||
if (lsData[id]) {
|
||||
return lsData[id].collapsed;
|
||||
}
|
||||
return fallBack;
|
||||
}
|
||||
|
||||
elements.forEach(function(el, i) {
|
||||
el.dataset.index = i;
|
||||
var coll = el.parentElement.classList.contains('js-show-hide--collapsed');
|
||||
var coll = collapsedStateInLocalStorage(i, el.parentElement.dataset.collapsed === 'true');
|
||||
if (coll) {
|
||||
el.parentElement.classList.add('js-show-hide--collapsed')
|
||||
}
|
||||
Array.from(el.parentElement.children).forEach(function(el) {
|
||||
if (!el.classList.contains('js-show-hide__toggle')) {
|
||||
el.classList.add('js-show-hide__target');
|
||||
|
||||
@ -13,8 +13,8 @@ table.js-sortable th.sorted-asc::after,
|
||||
table.js-sortable th.sorted-desc::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
top: 15px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
transform: translateY(-100%);
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
<div .asidenav>
|
||||
<div .asidenav__box>
|
||||
<h3 .asidenav__box-title>NavbarLefts
|
||||
<ul .asidenav__list>
|
||||
$forall menuType <- menuTypes
|
||||
$case menuType
|
||||
@ -8,6 +7,7 @@
|
||||
<li .asidenav__list-item :Just route == mcurrentRoute:.asidenav__list-item--active>
|
||||
<a .asidenav__link href=@{route}>#{label}
|
||||
$of _
|
||||
|
||||
<div .asidenav__box>
|
||||
<h3 .asidenav__box-title>WiSe 17/18
|
||||
<ul .asidenav__list>
|
||||
|
||||
@ -134,7 +134,7 @@
|
||||
var nextInput = document.createElement('input');
|
||||
var remover = document.createElement('div');
|
||||
cont.classList.add('file-input__container');
|
||||
desc.classList.add('file-input__label');
|
||||
desc.classList.add('file-input__label', 'btn');
|
||||
remover.classList.add('file-input__remover');
|
||||
nextInput.setAttribute('name', name);
|
||||
nextInput.setAttribute('type', 'file');
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* GENERAL STYLES FOR FORMS */
|
||||
|
||||
/* FORMS */
|
||||
/* TEXT INPUTS */
|
||||
input[type="text"],
|
||||
input[type="password"],
|
||||
input[type="url"],
|
||||
@ -27,36 +27,9 @@ input[type="email"]:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
input[type="submit"],
|
||||
input[type="button"],
|
||||
button {
|
||||
outline: 0;
|
||||
border: 0;
|
||||
box-shadow: 0;
|
||||
background-color: var(--lightbase);
|
||||
color: white;
|
||||
padding: 10px 17px;
|
||||
min-width: 100px;
|
||||
transition: all .1s;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
input[type="submit"][disabled],
|
||||
input[type="button"][disabled],
|
||||
button[disabled] {
|
||||
opacity: 0.3;
|
||||
background-color: var(--greybase);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
input[type="submit"]:not([disabled]):hover,
|
||||
input[type="button"]:not([disabled]):hover,
|
||||
button:not([disabled]):hover {
|
||||
background-color: var(--lighterbase);
|
||||
}
|
||||
/* BUTTON STYLE SEE default-layout.lucius */
|
||||
|
||||
/* TEXTAREAS */
|
||||
textarea {
|
||||
outline: 0;
|
||||
border: 0;
|
||||
@ -75,7 +48,7 @@ textarea:focus {
|
||||
background-color: transparent;
|
||||
border-bottom-color: var(--lightbase);
|
||||
}
|
||||
|
||||
/* FORM GROUPS */
|
||||
.form-group {
|
||||
position: relative;
|
||||
display: grid;
|
||||
@ -267,12 +240,13 @@ input[type="file"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
.file-input__label {
|
||||
background-color: var(--lighterbase);
|
||||
text-align: left;
|
||||
position: relative;
|
||||
min-width: 40px;
|
||||
height: 30px;
|
||||
}
|
||||
.file-input__label.btn {
|
||||
padding: 5px 13px;
|
||||
}
|
||||
.file-input__label::after,
|
||||
.file-input__label::before {
|
||||
position: absolute;
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
<ul .navbar__list.list--inline>
|
||||
$forall menuType <- menuTypes
|
||||
$case menuType
|
||||
$of NavbarLeft (MenuItem label route _)
|
||||
<li .navbar__list-item :Just route == mcurrentRoute:.navbar__list-item--active>
|
||||
<a .navbar__link href=@{route}>#{label}
|
||||
$of NavbarRight (MenuItem label route _)
|
||||
<li .navbar__list-item :Just route == mcurrentRoute:.navbar__list-item--active>
|
||||
<a .navbar__link href=@{route}>#{label}
|
||||
$of NavbarSecondary (MenuItem label route _)
|
||||
<li .navbar__list-item.navbar__list-item--secondary :Just route == mcurrentRoute:.navbar__list-item--active>
|
||||
<a .navbar__link href=@{route}>#{label}
|
||||
$of _
|
||||
|
||||
<div .navbar__pushdown>
|
||||
|
||||
@ -25,12 +25,22 @@
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.navbar__list-item--secondary {
|
||||
margin-left: 20px;
|
||||
background-color: var(--fontsec);
|
||||
}
|
||||
.navbar__list-item--secondary + .navbar__list-item--secondary {
|
||||
margin-left: 0;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.navbar__list-item--active > .navbar__link {
|
||||
background-color: white;
|
||||
color: var(--darkbase);
|
||||
}
|
||||
|
||||
.navbar .navbar__list-item > .navbar__link:hover {
|
||||
color: var(--whitebase);
|
||||
background-color: var(--darkbase);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user