Merge branch 'master' into nutzungsbedingungen

This commit is contained in:
Sarah Vaupel 2019-12-18 17:20:04 +01:00
commit 36b7106c26
103 changed files with 6103 additions and 4920 deletions

View File

@ -1,4 +0,0 @@
((haskell-mode . ((haskell-indent-spaces . 4)
(haskell-process-use-ghci . t)))
(hamlet-mode . ((hamlet/basic-offset . 4)
(haskell-process-use-ghci . t))))

View File

@ -33,6 +33,10 @@ npm install:
- n stable
- npm install -g npm
- hash -r
- apt-get install openssh-client -y
- install -m 0700 -d ~/.ssh
- install -T -m 0644 ${SSH_KNOWN_HOSTS} ~/.ssh/known_hosts
- for keyVar in ${!SSH_PRIVATE_KEY_NPM_*}; do install -T -m 0400 ${!keyVar} ~/.ssh/${keyVar}; echo "IdentityFile ~/.ssh/${keyVar}" >> ~/.ssh/config; done
artifacts:
paths:
- node_modules/
@ -78,6 +82,10 @@ yesod:build:dev:
- apt-get update -y
- apt-get install -y --no-install-recommends locales-all
- ln -s $(which g++-7) $(dirname $(which g++-7))/g++
- 'which ssh-agent || apt-get install openssh-client -y'
- install -m 0700 -d ~/.ssh
- install -T -m 0644 ${SSH_KNOWN_HOSTS} ~/.ssh/known_hosts
- for keyVar in ${!SSH_PRIVATE_KEY_STACK_*}; do install -T -m 0400 ${!keyVar} ~/.ssh/${keyVar}; echo "IdentityFile ~/.ssh/${keyVar}" >> ~/.ssh/config; done
artifacts:
paths:
- bin/
@ -101,6 +109,10 @@ yesod:build:
- apt-get update -y
- apt-get install -y --no-install-recommends locales-all
- ln -s $(which g++-7) $(dirname $(which g++-7))/g++
- apt-get install -y --no-install-recommends openssh-client
- install -m 0700 -d ~/.ssh
- install -T -m 0644 ${SSH_KNOWN_HOSTS} ~/.ssh/known_hosts
- for keyVar in ${!SSH_PRIVATE_KEY_STACK_*}; do install -T -m 0400 ${!keyVar} ~/.ssh/${keyVar}; echo "IdentityFile ~/.ssh/${keyVar}" >> ~/.ssh/config; done
artifacts:
paths:
- bin/
@ -226,8 +238,8 @@ deploy:uniworx3:
- apt-get update -y
- apt-get install -y --no-install-recommends openssh-client
- install -m 0700 -d ~/.ssh
- install -m 0644 ${SSH_KNOWN_HOSTS} ~/.ssh/known_hosts
- install -m 0400 ${SSH_PRIVATE_KEY_UNIWORX3} ~/.ssh/id
- install -T -m 0644 ${SSH_KNOWN_HOSTS} ~/.ssh/known_hosts
- install -T -m 0400 ${SSH_PRIVATE_KEY_UNIWORX3} ~/.ssh/SSH_PRIVATE_KEY_UNIWORX3; echo "IdentityFile ~/.ssh/SSH_PRIVATE_KEY_UNIWORX3" >> ~/.ssh/config;
dependencies:
- yesod:build

View File

@ -0,0 +1,9 @@
@use "~@fortawesome/fontawesome-pro/scss/fontawesome" with ( $fa-font-path: "~@fortawesome/fontawesome-pro/webfonts" )
@forward "~@fortawesome/fontawesome-pro/scss/fontawesome"
@use "~@fortawesome/fontawesome-pro/scss/solid"
@use "~typeface-roboto" as roboto
@use "~typeface-source-sans-pro" as source-sans-pro

View File

@ -4,13 +4,7 @@ import { I18n } from './services/i18n/i18n';
import { UtilRegistry } from './services/util-registry/util-registry';
import { isValidUtility } from './core/utility';
// load window.fetch polyfill
import 'whatwg-fetch';
import '@fortawesome/fontawesome-pro/css/all.css';
import 'typeface-roboto/index.css';
import 'typeface-source-sans-pro/index.css';
import './app.sass';
export class App {
httpClient = new HttpClient();

1191
frontend/src/app.sass Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
/* eslint-env node */
import { App } from './app';
import { Utility } from './core/utility';
@ -13,52 +15,50 @@ const TEST_UTILS = [
];
describe('App', () => {
let app;
beforeEach(() => {
app = new App();
global.App = new App();
});
it('should create', () => {
expect(app).toBeTruthy();
expect(global.App).toBeTruthy();
});
it('should setup all utlites when page is done loading', () => {
spyOn(app.utilRegistry, 'setupAll');
spyOn(global.App.utilRegistry, 'setupAll');
document.dispatchEvent(new Event('DOMContentLoaded'));
expect(app.utilRegistry.setupAll).toHaveBeenCalled();
expect(global.App.utilRegistry.setupAll).toHaveBeenCalled();
});
describe('provides services', () => {
it('HttpClient as httpClient', () => {
expect(app.httpClient).toBeTruthy();
expect(global.App.httpClient).toBeTruthy();
});
it('HtmlHelpers as htmlHelpers', () => {
expect(app.htmlHelpers).toBeTruthy();
expect(global.App.htmlHelpers).toBeTruthy();
});
it('I18n as i18n', () => {
expect(app.i18n).toBeTruthy();
expect(global.App.i18n).toBeTruthy();
});
it('UtilRegistry as utilRegistry', () => {
expect(app.utilRegistry).toBeTruthy();
expect(global.App.utilRegistry).toBeTruthy();
});
});
describe('registerUtilities()', () => {
it('should register the given utilities', () => {
spyOn(app.utilRegistry, 'register');
app.registerUtilities(TEST_UTILS);
expect(app.utilRegistry.register.calls.count()).toBe(TEST_UTILS.length);
expect(app.utilRegistry.register.calls.argsFor(0)).toEqual([TEST_UTILS[0]]);
expect(app.utilRegistry.register.calls.argsFor(1)).toEqual([TEST_UTILS[1]]);
spyOn(global.App.utilRegistry, 'register');
global.App.registerUtilities(TEST_UTILS);
expect(global.App.utilRegistry.register.calls.count()).toBe(TEST_UTILS.length);
expect(global.App.utilRegistry.register.calls.argsFor(0)).toEqual([TEST_UTILS[0]]);
expect(global.App.utilRegistry.register.calls.argsFor(1)).toEqual([TEST_UTILS[1]]);
});
it('should throw an error if not passed an array of utilities', () => {
expect(() => {
app.registerUtilities({});
global.App.registerUtilities({});
}).toThrow();
});
});

View File

@ -0,0 +1,223 @@
/* global global:writable */
import * as semver from 'semver';
export const LOCATION = {
LOCAL: 'local',
WINDOW: 'window',
};
const LOCATION_SHADOWING = [ LOCATION.WINDOW, LOCATION.LOCAL ];
export class StorageManager {
namespace;
version;
_options;
_global;
constructor(namespace, version, options) {
this.namespace = namespace;
this.version = semver.valid(version);
if (!namespace) {
throw new Error('Cannot setup StorageManager without namespace');
}
if (!this.version) {
throw new Error('Cannot setup StorageManager without valid semver version');
}
if (options !== undefined) {
this._options = options;
}
if (global !== undefined)
this._global = global;
else if (window !== undefined)
this._global = window;
else
throw new Error('Cannot setup StorageManager without window or global');
}
save(key, value, options=this._options) {
if (!key) {
throw new Error('StorageManager.save called with invalid key');
}
if (options && options.location !== undefined && !Object.values(LOCATION).includes(options.location)) {
throw new Error('StorageManager.save called with unsupported location option');
}
const location = options && options.location !== undefined ? options.location : LOCATION_SHADOWING[0];
switch (location) {
case LOCATION.LOCAL: {
this._saveToLocalStorage({ ...this._getFromLocalStorage(), [key]: value });
break;
}
case LOCATION.WINDOW: {
this._saveToWindow({ ...this._getFromLocalStorage(), [key]: value });
break;
}
default:
console.error('StorageManager.save cannot save item with unsupported location');
}
}
load(key, options=this._options) {
if (options && options.location !== undefined && !Object.values(LOCATION).includes(options.location)) {
throw new Error('StorageManager.load called with unsupported location option');
}
let locations = options && options.location !== undefined ? [options.location] : LOCATION_SHADOWING;
while (locations.length > 0) {
const location = locations.shift();
let val;
switch (location) {
case LOCATION.LOCAL: {
val = this._getFromLocalStorage()[key];
break;
}
case LOCATION.WINDOW: {
val = this._getFromWindow()[key];
break;
}
default:
console.error('StorageManager.load cannot load item with unsupported location');
}
if (val !== undefined || locations.length === 0) {
return val;
}
}
}
remove(key, options=this._options) {
if (options && options.location !== undefined && !Object.values(LOCATION).includes(options.location)) {
throw new Error('StorageManager.load called with unsupported location option');
}
const locations = options && options.location !== undefined ? [options.location] : LOCATION_SHADOWING;
for (const location of locations) {
switch (location) {
case LOCATION.LOCAL: {
let val = this._getFromLocalStorage();
delete val[key];
return this._saveToLocalStorage(val);
}
case LOCATION.WINDOW: {
let val = this._getFromWindow();
delete val[key];
return this._saveToWindow(val);
}
default:
console.error('StorageManager.load cannot load item with unsupported location');
}
}
}
clear(options) {
if (options && options.location !== undefined && !Object.values(LOCATION).includes(options.location)) {
throw new Error('StorageManager.clear called with unsupported location option');
}
const locations = options && options.location !== undefined ? [options.location] : LOCATION_SHADOWING;
for (const location of locations) {
switch (location) {
case LOCATION.LOCAL:
return this._clearLocalStorage();
case LOCATION.WINDOW:
return this._clearWindow();
default:
console.error('StorageManager.clear cannot clear with unsupported location');
}
}
}
_getFromLocalStorage() {
let state;
try {
state = JSON.parse(window.localStorage.getItem(this.namespace));
} catch {
state = null;
}
if (state === null || !state.version || !semver.satisfies(this.version, `^${state.version}`)) {
// remove item from localStorage if it stores an invalid state
this._clearLocalStorage();
return {};
}
if ('state' in state)
return state.state;
else {
delete state.version;
return state;
}
}
_saveToLocalStorage(state) {
if (!state)
return this._clearLocalStorage();
let versionedState;
if ('version' in state || 'state' in state) {
versionedState = { version: this.version, state: state };
} else {
versionedState = { version: this.version, ...state };
}
window.localStorage.setItem(this.namespace, JSON.stringify(versionedState));
}
_clearLocalStorage() {
window.localStorage.removeItem(this.namespace);
}
_getFromWindow() {
if (!this._global || !this._global.App)
return {};
if (!this._global.App.Storage)
this._global.App.Storage = {};
return this._global.App.Storage[this.namespace] || {};
}
_saveToWindow(value) {
if (!this._global || !this._global.App) {
throw new Error('StorageManager._saveToWindow called when window.App is not available');
}
if (!value)
return this._clearWindow();
if (!this._global.App.Storage)
this._global.App.Storage = {};
this._global.App.Storage[this.namespace] = value;
}
_clearWindow() {
if (!this._global || !this._global.App) {
throw new Error('StorageManager._saveToWindow called when window.App is not available');
}
if (this._global.App.Storage) {
delete this._global.App.Storage[this.namespace];
}
}
}

4
frontend/src/polyfill.js Normal file
View File

@ -0,0 +1,4 @@
import 'whatwg-fetch';
import { ResizeObserver as Polyfill } from '@juggle/resize-observer';
window.ResizeObserver = window.ResizeObserver || Polyfill;

View File

@ -1,5 +1,5 @@
import { Utility } from '../../core/utility';
import './alerts.scss';
import './alerts.sass';
const ALERTS_INITIALIZED_CLASS = 'alerts--initialized';
const ALERTS_ELEVATED_CLASS = 'alerts--elevated';

View File

@ -0,0 +1,186 @@
@use "../../common" as *
.alerts
position: fixed
bottom: 0
right: 5%
z-index: 20
text-align: right
display: flex
flex-direction: column
.alerts__toggler
width: 40px
height: 40px
position: absolute
top: 400px
left: 50%
transform: translateX(-50%)
cursor: pointer
&::before
@extend .fas
content: fa-content($fa-var-chevron-up)
position: absolute
left: 50%
top: 0
height: 30px
display: flex
align-items: center
justify-content: center
width: 30px
color: var(--color-grey)
font-size: 30px
transform: translateX(-50%)
&:hover::before
color: var(--color-grey-medium)
.alerts--elevated
z-index: 1000
.alerts__toggler--visible
top: -40px
opacity: 1
transition: top 0.5s cubic-bezier(0.73, 1.25, 0.61, 1), opacity 0.5s cubic-bezier(0.73, 1.25, 0.61, 1)
@media (max-width: 425px)
.alerts
left: 5%
.alert
position: relative
display: block
background-color: var(--color-lightblack)
font-size: 1rem
color: var(--color-lightwhite)
z-index: 0
padding: 0 50px
padding-right: 60px
animation: slide-in-alert .2s ease-out forwards
margin-bottom: 10px
transition: margin-bottom .2s ease-out
.alert a
color: var(--color-lightwhite)
&:hover
color: var(--color-grey)
@keyframes slide-in-alert
from
transform: translateY(120%)
to
transform: translateY(0)
@keyframes slide-out-alert
from
transform: translateY(0)
max-height: 200px
to
transform: translateY(250%)
opacity: 0
max-height: 0
overflow: hidden
@media (min-width: 425px)
.alert
max-width: 400px
.alert--invisible
animation: slide-out-alert .2s ease-out forwards
margin-bottom: 0
.alert__content
padding: 8px 0
min-height: 40px
position: relative
display: flex
font-weight: 600
align-items: center
text-align: left
.alert__icon
text-align: right
position: absolute
left: 0px
top: 0
width: 50px
height: 100%
z-index: 40
&::before
position: absolute
font-size: 24px
top: 50%
left: 50%
display: flex
align-items: center
justify-content: center
transform: translate(-50%, -50%)
border-radius: 50%
width: 30px
height: 30px
.alert__closer
cursor: pointer
text-align: right
position: absolute
right: 0px
top: 0
width: 60px
height: 100%
transition: all .3s ease
z-index: 40
&:hover
transform: scale(1.05, 1.05)
&::before
box-shadow: 0 0 4px white
background-color: rgba(255, 255, 255, 0.1)
color: white
&::before
@extend .fas
content: fa-content($fa-var-times)
position: absolute
top: 50%
left: 50%
display: flex
align-items: center
justify-content: center
transform: translate(-50%, -50%)
border-radius: 50%
width: 30px
height: 30px
transition: all .15s ease
@media (max-width: 768px)
.alert__closer
width: 40px
.alert-success
background-color: var(--color-success)
// .alert__icon::before {
// --alert-icon-default: '\f058';
// }
.alert-warning
background-color: var(--color-warning)
// .alert__icon::before {
// --alert-icon-default: '\f06a';
// }
.alert-error
background-color: var(--color-error)
// .alert__icon::before {
// --alert-icon-default: '\f071';
// }

View File

@ -1,221 +0,0 @@
.alerts {
position: fixed;
bottom: 0;
right: 5%;
z-index: 20;
text-align: right;
display: flex;
flex-direction: column;
}
.alerts__toggler {
width: 40px;
height: 40px;
position: absolute;
top: 400px;
left: 50%;
transform: translateX(-50%);
cursor: pointer;
&::before {
content: '\f077';
position: absolute;
font-family: 'Font Awesome 5 Free';
left: 50%;
top: 0;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
width: 30px;
color: var(--color-grey);
font-size: 30px;
transform: translateX(-50%);
}
&:hover::before {
color: var(--color-grey-medium);
}
}
.alerts--elevated {
z-index: 1000;
}
.alerts__toggler--visible {
top: -40px;
opacity: 1;
transition: top .5s cubic-bezier(0.73, 1.25, 0.61, 1),
opacity .5s cubic-bezier(0.73, 1.25, 0.61, 1);
}
@media (max-width: 425px) {
.alerts {
left: 5%;
}
}
.alert {
position: relative;
display: block;
background-color: var(--color-lightblack);
font-size: 1rem;
color: var(--color-lightwhite);
z-index: 0;
padding: 0 50px;
padding-right: 60px;
animation: slide-in-alert .2s ease-out forwards;
margin-bottom: 10px;
transition: margin-bottom .2s ease-out;
}
.alert a {
color: var(--color-lightwhite);
&:hover {
color: var(--color-grey);
}
}
@keyframes slide-in-alert {
from {
transform: translateY(120%);
}
to {
transform: translateY(0);
}
}
@keyframes slide-out-alert {
from {
transform: translateY(0);
max-height: 200px;
}
to {
transform: translateY(250%);
opacity: 0;
max-height: 0;
overflow: hidden;
}
}
@media (min-width: 425px) {
.alert {
max-width: 400px;
}
}
.alert--invisible {
animation: slide-out-alert .2s ease-out forwards;
margin-bottom: 0;
}
.alert__content {
padding: 8px 0;
min-height: 40px;
position: relative;
display: flex;
font-weight: 600;
align-items: center;
text-align: left;
}
.alert__icon {
text-align: right;
position: absolute;
left: 0px;
top: 0;
width: 50px;
height: 100%;
z-index: 40;
&::before {
/* content: var(--alert-icon, var(--alert-icon-default, '\f05a')); */
position: absolute;
/* font-family: 'Font Awesome 5 Free'; */
font-size: 24px;
top: 50%;
left: 50%;
display: flex;
align-items: center;
justify-content: center;
transform: translate(-50%, -50%);
border-radius: 50%;
width: 30px;
height: 30px;
}
}
.alert__closer {
cursor: pointer;
text-align: right;
position: absolute;
right: 0px;
top: 0;
width: 60px;
height: 100%;
transition: all .3s ease;
z-index: 40;
&:hover {
transform: scale(1.05, 1.05);
&::before {
box-shadow: 0 0 4px white;
background-color: rgba(255, 255, 255, 0.1);
color: white;
}
}
&::before {
content: '\f00d';
position: absolute;
font-family: 'Font Awesome 5 Free';
top: 50%;
left: 50%;
display: flex;
align-items: center;
justify-content: center;
transform: translate(-50%, -50%);
border-radius: 50%;
width: 30px;
height: 30px;
transition: all .15s ease;
}
}
@media (max-width: 768px) {
.alert__closer {
width: 40px;
}
}
.alert-success {
background-color: var(--color-success);
/* .alert__icon::before {
* --alert-icon-default: '\f058';
* }
*/
}
.alert-warning {
background-color: var(--color-warning);
/* .alert__icon::before {
* --alert-icon-default: '\f06a';
* }
*/
}
.alert-error {
background-color: var(--color-error);
/* .alert__icon::before {
* --alert-icon-default: '\f071';
* }
*/
}

View File

@ -1,5 +1,5 @@
import { Utility } from '../../core/utility';
import './asidenav.scss';
import './asidenav.sass';
const FAVORITES_BTN_CLASS = 'navbar__list-item--favorite';
const FAVORITES_BTN_ACTIVE_CLASS = 'navbar__list-item--active';

View File

@ -0,0 +1,330 @@
.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%)
height: 100%
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
&::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)
.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
// 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: 80px
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-label
line-height: 1
// hover sub-menus
.asidenav__nested-list-wrapper
position: absolute
z-index: 10
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
@media (max-width: 425px)
.asidenav__list-item
padding-left: 10px
.asidenav__nested-list
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)
.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)
&: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
display: none
.asidenav__list-item--active
.asidenav__link-wrapper
background-color: var(--color-lightwhite)

