feat: improve navigation

This commit is contained in:
Gregor Kleen 2020-02-06 16:21:22 +01:00
parent 51fc6dc541
commit 95ffda25b6
17 changed files with 784 additions and 403 deletions

View File

@ -160,7 +160,7 @@ h4
--current-header-height: var(--header-height-collapsed)
position: relative
background-color: white
transition: padding-left .2s ease-out, margin-top 0.2s cubic-bezier(0.03, 0.43, 0.58, 1)
transition: padding-left .2s ease-out, margin-top 0.2s ease
margin-top: var(--current-header-height)
margin-left: 0
@ -203,7 +203,7 @@ h4
.main__content
margin-left: var(--asidenav-width-md, 50px)
@media (min-width: 769px) and (min-height: 501px)
@media (min-width: 769px)
.main__content
margin-left: var(--asidenav-width-lg, 20%)
@ -641,7 +641,7 @@ section
.ribbon
position: fixed
top: calc(40px + var(--header-height))
transition: all 0.2s cubic-bezier(0.03, 0.43, 0.58, 1)
transition: all 0.2s ease
right: -63px
transform: rotate(45deg)
width: 250px
@ -652,7 +652,7 @@ section
font-size: 1.25rem
line-height: 2em
box-shadow: 0 0 3px rgba(0, 0, 0, 0.4)
z-index: 19
z-index: 21
pointer-events: none
.navbar__container-radio:checked ~ &
@ -1003,9 +1003,12 @@ th, td
.breadcrumbs__container
position: relative
color: var(--color-lightwhite)
padding: 4px 13px 4px 40px
padding: 4px 20px 4px 40px
background-color: var(--color-dark)
line-height: 30px
margin: 0 -5px
a
color: var(--color-lightwhite)
@media (min-width: 426px)
.breadcrumbs__container
@ -1015,45 +1018,31 @@ th, td
.breadcrumbs__container
padding: 7px 40px
.breadcrumbs__link
color: var(--color-lightwhite)
ul.breadcrumbs__list
display: flex
align-items: center
height: 30px
&:hover
color: var(--color-white)
& > li
display: block
.breadcrumbs__item
padding-right: 14px
position: relative
line-height: 28px
opacity: 0.8
z-index: 1
margin-right: 10px
margin: 0 5px
&:hover
opacity: 1
&::after
content: ''
position: absolute
top: 5.5px
right: 0
width: 7px
height: 7px
border-style: solid
border-width: 0
border-bottom-width: 1px
border-right-width: 1px
border-color: var(--color-white)
transform: rotate(-45deg)
z-index: 10
@media (min-width: 426px)
top: 11px
.breadcrumbs__item-separator
line-height: 0
opacity: 0.5
margin: 0 5px
margin-top: 1px
a.breadcrumbs__home
position: absolute
left: 10px
top: 8px
left: 15px
top: 5px
width: 20px
height: 30px
opacity: 0.5
@ -1061,14 +1050,16 @@ a.breadcrumbs__home
color: var(--color-lightwhite)
text-align: center
line-height: 30px
@media (min-width: 426px)
top: 8px
&:hover
opacity: 1
.breadcrumbs__last-item
line-height: 28px
vertical-align: bottom
font-weight: 600
opacity: 1
.recipient-category
max-width: 400px
@ -1144,7 +1135,7 @@ a.breadcrumbs__home
text-align: center
padding: 20px
position: relative
margin: 40px 0
margin: 40px 0 0 0
&::before
content: ''
@ -1183,70 +1174,3 @@ a.breadcrumbs__home
.checkbox
display: inline-block
margin-left: 7px
.pagenav
display: flex
align-items: flex-start
padding-bottom: 15px
margin-bottom: 20px
border-bottom: 1px solid #eee
.pagenav__list-item
flex: 1
position: relative
display: inline-flex
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.6)
margin: 10px 10px 0 0
.pagenav__link-wrapper
flex: 1
padding: 10px 10px 12px
text-decoration: none !important
&:hover
background-color: var(--color-grey-light)
@media (max-width: 1024px)
.pagenav
flex-direction: column
@media (min-width: 1025px)
.pagenav-secondary
position: relative
overflow: visible
padding-top: 10px
&::after
content: '\2026'
display: inline-block
padding: 10px 10px 12px
width: 40px
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.6)
box-sizing: border-box
text-align: center
transition: box-shadow 0.2s ease
&:hover
&::after
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.8)
.pagenav-secondary__list
display: block
.pagenav-secondary__list
position: absolute
display: none
right: 0
top: 50px
width: 250px
background-color: white
box-shadow: 0 0 6px 3px var(--color-grey-light)
z-index: 18
.pagenav__list-item--secondary
display: flex
box-shadow: none
margin: 0
&:hover
background-color: var(--color-grey-light)

View File

