diff --git a/frontend/src/utils/course-teaser/course-teaser.js b/frontend/src/utils/course-teaser/course-teaser.js new file mode 100644 index 000000000..c68da6074 --- /dev/null +++ b/frontend/src/utils/course-teaser/course-teaser.js @@ -0,0 +1,37 @@ +import { Utility } from '../../core/utility'; +import './course-teaser.scss'; + +var COURSE_TEASER_INITIALIZED_CLASS = 'course-teaser--initialized'; + +var COURSE_TEASER_EXPANDED_CLASS = 'course-teaser__expanded'; +var COURSE_TEASER_CHEVRON_CLASS = 'course-teaser__chevron'; + +@Utility({ + selector: '[uw-course-teaser]', +}) +export class CourseTeaser { + + _element; + + constructor(element) { + if (!element) { + throw new Error('CourseTeaser utility cannot be setup without an element!'); + } + if (element.classList.contains(COURSE_TEASER_INITIALIZED_CLASS)) { + return false; + } + this._element = element; + element.addEventListener('click', e => this._onToggleExpand(e)); + } + + _onToggleExpand(event) { + var isLink = event.target.tagName.toLowerCase() === 'a'; + var isChevron = event.target.classList.contains(COURSE_TEASER_CHEVRON_CLASS); + var isExpanded = event.target.classList.contains(COURSE_TEASER_EXPANDED_CLASS); + + if ((!isExpanded && !isLink) || isChevron) { + this._element.classList.toggle(COURSE_TEASER_EXPANDED_CLASS); + } + } + +} \ No newline at end of file diff --git a/frontend/src/utils/course-teaser/course-teaser.md b/frontend/src/utils/course-teaser/course-teaser.md new file mode 100644 index 000000000..70152d3b3 --- /dev/null +++ b/frontend/src/utils/course-teaser/course-teaser.md @@ -0,0 +1,8 @@ +# CourseTeaser + +Handles expanding and collapsing single course teaser widgets on click. + +## Example usage +```html +
+``` \ No newline at end of file diff --git a/frontend/src/utils/course-teaser/course-teaser.scss b/frontend/src/utils/course-teaser/course-teaser.scss new file mode 100644 index 000000000..1b7a7bb31 --- /dev/null +++ b/frontend/src/utils/course-teaser/course-teaser.scss @@ -0,0 +1,135 @@ +[uw-course-teaser] { + display: grid; + grid-gap: 5px 7px; + grid-template-columns: 50px 120px 1fr; + padding: 10px; + /* background-color: var(--course-bg-color); */ + transition: background-color .1s ease-out; + cursor: pointer; + + &:hover { + background-color: var(--course-bg-color); + } + + + [uw-course-teaser] { + margin-top: 10px; + } +} + +/* chevron */ +.course-teaser__chevron { + cursor: pointer; + padding: 10px; + grid-column: 1; + grid-row: 2; + justify-self: center; + align-self: center; + + &::before { + content: ''; + display: block; + margin-top: -8px; + border-width: 0 3px 3px 0; + width: 8px; + height: 8px; + border-color: var(--color-fontsec); + border-style: solid; + transform: rotate(45deg); + transition: transform .2s ease-out; + } +} + +/* semester */ +.course-teaser__semester { + grid-column: 2; + grid-row: 1; + justify-self: end; + font-size: 1.1rem; + a { + color: var(--color-fontsec); + } +} + +/* shorthand */ +.course-teaser__shorthand { + grid-column: 2; + grid-row: 2; + justify-self: end; + font-size: 1.2rem; + font-weight: bold; +} + +/* title */ +.course-teaser__title { + grid-column: 3; + grid-row: 2; + font-size: 1.2rem; + align-self: baseline; +} + +/* registration */ +.course-teaser__registration { + grid-column: 4; + grid-row: 2; + justify-self: end; + align-self: baseline; + color: var(--color-fontsec); +} + +/* school */ +.course-teaser__school-value { + grid-column: 3; + grid-row: 1; + align-self: end; + a { + color: var(--color-fontsec); + } +} + +/* description */ +.course-teaser__description { + grid-column: 3; + color: var(--color-fontsec); +} + +/* subtitle */ +.course-teaser__lecturer-label, +.course-teaser__duedate-label, +.course-teaser__school-label { + grid-column: 2; + justify-self: end; + color: var(--color-fontsec); + font-style: italic; +} + +/* hidden in closed state */ +.course-teaser__duedate-label, +.course-teaser__duedate-value, +.course-teaser__description, +.course-teaser__registration { + display: none; +} + +/* registered courses */ +.course-teaser__registered { + .course-teaser__registration { + display: block; + } + } + +/* expanded courses */ +.course-teaser__expanded { + max-height: 1000px; + + .course-teaser__chevron::before { + transform: translateY(7px) rotate(225deg); + } + + .course-teaser__school-label, + .course-teaser__school-value, + .course-teaser__duedate-label, + .course-teaser__duedate-value, + .course-teaser__description { + display: block; + } +} \ No newline at end of file diff --git a/frontend/src/utils/utils.js b/frontend/src/utils/utils.js index 04e77ec38..06e095af6 100644 --- a/frontend/src/utils/utils.js +++ b/frontend/src/utils/utils.js @@ -9,6 +9,7 @@ import { InputUtils } from './inputs/inputs'; import { MassInput } from './mass-input/mass-input'; import { Modal } from './modal/modal'; import { Tooltip } from './tooltips/tooltips'; +import { CourseTeaser } from './course-teaser/course-teaser'; export const Utils = [ Alerts, @@ -23,4 +24,5 @@ export const Utils = [ Modal, ShowHide, Tooltip, + CourseTeaser, ]; diff --git a/src/Handler/Utils/Table/Pagination.hs b/src/Handler/Utils/Table/Pagination.hs index c816d557b..5c4fffe48 100644 --- a/src/Handler/Utils/Table/Pagination.hs +++ b/src/Handler/Utils/Table/Pagination.hs @@ -1035,14 +1035,13 @@ dbTable PSValidator{..} dbtable@DBTable{ dbtIdent = dbtIdent'@(toPathPiece -> db columnCount = olength64 $ getColonnade dbtColonnade in case dbsTemplate of DBSTCourse c l r s -> do - wRows <- forM (zip [0..length rows] rows) $ \(cid, row') -> let + wRows <- forM rows $ \row' -> let Course{..} = row' ^. c . _entityVal lecturerUsers = row' ^. l courseLecturers = userSurname . entityVal <$> lecturerUsers isRegistered = row' ^. r courseSchoolName = schoolName $ row' ^. s . _entityVal courseSemester = (termToText . unTermKey) courseTerm - courseId = tshow cid in return $(widgetFile "table/course/course-teaser") return $(widgetFile "table/course/colonnade") diff --git a/templates/table/course/colonnade.lucius b/templates/table/course/colonnade.lucius index 49e4996b4..99925c2a4 100644 --- a/templates/table/course/colonnade.lucius +++ b/templates/table/course/colonnade.lucius @@ -9,139 +9,3 @@ .scrolltable { box-shadow: none!important; } - -.course-teaser { - display: grid; - grid-gap: 5px 7px; - grid-template-columns: 50px 120px 1fr; - padding: 10px; - /* background-color: var(--course-bg-color); */ - transition: background-color .1s ease-out; - cursor: pointer; - - &:hover { - background-color: var(--course-bg-color); - } - - + .course-teaser { - margin-top: 10px; - } -} - -/* chevron */ -.course-teaser__chevron { - cursor: pointer; - padding: 10px; - grid-column: 1; - grid-row: 2; - justify-self: center; - align-self: center; - - &::before { - content: ''; - display: block; - margin-top: -8px; - border-width: 0 3px 3px 0; - width: 8px; - height: 8px; - border-color: var(--color-fontsec); - border-style: solid; - transform: rotate(45deg); - transition: transform .2s ease-out; - } -} - -/* semester */ -.course-teaser__semester { - grid-column: 2; - grid-row: 1; - justify-self: end; - font-size: 1.1rem; - a { - color: var(--color-fontsec); - } -} - -/* shorthand */ -.course-teaser__shorthand { - grid-column: 2; - grid-row: 2; - justify-self: end; - font-size: 1.2rem; - font-weight: bold; -} - -/* title */ -.course-teaser__title { - grid-column: 3; - grid-row: 2; - font-size: 1.2rem; - align-self: baseline; -} - -/* registration */ -.course-teaser__registration { - grid-column: 4; - grid-row: 2; - justify-self: end; - align-self: baseline; - color: var(--color-fontsec); -} - -/* school */ -.course-teaser__school-value { - grid-column: 3; - grid-row: 1; - align-self: end; - a { - color: var(--color-fontsec); - } -} - -/* description */ -.course-teaser__description { - grid-column: 3; - color: var(--color-fontsec); -} - -/* subtitle */ -.course-teaser__lecturer-label, -.course-teaser__duedate-label, -.course-teaser__school-label { - grid-column: 2; - justify-self: end; - color: var(--color-fontsec); - font-style: italic; -} - -/* hidden in closed state */ -.course-teaser__duedate-label, -.course-teaser__duedate-value, -.course-teaser__description, -.course-teaser__registration { - display: none; -} - -/* registered courses */ -.course-teaser__registered { - .course-teaser__registration { - display: block; - } - } - -/* expanded courses */ -.course-teaser__expanded { - max-height: 1000px; - - .course-teaser__chevron::before { - transform: translateY(7px) rotate(225deg); - } - - .course-teaser__school-label, - .course-teaser__school-value, - .course-teaser__duedate-label, - .course-teaser__duedate-value, - .course-teaser__description { - display: block; - } -} diff --git a/templates/table/course/course-teaser.hamlet b/templates/table/course/course-teaser.hamlet index 29e475cda..183ac86f7 100644 --- a/templates/table/course/course-teaser.hamlet +++ b/templates/table/course/course-teaser.hamlet @@ -1,4 +1,4 @@ -
+
_{courseSemester} diff --git a/templates/table/course/course-teaser.julius b/templates/table/course/course-teaser.julius deleted file mode 100644 index 5f7424117..000000000 --- a/templates/table/course/course-teaser.julius +++ /dev/null @@ -1,25 +0,0 @@ -var COURSE_TEASER_EXPANDED_CLASS = 'course-teaser__expanded'; -var COURSE_TEASER_CHEVRON_CLASS = 'course-teaser__chevron'; - -document.addEventListener('DOMContentLoaded', function() { - var courseTeaserId = #{String courseId}; - var courseTeaser = document.querySelector('#courseteaser-' + courseTeaserId); - - courseTeaser.addEventListener('click', function(event) { - var isLink = event.target.tagName.toLowerCase() === 'a'; - var isChevron = event.target.classList.contains(COURSE_TEASER_CHEVRON_CLASS); - var isExpanded = courseTeaser.classList.contains(COURSE_TEASER_EXPANDED_CLASS); - - if ((!isExpanded && !isLink) || isChevron) { - courseTeaser.classList.toggle(COURSE_TEASER_EXPANDED_CLASS); - } - }); - - courseTeaser.addEventListener('keydown', function(event) { - var eventKey = event.key; - if (eventKey === ' ' || eventKey === 'Enter') { - event.preventDefault(); - courseTeaser.classList.toggle(COURSE_TEASER_EXPANDED_CLASS); - } - }); -}); \ No newline at end of file