View File

@ -1,406 +0,0 @@
.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%);
height: 100%;
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;
}
&::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);
.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;
}
/* 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: 80px;
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.0);
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-label {
line-height: 1;
}
/* hover sub-menus */
.asidenav__nested-list-wrapper {
position: absolute;
z-index: 10;
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;
}
@media (max-width: 425px) {
.asidenav__list-item {
padding-left: 10px;
}
.asidenav__nested-list {
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);
.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);
&: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 {
display: none;
}
.asidenav__list-item--active {
.asidenav__link-wrapper {
background-color: var(--color-lightwhite);
}
}
}
}

View File

@ -1,6 +1,6 @@
import { Utility } from '../../core/utility';
import { Datepicker } from '../form/datepicker';
import './async-form.scss';
import './async-form.sass';
const ASYNC_FORM_INITIALIZED_CLASS = 'check-all--initialized';
const ASYNC_FORM_RESPONSE_CLASS = 'async-form__response';

View File

@ -0,0 +1,71 @@
.async-form__response
margin: 20px 0
position: relative
width: 100%
font-size: 18px
text-align: center
padding-top: 60px
.async-form__response::before,
.async-form__response::after
position: absolute
top: 0px
left: 50%
display: block
.async-form__response--success::before
content: ''
width: 17px
height: 28px
border: solid #069e04
border-width: 0 5px 5px 0
transform: translateX(-50%) rotate(45deg)
.async-form__response--info::before
content: ''
width: 5px
height: 30px
top: 10px
background-color: #777
transform: translateX(-50%)
.async-form__response--info::after
content: ''
width: 5px
height: 5px
background-color: #777
transform: translateX(-50%)
.async-form__response--warning::before
content: ''
width: 5px
height: 30px
background-color: rgb(255, 187, 0)
transform: translateX(-50%)
.async-form__response--warning::after
content: ''
width: 5px
height: 5px
top: 35px
background-color: rgb(255, 187, 0)
transform: translateX(-50%)
.async-form__response--error::before
content: ''
width: 5px
height: 40px
background-color: #940d0d
transform: translateX(-50%) rotate(-45deg)
.async-form__response--error::after
content: ''
width: 5px
height: 40px
background-color: #940d0d
transform: translateX(-50%) rotate(45deg)
.async-form--loading
opacity: 0.1
transition: opacity 800ms ease-out
pointer-events: none

View File

@ -1,78 +0,0 @@
.async-form__response {
margin: 20px 0;
position: relative;
width: 100%;
font-size: 18px;
text-align: center;
padding-top: 60px;
}
.async-form__response::before,
.async-form__response::after {
position: absolute;
top: 0px;
left: 50%;
display: block;
}
.async-form__response--success::before {
content: '';
width: 17px;
height: 28px;
border: solid #069e04;
border-width: 0 5px 5px 0;
transform: translateX(-50%) rotate(45deg);
}
.async-form__response--info::before {
content: '';
width: 5px;
height: 30px;
top: 10px;
background-color: #777;
transform: translateX(-50%);
}
.async-form__response--info::after {
content: '';
width: 5px;
height: 5px;
background-color: #777;
transform: translateX(-50%);
}
.async-form__response--warning::before {
content: '';
width: 5px;
height: 30px;
background-color: rgb(255, 187, 0);
transform: translateX(-50%);
}
.async-form__response--warning::after {
content: '';
width: 5px;
height: 5px;
top: 35px;
background-color: rgb(255, 187, 0);
transform: translateX(-50%);
}
.async-form__response--error::before {
content: '';
width: 5px;
height: 40px;
background-color: #940d0d;
transform: translateX(-50%) rotate(-45deg);
}
.async-form__response--error::after {
content: '';
width: 5px;
height: 40px;
background-color: #940d0d;
transform: translateX(-50%) rotate(45deg);
}
.async-form--loading {
opacity: 0.1;
transition: opacity 800ms ease-out;
pointer-events: none;
}

View File

@ -0,0 +1,4 @@
.async-table-filter--loading
opacity: 0.7
pointer-events: none
transition: opacity 400ms ease-out

View File

@ -1,5 +0,0 @@
.async-table-filter--loading {
opacity: 0.7;
pointer-events: none;
transition: opacity 400ms ease-out;
}

View File

