Fradrive/frontend #194

Merged
savau merged 8 commits from fradrive/frontend into master 2022-12-15 19:33:17 +01:00
14 changed files with 38 additions and 632 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -34,9 +34,6 @@
// DIMENSIONS
--header-height: 100px
--header-height-collapsed: 60px
--asidenav-width-xl: 250px
--asidenav-width-lg: 20%
--asidenav-width-md: 60px
*
box-sizing: border-box
@ -207,18 +204,6 @@ h4
.main__content
--current-header-height: var(--header-height)
@media (min-width: 426px)
.main__content
margin-left: var(--asidenav-width-md, 50px)
@media (min-width: 769px)
.main__content
margin-left: var(--asidenav-width-lg, 20%)
@media (min-width: 1200px)
.main__content
margin-left: var(--asidenav-width-xl, 250px)
.main__content-body
padding: 13px
@ -1250,7 +1235,7 @@ th, td
.breadcrumbs__container
position: relative
color: var(--color-lightwhite)
padding: 4px 20px 4px 40px
padding: 7px 13px
background-color: var(--color-dark)
a
@ -1258,7 +1243,7 @@ th, td
@media (min-width: 426px)
.breadcrumbs__container
padding: 7px 20px 7px 40px
padding: 7px 20px
@media (min-width: 769px)
.breadcrumbs__container
@ -1287,17 +1272,9 @@ ul.breadcrumbs__list
margin-top: 1px
a.breadcrumbs__home
position: absolute
left: 10px
top: 5px
width: 20px
height: 30px
opacity: 0.5
text-decoration: none
color: var(--color-lightwhite)
text-align: center
line-height: 30px
margin-right: 7px
@media (min-width: 426px)
top: 8px
@ -1515,11 +1492,11 @@ a.breadcrumbs__home
min-width: calc((100vw - 40px - 8 * 7px) / 4)
@media (min-width: 426px)
min-width: calc((100vw - var(--asidenav-width-md, 50px) - 40px - 8 * 7px) / 4)
min-width: calc((100vw - 40px - 8 * 7px) / 4)
@media (min-width: 769px)
min-width: calc((100vw - var(--asidenav-width-lg, 20%) - 80px - 8 * 7px) / 4)
min-width: calc((100vw - 80px - 8 * 7px) / 4)
@media (min-width: 1200px)
min-width: calc((100vw - var(--asidenav-width-xl, 250px) - 80px - 8 * 7px) / 4)
min-width: calc((100vw - 80px - 8 * 7px) / 4)
a.active-allocations__allocation-ident
white-space: nowrap

View File