@ -58,7 +58,7 @@ export class UtilRegistry {
if (utilInstance) {
const instance = utilInstance.instance;
if (instance && typeof instance.start === 'function') {
instance.start();
instance.start.bind(instance)();
startedInstances.push(instance);
}
}
@ -91,6 +91,7 @@ export class UtilRegistry {
if (DEBUG_MODE > 0) {
console.error('Error while trying to initialize a utility!', { util , element, err });
}
utilInstance = null;
}
if (utilInstance) {

View File

@ -1,7 +1,6 @@
.main__aside
position: fixed
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3)
z-index: 1
top: 0
left: 0
width: var(--asidenav-width-lg, 20%)
@ -9,16 +8,7 @@
flex: 0 0 0
flex-basis: var(--asidenav-width-lg, 20%)
transition: all .2s ease-out
&::before
position: absolute
z-index: -1
left: 0
top: 0
width: 100%
height: 100%
background-color: var(--color-dark)
opacity: 0.05
z-index: 20
&::after
content: ''
@ -233,7 +223,7 @@
// hover sub-menus
.asidenav__nested-list-wrapper
position: absolute
z-index: 10
z-index: 22
display: none
color: var(--color-font)
background-color: var(--color-grey-light)
@ -270,6 +260,10 @@
min-height: calc(100% - var(--header-height-collapsed))
top: var(--header-height-collapsed)
.navbar__container-radio:checked ~ &
min-height: calc(100% - var(--header-height-collapsed) - 30px)
top: calc(var(--header-height-collapsed) + 30px)
.asidenav__box-title
width: var(--asidenav-width-md, 50px)
font-size: 18px
@ -278,6 +272,7 @@
word-break: break-all
background-color: var(--color-dark)
color: var(--color-lightwhite)
border: none
&:hover
background-color: var(--color-darker)

View File

@ -3,7 +3,7 @@ import './navbar.sass';
import * as throttle from 'lodash.throttle';
export const HEADER_CONTAINER_UTIL_SELECTOR = '.navbar__list-item--container-selector .navbar__link-wrapper';
const HEADER_CONTAINER_INITIALIZED_CLASS = '.navbar-header-container--initialized';
const HEADER_CONTAINER_INITIALIZED_CLASS = 'navbar-header-container--initialized';
@Utility({
selector: HEADER_CONTAINER_UTIL_SELECTOR,
@ -24,7 +24,7 @@ export class NavHeaderContainerUtil {
}
if (element.classList.contains(HEADER_CONTAINER_INITIALIZED_CLASS)) {
return false;
return;
}
this._element = element;
@ -55,6 +55,9 @@ export class NavHeaderContainerUtil {
}
start() {
if (!this.container)
return;
window.addEventListener('click', this.clickHandler.bind(this));
this.radioButton.addEventListener('change', this.throttleUpdateWasOpen.bind(this));
}

View File

@ -9,7 +9,7 @@
min-height: var(--header-height)
background-color: var(--color-primary)
color: white
z-index: 20
z-index: 22
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2)
overflow: auto
transition: all 0.2s cubic-bezier(0.03, 0.43, 0.58, 1)
@ -64,6 +64,7 @@
.navbar__container-list
/* margin: 10px 0 0 0 */
position: relative
padding: 0 40px
overflow: hidden
display: flex
@ -108,8 +109,6 @@
transform-origin: 10px 10px
transform: rotate(-0.25turn)
&.navbar__container-list--left
transform: rotate(0.25turn)
opacity: 0.5
transition: transform 0.2s, opacity 0.2s ease
@ -126,9 +125,12 @@
visibility: hidden
&.navbar__container-list--left .navbar__container-list-closer
left: 14.5px
transform: rotate(0.25turn)
right: auto
left: 10px
&:hover
transform: scale(1.4)
// links
.navbar__link-wrapper

View File

@ -0,0 +1,110 @@
import { Utility } from '../../core/utility';
import './pageactions.sass';
import * as throttle from 'lodash.throttle';
export const PAGEACTION_SECONDARY_UTIL_SELECTOR = '.pagenav__list-item';
const PAGEACTION_SECONDARY_INITIALIZED_CLASS = '.pagenav-list-item--initialized';
const PAGEACTION_SECONDARY_CLASS = 'pagenav-secondary';
@Utility({
selector: PAGEACTION_SECONDARY_UTIL_SELECTOR,
})
export class PageActionSecondaryUtil {
_element;
navIdent;
radioButton;
closeButton;
container;
wasOpen;
_throttleUpdateWasOpen;
constructor(element) {
if (!element) {
throw new Error('Pageaction Secondary utility needs to be passed an element!');
}
if (element.classList.contains(PAGEACTION_SECONDARY_INITIALIZED_CLASS)) {
return false;
}
this._element = element;
const childContainer = this._element.querySelector('.pagenav-item__children');
if (!childContainer) {
return false;
}
if (this._element.classList.contains(PAGEACTION_SECONDARY_CLASS)) {
this.navIdent = 'secondary';
} else {
const links = Array.from(this._element.querySelectorAll('.pagenav-item__link')).filter(l => !childContainer.contains(l));
if (!links || Array.from(links).length !== 1) {
throw new Error('Pageaction Secondary utility could not find associated link!');
}
this.navIdent = links[0].id;
}
this.radioButton = document.getElementById(`pageaction-item__expand-${this.navIdent}`);
if (!this.radioButton) {
throw new Error('Pageaction Secondary utility could not find associated radio button!');
}
this.closeButton = document.getElementById('pageaction-item__expand-none');
if (!this.closeButton) {
throw new Error('Pageaction Secondary utility could not find radio button for closing!');
}
this.container = document.querySelector('.pagenav-item__children-wrapper');
if (!this.container) {
throw new Error('Pageaction Secondary utility could not find associated container!');
}
const closer = this._element.querySelector('.pagenav-item__close-label');
if (closer) {
closer.classList.add('pagenav-item__close-label--hidden');
}
this.updateWasOpen();
this.throttleUpdateWasOpen = throttle(this.updateWasOpen.bind(this), 100, { leading: false, trailing: true });
this._element.classList.add(PAGEACTION_SECONDARY_INITIALIZED_CLASS);
}
start() {
if (!this.container)
return;
window.addEventListener('click', this.clickHandler.bind(this));
this.radioButton.addEventListener('change', this.throttleUpdateWasOpen.bind(this));
}
clickHandler() {
if (!this.container.contains(event.target) && window.document.contains(event.target) && this.wasOpen) {
this.close();
}
}
close() {
this.radioButton.checked = false;
this.throttleUpdateWasOpen();
}
isOpen() {
return this.radioButton.checked;
}
updateWasOpen() {
this.wasOpen = this.isOpen();
}
destroy() { /* TODO */ }
}
export const PageActionsUtils = [
PageActionSecondaryUtil,
];

View File

@ -0,0 +1,190 @@
.pagenav
display: flex
align-content: flex-start
align-items: flex-start
flex-flow: row wrap
padding: 0 0 10px 0
margin: -5px -5px 20px -5px
border-bottom: 1px solid #eee
list-style: none
.pagenav-item__expand-radio
display: none
.pagenav-item__link
display: block
padding: 6px 10px
background-color: white
&:hover
background-color: var(--color-grey-light)
a.pagenav-item__link, .pagenav-item__link a
text-decoration: none
.pagenav__list-item
position: relative
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.6)
margin: 5px
padding: 0
display: grid
grid-template-areas: "label expand"
grid-template-columns: auto minmax(0, auto)
flex: 0 0 auto
& > *
grid-area: label
place-self: stretch / stretch
line-height: 20px
&.pagenav-item__children-wrapper
grid-column: label-start / expand-end
& > .pagenav-item__expand-label
display: flex
justify-content: center
align-items: center
grid-area: expand
background-color: white
transition: background-color 0.2s ease
padding: 6px 10px
cursor: pointer
.fas
line-height: 20px
&:hover
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.9)
& > .pagenav-item__expand-label
background-color: var(--color-grey-light)
.pagenav-item__link:hover ~ .pagenav-item__expand-label
background-color: white
.pagenav-item__expand-radio:checked ~ .pagenav-item__expand-label
background-color: var(--color-grey-light)
.pagenav-secondary &
grid-template-areas: "expand"
& > .pagenav-item__children-wrapper
grid-column: exand-start / exand-end
.pagenav-item__children
flex: 1 0 auto
list-style: none
margin: 0
padding: 0
display: grid
grid-template-rows: auto
justify-items: stretch
grid-auto-columns: max-content
.pagenav-item__link
max-width: 250px
& > li
display: flex
& > *
flex: 1 0 auto
.pagenav-item__close-label
display: none
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.6)
padding: 6px 10px
transition: all 0.2s ease
position: absolute
top: 100%
right: 0
background-color: white
z-index: -1
cursor: pointer
.fas
transition: all 0.2s ease
opacity: 0.5
transform: rotate(0.5turn)
line-height: 20px
&:hover
background-color: var(--color-grey-light)
.fas
transform: rotate(0)
opacity: 1
.pagenav-item__children-wrapper
display: none
position: absolute
right: 0
top: 100%
background-color: white
z-index: 21
margin: 0
padding: 0
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.6)
.pagenav-item__expand-radio:checked ~ &, .pagenav-item__expand-label:hover ~ &, &:hover
display: flex
.pagenav__list-item:hover &
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.9)
.pagenav-item__expand-radio:checked ~ &
.pagenav-item__close-label:not(.pagenav-item__close-label--hidden)
display: block
/* .pagenav__link-wrapper
/* flex: 1
/* padding: 10px 10px 12px
/* text-decoration: none !important
/* &:hover
/* background-color: var(--color-grey-light)
/* @media (max-width: 1024px)
/* .pagenav
/* flex-direction: column
/* @media (min-width: 1025px)
/* .pagenav-secondary
/* position: relative
/* overflow: visible
/* padding-top: 10px
/* &::after
/* content: '\2026'
/* display: inline-block
/* padding: 10px 10px 12px
/* width: 40px
/* box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.6)
/* box-sizing: border-box
/* text-align: center
/* transition: box-shadow 0.2s ease
/* &:hover
/* &::after
/* box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.8)
/* .pagenav-secondary__list
/* display: block
/* .pagenav-secondary__list
/* position: absolute
/* display: none
/* right: 0
/* top: 50px
/* width: 250px
/* background-color: white
/* box-shadow: 0 0 6px 3px var(--color-grey-light)
/* z-index: 18
/* .pagenav__list-item--secondary
/* display: flex
/* box-shadow: none
/* margin: 0
/* &:hover
/* background-color: var(--color-grey-light)

View File

@ -11,6 +11,7 @@ import { Modal } from './modal/modal';
import { Tooltip } from './tooltips/tooltips';
import { CourseTeaser } from './course-teaser/course-teaser';
import { NavbarUtils } from './navbar/navbar';
import { PageActionsUtils } from './pageactions/pageactions';
import { HideColumns } from './hide-columns/hide-columns';
export const Utils = [
@ -28,5 +29,6 @@ export const Utils = [
Tooltip,
CourseTeaser,
...NavbarUtils,
...PageActionsUtils,
HideColumns,
];

View File

@ -765,5 +765,18 @@
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js??ref--6-1!node_modules/postcss-loader/src/index.js??ref--6-2!node_modules/resolve-url-loader/index.js??ref--6-3!node_modules/sass-loader/dist/cjs.js??ref--6-4!frontend/src/utils/pageactions/pageactions.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
]
}

View File

@ -78,7 +78,7 @@ import Handler.Utils.ExamOffice.ExternalExam
import Handler.Utils.Profile
import Handler.Utils.Routes
import Utils.Form
-- import Utils.Sheet
import Utils.Sheet
import Utils.SystemMessage
import Text.Shakespeare.Text (st)
@ -117,6 +117,16 @@ instance RenderMessage UniWorX (UnsupportedAuthPredicate AuthTag (Route UniWorX)
mr = renderMessage f ls
(pieces, _) = renderRoute route
data NavQuickView
= NavQuickViewFavourite
| NavQuickViewPageActionSecondary
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
instance Universe NavQuickView
instance Finite NavQuickView
navQuick :: NavQuickView -> (NavQuickView -> Any)
navQuick x x' = Any $ x == x'
data NavType
= NavTypeLink
{ navModal :: Bool
@ -140,7 +150,7 @@ data NavLink = forall msg route. (RenderMessage UniWorX msg, HasRoute UniWorX ro
, navRoute :: route
, navAccess' :: Handler Bool
, navType :: NavType
, navQuick :: Bool
, navQuick' :: NavQuickView -> Any
, navForceActive :: Bool
}
@ -1670,9 +1680,7 @@ siteLayout' headingOverride widget = do
-> let courseRoute = CourseR courseTerm courseSchool courseShorthand CShowR
favouriteReason = fromMaybe FavouriteCurrent mFavourite
in do
items''' <- pageActions courseRoute
items'' <- catMaybes <$> mapM (runMaybeT . navAccess) items'''
items' <- filterM navLinkAccess $ items'' ^.. typesUsing @NavChildren @NavLink . filtered navQuick
items' <- pageQuickActions NavQuickViewFavourite courseRoute
items <- forM items' $ \n -> (n,) <$> toTextUrl n
return (c, courseRoute, items, favouriteReason)
@ -1720,7 +1728,7 @@ siteLayout' headingOverride widget = do
-- you to use normal widget features in default-layout.
navWidget :: (Nav, Text, Maybe Text, [(NavLink, Text, Text)]) -> Widget
navWidget (n, navIdent, navRoute', _navChildren') = case n of
navWidget (n, navIdent, navRoute', navChildren') = case n of
NavHeader{ navLink = navLink@NavLink{..}, .. }
| NavTypeLink{..} <- navType
, navModal
@ -1735,18 +1743,24 @@ siteLayout' headingOverride widget = do
ident = navIdent
in $(widgetFile "widgets/navbar/item")
NavPageActionPrimary{ navLink = navLink@NavLink{..}, .. }
| NavTypeLink{..} <- navType
, navModal
-> customModal Modal
{ modalTriggerId = Just navIdent
, modalId = Nothing
, modalTrigger = \(Just route) ident -> $(widgetFile "widgets/pageaction/primary")
, modalContent = Left $ SomeRoute navLink
}
| NavTypeLink{} <- navType
-> let route = navRoute'
ident = navIdent
in $(widgetFile "widgets/pageaction/primary")
-> let pWidget
| NavTypeLink{..} <- navType
, navModal
= customModal Modal
{ modalTriggerId = Just navIdent
, modalId = Nothing
, modalTrigger = \(Just route) ident -> $(widgetFile "widgets/pageaction/primary")
, modalContent = Left $ SomeRoute navLink
}
| NavTypeLink{} <- navType
= let route = navRoute'
ident = navIdent
in $(widgetFile "widgets/pageaction/primary")
| otherwise
= error "not implemented"
sWidgets = navChildren'
& map (\(l, i, r) -> navWidget (NavPageActionSecondary l, i, Just r, []))
in $(widgetFile "widgets/pageaction/primary-wrapper")
NavPageActionSecondary{ navLink = navLink@NavLink{..}, .. }
| NavTypeLink{..} <- navType
, navModal
@ -1821,10 +1835,13 @@ siteLayout' headingOverride widget = do
hasPageActions = hasPrimaryPageActions || hasSecondaryPageActions
hasSecondaryPageActions = has (folded . _1 . _NavPageActionSecondary) nav
hasPrimaryPageActions = has (folded . _1 . _NavPageActionPrimary ) nav
hasPrimarySubActions = has (folded . _1 . filtered (is _NavPageActionPrimary) . _navChildren . folded) nav
contentRibbon :: Maybe Widget
contentRibbon = fmap toWidget appRibbon
isNavHeaderContainer = has $ _1 . _NavHeaderContainer
isPageActionPrimary = has $ _1 . _NavPageActionPrimary
isPageActionSecondary = has $ _1 . _NavPageActionSecondary
MsgRenderer mr <- getMsgRenderer
let
@ -2171,7 +2188,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = AuthR LogoutR
, navAccess' = is _Just <$> maybeAuthId
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
}
@ -2183,7 +2200,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = AuthR LoginR
, navAccess' = is _Nothing <$> maybeAuthId
, navType = NavTypeLink { navModal = True }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
}
@ -2195,7 +2212,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = ProfileR
, navAccess' = is _Just <$> maybeAuthId
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
}
@ -2212,7 +2229,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
{ navMethod = POST
, navData = [(toPathPiece PostLanguage, lang)]
}
, navQuick = False
, navQuick' = mempty
, navForceActive = lang == activeLang
}
@ -2235,7 +2252,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = (HelpR, [(toPathPiece GetReferer, toPathPiece currentRoute) | let Just currentRoute = mCurrentRoute ])
, navAccess' = return True
, navType = NavTypeLink { navModal = True }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
}
@ -2244,7 +2261,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = LegalR :#: ("data-protection" :: Text)
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, return $ NavFooter NavLink
@ -2252,7 +2269,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = LegalR :#: ("terms-of-use" :: Text)
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, return $ NavFooter NavLink
@ -2260,7 +2277,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = LegalR :#: ("copyright" :: Text)
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, return $ NavFooter NavLink
@ -2268,7 +2285,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = LegalR :#: ("imprint" :: Text)
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, return $ NavFooter NavLink
@ -2276,7 +2293,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = InfoR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, return $ NavFooter NavLink
@ -2284,7 +2301,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = GlossaryR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, return NavHeader
@ -2295,7 +2312,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = NewsR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
}
@ -2307,7 +2324,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = CourseListR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
}
@ -2319,7 +2336,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = CorrectionsR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
}
@ -2331,7 +2348,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = ExamOfficeR EOExamsR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
}
@ -2345,7 +2362,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = UsersR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, NavLink
@ -2353,7 +2370,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = SchoolListR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, NavLink
@ -2361,7 +2378,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = AdminFeaturesR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, NavLink
@ -2369,7 +2386,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = MessageListR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, NavLink
@ -2377,7 +2394,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = AdminErrMsgR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, NavLink
@ -2385,7 +2402,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = AdminTestR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
]
@ -2400,7 +2417,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = CourseNewR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, NavLink
@ -2408,7 +2425,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = EExamListR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, NavLink
@ -2416,7 +2433,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = TermShowR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, NavLink
@ -2424,7 +2441,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = AllocationListR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
, NavLink
@ -2432,7 +2449,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
, navRoute = InfoLecturerR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick = False
, navQuick' = mempty
, navForceActive = False
}
]
@ -2440,26 +2457,267 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
]
-- pageActions :: (MonadHandler m, HandlerSite m ~ UniWorX) => Route UniWorX -> m [Nav]
pageActions :: _
pageActions :: ( MonadHandler m
, HandlerSite m ~ UniWorX
, MonadCatch m
)
=> Route UniWorX -> m [Nav]
pageActions NewsR = return
[ NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuOpenCourses
, navRoute = (CourseListR, [("courses-openregistration", toPathPiece True)])
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick' = mempty
, navForceActive = False
}
, navChildren = []
}
, NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuOpenAllocations
, navRoute = (AllocationListR, [("allocations-active", toPathPiece True)])
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick' = mempty
, navForceActive = False
}
, navChildren = []
}
]
pageActions (CourseR tid ssh csh CShowR) = do
sheetListSecondary <- pageQuickActions NavQuickViewPageActionSecondary $ CourseR tid ssh csh SheetListR
return
[ NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuMaterialList
, navRoute = CourseR tid ssh csh MaterialListR
, navAccess' =
let lecturerAccess = hasWriteAccessTo $ CourseR tid ssh csh MaterialNewR -- Always show for lecturers to create new material
materialAccess mnm = hasReadAccessTo $ CMaterialR tid ssh csh mnm MShowR -- otherwise show only if the user can see at least one of the contents
existsVisible = do
matNames <- E.select . E.from $ \(course `E.InnerJoin` material) -> do
E.on $ course E.^. CourseId E.==. material E.^. MaterialCourse
E.where_ $ course E.^. CourseTerm E.==. E.val tid
E.&&. course E.^. CourseSchool E.==. E.val ssh
E.&&. course E.^. CourseShorthand E.==. E.val csh
return $ material E.^. MaterialName
anyM matNames (materialAccess . E.unValue)
in runDB $ lecturerAccess `or2M` existsVisible
, navType = NavTypeLink { navModal = False }
, navQuick' = navQuick NavQuickViewFavourite
, navForceActive = False
}
, navChildren = [] -- TODO: MaterialNewR
}
, NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuSheetList
, navRoute = CourseR tid ssh csh SheetListR
, navAccess' =
let lecturerAccess = hasWriteAccessTo $ CourseR tid ssh csh SheetNewR -- Always show for lecturers to create new sheets
sheetAccess shn = hasReadAccessTo $ CSheetR tid ssh csh shn SShowR -- othwerwise show only if the user can see at least one of the contents
existsVisible = do
sheetNames <- E.select . E.from $ \(course `E.InnerJoin` sheet) -> do
E.on $ course E.^. CourseId E.==. sheet E.^. SheetCourse
E.where_ $ course E.^. CourseTerm E.==. E.val tid
E.&&. course E.^. CourseSchool E.==. E.val ssh
E.&&. course E.^. CourseShorthand E.==. E.val csh
return $ sheet E.^. SheetName
anyM sheetNames $ sheetAccess . E.unValue
in runDB $ lecturerAccess `or2M` existsVisible
, navType = NavTypeLink { navModal = False }
, navQuick' = navQuick NavQuickViewFavourite
, navForceActive = False
}
, navChildren = sheetListSecondary
}
, NavPageActionSecondary
{ navLink = NavLink
{ navLabel = MsgMenuCourseDelete
, navRoute = CourseR tid ssh csh CDeleteR
, navAccess' = return True
, navType = NavTypeLink { navModal = False }
, navQuick' = mempty
, navForceActive = False
}
} -- TODO
]
pageActions (CourseR tid ssh csh SheetListR) = return
[ NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuSheetCurrent
, navRoute = CourseR tid ssh csh SheetCurrentR
, navAccess' = runDB . maybeT (return False) $
True <$ MaybeT (sheetCurrent tid ssh csh)
, navType = NavTypeLink { navModal = False }
, navQuick' = navQuick NavQuickViewFavourite <> navQuick NavQuickViewPageActionSecondary
, navForceActive = False
}
, navChildren = []
} -- TODO
]
pageActions _ = return []
-- pageActions (NewsR) =
-- pageActions (CourseR tid ssh csh CShowR) =
-- [ MenuItem
-- { menuItemType = PageActionPrime
-- , menuItemLabel = MsgMenuOpenCourses
-- , menuItemLabel = MsgMenuMaterialList
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute (CourseListR, [("courses-openregistration", "True")])
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh MaterialListR
-- , menuItemModal = False
-- , menuItemAccessCallback' =
-- let lecturerAccess = hasWriteAccessTo $ CourseR tid ssh csh MaterialNewR -- Always show for lecturers to create new material
-- materialAccess mnm = hasReadAccessTo $ CMaterialR tid ssh csh mnm MShowR -- otherwise show only if the user can see at least one of the contents
-- existsVisible = do
-- matNames <- E.select . E.from $ \(course `E.InnerJoin` material) -> do
-- E.on $ course E.^. CourseId E.==. material E.^. MaterialCourse
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- return $ material E.^. MaterialName
-- anyM matNames (materialAccess . E.unValue)
-- in runDB $ lecturerAccess `or2M` existsVisible
-- }
-- , MenuItem
-- { menuItemType = PageActionPrime
-- , menuItemLabel = MsgMenuSheetList
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh SheetListR
-- , menuItemModal = False
-- , menuItemAccessCallback' =
-- let lecturerAccess = hasWriteAccessTo $ CourseR tid ssh csh SheetNewR -- Always show for lecturers to create new sheets
-- sheetAccess shn = hasReadAccessTo $ CSheetR tid ssh csh shn SShowR -- othwerwise show only if the user can see at least one of the contents
-- existsVisible = do
-- sheetNames <- E.select . E.from $ \(course `E.InnerJoin` sheet) -> do
-- E.on $ course E.^. CourseId E.==. sheet E.^. SheetCourse
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- return $ sheet E.^. SheetName
-- anyM sheetNames $ sheetAccess . E.unValue
-- in runDB $ lecturerAccess `or2M` existsVisible
-- }
-- ] ++ pageActions (CourseR tid ssh csh SheetListR) ++
-- [ MenuItem
-- { menuItemType = PageActionPrime
-- , menuItemLabel = MsgMenuTutorialList
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CTutorialListR
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionPrime
-- , menuItemLabel = MsgMenuOpenAllocations
-- , menuItemLabel = MsgMenuExamList
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute (AllocationListR, [("allocations-active", "True")])
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CExamListR
-- , menuItemModal = False
-- , menuItemAccessCallback' =
-- let lecturerAccess = hasWriteAccessTo $ CourseR tid ssh csh CExamNewR
-- examAccess examn = hasReadAccessTo $ CExamR tid ssh csh examn EShowR
-- existsVisible = do
-- examNames <- E.select . E.from $ \(course `E.InnerJoin` exam) -> do
-- E.on $ course E.^. CourseId E.==. exam E.^. ExamCourse
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- return $ exam E.^. ExamName
-- anyM examNames $ examAccess . E.unValue
-- in runDB $ lecturerAccess `or2M` existsVisible
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseApplications
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CApplicationsR
-- , menuItemModal = False
-- , menuItemAccessCallback' =
-- let courseWhere course = course <$ do
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- existsApplications = E.selectExists . E.from $ \(course `E.InnerJoin` courseApplication) -> do
-- E.on $ course E.^. CourseId E.==. courseApplication E.^. CourseApplicationCourse
-- void $ courseWhere course
-- courseApplications = fmap (any E.unValue) . E.select . E.from $ \course -> do
-- void $ courseWhere course
-- return $ course E.^. CourseApplicationsRequired
-- courseAllocation = E.selectExists . E.from $ \(course `E.InnerJoin` allocationCourse) -> do
-- E.on $ course E.^. CourseId E.==. allocationCourse E.^. AllocationCourseCourse
-- void $ courseWhere course
-- in runDB $ courseAllocation `or2M` courseApplications `or2M` existsApplications
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseMembers
-- , menuItemIcon = Just "user-graduate"
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CUsersR
-- , menuItemModal = False
-- , menuItemAccessCallback' = do
-- now <- liftIO getCurrentTime
-- let courseWhere course = course <$ do
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- hasActiveAllocation = E.selectExists . E.from $ \(course `E.InnerJoin` allocationCourse `E.InnerJoin` allocation) -> do
-- E.on $ allocation E.^. AllocationId E.==. allocationCourse E.^. AllocationCourseAllocation
-- E.on $ allocationCourse E.^. AllocationCourseCourse E.==. course E.^. CourseId
-- void $ courseWhere course
-- E.where_ $ E.maybe E.false (E.<=. E.val now) (allocation E.^. AllocationRegisterByStaffFrom)
-- E.||. E.maybe E.false (E.<=. E.val now) (allocation E.^. AllocationRegisterByCourse)
-- hasParticipants = E.selectExists . E.from $ \(course `E.InnerJoin` courseParticipant) -> do
-- E.on $ course E.^. CourseId E.==. courseParticipant E.^. CourseParticipantCourse
-- void $ courseWhere course
-- runDB $ (not <$> hasActiveAllocation) `or2M` hasParticipants
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseCommunication
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CCommR
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseEdit
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CEditR
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseClone
-- , menuItemIcon = Just "copy"
-- , menuItemRoute = SomeRoute (CourseNewR, [("tid", toPathPiece tid), ("ssh", toPathPiece ssh), ("csh", toPathPiece csh)])
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseDelete
-- , menuItemIcon = Just "trash"
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CDeleteR
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseExamOffice
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CExamOfficeR
-- , menuItemModal = True
-- , menuItemAccessCallback' = do
-- uid <- requireAuthId
-- runDB $ do
-- cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh
-- E.selectExists $ do
-- (_school, isForced) <- courseExamOfficeSchools (E.val uid) (E.val cid)
-- E.where_ $ E.not_ isForced
-- }
-- ]
-- pageActions (AdminR) =
-- [ MenuItem
@ -2746,165 +3004,6 @@ pageActions _ = return []
-- , menuItemAccessCallback' = return True
-- }
-- ]
-- pageActions (CourseR tid ssh csh CShowR) =
-- [ MenuItem
-- { menuItemType = PageActionPrime
-- , menuItemLabel = MsgMenuMaterialList
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh MaterialListR
-- , menuItemModal = False
-- , menuItemAccessCallback' =
-- let lecturerAccess = hasWriteAccessTo $ CourseR tid ssh csh MaterialNewR -- Always show for lecturers to create new material
-- materialAccess mnm = hasReadAccessTo $ CMaterialR tid ssh csh mnm MShowR -- otherwise show only if the user can see at least one of the contents
-- existsVisible = do
-- matNames <- E.select . E.from $ \(course `E.InnerJoin` material) -> do
-- E.on $ course E.^. CourseId E.==. material E.^. MaterialCourse
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- return $ material E.^. MaterialName
-- anyM matNames (materialAccess . E.unValue)
-- in runDB $ lecturerAccess `or2M` existsVisible
-- }
-- , MenuItem
-- { menuItemType = PageActionPrime
-- , menuItemLabel = MsgMenuSheetList
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh SheetListR
-- , menuItemModal = False
-- , menuItemAccessCallback' =
-- let lecturerAccess = hasWriteAccessTo $ CourseR tid ssh csh SheetNewR -- Always show for lecturers to create new sheets
-- sheetAccess shn = hasReadAccessTo $ CSheetR tid ssh csh shn SShowR -- othwerwise show only if the user can see at least one of the contents
-- existsVisible = do
-- sheetNames <- E.select . E.from $ \(course `E.InnerJoin` sheet) -> do
-- E.on $ course E.^. CourseId E.==. sheet E.^. SheetCourse
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- return $ sheet E.^. SheetName
-- anyM sheetNames $ sheetAccess . E.unValue
-- in runDB $ lecturerAccess `or2M` existsVisible
-- }
-- ] ++ pageActions (CourseR tid ssh csh SheetListR) ++
-- [ MenuItem
-- { menuItemType = PageActionPrime
-- , menuItemLabel = MsgMenuTutorialList
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CTutorialListR
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionPrime
-- , menuItemLabel = MsgMenuExamList
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CExamListR
-- , menuItemModal = False
-- , menuItemAccessCallback' =
-- let lecturerAccess = hasWriteAccessTo $ CourseR tid ssh csh CExamNewR
-- examAccess examn = hasReadAccessTo $ CExamR tid ssh csh examn EShowR
-- existsVisible = do
-- examNames <- E.select . E.from $ \(course `E.InnerJoin` exam) -> do
-- E.on $ course E.^. CourseId E.==. exam E.^. ExamCourse
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- return $ exam E.^. ExamName
-- anyM examNames $ examAccess . E.unValue
-- in runDB $ lecturerAccess `or2M` existsVisible
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseApplications
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CApplicationsR
-- , menuItemModal = False
-- , menuItemAccessCallback' =
-- let courseWhere course = course <$ do
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- existsApplications = E.selectExists . E.from $ \(course `E.InnerJoin` courseApplication) -> do
-- E.on $ course E.^. CourseId E.==. courseApplication E.^. CourseApplicationCourse
-- void $ courseWhere course
-- courseApplications = fmap (any E.unValue) . E.select . E.from $ \course -> do
-- void $ courseWhere course
-- return $ course E.^. CourseApplicationsRequired
-- courseAllocation = E.selectExists . E.from $ \(course `E.InnerJoin` allocationCourse) -> do
-- E.on $ course E.^. CourseId E.==. allocationCourse E.^. AllocationCourseCourse
-- void $ courseWhere course
-- in runDB $ courseAllocation `or2M` courseApplications `or2M` existsApplications
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseMembers
-- , menuItemIcon = Just "user-graduate"
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CUsersR
-- , menuItemModal = False
-- , menuItemAccessCallback' = do
-- now <- liftIO getCurrentTime
-- let courseWhere course = course <$ do
-- E.where_ $ course E.^. CourseTerm E.==. E.val tid
-- E.&&. course E.^. CourseSchool E.==. E.val ssh
-- E.&&. course E.^. CourseShorthand E.==. E.val csh
-- hasActiveAllocation = E.selectExists . E.from $ \(course `E.InnerJoin` allocationCourse `E.InnerJoin` allocation) -> do
-- E.on $ allocation E.^. AllocationId E.==. allocationCourse E.^. AllocationCourseAllocation
-- E.on $ allocationCourse E.^. AllocationCourseCourse E.==. course E.^. CourseId
-- void $ courseWhere course
-- E.where_ $ E.maybe E.false (E.<=. E.val now) (allocation E.^. AllocationRegisterByStaffFrom)
-- E.||. E.maybe E.false (E.<=. E.val now) (allocation E.^. AllocationRegisterByCourse)
-- hasParticipants = E.selectExists . E.from $ \(course `E.InnerJoin` courseParticipant) -> do
-- E.on $ course E.^. CourseId E.==. courseParticipant E.^. CourseParticipantCourse
-- void $ courseWhere course
-- runDB $ (not <$> hasActiveAllocation) `or2M` hasParticipants
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseCommunication
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CCommR
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseEdit
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CEditR
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseClone
-- , menuItemIcon = Just "copy"
-- , menuItemRoute = SomeRoute (CourseNewR, [("tid", toPathPiece tid), ("ssh", toPathPiece ssh), ("csh", toPathPiece csh)])
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseDelete
-- , menuItemIcon = Just "trash"
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CDeleteR
-- , menuItemModal = False
-- , menuItemAccessCallback' = return True
-- }
-- , MenuItem
-- { menuItemType = PageActionSecondary
-- , menuItemLabel = MsgMenuCourseExamOffice
-- , menuItemIcon = Nothing
-- , menuItemRoute = SomeRoute $ CourseR tid ssh csh CExamOfficeR
-- , menuItemModal = True
-- , menuItemAccessCallback' = do
-- uid <- requireAuthId
-- runDB $ do
-- cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh
-- E.selectExists $ do
-- (_school, isForced) <- courseExamOfficeSchools (E.val uid) (E.val cid)
-- E.where_ $ E.not_ isForced
-- }
-- ]
-- pageActions (CourseR tid ssh csh CCorrectionsR) =
-- [ MenuItem
-- { menuItemType = PageActionPrime
@ -3464,6 +3563,16 @@ pageActions _ = return []
-- ]
-- pageActions _ = []
pageQuickActions :: ( MonadCatch m
, MonadHandler m
, HandlerSite m ~ UniWorX
)
=> NavQuickView -> Route UniWorX -> m [NavLink]
pageQuickActions qView route = do
items'' <- pageActions route
items' <- catMaybes <$> mapM (runMaybeT . navAccess) items''
filterM navLinkAccess $ items' ^.. typesUsing @NavChildren @NavLink . filtered (getAny . ($ qView) . navQuick')
i18nHeading :: (MonadWidget m, RenderMessage site msg, HandlerSite m ~ site) => msg -> m ()
i18nHeading msg = liftWidget $ toWidget =<< getMessageRender <*> pure msg

View File

@ -69,7 +69,7 @@ data Icon
| IconNotificationError
| IconFavourite
| IconLanguage
| IconNavContainerClose
| IconNavContainerClose | IconPageActionChildrenClose
| IconMenuNews
| IconMenuHelp
| IconMenuProfile
@ -80,62 +80,68 @@ data Icon
| IconMenuCorrections
| IconMenuExams
| IconMenuAdmin
| IconPageActionPrimaryExpand | IconPageActionSecondary
| IconBreadcrumbSeparator
deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic, Typeable)
iconText :: Icon -> Text
iconText = \case
IconNew -> "seedling"
IconOK -> "check"
IconNotOK -> "times"
IconWarning -> "exclamation"
IconProblem -> "bolt"
IconVisible -> "eye"
IconInvisible -> "eye-slash"
IconCourse -> "graduation-cap"
IconEnrolTrue -> "user-plus"
IconEnrolFalse -> "user-slash"
IconPlanned -> "cog"
IconAnnounce -> "bullhorn"
IconExam -> "poll-h"
IconExamRegisterTrue -> "calendar-check"
IconExamRegisterFalse -> "calendar-times"
IconCommentTrue -> "comment-alt"
IconCommentFalse -> "comment-alt-slash"
IconLink -> "link"
IconFileDownload -> "file-download"
IconFileUpload -> "file-upload"
IconFileZip -> "file-archive"
IconFileCSV -> "file-csv"
IconSFTQuestion -> "question-circle" -- for SheetFileType only, should all be round (similar)
IconSFTHint -> "life-ring" -- for SheetFileType only
IconSFTSolution -> "exclamation-circle" -- for SheetFileType only
IconSFTMarking -> "check-circle" -- for SheetFileType only
IconEmail -> "envelope"
IconRegisterTemplate -> "file-alt"
IconApplyTrue -> "file-alt"
IconApplyFalse -> "trash"
IconNoCorrectors -> "user-slash"
IconApplicationVeto -> "times"
IconApplicationFiles -> "file-alt"
IconTooltipDefault -> "question-circle"
IconNotificationSuccess -> "check-circle"
IconNotificationInfo -> "info-circle"
IconNotificationWarning -> "exclamation-circle"
IconNotificationError -> "exclamation-triangle"
IconFavourite -> "star"
IconLanguage -> "flag-alt"
IconNavContainerClose -> "chevron-up"
IconMenuNews -> "megaphone"
IconMenuHelp -> "question"
IconMenuProfile -> "cogs"
IconMenuLogin -> "sign-in-alt"
IconMenuLogout -> "sign-out-alt"
IconBreadcrumbsHome -> "home"
IconMenuExtra -> "ellipsis-h"
IconMenuCourseList -> "graduation-cap"
IconMenuCorrections -> "check"
IconMenuExams -> "poll-h"
IconMenuAdmin -> "screwdriver"
IconNew -> "seedling"
IconOK -> "check"
IconNotOK -> "times"
IconWarning -> "exclamation"
IconProblem -> "bolt"
IconVisible -> "eye"
IconInvisible -> "eye-slash"
IconCourse -> "graduation-cap"
IconEnrolTrue -> "user-plus"
IconEnrolFalse -> "user-slash"
IconPlanned -> "cog"
IconAnnounce -> "bullhorn"
IconExam -> "poll-h"
IconExamRegisterTrue -> "calendar-check"
IconExamRegisterFalse -> "calendar-times"
IconCommentTrue -> "comment-alt"
IconCommentFalse -> "comment-alt-slash"
IconLink -> "link"
IconFileDownload -> "file-download"
IconFileUpload -> "file-upload"
IconFileZip -> "file-archive"
IconFileCSV -> "file-csv"
IconSFTQuestion -> "question-circle" -- for SheetFileType only, should all be round (similar)
IconSFTHint -> "life-ring" -- for SheetFileType only
IconSFTSolution -> "exclamation-circle" -- for SheetFileType only
IconSFTMarking -> "check-circle" -- for SheetFileType only
IconEmail -> "envelope"
IconRegisterTemplate -> "file-alt"
IconApplyTrue -> "file-alt"
IconApplyFalse -> "trash"
IconNoCorrectors -> "user-slash"
IconApplicationVeto -> "times"
IconApplicationFiles -> "file-alt"
IconTooltipDefault -> "question-circle"
IconNotificationSuccess -> "check-circle"
IconNotificationInfo -> "info-circle"
IconNotificationWarning -> "exclamation-circle"
IconNotificationError -> "exclamation-triangle"
IconFavourite -> "star"
IconLanguage -> "flag-alt"
IconNavContainerClose -> "chevron-up"
IconPageActionChildrenClose -> "chevron-up"
IconMenuNews -> "megaphone"
IconMenuHelp -> "question"
IconMenuProfile -> "cogs"
IconMenuLogin -> "sign-in-alt"
IconMenuLogout -> "sign-out-alt"
IconBreadcrumbsHome -> "home"
IconMenuExtra -> "ellipsis-h"
IconMenuCourseList -> "graduation-cap"
IconMenuCorrections -> "check"
IconMenuExams -> "poll-h"
IconMenuAdmin -> "screwdriver"
IconPageActionPrimaryExpand -> "bars"
IconPageActionSecondary -> "ellipsis-h"
IconBreadcrumbSeparator -> "angle-right"
instance Universe Icon
instance Finite Icon

View File

@ -32,7 +32,7 @@ $if not isModal
<a .breadcrumbs__link href="@{fst back}">#{snd back} -->
^{headline}
$if not isModal && hasPageActions
$if hasPageActions
<!-- page actions -->
^{pageaction}

View File

@ -6,7 +6,12 @@ $newline never
$forall (bcRoute, bcTitle, hasAccess) <- parents
<li .breadcrumbs__item>
$if hasAccess
<a .breadcrumbs__link href="@{bcRoute}">#{bcTitle}
<a .breadcrumbs__link href="@{bcRoute}">
#{bcTitle}
$else
<span .breadcrumbs__link>#{bcTitle}
<li .breadcrumbs__last-item>#{title}
<span .breadcrumbs__link>
#{bcTitle}
<li .breadcrumbs__item-separator>
#{iconBreadcrumbSeparator}
<li .breadcrumbs__item .breadcrumbs__last-item>
#{title}

View File

@ -1,13 +1,19 @@
$newline never
<div .pagenav>
$if hasPrimaryPageActions
<div .pagenav-prime>
$forall n@(NavPageActionPrimary{}, _, _, _) <- nav
<div .pagenav__list-item>
^{navWidget n}
$if hasSecondaryPageActions || hasPrimarySubActions
<input .pagenav-item__expand-radio name=pagenav-item__expand-radio id=pageaction-item__expand-none type=radio checked>
<ul .pagenav>
$forall n <- filter isPageActionPrimary nav
<li .pagenav__list-item>
^{navWidget n}
$if hasSecondaryPageActions
<div .pagenav-secondary>
<div .pagenav-secondary__list>
$forall n@(NavPageActionPrimary{}, _, _, _) <- nav
<div .pagenav__list-item.pagenav__list-item--secondary>
^{navWidget n}
<li .pagenav__list-item .pagenav-secondary>
<input .pagenav-item__expand-radio name=pagenav-item__expand-radio id=pageaction-item__expand-secondary type=radio>
<label .pagenav-item__expand-label for=pageaction-item__expand-secondary>
<i .fas .fa-fw .fa-#{iconText IconPageActionSecondary}>
<div .pagenav-item__children-wrapper>
<ul .pagenav-item__children>
$forall n <- filter isPageActionSecondary nav
<li>
^{navWidget n}
<label .pagenav-item__close-label for=pageaction-item__expand-none>
#{iconPageActionChildrenClose}

View File

@ -0,0 +1,13 @@
$newline never
^{pWidget}
$if not (null sWidgets)
<input .pagenav-item__expand-radio name=pagenav-item__expand-radio id=pageaction-item__expand-#{navIdent} type=radio>
<label .pagenav-item__expand-label for=pageaction-item__expand-#{navIdent}>
<i .fas .fa-fw .fa-#{iconText IconPageActionPrimaryExpand}>
<div .pagenav-item__children-wrapper>
<ul .pagenav-item__children>
$forall sWgt <- sWidgets
<li>
^{sWgt}
<label .pagenav-item__close-label for=pageaction-item__expand-none>
#{iconPageActionChildrenClose}

View File

@ -1,2 +1,3 @@
$newline never
<a .pagenav__link-wrapper href=#{route} ##{ident}>_{SomeMessage navLabel}
<a .pagenav-item__link href=#{route} ##{ident}>
_{SomeMessage navLabel}

View File

@ -1,2 +1,3 @@
$newline never
<a .pagenav__link-wrapper.pagenav__link-wrapper--secondary href=#{route} ##{ident}>_{SomeMessage navLabel}
<a .pagenav-item__link href=#{route} ##{ident}>
_{SomeMessage navLabel}