@ -1,9 +1,10 @@
import { Utility } from '../../core/utility';
import { StorageManager, LOCATION } from '../../lib/storage-manager/storage-manager';
import { Datepicker } from '../form/datepicker';
import { HttpClient } from '../../services/http-client/http-client';
import * as debounce from 'lodash.debounce';
import './async-table-filter.scss';
import './async-table.scss';
import './async-table-filter.sass';
import './async-table.sass';
const INPUT_DEBOUNCE = 600;
const HEADER_HEIGHT = 80;
@ -40,6 +41,8 @@ export class AsyncTable {
};
_ignoreRequest = false;
_storageManager = new StorageManager(ASYNC_TABLE_LOCAL_STORAGE_KEY, '1.0.0', { location: LOCATION.WINDOW });
constructor(element, app) {
if (!element) {
throw new Error('Async Table utility cannot be setup without an element!');
@ -81,10 +84,10 @@ export class AsyncTable {
this._setupPageSizeSelect();
this._setupTableFilter();
this._processLocalStorage();
this._processStorage();
// clear currentTableUrl from previous requests
setLocalStorageParameter('currentTableUrl', null);
this._storageManager.remove('currentTableUrl');
// mark initialized
this._element.classList.add(ASYNC_TABLE_INITIALIZED_CLASS);
@ -100,7 +103,7 @@ export class AsyncTable {
this._ths.forEach((th) => {
th.clickHandler = (event) => {
setLocalStorageParameter('horizPos', (this._scrollTable || {}).scrollLeft);
this._storageManager.save('horizPos', (this._scrollTable || {}).scrollLeft);
this._linkClickHandler(event);
};
th.element.addEventListener('click', th.clickHandler);
@ -122,7 +125,7 @@ export class AsyncTable {
left: this._scrollTable.offsetLeft || 0,
behavior: 'smooth',
};
setLocalStorageParameter('scrollTo', scrollTo);
this._storageManager.save('scrollTo', scrollTo);
}
this._linkClickHandler(event);
};
@ -225,7 +228,7 @@ export class AsyncTable {
const prefix = findCssIdPrefix(focusedInput.id);
const focusId = focusedInput.id.replace(prefix, '');
callback = function(wrapper) {
const idPrefix = getLocalStorageParameter('cssIdPrefix');
const idPrefix = this._storageManager.load('cssIdPrefix');
const toBeFocused = wrapper.querySelector('#' + idPrefix + focusId);
if (toBeFocused) {
toBeFocused.focus();
@ -238,7 +241,7 @@ export class AsyncTable {
}
_serializeTableFilterToURL(tableFilterForm) {
const url = new URL(getLocalStorageParameter('currentTableUrl') || window.location.href);
const url = new URL(this._storageManager.load('currentTableUrl') || window.location.href);
// create new FormData and format any date values
const formData = Datepicker.unformatAll(this._massInputForm, new FormData(tableFilterForm));
@ -254,18 +257,18 @@ export class AsyncTable {
return url;
}
_processLocalStorage() {
const scrollTo = getLocalStorageParameter('scrollTo');
_processStorage() {
const scrollTo = this._storageManager.load('scrollTo');
if (scrollTo && this._scrollTable) {
window.scrollTo(scrollTo);
}
setLocalStorageParameter('scrollTo', null);
this._storageManager.remove('scrollTo');
const horizPos = getLocalStorageParameter('horizPos');
const horizPos = this._storageManager.load('horizPos');
if (horizPos && this._scrollTable) {
this._scrollTable.scrollLeft = horizPos;
}
setLocalStorageParameter('horizPos', null);
this._storageManager.remove('horizPos');
}
_removeListeners() {
@ -300,7 +303,7 @@ export class AsyncTable {
}
_changePagesizeHandler = () => {
const url = new URL(getLocalStorageParameter('currentTableUrl') || window.location.href);
const url = new URL(this._storageManager.load('currentTableUrl') || window.location.href);
// create new FormData and format any date values
const formData = Datepicker.unformatAll(this._pagesizeForm, new FormData(this._pagesizeForm));
@ -336,7 +339,7 @@ export class AsyncTable {
return false;
}
setLocalStorageParameter('currentTableUrl', url.href);
this._storageManager.save('currentTableUrl', url.href);
// reset table
this._removeListeners();
this._element.classList.remove(ASYNC_TABLE_INITIALIZED_CLASS);
@ -346,9 +349,9 @@ export class AsyncTable {
this._app.utilRegistry.setupAll(this._element);
if (callback && typeof callback === 'function') {
setLocalStorageParameter('cssIdPrefix', response.idPrefix);
this._storageManager.save('cssIdPrefix', response.idPrefix);
callback(this._element);
setLocalStorageParameter('cssIdPrefix', '');
this._storageManager.remove('cssIdPrefix');
}
}).catch((err) => console.error(err)
).finally(() => this._element.classList.remove(ASYNC_TABLE_LOADING_CLASS));
@ -365,17 +368,3 @@ function findCssIdPrefix(id) {
}
return '';
}
function setLocalStorageParameter(key, value) {
const currentLSState = JSON.parse(window.localStorage.getItem(ASYNC_TABLE_LOCAL_STORAGE_KEY)) || {};
if (value !== null) {
currentLSState[key] = value;
} else {
delete currentLSState[key];
}
window.localStorage.setItem(ASYNC_TABLE_LOCAL_STORAGE_KEY, JSON.stringify(currentLSState));
}
function getLocalStorageParameter(key) {
const currentLSState = JSON.parse(window.localStorage.getItem(ASYNC_TABLE_LOCAL_STORAGE_KEY)) || {};
return currentLSState[key];
}

View File

@ -0,0 +1,4 @@
.async-table--loading
opacity: 0.7
pointer-events: none
transition: opacity 400ms ease-out

View File

@ -1,5 +0,0 @@
.async-table--loading {
opacity: 0.7;
pointer-events: none;
transition: opacity 400ms ease-out;
}

View File

@ -1,5 +1,5 @@
import { Utility } from '../../core/utility';
import './course-teaser.scss';
import './course-teaser.sass';
var COURSE_TEASER_INITIALIZED_CLASS = 'course-teaser--initialized';

View File

@ -0,0 +1,246 @@
[uw-course-teaser]
--course-border-color: var(--color-grey)
--course-padding-hori: 10px
--course-padding-vert: 12px
display: grid
position: relative
grid-gap: 5px 7px
grid-template-columns: 130px 30px 1fr 60px
grid-template-areas: 'shrthnd . title chevron' 'shrthnd smstr school chevron' '. . rgstrd . ' 'tutor tutor name . ' 'duedate duedate date . ' 'dscrptn dscrptn dscrptn dscrptn'
padding: var(--course-padding-vert) var(--course-padding-hori)
transition: background-color .1s ease-out
cursor: pointer
&:hover
background-color: var(--course-bg-color)
+ [uw-course-teaser]
border-top: 1px solid var(--course-border-color)
@media (max-width: 768px)
grid-template-columns: 140px 1fr 30px
grid-template-areas: 'shrthnd title chevron' 'shrthnd title . ' 'smstr school school ' '. rgstrd rgstrd ' 'tutor name name ' 'duedate date date ' 'dscrptn dscrptn dscrptn'
@media (max-width: 426px)
grid-template-columns: 1fr
grid-template-areas: 'shrthnd' 'title' 'smstr' 'school' 'rgstrd' 'tutor' 'name' 'duedate' 'date' 'dscrptnlbl' 'dscrptn' 'chevron'
.course-teaser__not-expandable
cursor: initial
// chevron
.course-teaser__chevron
position: relative
padding: 10px
grid-area: chevron
justify-self: center
align-self: center
width: 100%
height: 100%
cursor: pointer
&::before
content: ''
position: absolute
display: block
margin-top: -7.35px
margin-left: -7.35px
// visually centered
border-width: 0 3px 3px 0
width: 8px
height: 8px
top: 50%
left: 50%
border-color: var(--color-fontsec)
border-style: solid
transform: rotate(135deg)
transform-origin: 7.25px 7.25px
// rotate about visual center
transition: all .2s ease-out
&:hover::before
transform: scale(1.4) rotate(45deg)
@media (max-width: 768px)
justify-self: end
width: auto
&::before
position: initial
@media (max-width: 426px)
&::before
transform: rotate(45deg)
margin-left: -7.35px
&:hover::before
transform: scale(1.4) rotate(45deg)
// semester
.course-teaser__semester
grid-area: smstr
justify-self: end
a
color: var(--color-fontsec)
@media (max-width: 768px)
justify-self: initial
// shorthand
.course-teaser__shorthand
position: relative
grid-area: shrthnd
font-size: 2rem
line-height: 1.25
min-height: calc(2rem * 1.25)
> a
position: absolute
height: 100%
width: 100%
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
word-break: break-any
text-decoration: none !important
// sry.
font-weight: 600
color: var(--color-grey-medium)
// @media (max-width: 768px) {
position: initial;
}
// title
.course-teaser__title
grid-area: title
font-size: 1.2rem
align-self: baseline
// registration
.course-teaser__registration
grid-area: rgstrd
color: var(--color-fontsec)
font-weight: bold
// school
.course-teaser__school
grid-area: school
a
color: var(--color-fontsec)
// duedate
.course-teaser__duedate
grid-area: date
// lecturer
.course-teaser__lecturer
grid-area: name
// description
.course-teaser__description
grid-area: dscrptn
max-height: 75vh
overflow: auto
// show description only as dots (overflow text-overflow) and only show when expanded. No "hidden fiddling"
// labels
.course-teaser__lecturer-label
grid-area: tutor
.course-teaser__duedate-label
grid-area: duedate
.course-teaser__description-label
grid-area: dscrptnlbl
.course-teaser__lecturer-label,
.course-teaser__description-label,
.course-teaser__duedate-label
justify-self: end
color: var(--color-fontsec)
font-style: italic
@media (max-width: 768px)
justify-self: initial
@media (max-width: 426px)
margin-top: 7px
font-weight: bold
font-style: initial
// hidden in closed state
.course-teaser__description,
.course-teaser__description-label
display: none
// expanded courses
.course-teaser__expanded
cursor: initial
.course-teaser__chevron
&::before
transform: rotate(45deg)
&:hover::before
transform: scale(1.4) rotate(135deg)
@media (max-width: 426px)
&::before
transform: rotate(225deg)
&:hover::before
transform: scale(1.4) rotate(225deg)
.course-teaser__school-label,
.course-teaser__school,
.course-teaser__duedate-label,
.course-teaser__duedate,
.course-teaser__description
display: block
@media (max-width: 426px)
.course-teaser__description-label
display: block
// course teaser: header styling
.course-teaser-header
padding-top: 10px
padding-bottom: 20px
line-height: 1.4
max-width: 85vw
.course-header
float: left
background-color: var(--color-dark)
position: relative
font-size: 16px
color: #fff
padding-top: 10px
padding-bottom: 10px
padding-left: 10px
padding-right: 35px
margin-bottom: 10px
font-weight: bold
text-align: left
border-radius: 20px 20px 20px 20px / 50% 50% 50% 50%
margin-right: 30px
.course-header-link
color: white
font-weight: bold
text-decoration: none
&:hover
color: inherit
.course-teaser-header:after
content: ""
display: table
clear: both

View File

@ -1,317 +0,0 @@
[uw-course-teaser] {
--course-border-color: var(--color-grey);
--course-padding-hori: 10px;
--course-padding-vert: 12px;
display: grid;
position: relative;
grid-gap: 5px 7px;
grid-template-columns: 130px 30px 1fr 60px;
grid-template-areas:
'shrthnd . title chevron'
'shrthnd smstr school chevron'
'. . rgstrd . '
'tutor tutor name . '
'duedate duedate date . '
'dscrptn dscrptn dscrptn dscrptn';
padding: var(--course-padding-vert) var(--course-padding-hori);
transition: background-color .1s ease-out;
cursor: pointer;
&:hover {
background-color: var(--course-bg-color);
}
+ [uw-course-teaser] {
border-top: 1px solid var(--course-border-color);
}
@media (max-width: 768px) {
grid-template-columns: 140px 1fr 30px;
grid-template-areas:
'shrthnd title chevron'
'shrthnd title . '
'smstr school school '
'. rgstrd rgstrd '
'tutor name name '
'duedate date date '
'dscrptn dscrptn dscrptn';
}
@media (max-width: 426px) {
grid-template-columns: 1fr;
grid-template-areas:
'shrthnd'
'title'
'smstr'
'school'
'rgstrd'
'tutor'
'name'
'duedate'
'date'
'dscrptnlbl'
'dscrptn'
'chevron';
}
}
.course-teaser__not-expandable {
cursor: initial;
}
/* chevron */
.course-teaser__chevron {
position: relative;
padding: 10px;
grid-area: chevron;
justify-self: center;
align-self: center;
width: 100%;
height: 100%;
cursor: pointer;
&::before {
content: '';
position: absolute;
display: block;
margin-top: -7.35px;
margin-left: -7.35px; /* visually centered */
border-width: 0 3px 3px 0;
width: 8px;
height: 8px;
top: 50%;
left: 50%;
border-color: var(--color-fontsec);
border-style: solid;
transform: rotate(135deg);
transform-origin: 7.25px 7.25px; /* rotate about visual center */
transition: all .2s ease-out;
}
&:hover::before {
transform: scale(1.4) rotate(45deg);
}
@media (max-width: 768px) {
justify-self: end;
width: auto;
&::before {
position: initial;
}
}
@media (max-width: 426px) {
&::before {
transform: rotate(45deg);
margin-left: -7.35px;
}
&:hover::before {
transform: scale(1.4) rotate(45deg);
}
}
}
/* semester */
.course-teaser__semester {
grid-area: smstr;
justify-self: end;
a {
color: var(--color-fontsec);
}
@media (max-width: 768px) {
justify-self: initial;
}
}
/* shorthand */
.course-teaser__shorthand {
position: relative;
grid-area: shrthnd;
font-size: 2rem;
line-height: 1.25;
min-height: calc(2rem * 1.25);
> a {
position: absolute;
height: 100%;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-break: break-any;
text-decoration: none !important; /* sry. */
font-weight: 600;
color: var(--color-grey-medium);
}
/* @media (max-width: 768px) {
* position: initial;
* }
*/
}
/* title */
.course-teaser__title {
grid-area: title;
font-size: 1.2rem;
align-self: baseline;
}
/* registration */
.course-teaser__registration {
grid-area: rgstrd;
color: var(--color-fontsec);
font-weight: bold;
}
/* school */
.course-teaser__school {
grid-area: school;
a {
color: var(--color-fontsec);
}
}
/* duedate */
.course-teaser__duedate {
grid-area: date;
}
/* lecturer */
.course-teaser__lecturer {
grid-area: name;
}
/* description */
.course-teaser__description {
grid-area: dscrptn;
max-height: 75vh;
overflow: auto;
}
/* show description only as dots (overflow text-overflow) and only show when expanded. No "hidden fiddling" */
/* labels */
.course-teaser__lecturer-label {
grid-area: tutor;
}
.course-teaser__duedate-label {
grid-area: duedate;
}
.course-teaser__description-label {
grid-area: dscrptnlbl;
}
.course-teaser__lecturer-label,
.course-teaser__description-label,
.course-teaser__duedate-label {
justify-self: end;
color: var(--color-fontsec);
font-style: italic;
@media (max-width: 768px) {
justify-self: initial;
}
@media (max-width: 426px) {
margin-top: 7px;
font-weight: bold;
font-style: initial;
}
}
/* hidden in closed state */
.course-teaser__description,
.course-teaser__description-label {
display: none;
}
/* expanded courses */
.course-teaser__expanded {
cursor: initial;
.course-teaser__chevron {
&::before {
transform: rotate(45deg);
}
&:hover::before {
transform: scale(1.4) rotate(135deg);
}
@media (max-width: 426px) {
&::before {
transform: rotate(225deg);
}
&:hover::before {
transform: scale(1.4) rotate(225deg);
}
}
}
.course-teaser__school-label,
.course-teaser__school,
.course-teaser__duedate-label,
.course-teaser__duedate,
.course-teaser__description {
display: block;
}
@media (max-width: 426px) {
.course-teaser__description-label {
display: block;
}
}
}
/*
course teaser: header styling
*/
.course-teaser-header {
padding-top: 10px;
padding-bottom: 20px;
line-height: 1.4;
max-width: 85vw;
.course-header {
float: left;
background-color: var(--color-dark);
position: relative;
font-size: 16px;
color: #fff;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 10px;
padding-right: 35px;
margin-bottom: 10px;
font-weight: bold;
text-align: left;
border-radius: 20px 20px 20px 20px / 50% 50% 50% 50%;
margin-right: 30px;
.course-header-link {
color: white;
font-weight: bold;
text-decoration: none;
&:hover {
color: inherit;
}
}
}
}
.course-teaser-header:after {
content: "";
display: table;
clear: both;
}

View File

@ -1,4 +1,4 @@
import './form.scss';
import './form.sass';
import { AutoSubmitButton } from './auto-submit-button';
import { AutoSubmitInput } from './auto-submit-input';
import { Datepicker } from './datepicker';

View File

@ -0,0 +1,35 @@
fieldset
border: 0
margin: 0
padding: 0
legend
display: none
@media (min-width: 769px)
.form-group__input
grid-column: 2
[uw-auto-submit-button][type='submit']
animation: fade-in 500ms ease-in-out backwards
animation-delay: 500ms
@keyframes fade-in
from
opacity: 0
.hidden
visibility: hidden !important
height: 0 !important
width: 0 !important
opacity: 0 !important
margin: 0 !important
padding: 0 !important
min-width: 0 !important
.select--pagesize
width: 5em
min-width: 75px
.label-pagesize
margin-right: 13px

View File

@ -1,45 +0,0 @@
fieldset {
border: 0;
margin: 0;
padding: 0;
legend {
display: none;
}
}
@media (min-width: 769px) {
.form-group__input {
grid-column: 2;
}
}
[uw-auto-submit-button][type='submit'] {
animation: fade-in 500ms ease-in-out backwards;
animation-delay: 500ms;
}
@keyframes fade-in {
from {
opacity: 0;
}
}
.hidden {
visibility: hidden !important;
height: 0 !important;
width: 0 !important;
opacity: 0 !important;
margin: 0 !important;
padding: 0 !important;
min-width: 0 !important;
}
.select--pagesize {
width: 5em;
min-width: 75px;
}
.label-pagesize {
margin-right: 13px;
}

View File

@ -0,0 +1,312 @@
import { Utility } from '../../core/utility';
import { StorageManager, LOCATION } from '../../lib/storage-manager/storage-manager';
import './hide-columns.sass';
const HIDE_COLUMNS_CONTAINER_IDENT = 'uw-hide-columns';
const TABLE_HEADER_IDENT = 'uw-hide-column-header';
const TABLE_UTILS_ATTR = 'table-utils';
const TABLE_UTILS_CONTAINER_SELECTOR = `[${TABLE_UTILS_ATTR}]`;
const TABLE_HIDER_CLASS = 'table-hider';
const TABLE_HIDER_VISIBLE_CLASS = 'table-hider--visible';
const TABLE_PILL_CLASS = 'table-pill';
const CELL_HIDDEN_CLASS = 'hide-columns--hidden-cell';
const CELL_ORIGINAL_COLSPAN = 'uw-hide-column-original-colspan';
@Utility({
selector: `[${HIDE_COLUMNS_CONTAINER_IDENT}] table`,
})
export class HideColumns {
_storageManager = new StorageManager('HIDE_COLUMNS', '1.0.0', { location: LOCATION.LOCAL });
_element;
_elementWrapper;
_tableUtilContainer;
_autoHide;
headerToHider = new Map();
hiderToHeader = new Map();
addHeaderHider(th, hider) {
this.headerToHider.set(th, hider);
this.hiderToHeader.set(hider, th);
}
constructor(element) {
this._autoHide = this._storageManager.load('autoHide', {}) || false;
if (!element) {
throw new Error('Hide Columns utility cannot be setup without an element!');
}
// do not provide hide-column ability in tables inside modals or async forms with response
if (element.closest('[uw-modal], .async-form__response')) {
return false;
}
this._element = element;
const hideColumnsContainer = this._element.closest(`[${HIDE_COLUMNS_CONTAINER_IDENT}]`);
if (!hideColumnsContainer) {
throw new Error('Hide Columns utility needs to be setup on a table inside a hide columns container!');
}
this._elementWrapper = hideColumnsContainer;
// get or create table utils container
this._tableUtilContainer = hideColumnsContainer.querySelector(TABLE_UTILS_CONTAINER_SELECTOR);
if (!this._tableUtilContainer) {
this._tableUtilContainer = document.createElement('div');
this._tableUtilContainer.setAttribute(TABLE_UTILS_ATTR, '');
const tableContainer = this._element.closest(`[${HIDE_COLUMNS_CONTAINER_IDENT}] > *`);
hideColumnsContainer.insertBefore(this._tableUtilContainer, tableContainer);
}
this._element.querySelectorAll('th').forEach(th => this.setupHideButton(th));
}
setupHideButton(th) {
const preHidden = this.isHiddenColumn(th);
const hider = document.createElement('span');
const hiderIcon = document.createElement('i');
hiderIcon.classList.add('fas', 'fa-fw');
hider.appendChild(hiderIcon);
const hiderContent = document.createElement('span');
hiderContent.classList.add('table-hider__label');
hiderContent.innerHTML = th.innerText;
hider.appendChild(hiderContent);
this.addHeaderHider(th, hider);
th.addEventListener('mouseover', () => {
hider.classList.add(TABLE_HIDER_VISIBLE_CLASS);
});
th.addEventListener('mouseout', () => {
if (hider.classList.contains(TABLE_HIDER_CLASS)) {
hider.classList.remove(TABLE_HIDER_VISIBLE_CLASS);
}
});
hider.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
this.switchColumnDisplay(th, hider);
// this._tableHiderContainer.getElementsByClassName(TABLE_HIDER_CLASS).forEach(hider => this.hideHiderBehindHeader(hider));
});
hider.addEventListener('mouseover', () => {
hider.classList.add(TABLE_HIDER_VISIBLE_CLASS);
const currentlyHidden = this.isHiddenColumn(th);
this.updateHiderIcon(hider, !currentlyHidden);
});
hider.addEventListener('mouseout', () => {
if (hider.classList.contains(TABLE_HIDER_CLASS)) {
hider.classList.remove(TABLE_HIDER_VISIBLE_CLASS);
}
const currentlyHidden = this.isHiddenColumn(th);
this.updateHiderIcon(hider, currentlyHidden);
});
new ResizeObserver(() => { this.repositionHider(hider); }).observe(th);
// reposition hider on each window resize event
// window.addEventListener('resize', () => this.repositionHider(hider));
this.updateColumnDisplay(this.colIndex(th), preHidden);
this.updateHider(hider, preHidden);
if (preHidden) {
this._tableUtilContainer.appendChild(hider);
} else {
this.hideHiderBehindHeader(hider);
}
}
switchColumnDisplay(th, hider) {
const hidden = !this.isHiddenColumn(th);
const originalColspan = Math.max(1, th.getAttribute(CELL_ORIGINAL_COLSPAN)) || 1;
const colspan = Math.max(1, th.colSpan) || 1;
const columnIndex = this.colIndex(th);
for (var i = 0; i < Math.max(colspan, originalColspan); i++) {
this.updateColumnDisplay(columnIndex + i, hidden);
}
this.updateHider(hider, hidden);
// persist new hidden setting for column
if ((hidden && this.isEmptyColumn(columnIndex) && this._autoHide) || (!hidden && (!this.isEmptyColumn(columnIndex) || !this._autoHide))) {
this._storageManager.remove(this.getStorageKey(th));
} else {
this._storageManager.save(this.getStorageKey(th), hidden);
}
}
updateColumnDisplay(columnIndex, hidden) {
this._element.getElementsByTagName('tr').forEach(row => {
const cell = this.getCol(row, columnIndex);
if (cell) {
const originalColspan = cell.getAttribute(CELL_ORIGINAL_COLSPAN);
const colspan = Math.max(1, cell.colSpan) || 1;
if (hidden) {
if (colspan > 1) {
if (!originalColspan) {
cell.setAttribute(CELL_ORIGINAL_COLSPAN, colspan);
}
cell.colSpan--;
} else {
cell.classList.add(CELL_HIDDEN_CLASS);
}
} else {
if (cell.classList.contains(CELL_HIDDEN_CLASS)) {
cell.classList.remove(CELL_HIDDEN_CLASS);
} else if (originalColspan && colspan < originalColspan) {
cell.colSpan++;
}
}
}
});
}
updateHider(hider, hidden) {
if (hidden) {
hider.classList.remove(TABLE_HIDER_CLASS);
hider.classList.add(TABLE_PILL_CLASS);
this._tableUtilContainer.appendChild(hider);
} else {
hider.classList.remove(TABLE_PILL_CLASS);
hider.classList.add(TABLE_HIDER_CLASS);
this.hideHiderBehindHeader(hider);
}
this.updateHiderIcon(hider, hidden);
}
updateHiderIcon(hider, hidden) {
hider.getElementsByClassName('fas').forEach(hiderIcon => {
hiderIcon.classList.remove(hidden ? 'fa-eye' : 'fa-eye-slash');
hiderIcon.classList.add(hidden ? 'fa-eye-slash' : 'fa-eye');
});
}
hideHiderBehindHeader(hider) {
if (!this.hiderToHeader.get(hider).contains(hider)) {
this.hiderToHeader.get(hider).appendChild(hider);
}
this.repositionHider(hider);
// remove visible class if necessary
hider.classList.remove(TABLE_HIDER_VISIBLE_CLASS);
}
repositionHider(hider) {
const thR = this.hiderToHeader.get(hider).getBoundingClientRect(),
hR = hider.getBoundingClientRect();
hider.style.left = (thR.width/2 - hR.width/2) + 'px';
hider.style.top = thR.height + 'px';
}
getStorageKey(th) {
// get handler name
const handlerIdent = document.querySelector('[uw-handler]').getAttribute('uw-handler');
// get hide-columns container ident (if not present, use table index in document as fallback)
let tIdent = this._elementWrapper.getAttribute(HIDE_COLUMNS_CONTAINER_IDENT);
if (!tIdent) {
const tablesInDocument = document.getElementsByTagName('TABLE');
for (let i = 0; i < tablesInDocument.length; i++) {
if (tablesInDocument[i] === this._element) {
tIdent = i;
break;
}
}
}
// check for unique table header ident from backend (if not present, use cell index as fallback)
let thIdent = th.getAttribute(TABLE_HEADER_IDENT);
if (!thIdent) {
thIdent = this.colIndex(th);
}
return `${handlerIdent}__${tIdent}__${thIdent}`;
}
isEmptyColumn(columnIndex) {
for (let row of this._element.getElementsByTagName('tr')) {
const cell = this.getCol(row, columnIndex);
if (cell.matches('th'))
continue;
if (cell.querySelector('.table__td-content')) {
for (let child of cell.children) {
if (!isEmptyElement(child))
return false;
}
return true;
} else {
return isEmptyElement(cell);
}
}
}
isHiddenColumn(th) {
const hidden = this._storageManager.load(this.getStorageKey(th)),
emptyColumn = this.isEmptyColumn(this.colIndex(th));
return hidden === true || hidden === undefined && emptyColumn && this._autoHide;
}
colSpan(cell) {
if (!cell)
return 1;
const originalColspan = cell.getAttribute(CELL_ORIGINAL_COLSPAN);
const colspan = Math.max(1, cell.colSpan) || 1;
return originalColspan ? Math.max(colspan, originalColspan) : colspan;
}
colIndex(cell) {
if (!cell)
return 0;
const rowParent = cell.closest('tr');
if (!rowParent)
return 0;
var i = 0;
for (const sibling of Array.from(rowParent.cells).slice(0, cell.cellIndex)) {
i += this.colSpan(sibling);
}
return i;
}
getCol(row, columnIndex) {
var c = 0;
for (const cell of row.cells) {
c += cell ? this.colSpan(cell) : 1;
if (columnIndex < c)
return cell;
}
}
}
function isEmptyElement(element) {
for (let child of element.childNodes) {
if (child.nodeName !== '#comment')
return false;
}
return true;
}

View File

@ -0,0 +1,61 @@
.table-hider
background-color: #fff
color: var(--color-link)
padding: 10px
cursor: pointer
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.6)
position: absolute
overflow: hidden
transition: transform .2s ease
transform: scaleY(0)
transform-origin: top
&:hover
background-color: var(--color-grey-light)
.table-hider__label
display: none
&.table-hider--visible
transform: scaleY(0.4)
transition: none
// TODO find better way to prevent transition on icons
.fas
transform: scaleY(2.5)
&:hover
transform: scaleY(1)
.fas
transform: scaleY(1)
[table-utils]
max-width: 85vw
margin-bottom: 10px
min-height: 0
line-height: 1.4
.table-pill
background-color: var(--color-dark)
float: left
color: #fff
padding: 10px
border-radius: 20px / 50%
margin-right: 20px
margin-bottom: 10px
cursor: pointer
.table-hider__label
font-size: 16px
font-weight: bold
margin-left: 5px
&:after
content: ""
display: block
clear: both
.hide-columns--hidden-cell
display: none

View File

@ -1,5 +1,5 @@
import { Utility } from '../../core/utility';
import './checkbox.scss';
import './checkbox.sass';
var CHECKBOX_CLASS = 'checkbox';
var CHECKBOX_INITIALIZED_CLASS = 'checkbox--initialized';

View File

@ -0,0 +1,71 @@
// CUSTOM CHECKBOXES
// Completely replaces legacy checkbox
.checkbox [type='checkbox'], #lang-checkbox
position: fixed
top: -1px
left: -1px
width: 1px
height: 1px
overflow: hidden
display: none
.checkbox
position: relative
display: inline-block
label
display: block
height: 20px
width: 20px
background-color: #f3f3f3
box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05)
border: 2px solid var(--color-primary)
border-radius: 4px
color: white
cursor: pointer
label::before,
label::after
position: absolute
display: block
top: 12px
left: 8px
height: 2px
width: 8px
background-color: var(--color-font)
\:checked + label
background-color: var(--color-primary)
[type='checkbox']:focus + label
border-color: #3273dc
box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25)
outline: 0
\:checked + label::before,
:checked + label::after
content: ''
\:checked + label::before
background-color: white
transform: rotate(45deg)
left: 2px
top: 11px
\:checked + label::after
background-color: white
transform: rotate(-45deg)
top: 9px
width: 12px
left: 7px
[disabled] + label
pointer-events: none
border: none
opacity: 0.6
filter: grayscale(1)
// special treatment for checkboxes in table headers
th .checkbox
margin-right: 7px
vertical-align: bottom

View File

@ -1,83 +0,0 @@
/* CUSTOM CHECKBOXES */
/* Completely replaces legacy checkbox */
.checkbox [type='checkbox'], #lang-checkbox {
position: fixed;
top: -1px;
left: -1px;
width: 1px;
height: 1px;
overflow: hidden;
display: none;
}
.checkbox {
position: relative;
display: inline-block;
label {
display: block;
height: 20px;
width: 20px;
background-color: #f3f3f3;
box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05);
border: 2px solid var(--color-primary);
border-radius: 4px;
color: white;
cursor: pointer;
}
label::before,
label::after {
position: absolute;
display: block;
top: 12px;
left: 8px;
height: 2px;
width: 8px;
background-color: var(--color-font);
}
:checked + label {
background-color: var(--color-primary);
}
[type='checkbox']:focus + label {
border-color: #3273dc;
box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
outline: 0;
}
:checked + label::before,
:checked + label::after {
content: '';
}
:checked + label::before {
background-color: white;
transform: rotate(45deg);
left: 2px;
top: 11px;
}
:checked + label::after {
background-color: white;
transform: rotate(-45deg);
top: 9px;
width: 12px;
left: 7px;
}
[disabled] + label {
pointer-events: none;
border: none;
opacity: 0.6;
filter: grayscale(1);
}
}
/* special treatment for checkboxes in table headers */
th .checkbox {
margin-right: 7px;
vertical-align: bottom;
}

View File

@ -1,5 +1,5 @@
import { Utility } from '../../core/utility';
import './file-input.scss';
import './file-input.sass';
const FILE_INPUT_CLASS = 'file-input';
const FILE_INPUT_INITIALIZED_CLASS = 'file-input--initialized';

View File

@ -0,0 +1,2 @@
.file-input__list:empty
display: none

View File

@ -1,3 +0,0 @@
.file-input__list:empty {
display: none;
}

View File

@ -1,8 +1,8 @@
import { Checkbox } from './checkbox';
import { FileInput } from './file-input';
import './inputs.scss';
import './radio.scss';
import './inputs.sass';
import './radio.sass';
export const InputUtils = [
Checkbox,

View File

@ -0,0 +1,211 @@
// GENERAL STYLES FOR FORMS
// FORM GROUPS
.form-section-title
color: var(--color-fontsec)
margin: 0
+ .form-group
margin-top: 11px
.form-group
position: relative
display: flex
display: grid
grid-template-columns: 1fr 3fr
grid-gap: 5px
justify-content: flex-start
align-items: flex-start
+ .form-group, + .form-section-legend, + .form-section-notification
margin-top: 11px
+ .form-section-title
margin-top: 40px
.form-section-legend
color: var(--color-fontsec)
margin: 7px 0
.form-group__hint, .form-section-title__hint
color: var(--color-fontsec)
font-size: 0.9rem
font-weight: 600
.form-section-title__hint
margin-top: 7px
+ .form-group
margin-top: 11px
.form-group-label
font-weight: 600
padding-top: 6px
.form-group-label__hint
margin-top: 7px
color: var(--color-fontsec)
font-size: 0.9rem
.form-group--required .form-group-label__caption::after, .form-group__required-marker::before
content: ' *'
color: var(--color-error)
font-weight: 600
.form-group--submit .form-group__input
grid-column: 2
@media (max-width: 768px)
.form-group--submit .form-group__input
grid-column: 1
.form-group--has-error
background-color: rgba(255, 0, 0, 0.1)
input, textarea
border-color: var(--color-error) !important
.form-error
display: block
.form-error
display: none
@media (max-width: 768px)
.form-group
grid-template-columns: 1fr
align-items: baseline
margin-top: 17px
flex-direction: column
// TEXT INPUTS
input[type='text'],
input[type='search'],
input[type='password'],
input[type='url'],
input[type='number'],
input[type='email'],
input[type*='date'],
input[type*='time'],
select
// from bulma.css
color: #363636
border-color: #dbdbdb
background-color: #f3f3f3
box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05)
width: 100%
max-width: 600px
align-items: center
border: 1px solid transparent
border-radius: 4px
font-size: 1rem
font-family: var(--font-base)
line-height: 1.5
padding: 4px 13px
input[type='number']
width: 100px
input[type*='date'],
input[type*='time'],
.flatpickr-input[type='text']
width: 50%
width: 250px
// BUTTON STYLE SEE default-layout.lucius
// TEXTAREAS
textarea
width: 100%
height: 170px
max-width: 600px
line-height: 1.5
color: #363636
background-color: #f3f3f3
padding: 4px 13px
font-size: 1rem
font-family: var(--font-base)
appearance: none
border: 1px solid #dbdbdb
border-radius: 2px
box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05)
vertical-align: top
// SHARED STATE RELATED STYLES
input,
select,
textarea
&:focus
border-color: #3273dc
box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25)
outline: 0
&[disabled]
background-color: #f3f3f3
color: #7a7a7a
box-shadow: none
border-color: #dbdbdb
&[readonly]
background-color: #f5f5f5
border-color: #dbdbdb
// OPTIONS
select[size="1"], select:not([size])
appearance: menulist
select,
option
font-size: 1rem
line-height: 1.5
padding: 4px 13px
border: 1px solid #dbdbdb
border-radius: 2px
outline: 0
color: #363636
min-width: 250px
width: auto
background-color: #f3f3f3
box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05)
@media (max-width: 425px)
select, option
width: 100%
// FILE INPUT
.file-input
display: none
.file-input__label
cursor: pointer
display: inline-block
background-color: var(--color-primary)
color: white
padding: 10px 17px
border-radius: 3px
.file-input__info
font-size: .9rem
font-style: italic
margin: 10px 0
color: var(--color-fontsec)
.file-input__list
margin-left: 40px
margin-top: 10px
font-weight: 600
// PREVIOUSLY UPLOADED FILES
.file-uploads-label
margin-bottom: 10px
.file-container
display: flex
align-items: center
margin-bottom: 10px
.checkbox
margin-left: 12px