@ -1,96 +0,0 @@
// SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Sarah Vaupel <vaupel.sarah@campus.lmu.de>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
import { Utility } from '../../core/utility';
import { EventManager, EventWrapper, EVENT_TYPE } from '../../lib/event-manager/event-manager';
import './asidenav.sass';
const FAVORITES_BTN_CLASS = 'navbar__list-item--favorite';
const FAVORITES_BTN_ACTIVE_CLASS = 'navbar__list-item--active';
const ASIDENAV_INITIALIZED_CLASS = 'asidenav--initialized';
const ASIDENAV_EXPANDED_CLASS = 'main__aside--expanded';
const ASIDENAV_LIST_ITEM_CLASS = 'asidenav__list-item';
const ASIDENAV_SUBMENU_CLASS = 'asidenav__nested-list-wrapper';
@Utility({
selector: '[uw-asidenav]',
})
export class Asidenav {
_element;
_asidenavSubmenus;
_eventManager;
constructor(element) {
if (!element) {
throw new Error('Asidenav utility cannot be setup without an element!');
}
this._element = element;
this._eventManager = new EventManager();
if (this._element.classList.contains(ASIDENAV_INITIALIZED_CLASS)) {
return false;
}
this._initFavoritesButton();
this._initAsidenavSubmenus();
// mark initialized
this._element.classList.add(ASIDENAV_INITIALIZED_CLASS);
}
destroy() {
this._eventManager.cleanUp();
if(this._element.classList.contains(ASIDENAV_INITIALIZED_CLASS))
this._element.classList.remove(ASIDENAV_INITIALIZED_CLASS);
}
_initFavoritesButton() {
const favoritesBtn = document.querySelector('.' + FAVORITES_BTN_CLASS);
if (favoritesBtn) {
const favoritesButtonEvent = new EventWrapper(EVENT_TYPE.CLICK, (event) => {
favoritesBtn.classList.toggle(FAVORITES_BTN_ACTIVE_CLASS);
this._element.classList.toggle(ASIDENAV_EXPANDED_CLASS);
event.preventDefault();
}, favoritesBtn, true);
this._eventManager.registerNewListener(favoritesButtonEvent);
}
}
_initAsidenavSubmenus() {
this._asidenavSubmenus = Array.from(this._element.querySelectorAll('.' + ASIDENAV_LIST_ITEM_CLASS))
.map(function(listItem) {
const submenu = listItem.querySelector('.' + ASIDENAV_SUBMENU_CLASS);
return { listItem, submenu };
}).filter(function(union) {
return union.submenu !== null;
});
this._asidenavSubmenus.forEach((union) => {
union.hoverHandler = this._createMouseoverHandler(union);
let currentHoverEvent = new EventWrapper(EVENT_TYPE.MOUSE_OVER, union.hoverHandler, union.listItem);
this._eventManager.registerNewListener(currentHoverEvent);
});
}
_createMouseoverHandler(union) {
return () => {
const rectListItem = union.listItem.getBoundingClientRect();
const rectSubMenu = union.submenu.getBoundingClientRect();
union.submenu.style.left = (rectListItem.left + rectListItem.width) + 'px';
if (window.innerHeight - rectListItem.top < rectSubMenu.height) {
union.submenu.style.top = (rectListItem.top + rectListItem.height - rectSubMenu.height) + 'px';
} else {
union.submenu.style.top = rectListItem.top + 'px';
}
};
}
}

View File

@ -1,21 +0,0 @@
# Asidenav
Correctly positions hovered asidenav submenus and handles the favorites button on mobile
## Attribute: `uw-asidenav`
## Example usage:
```html
<div uw-asidenav>
<div .asidenav>
<div .asidenav__box>
<ul .asidenav__list.list--iconless>
<li .asidenav__list-item>
<a .asidenav__link-wrapper href='#'>
<div .asidenav__link-shorthand>EIP
<div .asidenav__link-label>Einführung in die Programmierung
<div .asidenav__nested-list-wrapper>
<ul .asidenav__nested-list.list--iconless>
Übungsblätter
...
```

View File

@ -1,3 +0,0 @@
SPDX-FileCopyrightText: 2022 Sarah Vaupel <vaupel.sarah@campus.lmu.de>
SPDX-License-Identifier: AGPL-3.0-or-later

View File