View File

@ -1,253 +0,0 @@
/* GENERAL STYLES FOR FORMS */
/* FORM GROUPS */
.form-section-title {
color: var(--color-fontsec);
margin: 0;
+ .form-group {
margin-top: 11px;
}
}
.form-group {
position: relative;
display: flex;
display: grid;
grid-template-columns: 1fr 3fr;
grid-gap: 5px;
justify-content: flex-start;
align-items: flex-start;
+ .form-group, + .form-section-legend, + .form-section-notification {
margin-top: 11px;
}
+ .form-section-title {
margin-top: 40px;
}
}
.form-section-legend {
color: var(--color-fontsec);
margin: 7px 0;
}
.form-group__hint, .form-section-title__hint {
color: var(--color-fontsec);
font-size: 0.9rem;
font-weight: 600;
}
.form-section-title__hint {
margin-top: 7px;
+ .form-group {
margin-top: 11px;
}
}
.form-group-label {
font-weight: 600;
padding-top: 6px;
}
.form-group-label__hint {
margin-top: 7px;
color: var(--color-fontsec);
font-size: 0.9rem;
}
.form-group--required .form-group-label__caption::after, .form-group__required-marker::before {
content: ' *';
color: var(--color-error);
font-weight: 600;
}
.form-group--submit .form-group__input {
grid-column: 2;
}
@media (max-width: 768px) {
.form-group--submit .form-group__input {
grid-column: 1;
}
}
.form-group--has-error {
background-color: rgba(255, 0, 0, 0.1);
input, textarea {
border-color: var(--color-error) !important;
}
.form-error {
display: block;
}
}
.form-error {
display: none;
}
@media (max-width: 768px) {
.form-group {
grid-template-columns: 1fr;
align-items: baseline;
margin-top: 17px;
flex-direction: column;
}
}
/* TEXT INPUTS */
input[type='text'],
input[type='search'],
input[type='password'],
input[type='url'],
input[type='number'],
input[type='email'],
input[type*='date'],
input[type*='time'],
select {
/* from bulma.css */
color: #363636;
border-color: #dbdbdb;
background-color: #f3f3f3;
box-shadow: inset 0 1px 2px 1px rgba(50,50,50,.05);
width: 100%;
max-width: 600px;
align-items: center;
border: 1px solid transparent;
border-radius: 4px;
font-size: 1rem;
font-family: var(--font-base);
line-height: 1.5;
padding: 4px 13px;
}
input[type='number'] {
width: 100px;
}
input[type*='date'],
input[type*='time'],
.flatpickr-input[type='text'] {
width: 50%;
width: 250px;
}
/* BUTTON STYLE SEE default-layout.lucius */
/* TEXTAREAS */
textarea {
width: 100%;
height: 170px;
max-width: 600px;
line-height: 1.5;
color: #363636;
background-color: #f3f3f3;
padding: 4px 13px;
font-size: 1rem;
font-family: var(--font-base);
appearance: none;
border: 1px solid #dbdbdb;
border-radius: 2px;
box-shadow: inset 0 1px 2px 1px rgba(50,50,50,.05);
vertical-align: top;
}
/* SHARED STATE RELATED STYLES */
input,
select,
textarea {
&:focus {
border-color: #3273dc;
box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
outline: 0;
}
&[disabled] {
background-color: #f3f3f3;
color: #7a7a7a;
box-shadow: none;
border-color: #dbdbdb;
}
&[readonly] {
background-color: #f5f5f5;
border-color: #dbdbdb;
}
}
/* OPTIONS */
select[size = "1"], select:not([size]) {
appearance: menulist;
}
select,
option {
font-size: 1rem;
line-height: 1.5;
padding: 4px 13px;
border: 1px solid #dbdbdb;
border-radius: 2px;
outline: 0;
color: #363636;
min-width: 250px;
width: auto;
background-color: #f3f3f3;
box-shadow: inset 0 1px 2px 1px rgba(50,50,50,.05);
}
@media (max-width: 425px) {
select, option {
width: 100%;
}
}
/* FILE INPUT */
.file-input {
display: none;
}
.file-input__label {
cursor: pointer;
display: inline-block;
background-color: var(--color-primary);
color: white;
padding: 10px 17px;
border-radius: 3px;
}
.file-input__info {
font-size: .9rem;
font-style: italic;
margin: 10px 0;
color: var(--color-fontsec);
}
.file-input__list {
margin-left: 40px;
margin-top: 10px;
font-weight: 600;
}
/* PREVIOUSLY UPLOADED FILES */
.file-uploads-label {
margin-bottom: 10px;
}
.file-container {
display: flex;
align-items: center;
margin-bottom: 10px;
.checkbox {
margin-left: 12px;
}
}

View File

@ -0,0 +1,55 @@
// CUSTOM RADIO BOXES
// Completely replaces native radiobox
.radio-group
display: flex
.radio
position: relative
display: inline-block
[type='radio']
position: fixed
top: -1px
left: -1px
width: 1px
height: 1px
overflow: hidden
label
display: block
height: 34px
min-width: 42px
line-height: 34px
text-align: center
padding: 0 13px
background-color: #f3f3f3
box-shadow: inset 2px 1px 2px 1px rgba(50, 50, 50, 0.05)
color: var(--color-font)
cursor: pointer
\:checked + label
background-color: var(--color-primary)
color: var(--color-lightwhite)
box-shadow: inset -2px -1px 2px 1px rgba(255, 255, 255, 0.15)
\:focus + label
border-color: #3273dc
box-shadow: 0 0 0.125em 0 rgba(50, 115, 220, 0.8)
outline: 0
[disabled] + label
pointer-events: none
border: none
opacity: 0.6
filter: grayscale(1)
.radio:first-child
label
border-top-left-radius: 4px
border-bottom-left-radius: 4px
.radio:last-child
label
border-top-right-radius: 4px
border-bottom-right-radius: 4px

View File

@ -1,66 +0,0 @@
/* CUSTOM RADIO BOXES */
/* Completely replaces native radiobox */
.radio-group {
display: flex;
}
.radio {
position: relative;
display: inline-block;
[type='radio'] {
position: fixed;
top: -1px;
left: -1px;
width: 1px;
height: 1px;
overflow: hidden;
}
label {
display: block;
height: 34px;
min-width: 42px;
line-height: 34px;
text-align: center;
padding: 0 13px;
background-color: #f3f3f3;
box-shadow: inset 2px 1px 2px 1px rgba(50, 50, 50, 0.05);
color: var(--color-font);
cursor: pointer;
}
:checked + label {
background-color: var(--color-primary);
color: var(--color-lightwhite);
box-shadow: inset -2px -1px 2px 1px rgba(255, 255, 255, 0.15);
}
:focus + label {
border-color: #3273dc;
box-shadow: 0 0 0.125em 0 rgba(50,115,220,0.8);
outline: 0;
}
[disabled] + label {
pointer-events: none;
border: none;
opacity: 0.6;
filter: grayscale(1);
}
}
.radio:first-child {
label {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
}
.radio:last-child {
label {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
}

View File

@ -1,6 +1,6 @@
import { Utility } from '../../core/utility';
import { Datepicker } from '../form/datepicker';
import './mass-input.scss';
import './mass-input.sass';
const MASS_INPUT_CELL_SELECTOR = '.massinput__cell';
const MASS_INPUT_ADD_CELL_SELECTOR = '.massinput__cell--add';

View File

@ -0,0 +1,14 @@
.massinput-list__wrapper, .massinput-list__cell
display: grid
grid: auto / auto 50px
max-width: 600px
grid-gap: 7px
.massinput-list__field
grid-column: 1
.massinput-list__add, .massinput-list__delete
grid-column: 2
.massinput-list__cell
grid-column: 1 / 3

View File

@ -1,18 +0,0 @@
.massinput-list__wrapper, .massinput-list__cell {
display: grid;
grid: auto / auto 50px;
max-width: 600px;
grid-gap: 7px;
}
.massinput-list__field {
grid-column: 1;
}
.massinput-list__add, .massinput-list__delete {
grid-column: 2;
}
.massinput-list__cell {
grid-column: 1 / 3;
}

View File

@ -1,5 +1,5 @@
import { Utility } from '../../core/utility';
import './modal.scss';
import './modal.sass';
const MODAL_HEADERS = {
'Is-Modal': 'True',

View File

@ -0,0 +1,103 @@
@use "../../common" as *
.modals-wrapper
position: fixed
left: 0
top: 0
width: 100%
height: 100%
z-index: -1
display: flex
align-items: center
justify-content: center
&.modals-wrapper--open
z-index: 200
width: 100%
height: 100%
.modal
position: relative
display: none
background-color: rgba(255, 255, 255, 1)
min-width: 60vw
max-width: 70vw
min-height: 100px
max-height: calc(100vh - 30px)
border-radius: 2px
z-index: -1
color: var(--color-font)
overflow: auto
overscroll-behavior: contain
pointer-events: none
opacity: 0
&.modal--open
display: flex
opacity: 1
pointer-events: auto
z-index: 200
transition: opacity .2s .1s ease-in-out, transform .3s ease-in-out
@media (max-width: 1024px)
.modal
min-width: 80vw
@media (max-width: 768px)
.modal
min-width: 90vw
@media (max-width: 425px)
.modal
min-width: calc(100vw - 20px)
.modal__overlay
position: fixed
left: 0
top: 0
height: 100%
width: 100%
background-color: transparent
z-index: -1
transition: all .2s ease
display: none
&.modal__overlay--open
display: block
z-index: 199
opacity: 1
background-color: rgba(0, 0, 0, 0.4)
.modal__trigger
cursor: pointer
div.modal__trigger
display: inline-block
.modal__trigger-label
font-style: italic
text-decoration: underline
.modal__closer
position: absolute
top: 20px
right: 20px
display: flex
align-items: center
justify-content: center
width: 30px
height: 30px
background-color: var(--color-darker)
border-radius: 2px
cursor: pointer
z-index: 20
&::before
@extend .fas
content: fa-content($fa-var-times)
color: white
.modal__content
margin: 20px 40px
width: 100%

View File

@ -1,118 +0,0 @@
.modals-wrapper {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1;
display: flex;
align-items: center;
justify-content: center;
&.modals-wrapper--open {
z-index: 200;
width: 100%;
height: 100%;
}
}
.modal {
position: relative;
display: none;
background-color: rgba(255, 255, 255, 1);
min-width: 60vw;
max-width: 70vw;
min-height: 100px;
max-height: calc(100vh - 30px);
border-radius: 2px;
z-index: -1;
color: var(--color-font);
overflow: auto;
overscroll-behavior: contain;
pointer-events: none;
opacity: 0;
&.modal--open {
display: flex;
opacity: 1;
pointer-events: auto;
z-index: 200;
transition:
opacity .2s .1s ease-in-out,
transform .3s ease-in-out;
}
}
@media (max-width: 1024px) {
.modal {
min-width: 80vw;
}
}
@media (max-width: 768px) {
.modal {
min-width: 90vw;
}
}
@media (max-width: 425px) {
.modal {
min-width: calc(100vw - 20px);
}
}
.modal__overlay {
position: fixed;
left: 0;
top: 0;
height: 100%;
width: 100%;
background-color: transparent;
z-index: -1;
transition: all .2s ease;
display: none;
&.modal__overlay--open {
display: block;
z-index: 199;
opacity: 1;
background-color: rgba(0, 0, 0, 0.4);
}
}
.modal__trigger {
cursor: pointer;
}
div.modal__trigger {
display: inline-block;
}
.modal__trigger-label {
font-style: italic;
text-decoration: underline;
}
.modal__closer {
position: absolute;
top: 20px;
right: 20px;
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
background-color: var(--color-darker);
border-radius: 2px;
cursor: pointer;
z-index: 20;
&::before {
content: '\f00d';
font-family: 'Font Awesome 5 Free';
color: white;
}
}
.modal__content {
margin: 20px 40px;
width: 100%;
}

View File

@ -1,5 +1,5 @@
import { Utility } from '../../core/utility';
import './navbar.scss';
import './navbar.sass';
export const LANGUAGE_SELECT_UTIL_SELECTOR = '[uw-language-select]';

View File

@ -0,0 +1,228 @@
.navbar-container
position: relative
.navbar-shadow
position: fixed
right: 0
top: 0
height: var(--header-height-collapsed)
width: 20px
z-index: 50
background-image: linear-gradient(to left, rgba(0, 0, 0, 0.4), transparent)
transition: height 0.2s cubic-bezier(0.03, 0.43, 0.58, 1)
@media (min-width: 768px)
.navbar-shadow
height: var(--header-height)
@media (min-width: 1025px)
.navbar-shadow
display: none
.navbar
position: fixed
display: flex
flex-direction: row
align-items: center
justify-content: flex-start
right: 0
top: 0
left: var(--asidenav-width-xl)
height: var(--header-height)
background-color: var(--color-primary)
color: white
z-index: 20
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)
@media (max-width: 1199px)
.navbar
left: var(--asidenav-width-lg)
@media (max-width: 768px)
.navbar
left: 0
// links
.navbar__link-wrapper
display: flex
flex-direction: column
justify-content: flex-end
align-items: center
height: 80px
min-width: 90px
color: var(--color-lightwhite)
transition: height 0.2s cubic-bezier(0.03, 0.43, 0.58, 1)
overflow: hidden
cursor: pointer
.navbar__link-icon
opacity: 0.7
transition: opacity 0.2s ease
margin-bottom: 7px
.navbar__link-label
transition: opacity .2s ease
padding: 2px 4px
text-transform: uppercase
font-weight: 600
@media (min-width: 769px)
.navbar__link-wrapper
border: 1px solid rgba(255, 255, 255, 0.7)
@media (max-width: 768px)
.navbar__link-wrapper
box-shadow: none
min-width: 0
align-items: center
justify-content: center
.navbar__link-label
padding: 0 7px
.navbar__link-icon
transform: scale(0.65)
margin-bottom: 0
// navbar list
.navbar__list
white-space: nowrap
+ .navbar__list
margin-left: 12px
@media (min-width: 769px)
.navbar__list:last-of-type
padding-right: 40px
@media (max-width: 768px)
.navbar__list
+ .navbar__list
margin-left: 0
padding-right: 40px
// list item
.navbar__list-item
position: relative
transition: background-color .1s ease
&:not(.navbar__list-item--favorite) + .navbar__list-item--lang-wrapper
margin-left: 12px
&:not(.navbar__list-item--favorite) + .navbar__list-item
margin-left: 12px
@media (max-width: 500px)
.navbar__list-item
min-width: 60px
&:not(.navbar__list-item--favorite) + .navbar__list-item
margin-left: 0
&:not(.navbar__list-item--favorite) + .navbar__list-item--lang-wrapper
margin-left: 0
.navbar__list-left
flex: 5
padding-left: 40px
@media (max-width: 768px)
.navbar__list-left
padding-left: 0
// "Favorites" list item, only visible on small screens and logged in
.navbar__list-item
&.navbar__list-item--favorite
display: none
.navbar__list-item--favorite
display: none
background-color: var(--color-primary)
.logged-in
.navbar__list
li.navbar__list-item--favorite,
.navbar__list-item--favorite
display: inline-block
@media (min-width: 426px)
.logged-in
.navbar__list
.navbar__list-item--favorite
display: none !important
.navbar__list-item--active
background-color: var(--color-lightwhite)
color: var(--color-dark)
.navbar__link-wrapper
color: var(--color-dark)
.navbar__list-item--active .navbar__link-wrapper
color: var(--color-dark)
.navbar .navbar__list-item:not(.navbar__list-item--active):not(.navbar__list-item--favorite):hover .navbar__link-wrapper, #lang-checkbox:checked ~ * .navbar__link-wrapper
background-color: var(--color-dark)
color: var(--color-lightwhite)
.navbar__link-icon
opacity: 1
// sticky state
.navbar--sticky
height: var(--header-height-collapsed)
z-index: 100
.navbar__link-wrapper
height: var(--header-height-collapsed)
.navbar__pushdown
height: var(--header-height)
transition: height 0.2s cubic-bezier(0.03, 0.43, 0.58, 1)
.navbar--sticky + .navbar__pushdown
display: block
height: var(--header-height-collapsed)
@media (max-width: 768px)
.navbar,
.navbar__pushdown
height: var(--header-height-collapsed)
.navbar__link-wrapper
height: var(--header-height-collapsed)
@media (max-height: 500px)
.navbar,
.navbar__pushdown
height: var(--header-height-collapsed)
.navbar__link-wrapper
height: var(--header-height-collapsed)
#lang-dropdown
display: none
position: fixed
top: var(--header-height)
right: 0
min-width: 200px
z-index: 10
background-color: white
border-radius: 2px
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3)
select
display: block
button
display: block
width: 100%
#lang-checkbox:checked ~ #lang-dropdown
display: block
@media (max-width: 768px)
#lang-dropdown
top: var(--header-height-collapsed)

View File

@ -1,305 +0,0 @@
.navbar-container {
position: relative;
}
.navbar-shadow {
position: fixed;
right: 0;
top: 0;
height: var(--header-height-collapsed);
width: 20px;
z-index: 50;
background-image: linear-gradient(to left, rgba(0, 0, 0, 0.4), transparent);
transition: height .2s cubic-bezier(0.03, 0.43, 0.58, 1);
}
@media (min-width: 768px) {
.navbar-shadow {
height: var(--header-height);
}
}
@media (min-width: 1025px) {
.navbar-shadow {
display: none;
}
}
.navbar {
position: fixed;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
right: 0;
top: 0;
left: var(--asidenav-width-xl);
height: var(--header-height);
background-color: var(--color-primary);
color: white;
z-index: 20;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
overflow: auto;
transition: all .2s cubic-bezier(0.03, 0.43, 0.58, 1);
}
@media (max-width: 1199px) {
.navbar {
left: var(--asidenav-width-lg);
}
}
@media (max-width: 768px) {
.navbar {
left: 0;
}
}
/* links */
.navbar__link-wrapper {
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
height: 80px;
min-width: 90px;
color: var(--color-lightwhite);
transition: height .2s cubic-bezier(0.03, 0.43, 0.58, 1);
overflow: hidden;
cursor: pointer;
}
.navbar__link-icon {
opacity: 0.7;
transition: opacity 0.2s ease;
margin-bottom: 7px;
}
.navbar__link-label {
transition: opacity .2s ease;
padding: 2px 4px;
text-transform: uppercase;
font-weight: 600;
}
@media (min-width: 769px) {
.navbar__link-wrapper {
border: 1px solid rgba(255, 255, 255, 0.7);
}
}
@media (max-width: 768px) {
.navbar__link-wrapper {
box-shadow: none;
min-width: 0;
align-items: center;
justify-content: center;
}
.navbar__link-label {
padding: 0 7px;
}
.navbar__link-icon {
transform: scale(0.65);
margin-bottom: 0;
}
}
/* navbar list */
.navbar__list {
white-space: nowrap;
+ .navbar__list {
margin-left: 12px;
}
}
@media (min-width: 769px) {
.navbar__list:last-of-type {
padding-right: 40px;
}
}
@media (max-width: 768px) {
.navbar__list {
+ .navbar__list {
margin-left: 0;
padding-right: 40px;
}
}
}
/* list item */
.navbar__list-item {
position: relative;
transition: background-color .1s ease;
&:not(.navbar__list-item--favorite) + .navbar__list-item--lang-wrapper {
margin-left: 12px;
}
&:not(.navbar__list-item--favorite) + .navbar__list-item {
margin-left: 12px;
}
}
@media (max-width: 500px) {
.navbar__list-item {
min-width: 60px;
&:not(.navbar__list-item--favorite) + .navbar__list-item {
margin-left: 0;
}
&:not(.navbar__list-item--favorite) + .navbar__list-item--lang-wrapper {
margin-left: 0;
}
}
}
.navbar__list-left {
flex: 5;
padding-left: 40px;
}
@media (max-width: 768px) {
.navbar__list-left {
padding-left: 0;
}
}
/* "Favorites" list item, only visible on small screens and logged in */
.navbar__list-item {
&.navbar__list-item--favorite {
display: none;
}
}
.navbar__list-item--favorite {
display: none;
background-color: var(--color-primary);
}
.logged-in {
.navbar__list {
li.navbar__list-item--favorite,
.navbar__list-item--favorite {
display: inline-block;
}
}
}
@media (min-width: 426px) {
.logged-in {
.navbar__list {
.navbar__list-item--favorite {
display: none !important;
}
}
}
}
.navbar__list-item--active {
background-color: var(--color-lightwhite);
color: var(--color-dark);
.navbar__link-wrapper {
color: var(--color-dark);
}
}
.navbar__list-item--active .navbar__link-wrapper {
color: var(--color-dark);
}
.navbar .navbar__list-item:not(.navbar__list-item--active):not(.navbar__list-item--favorite):hover .navbar__link-wrapper, #lang-checkbox:checked ~ * .navbar__link-wrapper {
background-color: var(--color-dark);
color: var(--color-lightwhite);
.navbar__link-icon {
opacity: 1;
}
}
/* sticky state */
.navbar--sticky {
height: var(--header-height-collapsed);
z-index: 100;
.navbar__link-wrapper {
height: var(--header-height-collapsed);
}
}
.navbar__pushdown {
height: var(--header-height);
transition: height .2s cubic-bezier(0.03, 0.43, 0.58, 1);
}
.navbar--sticky + .navbar__pushdown {
display: block;
height: var(--header-height-collapsed);
}
@media (max-width: 768px) {
.navbar,
.navbar__pushdown {
height: var(--header-height-collapsed);
}
.navbar__link-wrapper {
height: var(--header-height-collapsed);
}
}
@media (max-height: 500px) {
.navbar,
.navbar__pushdown {
height: var(--header-height-collapsed);
}
.navbar__link-wrapper {
height: var(--header-height-collapsed);
}
}
#lang-dropdown {
display: none;
position: fixed;
top: var(--header-height);
right: 0;
min-width: 200px;
z-index: 10;
background-color: white;
border-radius: 2px;
box-shadow: 0 0 10px rgba(0,0,0,0.3);
select {
display: block;
}
button {
display: block;
width: 100%;
}
}
#lang-checkbox:checked ~ #lang-dropdown {
display: block;
}
@media (max-width: 768px) {
#lang-dropdown {
top: var(--header-height-collapsed);
}
}

View File