@ -1,376 +0,0 @@
// SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Steffen Jost <jost@cip.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
// SPDX-License-Identifier: LicenseRef-Fraport-Corporate-Design
@use "../../common" as *
@use "../../app" as *
.main__aside
position: fixed
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3)
top: 0
left: 0
width: var(--asidenav-width-lg, 20%)
height: 100%
flex: 0 0 0
flex-basis: var(--asidenav-width-lg, 20%)
transition: all .2s ease-out
z-index: 20
&::after
content: ''
position: absolute
z-index: -2
left: 0
top: 0
width: 100%
height: 100%
background-color: var(--color-grey-light)
@media (max-width: 425px)
.main__aside
position: fixed
top: var(--header-height-collapsed)
left: 0
right: 0
bottom: 0
height: 100% !important
width: 100%
z-index: 5
overflow: hidden
transform: translateX(-110%)
transition: transform .2s ease-out
&.main__aside--expanded
transform: translateX(0%)
.asidenav__box-subtitle
display: inherit
.asidenav__box-title
font-size: 18px
padding-left: 10px
.asidenav__box-subtitle
display: none
@media (min-width: 1200px)
.main__aside
width: var(--asidenav-width-xl, 250px)
.asidenav
color: var(--color-font)
min-height: calc(100% - var(--header-height))
height: 400px
overflow-y: auto
overflow-x: hidden
&::-webkit-scrollbar
width: 0
.asidenav__box
transition: opacity .2s ease
+ .asidenav__box
margin-top: 10px
.asidenav__box-title
padding: 7px 13px
margin-top: 30px
background-color: transparent
transition: all .2s ease
padding: 10px 13px
margin: 0
border-bottom: 1px solid var(--color-grey)
height: 44px
.asidenav-term-identifier--long
display: inherit
.asidenav-term-identifier--short
display: none
.asidenav__box-subtitle
color: var(--color-fontsec)
font-size: 0.9rem
font-weight: 600
padding: 0 13px
margin: 3px 0
.asidenav__box-explanation
@extend .explanation
padding: 0 13px
margin: 3px 0
opacity: .66
font-size: .7rem
/* transition: opacity .2s ease, font-size .2s ease
/* &:hover
/* font-size: .9rem
/* opacity: 1
// LOGO
.asidenav__logo
height: var(--header-height)
display: flex
align-items: center
@media (max-width: 768px)
.asidenav__logo
display: none
.asidenav__logo-link
flex: 1
top: 10px
left: 20px
height: 80px
padding: 0 20px
display: flex
flex-basis: var(--asidenav-width-xl, 250px)
font-size: 16px
align-items: center
color: var(--color-dark)
transform-origin: left
&:hover
color: var(--color-primary)
.asidenav__logo-lmu
width: 160px
height: 100%
.asidenav__logo-uni2work
display: flex
align-items: flex-end
min-width: 70px
margin-left: 12px
text-transform: uppercase
width: 100%
height: 100%
padding: 2px 4px
border: 1px solid currentColor
letter-spacing: 2px
background-color: white
transition: background-color .3s ease
@media (max-width: 1199px)
.asidenav__logo-link
flex-basis: var(--asidenav-width-lg, 20%)
font-size: 16px
.asidenav__logo-lmu
display: none
.asidenav__logo-uni2work
margin-left: 0
// SEAL
.asidenav__sigillum
position: absolute
bottom: -40px
right: 25px
opacity: 0.1
> img
width: 350px
@media (max-width: 768px)
.asidenav__sigillum
right: auto
left: 50%
transform: translateX(-50%)
// LIST-ITEM
.asidenav__list-item
color: var(--color-font)
display: flex
flex-direction: column
justify-content: flex-start
align-items: center
&:not(.asidenav__list-item--active):hover
background-color: var(--color-lightwhite)
> .asidenav__link-wrapper
color: var(--color-font)
&:hover
.asidenav__link-shorthand
// transform: scale(1.05, 1.0);
// transform-origin: right;
text-shadow: none
.asidenav__nested-list-wrapper
display: block
// small list-item-padding for medium to large screens
@media (min-width: 769px)
.asidenav__list-item
padding-left: 10px
.asidenav__list-item--active
background-color: var(--color-lightwhite)
.asidenav__link-wrapper
color: var(--color-link)
.asidenav__link-shorthand
transform: scale(1.05, 1)
transform-origin: right
text-shadow: none
.asidenav__link-wrapper
position: relative
display: flex
flex: 1
align-items: center
padding: 8px 3px
justify-content: flex-start
color: var(--color-font)
width: 100%
z-index: 1
.asidenav__link-shorthand
display: none
.asidenav__link-favourite-toggle
opacity: .33
&:hover
opacity: 1
button
display: flex
text-decoration: none
.asidenav__link-label
display: flex
justify-content: space-between
align-items: center
line-height: 1
& > .asidenav__link-label-text
word-break: break-word
flex: 1 1 auto
& > .asidenav__link-favourite-toggle
flex: 0 0 $fa-fw-width
margin: 0 5px
// hover sub-menus
.asidenav__nested-list-wrapper
position: absolute
z-index: 22
display: none
color: var(--color-font)
background-color: var(--color-grey-light)
box-shadow: 1px 1px 1px 0px var(--color-grey)
.asidenav__nested-list
min-width: 200px
.asidenav__nested-list--unavailable
font-size: 0.9rem
color: var(--color-fontsec)
font-weight: 600
padding: 7px
min-width: 200px
@media (max-width: 425px)
.asidenav__list-item
padding-left: 10px
.asidenav__nested-list
display: none
.asidenav__nested-list--unavailable
display: none
.asidenav__nested-list-item
position: relative
&:hover
background-color: var(--color-lightwhite)
.asidenav__link-wrapper
padding-left: 13px
padding-right: 13px
transition: all .2s ease
color: var(--color-font)
// TABLET
@media (min-width: 426px) and (max-width: 768px)
.main__aside
width: var(--asidenav-width-md, 50px)
flex-basis: var(--asidenav-width-md, 50px)
overflow: hidden
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
text-align: center
padding: 10px 1px
word-break: break-all
background-color: var(--color-dark)
color: var(--color-lightwhite)
border: none
&:hover
background-color: var(--color-darker)
&::before
display: none
.asidenav-term-identifier--long
display: none
.asidenav-term-identifier--short
display: inherit
.asidenav__box-subtitle
padding: 0 3px
font-size: 0.85rem
.asidenav__link-shorthand
display: flex
position: static
height: 50px
width: var(--asidenav-width-md, 50px)
text-align: center
opacity: 1
font-size: 15px
line-height: 1em
margin-right: 13px
flex-shrink: 0
padding: 1px
outline: 1px solid white
word-break: break-all
align-items: center
justify-content: center
.asidenav__list-item
padding-left: 0
+ .asidenav__list-item
margin: 0
.asidenav__link-wrapper
color: var(--color-font)
padding: 0
.asidenav__nested-list, .asidenav__link-label, .asidenav__nested-list--unavailable
display: none
.asidenav__list-item--active
.asidenav__link-wrapper
background-color: var(--color-lightwhite)

View File

@ -1,31 +0,0 @@
// SPDX-FileCopyrightText: 2022 Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Sarah Vaupel <vaupel.sarah@campus.lmu.de>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
import { Asidenav, ASIDENAV_INITIALIZED_CLASS } from './asidenav';
describe('Asidenav', () => {
let asidenav;
beforeEach(() => {
const element = document.createElement('div');
asidenav = new Asidenav(element);
});
it('should create', () => {
expect(asidenav).toBeTruthy();
});
it('should destory asidenav', () => {
asidenav.destroy();
expect(asidenav._eventManager._registeredListeners.length).toBe(0);
expect(asidenav._element.classList).not.toContain(ASIDENAV_INITIALIZED_CLASS);
});
it('should throw if called without an element', () => {
expect(() => {
new Asidenav();
}).toThrow();
});
});

View File

@ -10,7 +10,7 @@
position: fixed
right: 0
top: 0
left: var(--asidenav-width-xl)
left: 0
min-height: var(--header-height)
background-color: var(--color-primary)
color: white
@ -21,9 +21,6 @@
margin: 0
padding: 10px 0
@media (max-width: 1199px)
left: var(--asidenav-width-lg)
@media (max-width: 768px), (max-height: 500px)
min-height: var(--header-height-collapsed)
padding: 0
@ -42,6 +39,8 @@
& > *
flex-grow: 1
// LIST WRAPPER
.navbar__list-wrapper
display: flex
flex-flow: row nowrap
@ -137,6 +136,18 @@
&:hover
transform: scale(1.4)
// LOGO
.navbar__logo
margin-right: 40px
@media (max-width: 1199px)
display: none
.navbar__logo-lmu
height: 100%
width: 160px
// links
.navbar__link-wrapper
display: flex

View File

@ -3,7 +3,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import { Alerts } from './alerts/alerts';
import { Asidenav } from './asidenav/asidenav';
import { AsyncForm } from './async-form/async-form';
import { ShowHide } from './show-hide/show-hide';
import { AsyncTable } from './async-table/async-table';
@ -22,7 +21,6 @@ import { SortTable } from './sort-table/sort-table';
export const Utils = [
Alerts,
Asidenav,
AsyncForm,
AsyncTable,
CheckAll,

View File

@ -282,7 +282,7 @@ siteLayout' overrideHeading widget = do
showFavToggle FavouriteCurrent = isJust muid
showFavToggle _favouriteReason = False
favouriteToggleRes <- runFormPost $ courseFavouriteToggleForm currentReason
let favouriteToggleWgt = favouriteToggleRes & \((_, favouriteToggleView), favouriteToggleEncoding) ->
let _favouriteToggleWgt = favouriteToggleRes & \((_, favouriteToggleView), favouriteToggleEncoding) ->
wrapForm favouriteToggleView def
{ formAction = maybeRoute
, formEncoding = favouriteToggleEncoding
@ -343,12 +343,12 @@ siteLayout' overrideHeading widget = do
navItems = map (view _2) favourites ++ toListOf (folded . typesUsing @NavChildren @NavLink . to navBaseRoute) nav
highR = find (`elem` navItems) . uncurry (++) $ partition (`elem` map (view _2) favourites) crumbs
highlightNav = (||) <$> navForceActive <*> (highlight . navBaseRoute)
favouriteTermReason :: TermIdentifier -> FavouriteReason -> [((CourseName, TermId, SchoolId, CourseShorthand), Route UniWorX, Maybe [(Text, Text)], FavouriteReason, Bool, Bool, Bool)]
favouriteTermReason tid favReason' = favourites
_favouriteTermReason :: TermIdentifier -> FavouriteReason -> [((CourseName, TermId, SchoolId, CourseShorthand), Route UniWorX, Maybe [(Text, Text)], FavouriteReason, Bool, Bool, Bool)]
_favouriteTermReason tid favReason' = favourites
& filter (\((_, tid', _, _), _, _, favReason, _, _, _) -> unTermKey tid' == tid && favReason == favReason')
& sortOn (\((cName, _, _, _), _, _, _, _, _, _) -> cName)
anyFavToggle = flip any ((,) <$> universeF <*> favouriteTerms) $ \(reason, term) ->
showFavToggle reason && not (null $ favouriteTermReason term reason)
_anyFavToggle = flip any ((,) <$> universeF <*> favouriteTerms) $ \(reason, term) ->
showFavToggle reason && not (null $ _favouriteTermReason term reason)
-- We break up the default layout into two components:
-- default-layout is the contents of the body tag, and
@ -458,10 +458,7 @@ siteLayout' overrideHeading widget = do
toWidget $(cassiusFile "templates/widgets/navbar/container-radio.cassius")
where isNavHeaderPrimary = has $ _1 . _navHeaderRole . only NavHeaderPrimary
isNavHeaderSecondary = has $ _1 . _navHeaderRole . only NavHeaderSecondary
asidenav :: WidgetFor UniWorX ()
asidenav = $(widgetFile "widgets/asidenav/asidenav")
where
logo = preEscapedToMarkup $ decodeUtf8 $(embedFile "assets/fraport_logo_text.svg")
logo = preEscapedToMarkup $ decodeUtf8 $(embedFile "assets/fraport_logo_text.svg")
footer :: WidgetFor UniWorX ()
footer = $(widgetFile "widgets/footer/footer")
where isNavFooter = has $ _1 . _NavFooter

View File

@ -11,8 +11,6 @@ $if not isModal
$forall (_, containerIdent, _, _) <- containers
<input name=nav-container type=radio .navbar__container-radio ##{containerIdent}-radio uw-no-radiobox>
<!-- secondary navigation at the side -->
^{asidenav}
<!-- navigation -->
^{navbar}

View File

@ -1,55 +0,0 @@
$newline never
$# SPDX-FileCopyrightText: 2022 Felix Hamann <felix.hamann@campus.lmu.de>,Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <vaupel.sarah@campus.lmu.de>,Steffen Jost <jost@cip.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
$#
$# SPDX-License-Identifier: AGPL-3.0-or-later
<aside .main__aside uw-asidenav>
<div .asidenav__logo>
<a href="/" .asidenav__logo-link>
<div .asidenav__logo-lmu >
#{logo}
<div .asidenav>
$if null favouriteTerms && is _Just muid
<div .asidenav__box-explanation>
_{MsgFavouritesEmptyTip}
$else
$forall tid <- favouriteTerms
<div .asidenav__box>
<h3 .asidenav__box-title uw-show-hide data-show-hide-id="#{termToText tid}" data-show-hide-align=right>
<div .asidenav-term-identifier--long>
_{ShortTermIdentifier tid}
<div .asidenav-term-identifier--short>
#{toPathPiece tid}
$forall favReason <- sortOn Down universeF
$if not (null $ favouriteTermReason tid favReason)
<h3 .asidenav__box-subtitle>
_{favReason}
<ul .asidenav__list.list--iconless>
$forall ((cName, _, _, csh), courseRoute, mPageActions, _, courseVisible, _, mayEdit) <- favouriteTermReason tid favReason
<li .asidenav__list-item :highlight courseRoute:.asidenav__list-item--active>
<a .asidenav__link-wrapper href=@{courseRoute}>
<div .asidenav__link-shorthand>#{csh}
<div .asidenav__link-label>
<div .asidenav__link-label-text>
#{cName}
$if mayEdit && not courseVisible
\ #{iconInvisible}
$if showFavToggle favReason
<div .asidenav__link-favourite-toggle>
^{favouriteToggleWgt}
<div .asidenav__nested-list-wrapper>
$maybe pageActions <- mPageActions
<ul .asidenav__nested-list.list--iconless>
$forall (label, route) <- pageActions
<li .asidenav__nested-list-item>
<a .asidenav__link-wrapper href=#{route}>#{label}
$nothing
<p .asidenav__nested-list--unavailable>
_{MsgFavouritesUnavailableTip}
$if anyFavToggle
<div .asidenav__box-explanation>
_{MsgFavouritesToggleTip}

View File

@ -5,9 +5,11 @@ $#
$# SPDX-License-Identifier: AGPL-3.0-or-later
<div .breadcrumbs__container>
<a .breadcrumbs__home href=@{NewsR}>
<i .fas .fa-fw .fa-#{iconText IconBreadcrumbsHome}>
<ul .breadcrumbs__list.list--inline>
<a .breadcrumbs__link.breadcrumbs__home href=@{NewsR}>
<i .fas .fa-fw .fa-#{iconText IconBreadcrumbsHome}>
$forall (bcRoute, bcTitle, hasAccess) <- parents
<li .breadcrumbs__item>
$if hasAccess

View File

@ -9,6 +9,11 @@ $# SPDX-License-Identifier: AGPL-3.0-or-later
<div .navbar__stack>
<div .navbar__list-wrapper>
<ul .navbar__list.navbar__list-left>
<a .navbar__list-item.navbar__logo href="/">
<div .navbar__logo-lmu >
#{logo}
$# manually add favorites to navbar for small screens
<li .navbar__list-item.navbar__list-item--favorite>
<a .navbar__link-wrapper href="#">