@ -1,5 +1,6 @@
import { Utility } from '../../core/utility';
import './show-hide.scss';
import { StorageManager, LOCATION } from '../../lib/storage-manager/storage-manager';
import './show-hide.sass';
const SHOW_HIDE_LOCAL_STORAGE_KEY = 'SHOW_HIDE';
const SHOW_HIDE_INITIALIZED_CLASS = 'show-hide--initialized';
@ -15,6 +16,8 @@ export class ShowHide {
_showHideId;
_element;
_storageManager = new StorageManager(SHOW_HIDE_LOCAL_STORAGE_KEY, '1.0.0', { location: LOCATION.LOCAL });
constructor(element) {
if (!element) {
throw new Error('ShowHide utility cannot be setup without an element!');
@ -41,9 +44,9 @@ export class ShowHide {
}
if (this._showHideId) {
let localStorageCollapsed = this._getLocalStorage()[this._showHideId];
if (typeof localStorageCollapsed !== 'undefined') {
collapsed = localStorageCollapsed;
let storageCollapsed = this._storageManager.load(this._showHideId);
if (typeof storageCollapsed !== 'undefined') {
collapsed = storageCollapsed;
}
}
this._element.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS, collapsed);
@ -70,18 +73,7 @@ export class ShowHide {
const newState = this._element.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS);
if (this._showHideId) {
this._setLocalStorage(this._showHideId, newState);
this._storageManager.save(this._showHideId, newState);
}
}
// maybe move these to a LocalStorageHelper?
_setLocalStorage(id, state) {
const lsData = this._getLocalStorage();
lsData[id] = state;
window.localStorage.setItem(SHOW_HIDE_LOCAL_STORAGE_KEY, JSON.stringify(lsData));
}
_getLocalStorage() {
return JSON.parse(window.localStorage.getItem(SHOW_HIDE_LOCAL_STORAGE_KEY)) || {};
}
}

View File

@ -0,0 +1,44 @@
$show-hide-toggle-size: 6px
.show-hide__toggle
position: relative
cursor: pointer
&:hover
background-color: var(--color-grey-lighter)
cursor: pointer
.show-hide__toggle::before
content: ''
position: absolute
width: $show-hide-toggle-size
height: $show-hide-toggle-size
left: -15px
top: 50%
color: var(--color-primary)
border-right: 2px solid currentColor
border-top: 2px solid currentColor
transition: transform .2s ease
transform: translateY(-50%) rotate(-45deg)
@media (max-width: 768px)
left: auto
right: 20px
color: var(--color-font)
.show-hide__toggle--right::before
left: auto
right: 20px
color: var(--color-font)
.show-hide--collapsed
.show-hide__toggle::before
transform: translateY(-50%) rotate(135deg)
& > :not(.show-hide__toggle)
display: block
height: 0
margin: 0
padding: 0
max-height: 0
overflow-y: hidden

View File

@ -1,54 +0,0 @@
$show-hide-toggle-size: 6px;
.show-hide__toggle {
position: relative;
cursor: pointer;
&:hover {
background-color: var(--color-grey-lighter);
cursor: pointer;
}
}
.show-hide__toggle::before {
content: '';
position: absolute;
width: $show-hide-toggle-size;
height: $show-hide-toggle-size;
left: -15px;
top: 50%;
color: var(--color-primary);
border-right: 2px solid currentColor;
border-top: 2px solid currentColor;
transition: transform .2s ease;
transform: translateY(-50%) rotate(-45deg);
@media (max-width: 768px) {
left: auto;
right: 20px;
color: var(--color-font);
}
}
.show-hide__toggle--right::before {
left: auto;
right: 20px;
color: var(--color-font);
}
.show-hide--collapsed {
.show-hide__toggle::before {
transform: translateY(-50%) rotate(135deg);
}
:not(.show-hide__toggle) {
display: block;
height: 0;
margin: 0;
padding: 0;
max-height: 0;
overflow-y: hidden;
}
}

View File

@ -1,4 +1,4 @@
import './tabber.scss';
import './tabber.sass';
(function($) {

View File

@ -0,0 +1,35 @@
.tab-group
border-top: 2px solid #dcdcdc
padding-top: 30px
.tab-group-openers
display: flex
justify-content: stretch
line-height: 40px
font-size: 14px
margin-bottom: 40px
.tab-opener
display: inline-block
flex: 1
text-align: center
padding: 0 13px
margin: 0 2px
background-color: var(--color-dark)
color: white
font-size: 16px
text-transform: uppercase
font-weight: 600
transition: all .1s ease
border-bottom: 5px solid rgba(100, 100, 100, 0.2)
.tab-opener:not(.tab-visible):hover
cursor: pointer
background-color: transparent
color: rgb(52, 48, 58)
border-bottom-color: grey
.tab-opener.tab-visible
background-color: transparent
color: rgb(52, 48, 58)
border-bottom-color: var(--color-primary)

View File

@ -1,39 +0,0 @@
.tab-group {
border-top: 2px solid #dcdcdc;
padding-top: 30px;
}
.tab-group-openers {
display: flex;
justify-content: stretch;
line-height: 40px;
font-size: 14px;
margin-bottom: 40px;
}
.tab-opener {
display: inline-block;
flex: 1;
text-align: center;
padding: 0 13px;
margin: 0 2px;
background-color: var(--color-dark);
color: white;
font-size: 16px;
text-transform: uppercase;
font-weight: 600;
transition: all .1s ease;
border-bottom: 5px solid rgba(100, 100, 100, 0.2);
}
.tab-opener:not(.tab-visible):hover {
cursor: pointer;
background-color: transparent;
color: rgb(52, 48, 58);
border-bottom-color: grey;
}
.tab-opener.tab-visible {
background-color: transparent;
color: rgb(52, 48, 58);
border-bottom-color: var(--color-primary);
}

View File

@ -1,5 +1,5 @@
import { Utility } from '../../core/utility';
import './tooltips.scss';
import './tooltips.sass';
// empty 'shell' to be able to load styles
@Utility({

View File

@ -0,0 +1,92 @@
.tooltip
position: relative
display: inline-block
vertical-align: middle
&:hover .tooltip__content
display: inline-block
.tooltip__handle
color: var(--color-light)
height: 1.5rem
line-height: 1.5rem
font-size: 1.2rem
display: inline-block
text-align: center
margin: 0 10px
cursor: default
position: relative
&::before
position: absolute
top: 0
left: 0
top: 50%
left: 50%
transform: translate(-50%, -50%)
font-size: 15px
&.tooltip__handle.urgency__success
color: var(--color-success)
&.tooltip__handle.urgency__warning
color: var(--color-warning)
&.tooltip__handle.urgency__error
color: var(--color-error)
&:hover
color: var(--color-dark)
&.tooltip__handle.urgency__success
color: var(--color-success-dark)
&.tooltip__handle.urgency__warning
color: var(--color-warning-dark)
&.tooltip__handle.urgency__error
color: var(--color-error-dark)
.tooltip.tooltip__inline
.tooltip__handle
height: 1.0rem
line-height: 1.0rem
font-size: 1.0rem
.tooltip__content
position: absolute
display: none
top: -10px
transform: translateY(-100%)
left: 3px
width: 275px
z-index: 10
background-color: #fafafa
border-radius: 4px
padding: 13px 17px
box-shadow: 0 0 20px 4px rgba(0, 0, 0, 0.1)
&::after
content: ''
width: 16px
height: 16px
background-color: #fafafa
transform: rotate(45deg)
position: absolute
left: 10px
bottom: -8px
@media (max-width: 768px)
.tooltip
display: block
margin-top: 10px
.tooltip__content
left: 3px
right: 3px
width: auto
// fix font color when used in tableheaders
th .tooltip__content
color: var(--color-font)
font-weight: normal

View File

@ -1,109 +0,0 @@
.tooltip {
position: relative;
display: inline-block;
vertical-align: middle;
&:hover .tooltip__content {
display: inline-block;
}
}
.tooltip__handle {
color: var(--color-light);
height: 1.5rem;
line-height: 1.5rem;
font-size: 1.2rem;
display: inline-block;
text-align: center;
margin: 0 10px;
cursor: default;
position: relative;
&::before {
position: absolute;
top: 0;
left: 0;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 15px;
}
&.tooltip__handle.urgency__success {
color: var(--color-success);
}
&.tooltip__handle.urgency__warning {
color: var(--color-warning);
}
&.tooltip__handle.urgency__error {
color: var(--color-error);
}
&:hover {
color: var(--color-dark);
&.tooltip__handle.urgency__success {
color: var(--color-success-dark);
}
&.tooltip__handle.urgency__warning {
color: var(--color-warning-dark);
}
&.tooltip__handle.urgency__error {
color: var(--color-error-dark);
}
}
}
.tooltip.tooltip__inline {
.tooltip__handle {
height: 1.0rem;
line-height: 1.0rem;
font-size: 1.0rem;
}
}
.tooltip__content {
position: absolute;
display: none;
top: -10px;
transform: translateY(-100%);
left: 3px;
width: 275px;
z-index: 10;
background-color: #fafafa;
border-radius: 4px;
padding: 13px 17px;
box-shadow: 0 0 20px 4px rgba(0, 0, 0, 0.1);
&::after {
content: '';
width: 16px;
height: 16px;
background-color: #fafafa;
transform: rotate(45deg);
position: absolute;
left: 10px;
bottom: -8px;
}
}
@media (max-width: 768px) {
.tooltip {
display: block;
margin-top: 10px;
.tooltip__content {
left: 3px;
right: 3px;
width: auto;
}
}
}
/* fix font color when used in tableheaders */
th .tooltip__content {
color: var(--color-font);
font-weight: normal;
}

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 { HideColumns } from './hide-columns/hide-columns';
export const Utils = [
Alerts,
@ -27,4 +28,5 @@ export const Utils = [
Tooltip,
CourseTeaser,
...NavbarUtils,
HideColumns,
];

2584
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
"author": "",
"license": "ISC",
"scripts": {
"start": "run-p frontend:build:watch yesod:start",
"start": "npm-run-all frontend:build --parallel \"frontend:build:watch\" \"yesod:start\"",
"test": "run-s frontend:test yesod:test",
"lint": "run-s frontend:lint yesod:lint",
"build": "run-s frontend:build yesod:build",
@ -85,11 +85,15 @@
"lint-staged": "^8.2.1",
"lodash.debounce": "^4.0.8",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.13.0",
"npm-run-all": "^4.1.5",
"null-loader": "^2.0.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"resolve-url-loader": "^3.1.1",
"sass": "^1.23.7",
"sass-loader": "^7.3.1",
"semver": "^6.3.0",
"standard-version": "^6.0.1",
"style-loader": "^0.23.1",
"terser-webpack-plugin": "^2.2.3",
@ -97,14 +101,16 @@
"typeface-source-sans-pro": "0.0.75",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-manifest-plugin": "^2.2.0"
"webpack-manifest-plugin": "^2.2.0",
"webpack-plugin-hash-output": "^3.2.1"
},
"dependencies": {
"@babel/runtime": "^7.7.6",
"@juggle/resize-observer": "^2.5.0",
"core-js": "^3.4.8",
"moment": "^2.24.0",
"npm": "^6.13.3",
"tail.datetime": "git+https://github.com/uni2work/tail.DateTime.git#master",
"npm": "^6.13.4",
"tail.datetime": "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/tail.DateTime.git#master",
"whatwg-fetch": "^3.0.0"
}
}

View File

@ -1,5 +1,5 @@
{
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/typeface-roboto/index.css": [
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/app.scss": [
{
"modules": {
"byIdentifier": {},
@ -12,7 +12,7 @@
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/typeface-source-sans-pro/index.css": [
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/alerts/alerts.scss": [
{
"modules": {
"byIdentifier": {},
@ -25,276 +25,7 @@
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/@fortawesome/fontawesome-pro/css/all.css": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/async-form/async-form.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/asidenav/asidenav.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/show-hide/show-hide.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/inputs/inputs.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/inputs/radio.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/form/form.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/alerts/alerts.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/tooltips/tooltips.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/course-teaser/course-teaser.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/modal/modal.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/navbar/navbar.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/async-table/async-table.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/async-table/async-table-filter.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/mass-input/mass-input.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/inputs/file-input.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/dist/cjs.js!frontend/src/utils/inputs/checkbox.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!frontend/src/utils/form/datepicker.css": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
},
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js??ref--5-2!node_modules/typeface-source-sans-pro/index.css": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js??ref--5-2!node_modules/typeface-roboto/index.css": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js??ref--5-2!node_modules/@fortawesome/fontawesome-pro/css/all.css": [
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/async-form/async-form.scss": [
{
"modules": {
"byIdentifier": {},
@ -320,7 +51,20 @@
}
}
],
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/async-form/async-form.scss": [
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/async-table/async-table-filter.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/async-table/async-table.scss": [
{
"modules": {
"byIdentifier": {},
@ -385,71 +129,6 @@
}
}
],
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/tooltips/tooltips.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/course-teaser/course-teaser.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/modal/modal.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/async-table/async-table.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/async-table/async-table-filter.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/mass-input/mass-input.scss": [
{
"modules": {
@ -463,7 +142,7 @@
}
}
],
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/alerts/alerts.scss": [
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/hide-columns/hide-columns.scss": [
{
"modules": {
"byIdentifier": {},
@ -489,7 +168,33 @@
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js??ref--5-2!frontend/src/utils/form/datepicker.css": [
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/course-teaser/course-teaser.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/tooltips/tooltips.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/sass-loader/dist/cjs.js??ref--6-3!frontend/src/utils/modal/modal.scss": [
{
"modules": {
"byIdentifier": {},
@ -527,5 +232,512 @@
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js??ref--5-2!frontend/src/utils/form/datepicker.css": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"modules": {
"byIdentifier": {
"multi frontend/src/polyfill.js frontend/src/main.js": 0
},
"usedIds": {
"0": 0
}
},
"chunks": {
"byName": {},
"bySource": {},
"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/app.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/alerts/alerts.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/asidenav/asidenav.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/show-hide/show-hide.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/async-form/async-form.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/async-table/async-table-filter.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/async-table/async-table.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/form/form.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/inputs/inputs.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/inputs/radio.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/mass-input/mass-input.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/hide-columns/hide-columns.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/navbar/navbar.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/tooltips/tooltips.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/course-teaser/course-teaser.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/modal/modal.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/inputs/file-input.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/inputs/checkbox.scss": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
],
"mini-css-extract-plugin node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js??ref--5-2!node_modules/resolve-url-loader/index.js??ref--5-3!frontend/src/utils/form/datepicker.css": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/app.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/async-form/async-form.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/alerts/alerts.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/asidenav/asidenav.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/form/form.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/hide-columns/hide-columns.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/navbar/navbar.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/course-teaser/course-teaser.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/modal/modal.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/tooltips/tooltips.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/mass-input/mass-input.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/inputs/radio.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/inputs/inputs.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/show-hide/show-hide.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/async-table/async-table.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/async-table/async-table-filter.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/inputs/file-input.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"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/inputs/checkbox.sass": [
{
"modules": {
"byIdentifier": {},
"usedIds": {}
},
"chunks": {
"byName": {},
"bySource": {},
"usedIds": []
}
}
]
}

View File

@ -19,10 +19,12 @@ let
'';
override = oldAttrs: {
nativeBuildInputs = oldAttrs.nativeBuildInputs ++ (with pkgs; [ nodejs-12_x postgresql openldap ]) ++ (with haskellPackages; [ stack yesod-bin hlint cabal-install ]);
nativeBuildInputs = oldAttrs.nativeBuildInputs ++ (with pkgs; [ nodejs-12_x postgresql openldap google-chrome ]) ++ (with haskellPackages; [ stack yesod-bin hlint cabal-install ]);
shellHook = ''
export PROMPT_INFO="${oldAttrs.name}"
export CHROME_BIN=$(which google-chrome-stable)
if [[ -z "$PGHOST" ]]; then
set -xe

View File

@ -71,6 +71,7 @@ import Handler.Utils.SchoolLdap
import Handler.Utils.ExamOffice.Exam
import Handler.Utils.ExamOffice.Course
import Handler.Utils.Profile
import Handler.Utils.Routes
import Utils.Form
import Utils.Sheet
import Utils.SystemMessage
@ -96,86 +97,12 @@ import qualified Ldap.Client as Ldap
import UnliftIO.Pool
-- This is where we define all of the routes in our application. For a full
-- explanation of the syntax, please see:
-- http://www.yesodweb.com/book/routing-and-handlers
--
-- Note that this is really half the story; in Application.hs, mkYesodDispatch
-- generates the rest of the code. Please see the following documentation
-- for an explanation for this split:
-- http://www.yesodweb.com/book/scaffolding-and-the-site-template#scaffolding-and-the-site-template_foundation_and_application_modules
--
-- This function also generates the following type synonyms:
-- type Handler x = HandlerT UniWorX IO x
-- type Widget = WidgetT UniWorX IO ()
mkYesodData "UniWorX" uniworxRoutes
deriving instance Generic CourseR
deriving instance Generic SheetR
deriving instance Generic SubmissionR
deriving instance Generic MaterialR
deriving instance Generic TutorialR
deriving instance Generic ExamR
deriving instance Generic CourseApplicationR
deriving instance Generic AllocationR
deriving instance Generic SchoolR
deriving instance Generic ExamOfficeR
deriving instance Generic CourseNewsR
deriving instance Generic CourseEventR
deriving instance Generic (Route UniWorX)
data RouteChildren
type instance Children RouteChildren a = ChildrenRouteChildren a
type family ChildrenRouteChildren a where
ChildrenRouteChildren (Route EmbeddedStatic) = '[]
ChildrenRouteChildren (Route Auth) = '[]
ChildrenRouteChildren UUID = '[]
ChildrenRouteChildren (Key a) = '[]
ChildrenRouteChildren (CI a) = '[]
ChildrenRouteChildren a = Children ChGeneric a
-- | Convenient Type Synonyms:
type DB = YesodDB UniWorX
type Form x = Html -> MForm (HandlerFor UniWorX) (FormResult x, Widget)
type MsgRenderer = MsgRendererS UniWorX -- see Utils
type MailM a = MailT (HandlerFor UniWorX) a
-- Pattern Synonyms for convenience
pattern CSheetR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> SheetR -> Route UniWorX
pattern CSheetR tid ssh csh shn ptn
= CourseR tid ssh csh (SheetR shn ptn)
pattern CMaterialR :: TermId -> SchoolId -> CourseShorthand -> MaterialName -> MaterialR -> Route UniWorX
pattern CMaterialR tid ssh csh mnm ptn
= CourseR tid ssh csh (MaterialR mnm ptn)
pattern CTutorialR :: TermId -> SchoolId -> CourseShorthand -> TutorialName -> TutorialR -> Route UniWorX
pattern CTutorialR tid ssh csh tnm ptn
= CourseR tid ssh csh (TutorialR tnm ptn)
pattern CExamR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> ExamR -> Route UniWorX
pattern CExamR tid ssh csh tnm ptn
= CourseR tid ssh csh (ExamR tnm ptn)
pattern CSubmissionR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> CryptoFileNameSubmission -> SubmissionR -> Route UniWorX
pattern CSubmissionR tid ssh csh shn cid ptn
= CSheetR tid ssh csh shn (SubmissionR cid ptn)
pattern CApplicationR :: TermId -> SchoolId -> CourseShorthand -> CryptoFileNameCourseApplication -> CourseApplicationR -> Route UniWorX
pattern CApplicationR tid ssh csh appId ptn
= CourseR tid ssh csh (CourseApplicationR appId ptn)
pattern CNewsR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseNews -> CourseNewsR -> Route UniWorX
pattern CNewsR tid ssh csh nId ptn
= CourseR tid ssh csh (CourseNewsR nId ptn)
pattern CEventR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseEvent -> CourseEventR -> Route UniWorX
pattern CEventR tid ssh csh nId ptn
= CourseR tid ssh csh (CourseEventR nId ptn)
-- Requires `rendeRoute`, thus cannot currently be moved to Foundation.I18n
instance RenderMessage UniWorX (UnsupportedAuthPredicate AuthTag (Route UniWorX)) where
renderMessage f ls (UnsupportedAuthPredicate tag route) = mr . MsgUnsupportedAuthPredicate (mr tag) $ Text.intercalate "/" pieces
@ -1486,6 +1413,7 @@ siteLayout' headingOverride widget = do
primaryLanguage <- unsafeHead . Text.splitOn "-" <$> selectLanguage appLanguages
mcurrentRoute <- getCurrentRoute
let currentHandler = classifyHandler <$> mcurrentRoute
-- Get the breadcrumbs, as defined in the YesodBreadcrumbs instance.
let

View File

@ -1,10 +1,84 @@
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Foundation.Routes
( uniworxRoutes
( module Foundation.Routes.Definitions
, module Foundation.Routes
) where
import ClassyPrelude.Yesod
import Yesod.Routes.TH.Types (ResourceTree)
import Import.NoFoundation
import Foundation.Type
import Foundation.Routes.Definitions
uniworxRoutes :: [ResourceTree String]
uniworxRoutes = $(parseRoutesFile "routes")
-- This is where we define all of the routes in our application. For a full
-- explanation of the syntax, please see:
-- http://www.yesodweb.com/book/routing-and-handlers
--
-- Note that this is really half the story; in Application.hs, mkYesodDispatch
-- generates the rest of the code. Please see the following documentation
-- for an explanation for this split:
-- http://www.yesodweb.com/book/scaffolding-and-the-site-template#scaffolding-and-the-site-template_foundation_and_application_modules
--
-- This function also generates the following type synonyms:
-- type Handler x = HandlerT UniWorX IO x
-- type Widget = WidgetT UniWorX IO ()
mkYesodData "UniWorX" uniworxRoutes
deriving instance Generic CourseR
deriving instance Generic SheetR
deriving instance Generic SubmissionR
deriving instance Generic MaterialR
deriving instance Generic TutorialR
deriving instance Generic ExamR
deriving instance Generic CourseApplicationR
deriving instance Generic AllocationR
deriving instance Generic SchoolR
deriving instance Generic ExamOfficeR
deriving instance Generic CourseNewsR
deriving instance Generic CourseEventR
deriving instance Generic (Route UniWorX)
data RouteChildren
type instance Children RouteChildren a = ChildrenRouteChildren a
type family ChildrenRouteChildren a where
ChildrenRouteChildren (Route EmbeddedStatic) = '[]
ChildrenRouteChildren (Route Auth) = '[]
ChildrenRouteChildren UUID = '[]
ChildrenRouteChildren (Key a) = '[]
ChildrenRouteChildren (CI a) = '[]
ChildrenRouteChildren a = Children ChGeneric a
-- Pattern Synonyms for convenience
pattern CSheetR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> SheetR -> Route UniWorX
pattern CSheetR tid ssh csh shn ptn
= CourseR tid ssh csh (SheetR shn ptn)
pattern CMaterialR :: TermId -> SchoolId -> CourseShorthand -> MaterialName -> MaterialR -> Route UniWorX
pattern CMaterialR tid ssh csh mnm ptn
= CourseR tid ssh csh (MaterialR mnm ptn)
pattern CTutorialR :: TermId -> SchoolId -> CourseShorthand -> TutorialName -> TutorialR -> Route UniWorX
pattern CTutorialR tid ssh csh tnm ptn
= CourseR tid ssh csh (TutorialR tnm ptn)
pattern CExamR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> ExamR -> Route UniWorX
pattern CExamR tid ssh csh tnm ptn
= CourseR tid ssh csh (ExamR tnm ptn)
pattern CSubmissionR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> CryptoFileNameSubmission -> SubmissionR -> Route UniWorX
pattern CSubmissionR tid ssh csh shn cid ptn
= CSheetR tid ssh csh shn (SubmissionR cid ptn)
pattern CApplicationR :: TermId -> SchoolId -> CourseShorthand -> CryptoFileNameCourseApplication -> CourseApplicationR -> Route UniWorX
pattern CApplicationR tid ssh csh appId ptn
= CourseR tid ssh csh (CourseApplicationR appId ptn)
pattern CNewsR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseNews -> CourseNewsR -> Route UniWorX
pattern CNewsR tid ssh csh nId ptn
= CourseR tid ssh csh (CourseNewsR nId ptn)
pattern CEventR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseEvent -> CourseEventR -> Route UniWorX
pattern CEventR tid ssh csh nId ptn
= CourseR tid ssh csh (CourseEventR nId ptn)

View File

@ -0,0 +1,10 @@
module Foundation.Routes.Definitions
( uniworxRoutes
) where
import ClassyPrelude.Yesod
import Yesod.Routes.TH.Types (ResourceTree)
uniworxRoutes :: [ResourceTree String]
uniworxRoutes = $(parseRoutesFile "routes")

View File

@ -89,7 +89,7 @@ getAllocationListR = do
dbtSorting = mconcat
[ sortTerm $ queryAllocation . to (E.^. AllocationTerm)
, sortSchool $ queryAllocation . to (E.^. AllocationSchool)
, sortSchoolShort $ queryAllocation . to (E.^. AllocationSchool)
, sortAllocationName $ queryAllocation . to (E.^. AllocationName)
, singletonMap "available" . SortColumn $ view queryAvailable
, if
@ -124,7 +124,7 @@ getAllocationListR = do
psValidator :: PSValidator _ _
psValidator = def
& defaultSorting [SortDescBy "term", SortAscBy "school", SortAscBy "allocation"]
& defaultSorting [SortDescBy "term", SortAscBy "school-short", SortAscBy "allocation"]
table <- runDB $ dbTableWidget' psValidator DBTable{..}

View File

@ -2,7 +2,9 @@ module Handler.Utils.Routes
( classifyHandler
) where
import Import
import Import.NoFoundation
import Foundation.Routes
import Foundation.Type
import Utils.TH.Routes

View File

@ -11,11 +11,11 @@ packages:
- .
extra-deps:
- git: https://github.com/uni2work/encoding.git
- git: git@gitlab2.rz.ifi.lmu.de:uni2work/encoding.git
commit: 67bb87ceff53f0178c988dd4e15eeb2daee92b84
- git: https://github.com/uni2work/memcached-binary.git
- git: git@gitlab2.rz.ifi.lmu.de:uni2work/memcached-binary.git
commit: b5461747e7be226d3b67daebc3c9aefe8a4490ad
- git: https://github.com/uni2work/conduit-resumablesink.git
- git: git@gitlab2.rz.ifi.lmu.de:uni2work/conduit-resumablesink.git
commit: cbea6159c2975d42f948525e03e12fc390da53c5
- zip-stream-0.2.0.1

View File

@ -1,3 +0,0 @@
#admin-studyterms
select, option, input
min-width: 50px

View File

@ -1,104 +0,0 @@
.allocation__label, .allocation__explanation {
color: var(--color-fontsec);
font-style: italic;
}
.allocation__state {
color: var(--color-font);
font-weight: 600;
font-style: normal;
}
.allocation__courses {
margin: 20px 0 0 40px;
}
.allocation-course {
display: grid;
grid-template-columns: minmax(105px, 1fr) 9fr;
grid-template-areas:
'name name '
'. registered '
'prio-label prio '
'instr-label instr '
'form-label form ';
grid-gap: 5px 7px;
margin: 12px 0;
padding: 0 10px 12px 7px;
border-left: 1px solid var(--color-grey);
/* &:last-child {
* padding: 12px 10px 0 10px;
* }
*
* & + .allocation-course {
* border-top: 1px solid var(--color-grey);
* }
*/
&:nth-child(2n) {
background-color: rgba(0, 0, 0, 0.015);
}
.allocation-course__registered {
grid-area: registered;
}
.allocation-course__priority {
grid-area: prio;
}
.allocation-course__priority-label {
grid-area: prio-label;
justify-self: end;
align-self: center;
text-align: right;
}
.allocation-course__name {
grid-area: name;
align-self: center;
font-size: 1.2rem;
}
.allocation-course__instructions {
grid-area: instr;
}
.allocation-course__instructions-label {
grid-area: instr-label;
justify-self: end;
text-align: right;
}
.allocation-course__application {
grid-area: form;
}
.allocation-course__application-label {
grid-area: form-label;
justify-self: end;
text-align: right;
padding-top: 6px;
}
}
@media (max-width: 426px) {
.allocation-course {
grid-template-columns: 1fr;
grid-template-areas:
'name '
'registered '
'prio-label '
'prio '
'instr-label'
'instr '
'form-label '
'form ';
}
.allocation-course__application-label {
padding-top: 0;
}
}

View File

@ -1,3 +0,0 @@
.comment
white-space: pre-wrap
font-family: monospace

View File

@ -4,4 +4,4 @@ $#
$# participantTable : widget table
^{participantTable}
_{MsgCourseMembersCountOf (fromIntegral numParticipants) (courseCapacity course)}.
_{MsgCourseMembersCountOf (fromIntegral numParticipants) (courseCapacity course)}.

View File

@ -1,42 +0,0 @@
th {
vertical-align: top;
text-align: left;
}
th, td {
padding-bottom: 7px;
}
.course-news {
max-height: 50vh;
overflow: auto;
.course-news-item {
padding: 12px 0;
border-bottom: 1px solid #d3d3d3;
&:last-child {
padding-bottom: 0;
border-bottom: none;
}
&:first-child {
padding-top: 0;
}
.course-news-item__last-edit {
color: var(--color-fontsec);
font-style: italic;
}
.course-news-item__title .modal__trigger-label {
font-style: normal;
}
.course-news-item__summary .modal__trigger-label {
font-weight: normal;
font-style: normal;
color: var(--color-font);
}
}
}

View File

@ -1,4 +0,0 @@
.bound_explanation {
color: var(--color-fontsec);
font-style: italic;
}

View File

@ -1,52 +0,0 @@
.action {
max-width: 800px;
padding: 3px 0;
&:not(:last-child) {
margin-bottom: 7px;
}
&:not(:first-child) {
margin-top: 7px;
}
}
.action__options {
max-height: 450px;
overflow-y: auto;
}
.action__option {
display: flex;
&:not(:last-child) {
margin-bottom: 10px;
}
}
.action__label,
.action__option-label {
margin-left: 15px;
vertical-align: top;
}
.action__fieldset {
margin: 7px 0 5px 9px;
padding: 5px 0 10px;
border-left: 1px solid #bcbcbc;
padding-left: 16px;
position: relative;
}
.action__toggle-all {
display: flex;
border-bottom: 1px solid #bcbcbc;
padding-bottom: 8px;
margin-bottom: 8px;
}
.action__checked-counter {
position: absolute;
right: 5px;
top: 5px;
}

View File

@ -11,7 +11,7 @@ $if not isModal
<div .main>
<div .main__content uw-poc>
<div .main__content uw-poc :isJust currentHandler:uw-handler=#{fromMaybe "" currentHandler}>
$if not isModal
<!-- breadcrumbs -->

View File

@ -1,786 +0,0 @@
:root {
/* THEME INDEPENDENT COLORS */
--color-error: #8c0707;
--color-error-dark: #500303;
--color-warning: #fc9900;
--color-warning-dark: #c27400;
--color-success: #23d160;
--color-success-dark: #1ca64c;
--color-info: #c4c4c4;
--color-info-dark: #919191;
--color-lightblack: #1A2A36;
--color-lightwhite: #fcfffa;
--color-grey: #B1B5C0;
--color-grey-light: #efefef;
--color-grey-lighter: #f5f5f5;
--color-grey-medium: #9A989E;
--color-font: #34303a;
--color-fontsec: #5b5861;
/* FONTS */
--font-base: "Source Sans Pro", "Trebuchet MS", sans-serif;
--font-logo: "Roboto", var(--font-base);
/* DIMENSIONS */
--header-height: 100px;
--header-height-collapsed: 60px;
--asidenav-width-xl: 250px;
--asidenav-width-lg: 20%;
--asidenav-width-md: 60px;
}
* {
box-sizing: border-box;
padding: 0;
margin: 0;
-webkit-font-smoothing: antialiased;
}
body {
background-color: white;
color: var(--color-font);
font-family: var(--font-base);
font-weight: 400;
font-size: 16px;
overflow-y: scroll;
}
/* THEMES */
body {
/* DEFAULT LMU THEME */
--color-lmu-green: #0a9342;
--color-primary: var(--color-lmu-green);
--color-light: #31cc72;
--color-lighter: #35db7a;
--color-dark: #087536;
--color-darker: #075728;
--color-link: var(--color-font);
--color-link-hover: var(--color-font);
--color-lmu-box-border: var(--color-lightwhite);
&.theme--lavender {
--color-primary: #584c9c;
--color-light: #5969b5;
--color-lighter: #5f7dc2;
--color-dark: #4c4279;
--color-darker: #3c2765;
--color-link: var(--color-dark);
--color-link-hover: var(--color-darker);
}
&.theme--neutral-blue {
--color-primary: #3E606F;
--color-light: rgb(189, 201, 219);
--color-lighter: rgb(145, 159, 170);
--color-dark: rgb(42, 74, 88);
--color-darker: #193441;
}
&.theme--aberdeen-reds {
--color-primary: #820333;
--color-light: #C9283E;
--color-lighter: #F0433A;
--color-dark: #540032;
--color-darker: #2E112D;
}
&.theme--moss-green {
--color-primary: #5C996B;
--color-light: #7ACC8F;
--color-lighter: #99FFB2;
--color-dark: #3D6647;
--color-darker: #1F3324;
}
&.theme--sky-love {
--color-primary: #87ABE5;
--color-light: #A0C6F2;
--color-lighter: #BAE2FF;
--color-dark: #7A95DE;
--color-darker: #6B7BC9;
--color-link: var(--color-lightblack);
--color-link-hover: var(--color-darker);
}
}
/* END THEMES */
.emph {
font-style: italic;
}
a,
a:visited {
text-decoration: none;
font-weight: 600;
transition: color .2s ease, background-color .2s ease;
}
a {
color: var(--color-link);
}
a:hover {
color: var(--color-link-hover);
}
ul {
margin-left: 20px;
}
h1, h2, h3, .div-h3 , h4, h5 {
font-weight: 600;
}
h1 {
font-size: 32px;
margin-bottom: 10px;
}
h2 {
font-size: 24px;
margin: 10px 0;
&:first-child {
margin-top: 0;
}
}
h3, .div-h3 {
font-size: 20px;
margin: 10px 0;
&:first-child {
margin-top: 0;
}
}
h4 {
font-size: 16px;
margin: 0;
}
@media (max-width: 768px) {
h1 {
font-size: 24px;
}
h2 {
font-size: 20px;
}
h3, .div-h3 {
font-size: 16px;
}
}
/* LAYOUT */
.main {
position: relative;
}
.main__content {
position: relative;
background-color: white;
transition: padding-left .2s ease-out;
margin-top: var(--header-height-collapsed);
margin-left: 0;
> .container {
margin: 20px 0;
}
}
.main__content, .modal__content {
a {
text-decoration: underline;
}
p, form, .div-p {
margin: 0.5rem 0;
&:last-child {
margin: 0.5rem 0 0;
&:first-child {
margin: 0;
}
}
}
}
@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%);
margin-top: var(--header-height);
}
}
@media (min-width: 1200px) {
.main__content {
margin-left: var(--asidenav-width-xl, 250px);
}
}
.main__content-body {
padding: 13px;
}
@media (min-width: 426px) {
.main__content-body {
padding: 13px 20px;
}
}
@media (min-width: 769px) {
.main__content-body {
padding: 20px 40px;
}
}
.pseudo-focus {
outline: 5px auto var(--color-light);
outline: 5px auto -webkit-focus-ring-color;
}
/* CONTAINER */
.container {
+ .container {
margin-top: 20px;
}
}
/* GENERAL BUTTON STYLES */
input[type="submit"],
input[type="button"],
button,
.btn {
outline: 0;
border: 0;
box-shadow: 0;
background-color: var(--color-dark);
color: white;
padding: 10px 17px;
min-width: 100px;
transition: all .1s;
font-size: 16px;
cursor: pointer;
display: inline-block;
text-decoration: none;
a:hover {
color: white;
}
&:focus {
border-color: #3273dc;
box-shadow: 0 0 0 0.25rem rgba(50,115,220,.25);
outline: 0;
}
}
input[type="submit"][disabled],
input[type="button"][disabled],
button[disabled],
.btn[disabled] {
opacity: 0.3;
background-color: var(--color-grey);
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(--color-light);
color: white;
}
.btn-primary {
background-color: var(--color-primary);
}
.btn-info {
background-color: var(--color-info)
}
.btn--small {
padding: 4px 7px;
background-color: var(--color-darker);
}
input[type="submit"].btn-info:hover,
input[type="button"].btn-info:hover,
.btn-info:hover {
background-color: var(--color-grey)
}
/* GENERAL TABLE STYLES */
.table {
margin: 21px 0;
width: 100%;
}
.table:only-child {
margin: 0;
}
.table--striped {
.table__row:not(.no-stripe):not(.table__row--sum):nth-child(even) {
background-color: rgba(0, 0, 0, 0.03);
}
}
.table--hover {
.table__row:not(.no-hover):not(.table__row--sum):not(.table__row--head):not(.table__row--foot):hover {
background-color: rgba(0, 0, 0, 0.07);
}
}
.table__row--sum td.table__td::before {
content: 'Σ';
font-weight: bold;
margin-right: .25em;
}
/* SCROLLTABLE */
.scrolltable {
overflow: auto;
}
.scrolltable--bordered {
box-shadow: 0 0 1px 1px var(--color-grey-light);
}
@media (max-width: 425px) {
.scrolltable {
margin-left: -10px;
padding-left: 10px;
margin-right: -10px;
padding-right: 10px;
}
}
/* TABLE DESIGN */
.table__td, .table__th {
padding-top: 14px;
padding-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
max-width: 300px;
}
.table__td {
font-size: 16px;
color: var(--color-font);
line-height: 1.4;
vertical-align: top;
}
.table__td--automatic {
font-style: oblique;
color: var(--color-fontsec);
}
.table__td--overriden {
font-weight: bold;
}
.table__th {
background-color: var(--color-dark);
position: relative;
font-size: 16px;
color: white;
line-height: 1.4;
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
text-align: left;
a {
color: white;
text-decoration: none;
font-weight: bold;
&:hover {
color: inherit;
}
&::before {
content: "\f0c1";
font-family: "Font Awesome 5 Free";
font-weight: 900;
margin-right: 0.25em;
}
}
}
@media (max-width: 1200px) {
.table th {
padding: 4px 6px;
}
}
.table__td-content {
max-height: 200px;
overflow-y: auto;
}
.table__th-link {
font-weight: bold;
&::before {
display: none;
}
}
.table--vertical {
th {
background-color: transparent;
color: var(--color-font);
width: 170px;
text-align: right;
padding-right: 15px;
font-weight: 400;
}
td {
font-weight: 600;
color: var(--color-font);
}
}
.table--condensed {
margin: 0;
.table__th,
.table__td {
padding: 4px 8px;
}
}
/* UNORDERED LIST */
.list-ul__item {
// padding: 4px 0;
line-height: 25px;
}
/* LIST MODIFIERS */
.list--iconless {
list-style-type: none;
margin-left: 0;
}
.list--inline {
ul {
display: inline-block;
margin-left: 0;
li {
display: inline-block;
}
}
}
ul.list--inline {
display: inline-block;
margin-left: 0;
li {
display: inline-block;
}
}
.list--comma-separated li {
&::after {
content: ', ';
white-space: pre;
}
&:last-of-type::after {
content: none;
}
}
.list--space-separated li {
&::after {
content: ' ';
white-space: pre;
}
&:last-of-type::after {
content: none;
}
}
.list--icon-width li {
width: 1rem;
height: 1rem;
}
/* DEFINITION LIST */
.deflist {
display: grid;
grid-template-columns: 100%;
}
.deflist__dt,
.deflist__dd {
padding: 2px 0;
}
.deflist__dt {
font-weight: 600;
}
.deflist__dd {
font-size: 18px;
margin-bottom: 10px;
> p, > .div-p {
margin-top: 0;
}
}
@media (min-width: 768px) {
.deflist {
grid-template-columns: fit-content(25vw) 1fr;
.deflist {
margin-top: -10px;
margin-right: -15px;
.deflist__dd {
padding-right: 15px;
}
}
}
.deflist__dt,
.deflist__dd {
padding: 12px 0;
margin: 0;
font-size: 16px;
&:last-of-type {
border: 0;
}
}
.deflist__dt {
padding-right: 50px;
}
.deflist__dd {
padding-right: 15px;
}
}
section {
padding-bottom: 30px;
border-bottom: 1px solid #d3d3d3;
+ section {
margin-top: 20px;
}
&:last-child {
border-bottom: none;
padding-bottom: 0px;
}
}
.pseudonym {
font-family: monospace;
}
.headline-one {
margin-bottom: 10px;
}
/* Notification style used as requested by @hamanf in #298, but class was not globally available. Copied from dead-code. For @hamanf to clean up: */
.notification {
position: relative;
border-radius: 3px;
padding: 10px 20px 20px;
margin: 40px auto;
box-shadow: 0 0 4px 2px inset currentColor;
padding-left: 100px;
min-height: 100px;
max-width: 700px;
font-weight: 600;
vertical-align: center;
display: grid;
grid-column: 2;
&::before {
font-family: "Font Awesome 5 Free";
font-weight: 600;
position: absolute;
display: flex;
left: 0;
top: 0;
height: 100%;
width: 100px;
font-size: 50px;
align-items: center;
justify-content: center;
}
.notification__content {
grid-column: 1;
align-self: center;
color: var(--color-font);
}
&.notification--broad {
max-width: none;
}
}
.form-section-notification {
display: grid;
grid-template-columns: 1fr 3fr;
grid-gap: 5px;
fieldset {
display: grid;
grid-template-columns: 1fr 3fr;
grid-gap: 5px;
grid-column: 1/3;
}
.notification {
margin: 0;
}
+ .form-group, + .form-section-legend, + .form-section-notification {
margin-top: 11px;
}
+ .form-section-title {
margin-top: 40px;
}
}
@media (max-width: 768px) {
.form-section-notification {
grid-template-columns: 1fr;
margin-top: 17px;
fieldset {
grid-template-columns: 1fr;
grid-column: 1/2;
}
}
.notification {
grid-column: 1;
max-width: none;
padding-left: 40px;
&::before {
height: auto;
width: 45px;
font-size: 40px;
top: 15px;
}
}
}
.notification-error {
color: var(--color-error) ;
}
.notification-warning {
color: var(--color-warning) ;
}
.notification-info {
color: var(--color-lightblack) ;
}
.notification-success {
color: var(--color-warning) ;
}
/*
"Heated" element.
Set custom property "--hotness" to a value from 0 to 1 to turn
the element's background to a color on a gradient from green to red.
TBD:
- move to a proper place
- think about font-weight...
Example:
<div .heated style="--hotness: 0.2">Lorem ipsum
*/
.heated {
--hotness: 0;
--red: calc(var(--hotness) * 200);
--green: calc(255 - calc(var(--hotness) * 255));
--opacity: calc(calc(var(--red) / 600) + 0.1);
font-weight: var(--weight, 600);
background-color: rgba(var(--red), var(--green), 0, var(--opacity));
}
.uuid {
font-family: monospace;
}
.form--inline {
display: inline-block;
}
.ribbon {
position: fixed;
top: calc(40px + var(--header-height));
transition: all .2s cubic-bezier(0.03, 0.43, 0.58, 1);
right: -63px;
transform: rotate(45deg);
width: 250px;
background: var(--color-error);
text-align: center;
color: var(--color-lightwhite);
font-weight: 600;
font-size: 1.25rem;
line-height: 2em;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.4);
z-index: 19;
pointer-events: none;
}
@media (max-width: 768px) {
.ribbon {
top: calc(20px + var(--header-height-collapsed));
right: -83px;
transform: rotate(45deg) scale(0.6);
}
}

View File

@ -1,6 +0,0 @@
.occurrence--not-registered, .no-bonus
text-decoration: line-through
.result
font-size: 3rem
margin: 30px 30px 0 !important

View File

@ -1,14 +0,0 @@
.glossary
dt, .dt
font-weight: 600
&.sec
font-style: italic
font-size: 0.9rem
font-weight: 600
color: var(--color-fontsec)
dd, .dd
margin-left: 12px
dd + dt, .dd + dt, dd + .dt, .dd + .dt
margin-top: 17px

View File

@ -1,5 +1,5 @@
$newline never
<th .table__th *{attrs} :isSortable:.sortable :isSorted SortAsc:.sorted-asc :isSorted SortDesc:.sorted-desc>
<th .table__th *{attrs} :isSortable:.sortable :isSorted SortAsc:.sorted-asc :isSorted SortDesc:.sorted-desc uw-hide-column-header=#{maybe "" toPathPiece sortableKey}>
$maybe flag <- sortableKey
$case directions
$of [SortAsc]

View File

@ -1,4 +1,5 @@
$newline never
<div table-utils>
<div .scrolltable .scrolltable--bordered>
<table *{dbsAttrs'}>
$maybe wHeaders' <- wHeaders

View File

@ -1,40 +0,0 @@
/* SORTABLE TABLE-HEADERS*/
.table__th.sortable {
position: relative;
padding-right: 24px;
cursor: pointer;
}
.table__th.sortable::after,
.table__th.sortable::before {
content: '';
position: absolute;
top: 50%;
right: 4px;
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-bottom: 8px solid rgba(255, 255, 255, 0.4);
}
.table__th.sortable::before {
/* magic numbers to move arrow back in the right position after flipping it.
this allows us to use the same border for the up and the down arrow */
transform: translateY(150%) scale(1, -1);
transform-origin: top;
}
.table__th.sortable::after {
transform: translateY(-150%);
}
.table__th.sortable:hover::before,
.table__th.sortable:hover::after {
border-bottom-color: rgba(255, 255, 255, 0.7);
}
.table__th.sorted-asc::before,
.table__th.sorted-desc::after {
border-bottom-color: white !important;
}

View File

@ -1,45 +0,0 @@
:root {
--color-grey-light: #efefef;
--color-grey-lighter: #f5f5f5;
--color-fontsec: #5b5861;
--course-bg-color: var(--color-grey-lighter);
--course-expanded-bg-color: var(--color-grey-light);
}
.scrolltable {
box-shadow: none!important;
}
.course-header::after,
.course-header::before {
content: '';
position: absolute;
right: 10px;
top: 20px;
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-bottom: 8px solid rgba(255, 255, 255, 0.4);
}
.course-header::before {
/* magic numbers to move arrow back in the right position after flipping it.
this allows us to use the same border for the up and the down arrow */
transform: translateY(150%) scale(1, -1);
transform-origin: top;
}
.course-header::after {
transform: translateY(-150%);
}
.course-header:hover::before,
.course-header:hover::after {
border-bottom-color: rgba(255, 255, 255, 0.7);
}
.sorted-asc::before,
.sorted-desc::after {
border-bottom-color: white !important;
}

View File

@ -1,8 +0,0 @@
.csv-export {
margin-bottom: 13px;
}
.csv-import {
margin-bottom: 13px;
}

View File

@ -1,7 +0,0 @@
.table-filter {
margin-bottom: 13px;
}
.table-filter__toggle {
padding: 3px 7px;
}

View File

@ -1,3 +1,3 @@
$newline never
<div ##{wIdent "table-wrapper"} :not (null rows && (dbsEmptyStyle == DBESNoHeading)):uw-async-table data-async-table-db-header=#{toPathPiece HeaderDBTableShortcircuit}>
<div ##{wIdent "table-wrapper"} :not (null rows && (dbsEmptyStyle == DBESNoHeading)):uw-async-table uw-hide-columns=#{dbtIdent} data-async-table-db-header=#{toPathPiece HeaderDBTableShortcircuit}>
^{table}

View File

@ -1,61 +0,0 @@
/* TABLE HEADER */
.table-header {
display: flex;
flex-flow: row-reverse;
justify-content: space-between;
margin-bottom: 15px;
}
/* TABLE FOOTER */
.table-footer {
display: flex;
flex-flow: row-reverse;
justify-content: space-between;
margin-top: 15px;
}
/* PAGINATION */
.pagination {
margin-top: 20px;
overflow: auto;
.pages {
text-align: center;
white-space: nowrap;
margin: 0;
.page-link {
margin-top: 7px;
display: inline-block;
background-color: var(--color-grey-medium);
+ .page-link {
margin-left: 7px;
}
a {
color: var(--color-lightwhite);
padding: 7px 13px;
display: inline-block;
text-decoration: none;
}
&:not(.current):hover {
background-color: var(--color-primary);
a {
color: var(--color-lightwhite);
}
}
&.current {
pointer-events: none;
background-color: var(--color-dark);
a {
pointer-events: none;
}
}
}
}
}

View File

@ -1,11 +0,0 @@
#changelog {
font-size: 14px;
white-space: pre-wrap;
font-family: monospace;
}
#gitrev {
font-size: 12px;
white-space: pre-wrap;
font-family: monospace;
}

View File

@ -1,62 +0,0 @@
.breadcrumbs__container {
position: relative;
color: var(--color-lightwhite);
padding: 4px 13px;
background-color: var(--color-dark);
line-height: 30px;
}
@media (min-width: 426px) {
.breadcrumbs__container {
padding: 7px 20px;
}
}
@media (min-width: 769px) {
.breadcrumbs__container {
padding: 7px 40px;
}
}
.breadcrumbs__link {
color: var(--color-lightwhite);
&:hover {
color: var(--color-white);
}
}
.breadcrumbs__item {
padding-right: 14px;
position: relative;
line-height: 28px;
opacity: 0.8;
z-index: 1;
margin-right: 10px;
&:hover {
opacity: 1;
}
&::after {
content: '';
position: absolute;
top: 11px;
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;
}
}
.breadcrumbs__last-item {
line-height: 28px;
vertical-align: bottom;
font-weight: 600;
}

View File

@ -1,65 +0,0 @@
.recipient-category {
max-width: 400px;
padding: 3px 0;
&:not(:last-child) {
margin-bottom: 7px;
}
&:not(:first-child) {
margin-top: 7px;
}
}
.recipient-category__options {
max-height: 150px;
overflow-y: auto;
}
.recipient-category__option {
display: flex;
&:not(:last-child) {
margin-bottom: 10px;
}
}
.recipient-category__label,
.recipient-category__option-label {
margin-left: 15px;
vertical-align: top;
}
.recipient-category__fieldset {
margin: 7px 0 5px 9px;
padding: 5px 0 10px;
border-left: 1px solid #bcbcbc;
padding-left: 16px;
position: relative;
}
.recipient-category__option-add {
display: flex;
.btn-mass-input-add {
margin-left: 10px;
padding: 10px 0;
}
}
.recipient-category__options + .recipient-category__option-add {
margin-top: 10px;
}
.recipient-category__toggle-all {
display: flex;
border-bottom: 1px solid #bcbcbc;
padding-bottom: 8px;
margin-bottom: 8px;
}
.recipient-category__checked-counter {
position: absolute;
right: 5px;
top: 5px;
}

View File

@ -1,3 +0,0 @@
.table__td--csv, .table__th--csv {
font-family: monospace;
}

View File

@ -1,5 +0,0 @@
.confirmationText {
white-space: pre-wrap;
font-size: 14px;
font-family: monospace;
}

View File

@ -1,3 +1,3 @@
$newline never
<div ##{fvId <> "-wrapper"}>
<div .func-field__wrapper>
^{formView}

View File

@ -1,4 +0,0 @@
##{fvId <> "-wrapper"} {
max-height: 75vh;
overflow: auto;
}

View File

@ -1,24 +0,0 @@
.footer {
text-align: center;
padding: 20px;
position: relative;
margin: 40px 0;
&::before {
content: '';
position: absolute;
top: 0;
left: 10%;
width: 80%;
height: 2px;
background-color: var(--color-grey-light);
}
}
.footer-links * {
margin-right: 0.5em;
&:last {
margin-right: 0;
}
}

View File

@ -1,3 +0,0 @@
.table--grading-key
th, td
padding: 3px;

View File

@ -1,8 +0,0 @@
.btn.btn-mass-input-delete,
.btn.btn-mass-input-add {
background-color: #999;
min-width: 50px;
padding: 5px 15px;
font-weight: 700;
font-size: 1.3rem;
}

View File

@ -1,11 +0,0 @@
.file-input__unpack {
font-size: .9rem;
display: flex;
align-items: center;
margin-top: 10px;
.checkbox {
display: inline-block;
margin-left: 7px;
}
}

Some files were not shown because too many files have changed in this diff Show More