mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender-pwa.git
synced 2025-08-07 04:09:17 +02:00
lint:#13 formatted
This commit is contained in:
8
.gitattributes
vendored
Normal file
8
.gitattributes
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
*.ts text eol=lf
|
||||
*.go text eol=lf
|
||||
*.js text eol=lf
|
||||
*.json text eol=lf
|
||||
*.vue text eol=lf
|
||||
*.md text eol=lf
|
||||
*.css text eol=lf
|
||||
*.scss text eol=lf
|
@@ -4,13 +4,19 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>HTWKalender</title>
|
||||
<meta name="description" content="Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.">
|
||||
<meta name="keywords" content="HTWK, calendar, iCal, dates, events, schedule">
|
||||
<meta
|
||||
name="description"
|
||||
content="Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format."
|
||||
/>
|
||||
<meta
|
||||
name="keywords"
|
||||
content="HTWK, calendar, iCal, dates, events, schedule"
|
||||
/>
|
||||
<link rel="icon" href="/favicon.ico" sizes="32x32" />
|
||||
<link rel="icon" type="image/svg+xml" href="/htwk.svg" />
|
||||
<link rel="mask-icon" href="/htwk-mask.svg" color="#00494c" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<meta name="theme-color" content="#1b2022">
|
||||
<meta name="theme-color" content="#1b2022" />
|
||||
<link
|
||||
id="theme-link"
|
||||
rel="stylesheet"
|
||||
|
@@ -3,15 +3,14 @@
|
||||
@each $name, $color in $colors {
|
||||
@for $i from 0 through 5 {
|
||||
@if ($i == 0) {
|
||||
--#{$name}-50:#{tint($color, (5 - $i) * 19%)};
|
||||
}
|
||||
@else {
|
||||
--#{$name}-#{$i * 100}:#{tint($color, (5 - $i) * 19%)};
|
||||
--#{$name}-50: #{tint($color, (5 - $i) * 19%)};
|
||||
} @else {
|
||||
--#{$name}-#{$i * 100}: #{tint($color, (5 - $i) * 19%)};
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 4 {
|
||||
--#{$name}-#{($i + 5) * 100}:#{shade($color, $i * 15%)};
|
||||
--#{$name}-#{($i + 5) * 100}: #{shade($color, $i * 15%)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
// core
|
||||
.p-component, .p-component * {
|
||||
.p-component,
|
||||
.p-component * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@@ -17,7 +18,8 @@
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.p-disabled, .p-disabled * {
|
||||
.p-disabled,
|
||||
.p-disabled * {
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
@@ -66,7 +68,9 @@
|
||||
.p-connected-overlay {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
transition: transform .12s cubic-bezier(0, 0, 0.2, 1), opacity .12s cubic-bezier(0, 0, 0.2, 1);
|
||||
transition:
|
||||
transform 0.12s cubic-bezier(0, 0, 0.2, 1),
|
||||
opacity 0.12s cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.p-connected-overlay-visible {
|
||||
@@ -77,7 +81,7 @@
|
||||
.p-connected-overlay-hidden {
|
||||
opacity: 0;
|
||||
transform: scaleY(1);
|
||||
transition: opacity .1s linear;
|
||||
transition: opacity 0.1s linear;
|
||||
}
|
||||
|
||||
/* Vue based overlay animations */
|
||||
@@ -91,11 +95,13 @@
|
||||
}
|
||||
|
||||
.p-connected-overlay-enter-active {
|
||||
transition: transform .12s cubic-bezier(0, 0, 0.2, 1), opacity .12s cubic-bezier(0, 0, 0.2, 1);
|
||||
transition:
|
||||
transform 0.12s cubic-bezier(0, 0, 0.2, 1),
|
||||
opacity 0.12s cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.p-connected-overlay-leave-active {
|
||||
transition: opacity .1s linear;
|
||||
transition: opacity 0.1s linear;
|
||||
}
|
||||
|
||||
/* Toggleable Content */
|
||||
@@ -136,7 +142,8 @@
|
||||
transition-duration: $transitionDuration;
|
||||
}
|
||||
|
||||
.p-disabled, .p-component:disabled {
|
||||
.p-disabled,
|
||||
.p-component:disabled {
|
||||
opacity: $disabledOpacity;
|
||||
}
|
||||
|
||||
|
@@ -79,7 +79,8 @@
|
||||
color: $menuitemTextActiveColor;
|
||||
}
|
||||
|
||||
.p-menuitem-icon, .p-submenu-icon {
|
||||
.p-menuitem-icon,
|
||||
.p-submenu-icon {
|
||||
color: $menuitemIconActiveColor;
|
||||
}
|
||||
}
|
||||
@@ -103,7 +104,8 @@
|
||||
color: $menuitemTextHoverColor;
|
||||
}
|
||||
|
||||
.p-menuitem-icon, .p-submenu-icon {
|
||||
.p-menuitem-icon,
|
||||
.p-submenu-icon {
|
||||
color: $menuitemTextHoverColor;
|
||||
}
|
||||
}
|
||||
@@ -117,7 +119,8 @@
|
||||
color: $menuitemTextHoverColor;
|
||||
}
|
||||
|
||||
.p-menuitem-icon, .p-submenu-icon {
|
||||
.p-menuitem-icon,
|
||||
.p-submenu-icon {
|
||||
color: $menuitemIconHoverColor;
|
||||
}
|
||||
}
|
||||
@@ -135,7 +138,8 @@
|
||||
color: $menuitemTextHoverColor;
|
||||
}
|
||||
|
||||
.p-menuitem-icon, .p-submenu-icon {
|
||||
.p-menuitem-icon,
|
||||
.p-submenu-icon {
|
||||
color: $menuitemIconHoverColor;
|
||||
}
|
||||
}
|
||||
@@ -181,7 +185,8 @@
|
||||
color: $horizontalMenuRootMenuitemTextHoverColor;
|
||||
}
|
||||
|
||||
.p-menuitem-icon, .p-submenu-icon {
|
||||
.p-menuitem-icon,
|
||||
.p-submenu-icon {
|
||||
color: $horizontalMenuRootMenuitemIconHoverColor;
|
||||
}
|
||||
}
|
||||
@@ -192,16 +197,16 @@
|
||||
|
||||
@mixin placeholder {
|
||||
::-webkit-input-placeholder {
|
||||
@content
|
||||
@content;
|
||||
}
|
||||
:-moz-placeholder {
|
||||
@content
|
||||
@content;
|
||||
}
|
||||
::-moz-placeholder {
|
||||
@content
|
||||
@content;
|
||||
}
|
||||
:-ms-input-placeholder {
|
||||
@content
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +225,6 @@
|
||||
.p-menuitem-link {
|
||||
padding-left: $val * ($index + 1);
|
||||
}
|
||||
|
||||
}
|
||||
@if $index < $length {
|
||||
@include nested-submenu-indents($val, $index + 2, $length);
|
||||
|
@@ -44,7 +44,8 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.p-button-group .p-button:not(:last-child), .p-button-group .p-button:not(:last-child):hover {
|
||||
.p-button-group .p-button:not(:last-child),
|
||||
.p-button-group .p-button:not(:last-child):hover {
|
||||
border-right: 0 none;
|
||||
}
|
||||
|
||||
@@ -258,7 +259,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.p-button.p-button-secondary, .p-button-group.p-button-secondary > .p-button, .p-splitbutton.p-button-secondary > .p-button {
|
||||
.p-button.p-button-secondary,
|
||||
.p-button-group.p-button-secondary > .p-button,
|
||||
.p-splitbutton.p-button-secondary > .p-button {
|
||||
color: $secondaryButtonTextColor;
|
||||
background: $secondaryButtonBg;
|
||||
border: $secondaryButtonBorder;
|
||||
@@ -316,7 +319,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.p-button.p-button-info, .p-button-group.p-button-info > .p-button, .p-splitbutton.p-button-info > .p-button {
|
||||
.p-button.p-button-info,
|
||||
.p-button-group.p-button-info > .p-button,
|
||||
.p-splitbutton.p-button-info > .p-button {
|
||||
color: $infoButtonTextColor;
|
||||
background: $infoButtonBg;
|
||||
border: $infoButtonBorder;
|
||||
@@ -374,7 +379,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.p-button.p-button-success, .p-button-group.p-button-success > .p-button, .p-splitbutton.p-button-success > .p-button {
|
||||
.p-button.p-button-success,
|
||||
.p-button-group.p-button-success > .p-button,
|
||||
.p-splitbutton.p-button-success > .p-button {
|
||||
color: $successButtonTextColor;
|
||||
background: $successButtonBg;
|
||||
border: $successButtonBorder;
|
||||
@@ -432,7 +439,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.p-button.p-button-warning, .p-button-group.p-button-warning > .p-button, .p-splitbutton.p-button-warning > .p-button {
|
||||
.p-button.p-button-warning,
|
||||
.p-button-group.p-button-warning > .p-button,
|
||||
.p-splitbutton.p-button-warning > .p-button {
|
||||
color: $warningButtonTextColor;
|
||||
background: $warningButtonBg;
|
||||
border: $warningButtonBorder;
|
||||
@@ -490,7 +499,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.p-button.p-button-help, .p-button-group.p-button-help > .p-button, .p-splitbutton.p-button-help > .p-button {
|
||||
.p-button.p-button-help,
|
||||
.p-button-group.p-button-help > .p-button,
|
||||
.p-splitbutton.p-button-help > .p-button {
|
||||
color: $helpButtonTextColor;
|
||||
background: $helpButtonBg;
|
||||
border: $helpButtonBorder;
|
||||
@@ -548,7 +559,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.p-button.p-button-danger, .p-button-group.p-button-danger > .p-button, .p-splitbutton.p-button-danger > .p-button {
|
||||
.p-button.p-button-danger,
|
||||
.p-button-group.p-button-danger > .p-button,
|
||||
.p-splitbutton.p-button-danger > .p-button {
|
||||
color: $dangerButtonTextColor;
|
||||
background: $dangerButtonBg;
|
||||
border: $dangerButtonBorder;
|
||||
@@ -607,7 +620,9 @@
|
||||
}
|
||||
|
||||
@if variable-exists(contrastButtonTextColor) {
|
||||
.p-button.p-button-contrast, .p-button-group.p-button-contrast > .p-button, .p-splitbutton.p-button-contrast > .p-button {
|
||||
.p-button.p-button-contrast,
|
||||
.p-button-group.p-button-contrast > .p-button,
|
||||
.p-splitbutton.p-button-contrast > .p-button {
|
||||
color: $contrastButtonTextColor;
|
||||
background: $contrastButtonBg;
|
||||
border: $contrastButtonBorder;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@use 'sass:math';
|
||||
@use "sass:math";
|
||||
|
||||
// core
|
||||
.p-speeddial {
|
||||
@@ -25,7 +25,9 @@
|
||||
.p-speeddial-item {
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, opacity 0.8s;
|
||||
transition:
|
||||
transform 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,
|
||||
opacity 0.8s;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,8 @@
|
||||
.p-splitbutton .p-splitbutton-defaultbutton,
|
||||
.p-splitbutton.p-button-rounded > .p-splitbutton-defaultbutton.p-button,
|
||||
.p-splitbutton.p-button-outlined > .p-splitbutton-defaultbutton.p-button,
|
||||
.p-splitbutton.p-button-outlined > .p-splitbutton-defaultbutton.p-button-outlined.p-button:hover {
|
||||
.p-splitbutton.p-button-outlined
|
||||
> .p-splitbutton-defaultbutton.p-button-outlined.p-button:hover {
|
||||
flex: 1 1 auto;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
|
@@ -84,12 +84,19 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.p-datatable-resizable-table > .p-datatable-thead > tr > th.p-resizable-column:not(.p-frozen-column) {
|
||||
.p-datatable-resizable-table
|
||||
> .p-datatable-thead
|
||||
> tr
|
||||
> th.p-resizable-column:not(.p-frozen-column) {
|
||||
background-clip: padding-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.p-datatable-resizable-table-fit > .p-datatable-thead > tr > th.p-resizable-column:last-child .p-column-resizer {
|
||||
.p-datatable-resizable-table-fit
|
||||
> .p-datatable-thead
|
||||
> tr
|
||||
> th.p-resizable-column:last-child
|
||||
.p-column-resizer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -399,7 +406,10 @@
|
||||
}
|
||||
|
||||
&.p-datatable-scrollable > .p-datatable-wrapper > .p-datatable-table,
|
||||
&.p-datatable-scrollable > .p-datatable-wrapper > .p-virtualscroller > .p-datatable-table {
|
||||
&.p-datatable-scrollable
|
||||
> .p-datatable-wrapper
|
||||
> .p-virtualscroller
|
||||
> .p-datatable-table {
|
||||
> .p-datatable-thead,
|
||||
> .p-datatable-tfoot {
|
||||
background-color: $tableHeaderCellBg;
|
||||
|
@@ -36,7 +36,6 @@
|
||||
&:focus-visible {
|
||||
@include focused();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.p-column-filter-clear-button {
|
||||
|
@@ -80,7 +80,9 @@
|
||||
border: $inputListItemBorder;
|
||||
color: $inputListItemTextColor;
|
||||
background: $inputListItemBg;
|
||||
transition: transform $transitionDuration, $listItemTransition;
|
||||
transition:
|
||||
transform $transitionDuration,
|
||||
$listItemTransition;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
|
@@ -76,7 +76,9 @@
|
||||
border: $inputListItemBorder;
|
||||
color: $inputListItemTextColor;
|
||||
background: $inputListItemBg;
|
||||
transition: transform $transitionDuration, $listItemTransition;
|
||||
transition:
|
||||
transform $transitionDuration,
|
||||
$listItemTransition;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
|
@@ -29,19 +29,27 @@
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.p-timeline-vertical.p-timeline-alternate .p-timeline-event:nth-child(odd) .p-timeline-event-opposite {
|
||||
.p-timeline-vertical.p-timeline-alternate
|
||||
.p-timeline-event:nth-child(odd)
|
||||
.p-timeline-event-opposite {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.p-timeline-vertical.p-timeline-alternate .p-timeline-event:nth-child(odd) .p-timeline-event-content {
|
||||
.p-timeline-vertical.p-timeline-alternate
|
||||
.p-timeline-event:nth-child(odd)
|
||||
.p-timeline-event-content {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.p-timeline-vertical.p-timeline-alternate .p-timeline-event:nth-child(even) .p-timeline-event-opposite {
|
||||
.p-timeline-vertical.p-timeline-alternate
|
||||
.p-timeline-event:nth-child(even)
|
||||
.p-timeline-event-opposite {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.p-timeline-vertical.p-timeline-alternate .p-timeline-event:nth-child(even) .p-timeline-event-content {
|
||||
.p-timeline-vertical.p-timeline-alternate
|
||||
.p-timeline-event:nth-child(even)
|
||||
.p-timeline-event-content {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@@ -146,6 +154,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -150,7 +150,14 @@
|
||||
.p-treetable-scrollable-both .p-treetable-thead > tr > th,
|
||||
.p-treetable-scrollable-both .p-treetable-tbody > tr > td,
|
||||
.p-treetable-scrollable-both .p-treetable-tfoot > tr > td,
|
||||
.p-treetable-scrollable-horizontal .p-treetable-thead > tr > th .p-treetable-scrollable-horizontal .p-treetable-tbody > tr > td,
|
||||
.p-treetable-scrollable-horizontal
|
||||
.p-treetable-thead
|
||||
> tr
|
||||
> th
|
||||
.p-treetable-scrollable-horizontal
|
||||
.p-treetable-tbody
|
||||
> tr
|
||||
> td,
|
||||
.p-treetable-scrollable-horizontal .p-treetable-tfoot > tr > td {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
@@ -299,7 +306,6 @@
|
||||
&:hover {
|
||||
color: $highlightTextColor;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,8 +20,8 @@
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.p-fileupload > input[type='file'],
|
||||
.p-fileupload-basic input[type='file'] {
|
||||
.p-fileupload > input[type="file"],
|
||||
.p-fileupload-basic input[type="file"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
}
|
||||
|
||||
.p-fileupload-row {
|
||||
>div {
|
||||
> div {
|
||||
padding: $tableBodyCellPadding;
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,20 @@
|
||||
// core
|
||||
.p-colorpicker-panel .p-colorpicker-color {
|
||||
background: linear-gradient(to top, #000 0%, rgb(0 0 0 / 0) 100%), linear-gradient(to right, #fff 0%, rgb(255 255 255 / 0) 100%)
|
||||
background: linear-gradient(to top, #000 0%, rgb(0 0 0 / 0) 100%),
|
||||
linear-gradient(to right, #fff 0%, rgb(255 255 255 / 0) 100%);
|
||||
}
|
||||
|
||||
.p-colorpicker-panel .p-colorpicker-hue {
|
||||
background: linear-gradient(0deg, red 0, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, red)
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
red 0,
|
||||
#ff0 17%,
|
||||
#0f0 33%,
|
||||
#0ff 50%,
|
||||
#00f 67%,
|
||||
#f0f 83%,
|
||||
red
|
||||
);
|
||||
}
|
||||
|
||||
// theme
|
||||
|
@@ -48,8 +48,8 @@
|
||||
|
||||
.ql-picker-options {
|
||||
background: $inputOverlayBg;
|
||||
border:$inputOverlayBorder;
|
||||
box-shadow:$inputOverlayShadow;
|
||||
border: $inputOverlayBorder;
|
||||
box-shadow: $inputOverlayShadow;
|
||||
border-radius: $borderRadius;
|
||||
padding: $inputListPadding;
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
top: 50%;
|
||||
margin-top: -.5rem;
|
||||
margin-top: -0.5rem;
|
||||
transition-property: all;
|
||||
transition-timing-function: ease;
|
||||
line-height: 1;
|
||||
@@ -25,7 +25,7 @@
|
||||
.p-float-label:has(textarea.p-filled) label,
|
||||
.p-float-label:has(.p-inputwrapper-focus) label,
|
||||
.p-float-label:has(.p-inputwrapper-filled) label {
|
||||
top: -.75rem;
|
||||
top: -0.75rem;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
@@ -6,5 +6,5 @@
|
||||
.p-icon-field > .p-input-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -.5rem;
|
||||
margin-top: -0.5rem;
|
||||
}
|
@@ -11,7 +11,9 @@
|
||||
}
|
||||
|
||||
.p-inputnumber-buttons-stacked .p-button.p-inputnumber-button .p-button-label,
|
||||
.p-inputnumber-buttons-horizontal .p-button.p-inputnumber-button .p-button-label {
|
||||
.p-inputnumber-buttons-horizontal
|
||||
.p-button.p-inputnumber-button
|
||||
.p-button-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -39,7 +41,9 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.p-inputnumber-buttons-stacked .p-inputnumber-button-group .p-button.p-inputnumber-button {
|
||||
.p-inputnumber-buttons-stacked
|
||||
.p-inputnumber-button-group
|
||||
.p-button.p-inputnumber-button {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@use 'sass:math';
|
||||
@use "sass:math";
|
||||
|
||||
// core
|
||||
.p-inputswitch {
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
.p-inputswitch-slider:before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
content: "";
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
|
@@ -175,8 +175,7 @@
|
||||
&.p-multiselect {
|
||||
&.p-multiselect-chip {
|
||||
.p-multiselect-label {
|
||||
padding: math.div(nth($inputPadding, 1), 2)
|
||||
nth($inputPadding, 2);
|
||||
padding: math.div(nth($inputPadding, 1), 2) nth($inputPadding, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,4 +274,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,13 +19,13 @@
|
||||
.p-radiobutton-icon {
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
transform: translateZ(0) scale(.1);
|
||||
transform: translateZ(0) scale(0.1);
|
||||
border-radius: 50%;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.p-radiobutton.p-highlight .p-radiobutton-icon {
|
||||
transform: translateZ(0) scale(1.0, 1.0);
|
||||
transform: translateZ(0) scale(1, 1);
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@use 'sass:math';
|
||||
@use "sass:math";
|
||||
|
||||
// core
|
||||
.p-rating {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@use 'sass:math';
|
||||
@use "sass:math";
|
||||
|
||||
// core
|
||||
.p-slider {
|
||||
|
@@ -116,8 +116,7 @@
|
||||
&.p-treeselect {
|
||||
&.p-treeselect-chip {
|
||||
.p-treeselect-label {
|
||||
padding: math.div(nth($inputPadding, 1), 2)
|
||||
nth($inputPadding, 2);
|
||||
padding: math.div(nth($inputPadding, 1), 2) nth($inputPadding, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -82,12 +82,20 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.p-megamenu-vertical:not(.p-megamenu-mobile) .p-megamenu-root-list > .p-menuitem-active > .p-megamenu-panel {
|
||||
.p-megamenu-vertical:not(.p-megamenu-mobile)
|
||||
.p-megamenu-root-list
|
||||
> .p-menuitem-active
|
||||
> .p-megamenu-panel {
|
||||
left: 100%;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.p-megamenu-vertical .p-megamenu-root-list > .p-menuitem > .p-menuitem-content > .p-menuitem-link > .p-submenu-icon {
|
||||
.p-megamenu-vertical
|
||||
.p-megamenu-root-list
|
||||
> .p-menuitem
|
||||
> .p-menuitem-content
|
||||
> .p-menuitem-link
|
||||
> .p-submenu-icon {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@@ -266,7 +274,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.p-menuitem-active {
|
||||
> .p-menuitem-content {
|
||||
> .p-menuitem-link {
|
||||
|
@@ -54,7 +54,12 @@
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.p-menubar .p-submenu-list .p-menuitem .p-menuitem-content .p-menuitem-link .p-submenu-icon {
|
||||
.p-menubar
|
||||
.p-submenu-list
|
||||
.p-menuitem
|
||||
.p-menuitem-content
|
||||
.p-menuitem-link
|
||||
.p-submenu-icon {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@@ -187,7 +192,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.p-menuitem-active {
|
||||
> .p-menuitem-content {
|
||||
> .p-menuitem-link {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@use 'sass:math';
|
||||
@use "sass:math";
|
||||
|
||||
// core
|
||||
.p-steps {
|
||||
@@ -99,7 +99,7 @@
|
||||
}
|
||||
|
||||
&:before {
|
||||
content:' ';
|
||||
content: " ";
|
||||
border-top: $divider;
|
||||
width: 100%;
|
||||
top: 50%;
|
||||
|
@@ -41,7 +41,10 @@
|
||||
|
||||
.p-message-leave-active {
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s cubic-bezier(0, 1, 0, 1), opacity 0.3s, margin 0.15s;
|
||||
transition:
|
||||
max-height 0.3s cubic-bezier(0, 1, 0, 1),
|
||||
opacity 0.3s,
|
||||
margin 0.15s;
|
||||
}
|
||||
|
||||
.p-message-leave-active .p-message-close {
|
||||
|
@@ -63,13 +63,23 @@
|
||||
}
|
||||
|
||||
.p-toast-message-enter-active {
|
||||
-webkit-transition: transform 0.3s, opacity 0.3s;
|
||||
transition: transform 0.3s, opacity 0.3s;
|
||||
-webkit-transition:
|
||||
transform 0.3s,
|
||||
opacity 0.3s;
|
||||
transition:
|
||||
transform 0.3s,
|
||||
opacity 0.3s;
|
||||
}
|
||||
|
||||
.p-toast-message-leave-active {
|
||||
-webkit-transition: max-height 0.45s cubic-bezier(0, 1, 0, 1), opacity 0.3s, margin-bottom 0.3s;
|
||||
transition: max-height 0.45s cubic-bezier(0, 1, 0, 1), opacity 0.3s, margin-bottom 0.3s;
|
||||
-webkit-transition:
|
||||
max-height 0.45s cubic-bezier(0, 1, 0, 1),
|
||||
opacity 0.3s,
|
||||
margin-bottom 0.3s;
|
||||
transition:
|
||||
max-height 0.45s cubic-bezier(0, 1, 0, 1),
|
||||
opacity 0.3s,
|
||||
margin-bottom 0.3s;
|
||||
}
|
||||
|
||||
// theme
|
||||
|
@@ -3,7 +3,7 @@
|
||||
display: inline-block;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
padding: 0 .5rem;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.p-overlay-badge {
|
||||
@@ -14,15 +14,15 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform: translate(50%,-50%);
|
||||
transform: translate(50%, -50%);
|
||||
transform-origin: 100% 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.p-badge.p-badge-dot {
|
||||
width: .5rem;
|
||||
min-width: .5rem;
|
||||
height: .5rem;
|
||||
width: 0.5rem;
|
||||
min-width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@use 'sass:math';
|
||||
@use "sass:math";
|
||||
|
||||
// core
|
||||
.p-chip {
|
||||
|
@@ -35,4 +35,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -25,27 +25,31 @@
|
||||
}
|
||||
|
||||
.p-progressbar-indeterminate .p-progressbar-value::before {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: p-progressbar-indeterminate-anim 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
animation: p-progressbar-indeterminate-anim 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
-webkit-animation: p-progressbar-indeterminate-anim 2.1s
|
||||
cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
animation: p-progressbar-indeterminate-anim 2.1s
|
||||
cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
}
|
||||
|
||||
.p-progressbar-indeterminate .p-progressbar-value::after {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: p-progressbar-indeterminate-anim-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
animation: p-progressbar-indeterminate-anim-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
-webkit-animation: p-progressbar-indeterminate-anim-short 2.1s
|
||||
cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
animation: p-progressbar-indeterminate-anim-short 2.1s
|
||||
cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
-webkit-animation-delay: 1.15s;
|
||||
animation-delay: 1.15s;
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
.p-progress-spinner::before {
|
||||
content: '';
|
||||
content: "";
|
||||
display: block;
|
||||
padding-top: 100%;
|
||||
}
|
||||
@@ -34,7 +34,9 @@
|
||||
stroke-dasharray: 89, 200;
|
||||
stroke-dashoffset: 0;
|
||||
stroke: $progressSpinnerStrokeColor;
|
||||
animation: p-progress-spinner-dash 1.5s ease-in-out infinite, p-progress-spinner-color 6s ease-in-out infinite;
|
||||
animation:
|
||||
p-progress-spinner-dash 1.5s ease-in-out infinite,
|
||||
p-progress-spinner-color 6s ease-in-out infinite;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
}
|
||||
|
||||
.p-skeleton::after {
|
||||
content: '';
|
||||
content: "";
|
||||
animation: p-skeleton-animation 1.2s infinite;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
@@ -38,6 +38,11 @@
|
||||
border-radius: $borderRadius;
|
||||
|
||||
&:after {
|
||||
background: linear-gradient(90deg, rgba(255, 255, 255, 0), $skeletonAnimationBg, rgba(255, 255, 255, 0));
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0),
|
||||
$skeletonAnimationBg,
|
||||
rgba(255, 255, 255, 0)
|
||||
);
|
||||
}
|
||||
}
|
@@ -52,12 +52,16 @@
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.p-galleria-item-nav-onhover .p-galleria-item-wrapper:hover .p-galleria-item-nav {
|
||||
.p-galleria-item-nav-onhover
|
||||
.p-galleria-item-wrapper:hover
|
||||
.p-galleria-item-nav {
|
||||
pointer-events: all;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.p-galleria-item-nav-onhover .p-galleria-item-wrapper:hover .p-galleria-item-nav.p-disabled {
|
||||
.p-galleria-item-nav-onhover
|
||||
.p-galleria-item-wrapper:hover
|
||||
.p-galleria-item-nav.p-disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -206,14 +210,16 @@
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.p-galleria-indicator-onitem.p-galleria-indicators-right .p-galleria-indicators {
|
||||
.p-galleria-indicator-onitem.p-galleria-indicators-right
|
||||
.p-galleria-indicators {
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.p-galleria-indicator-onitem.p-galleria-indicators-bottom .p-galleria-indicators {
|
||||
.p-galleria-indicator-onitem.p-galleria-indicators-bottom
|
||||
.p-galleria-indicators {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
|
@@ -22,7 +22,9 @@
|
||||
}
|
||||
|
||||
.p-confirm-popup-enter-active {
|
||||
transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), opacity 0.12s cubic-bezier(0, 0, 0.2, 1);
|
||||
transition:
|
||||
transform 0.12s cubic-bezier(0, 0, 0.2, 1),
|
||||
opacity 0.12s cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.p-confirm-popup-leave-active {
|
||||
@@ -33,7 +35,7 @@
|
||||
.p-confirm-popup:before {
|
||||
bottom: 100%;
|
||||
left: calc(var(--overlayArrowLeft, 0) + 1.25rem);
|
||||
content: ' ';
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
@@ -104,13 +106,15 @@
|
||||
&:before {
|
||||
border-style: solid;
|
||||
|
||||
@if (nth($overlayContentBorder, 2) == 'none') {
|
||||
@if (nth($overlayContentBorder, 2) == "none") {
|
||||
border-color: rgba($overlayContentBg, 0);
|
||||
border-bottom-color: scale-color($overlayContentBg, $lightness: -5%);
|
||||
}
|
||||
@else {
|
||||
} @else {
|
||||
border-color: rgba(nth($overlayContentBorder, 3), 0);
|
||||
border-bottom-color: scale-color(nth($overlayContentBorder, 3), $lightness: -5%);
|
||||
border-bottom-color: scale-color(
|
||||
nth($overlayContentBorder, 3),
|
||||
$lightness: -5%
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,10 +124,9 @@
|
||||
}
|
||||
|
||||
&:before {
|
||||
@if (nth($overlayContentBorder, 2) == 'none') {
|
||||
@if (nth($overlayContentBorder, 2) == "none") {
|
||||
border-top-color: $overlayContentBg;
|
||||
}
|
||||
@else {
|
||||
} @else {
|
||||
border-top-color: nth($overlayContentBorder, 3);
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@use 'sass:math';
|
||||
@use "sass:math";
|
||||
|
||||
// core
|
||||
.p-overlaypanel {
|
||||
@@ -29,7 +29,9 @@
|
||||
}
|
||||
|
||||
.p-overlaypanel-enter-active {
|
||||
transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), opacity 0.12s cubic-bezier(0, 0, 0.2, 1);
|
||||
transition:
|
||||
transform 0.12s cubic-bezier(0, 0, 0.2, 1),
|
||||
opacity 0.12s cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.p-overlaypanel-leave-active {
|
||||
@@ -40,7 +42,7 @@
|
||||
.p-overlaypanel:before {
|
||||
bottom: 100%;
|
||||
left: calc(var(--overlayArrowLeft, 0) + 1.25rem);
|
||||
content: ' ';
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
@@ -109,13 +111,15 @@
|
||||
&:before {
|
||||
border-style: solid;
|
||||
|
||||
@if (nth($overlayContentBorder, 2) == 'none') {
|
||||
@if (nth($overlayContentBorder, 2) == "none") {
|
||||
border-color: rgba($overlayContentBg, 0);
|
||||
border-bottom-color: scale-color($overlayContentBg, $lightness: -5%);
|
||||
}
|
||||
@else {
|
||||
} @else {
|
||||
border-color: rgba(nth($overlayContentBorder, 3), 0);
|
||||
border-bottom-color: scale-color(nth($overlayContentBorder, 3), $lightness: -5%);
|
||||
border-bottom-color: scale-color(
|
||||
nth($overlayContentBorder, 3),
|
||||
$lightness: -5%
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,10 +129,9 @@
|
||||
}
|
||||
|
||||
&:before {
|
||||
@if (nth($overlayContentBorder, 2) == 'none') {
|
||||
@if (nth($overlayContentBorder, 2) == "none") {
|
||||
border-top-color: $overlayContentBg;
|
||||
}
|
||||
@else {
|
||||
} @else {
|
||||
border-top-color: nth($overlayContentBorder, 3);
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +1,19 @@
|
||||
// core
|
||||
.p-tooltip {
|
||||
position:absolute;
|
||||
display:none;
|
||||
padding: .25em .5rem;
|
||||
position: absolute;
|
||||
display: none;
|
||||
padding: 0.25em 0.5rem;
|
||||
max-width: 12.5rem;
|
||||
}
|
||||
|
||||
.p-tooltip.p-tooltip-right,
|
||||
.p-tooltip.p-tooltip-left {
|
||||
padding: 0 .25rem;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
.p-tooltip.p-tooltip-top,
|
||||
.p-tooltip.p-tooltip-bottom {
|
||||
padding:.25em 0;
|
||||
padding: 0.25em 0;
|
||||
}
|
||||
|
||||
.p-tooltip .p-tooltip-text {
|
||||
@@ -31,27 +31,27 @@
|
||||
}
|
||||
|
||||
.p-tooltip-right .p-tooltip-arrow {
|
||||
margin-top: -.25rem;
|
||||
border-width: .25em .25em .25em 0;
|
||||
margin-top: -0.25rem;
|
||||
border-width: 0.25em 0.25em 0.25em 0;
|
||||
}
|
||||
|
||||
.p-tooltip-left .p-tooltip-arrow {
|
||||
margin-top: -.25rem;
|
||||
border-width: .25em 0 .25em .25rem;
|
||||
margin-top: -0.25rem;
|
||||
border-width: 0.25em 0 0.25em 0.25rem;
|
||||
}
|
||||
|
||||
.p-tooltip.p-tooltip-top {
|
||||
padding: .25em 0;
|
||||
padding: 0.25em 0;
|
||||
}
|
||||
|
||||
.p-tooltip-top .p-tooltip-arrow {
|
||||
margin-left: -.25rem;
|
||||
border-width: .25em .25em 0;
|
||||
margin-left: -0.25rem;
|
||||
border-width: 0.25em 0.25em 0;
|
||||
}
|
||||
|
||||
.p-tooltip-bottom .p-tooltip-arrow {
|
||||
margin-left: -.25rem;
|
||||
border-width: 0 .25em .25rem;
|
||||
margin-left: -0.25rem;
|
||||
border-width: 0 0.25em 0.25rem;
|
||||
}
|
||||
|
||||
// theme
|
||||
|
@@ -12,7 +12,7 @@
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
content: '';
|
||||
content: "";
|
||||
}
|
||||
|
||||
.p-divider-content {
|
||||
@@ -33,7 +33,7 @@
|
||||
top: 0;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
content: '';
|
||||
content: "";
|
||||
}
|
||||
|
||||
.p-divider {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@use 'sass:math';
|
||||
@use "sass:math";
|
||||
|
||||
//core
|
||||
.p-stepper .p-stepper-nav {
|
||||
|
@@ -1,5 +1,8 @@
|
||||
@mixin focused-ring($ring-color) {
|
||||
box-shadow: 0 0 0 2px #1c2127, 0 0 0 4px $ring-color, 0 1px 2px 0 rgba(0, 0, 0, 0.0);
|
||||
box-shadow:
|
||||
0 0 0 2px #1c2127,
|
||||
0 0 0 4px $ring-color,
|
||||
0 1px 2px 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@layer primevue {
|
||||
@@ -9,13 +12,19 @@
|
||||
|
||||
.p-selectbutton > .p-button,
|
||||
.p-togglebutton.p-button {
|
||||
transition: background-color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
background-color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
|
||||
.p-accordion {
|
||||
.p-accordion-header {
|
||||
.p-accordion-header-link {
|
||||
transition: background-color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
background-color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +33,10 @@
|
||||
.p-tabview-nav {
|
||||
li {
|
||||
.p-tabview-nav-link {
|
||||
transition: background-color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
background-color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +46,10 @@
|
||||
.p-tabmenu-nav {
|
||||
.p-tabmenuitem {
|
||||
.p-menuitem-link {
|
||||
transition: background-color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
background-color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,31 +69,31 @@
|
||||
|
||||
.p-button {
|
||||
&:focus {
|
||||
@include focused-ring(rgba($buttonBg, .7));
|
||||
@include focused-ring(rgba($buttonBg, 0.7));
|
||||
}
|
||||
|
||||
&.p-button-secondary:enabled:focus {
|
||||
@include focused-ring(rgba($secondaryButtonBg, .7));
|
||||
@include focused-ring(rgba($secondaryButtonBg, 0.7));
|
||||
}
|
||||
|
||||
&.p-button-success:enabled:focus {
|
||||
@include focused-ring(rgba($successButtonBg, .7));
|
||||
@include focused-ring(rgba($successButtonBg, 0.7));
|
||||
}
|
||||
|
||||
&.p-button-info:enabled:focus {
|
||||
@include focused-ring(rgba($infoButtonBg, .7));
|
||||
@include focused-ring(rgba($infoButtonBg, 0.7));
|
||||
}
|
||||
|
||||
&.p-button-warning:enabled:focus {
|
||||
@include focused-ring(rgba($warningButtonBg, .7));
|
||||
@include focused-ring(rgba($warningButtonBg, 0.7));
|
||||
}
|
||||
|
||||
&.p-button-help:enabled:focus {
|
||||
@include focused-ring(rgba($helpButtonBg, .7));
|
||||
@include focused-ring(rgba($helpButtonBg, 0.7));
|
||||
}
|
||||
|
||||
&.p-button-danger:enabled:focus {
|
||||
@include focused-ring(rgba($dangerButtonBg, .7));
|
||||
@include focused-ring(rgba($dangerButtonBg, 0.7));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +113,7 @@
|
||||
|
||||
.p-speeddial-item {
|
||||
&.p-focus > .p-speeddial-action {
|
||||
@include focused-ring(rgba($buttonBg, .7));
|
||||
@include focused-ring(rgba($buttonBg, 0.7));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +124,7 @@
|
||||
.p-message {
|
||||
.p-message-close {
|
||||
&:hover {
|
||||
background: rgba(255,255,255,.1);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,7 +133,7 @@
|
||||
.p-toast-message {
|
||||
.p-toast-icon-close {
|
||||
&:hover {
|
||||
background: rgba(255,255,255,.1);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,7 +145,12 @@
|
||||
|
||||
.p-picklist-buttons .p-button,
|
||||
.p-orderlist-controls .p-button {
|
||||
transition: opacity $transitionDuration, background-color $transitionDuration, color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
opacity $transitionDuration,
|
||||
background-color $transitionDuration,
|
||||
color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
|
||||
.p-steps {
|
||||
|
@@ -41,7 +41,10 @@ $colors: (
|
||||
$shade000: rgba(255, 255, 255, 0.87) !default; //text color
|
||||
$shade100: rgba(255, 255, 255, 0.6) !default; //text secondary color
|
||||
$shade500: #6b7280 !default;
|
||||
$shade600: map-get($colors, "htwk-grau-140") !default; //input bg, border, divider
|
||||
$shade600: map-get(
|
||||
$colors,
|
||||
"htwk-grau-140"
|
||||
) !default; //input bg, border, divider
|
||||
$shade700: map-get($colors, "htwk-grau") !default; //menu bg
|
||||
$shade800: map-get($colors, "htwk-grau") !default; //elevated surface
|
||||
$shade900: rgba(map-get($colors, "htwk-schwarz"), 1) !default; //ground surface
|
||||
@@ -49,15 +52,33 @@ $shade900: rgba(map-get($colors, "htwk-schwarz"), 1) !default; //ground surface
|
||||
$hoverBg: rgba(255, 255, 255, 0.03) !default;
|
||||
|
||||
//global
|
||||
$fontFamily: "Source Sans Pro", -apple-system, BlinkMacSystemFont, Segoe UI, Twemoji Country Flags, Roboto, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol !default;
|
||||
$fontFamily:
|
||||
"Source Sans Pro",
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
Segoe UI,
|
||||
Twemoji Country Flags,
|
||||
Roboto,
|
||||
Arial,
|
||||
sans-serif,
|
||||
Apple Color Emoji,
|
||||
Segoe UI Emoji,
|
||||
Segoe UI Symbol !default;
|
||||
$fontSize: 1rem !default;
|
||||
$fontWeight: normal !default;
|
||||
$textColor: $shade000 !default;
|
||||
$textSecondaryColor: $shade100 !default;
|
||||
$borderRadius: 6px !default;
|
||||
$transitionDuration: 0.2s !default;
|
||||
$formElementTransition: background-color $transitionDuration, color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration !default;
|
||||
$actionIconTransition: background-color $transitionDuration, color $transitionDuration, box-shadow $transitionDuration !default;
|
||||
$formElementTransition:
|
||||
background-color $transitionDuration,
|
||||
color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration !default;
|
||||
$actionIconTransition:
|
||||
background-color $transitionDuration,
|
||||
color $transitionDuration,
|
||||
box-shadow $transitionDuration !default;
|
||||
$listItemTransition: box-shadow $transitionDuration !default;
|
||||
$primeIconFontSize: 1rem !default;
|
||||
$divider: 1px solid $shade600 !default;
|
||||
@@ -135,8 +156,10 @@ $inputListHeaderBorder: 1px solid $shade600 !default;
|
||||
$inputOverlayBg: $inputListBg !default;
|
||||
$inputOverlayHeaderBg: $inputListHeaderBg !default;
|
||||
$inputOverlayBorder: 1px solid $shade600 !default;
|
||||
$inputOverlayShadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2),
|
||||
0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12) !default;
|
||||
$inputOverlayShadow:
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.2),
|
||||
0 4px 5px 0 rgba(0, 0, 0, 0.14),
|
||||
0 1px 10px 0 rgba(0, 0, 0, 0.12) !default;
|
||||
|
||||
//password
|
||||
$passwordMeterBg: $shade600 !default;
|
||||
@@ -157,8 +180,10 @@ $buttonHoverBorderColor: $primaryLightColor !default;
|
||||
$buttonActiveBg: $primaryLighterColor !default;
|
||||
$buttonTextActiveColor: $primaryTextColor !default;
|
||||
$buttonActiveBorderColor: $primaryLighterColor !default;
|
||||
$raisedButtonShadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2),
|
||||
0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12) !default;
|
||||
$raisedButtonShadow:
|
||||
0px 3px 1px -2px rgba(0, 0, 0, 0.2),
|
||||
0px 2px 2px 0px rgba(0, 0, 0, 0.14),
|
||||
0px 1px 5px 0px rgba(0, 0, 0, 0.12) !default;
|
||||
$roundedButtonBorderRadius: 2rem !default;
|
||||
|
||||
$textButtonHoverBgOpacity: 0.04 !default;
|
||||
@@ -189,7 +214,8 @@ $infoButtonHoverBorderColor: map-get($colors, "htwk-cyan") !default;
|
||||
$infoButtonActiveBg: map-get($colors, "htwk-cyan") !default;
|
||||
$infoButtonTextActiveColor: $infoButtonTextColor !default;
|
||||
$infoButtonActiveBorderColor: map-get($colors, "htwk-cyan") !default;
|
||||
$infoButtonFocusShadow: 0 0 0 1px scale-color($infoButtonHoverBg, $lightness: 30%) !default;
|
||||
$infoButtonFocusShadow: 0 0 0 1px
|
||||
scale-color($infoButtonHoverBg, $lightness: 30%) !default;
|
||||
|
||||
$successButtonBg: map-get($colors, "htwk-gruen") !default;
|
||||
$successButtonTextColor: #052e16 !default;
|
||||
@@ -208,10 +234,16 @@ $warningButtonTextColor: #493c08 !default;
|
||||
$warningButtonBorder: 1px solid map-get($colors, "htwk-yellow") !default;
|
||||
$warningButtonHoverBg: scale-color($warningButtonBg, $lightness: 30%) !default;
|
||||
$warningButtonTextHoverColor: $warningButtonTextColor !default;
|
||||
$warningButtonHoverBorderColor: scale-color($warningButtonBg, $lightness: 10%) !default;
|
||||
$warningButtonHoverBorderColor: scale-color(
|
||||
$warningButtonBg,
|
||||
$lightness: 10%
|
||||
) !default;
|
||||
$warningButtonActiveBg: scale-color($warningButtonBg, $lightness: 30%) !default;
|
||||
$warningButtonTextActiveColor: $warningButtonTextColor !default;
|
||||
$warningButtonActiveBorderColor: scale-color($warningButtonBg, $lightness: 30%) !default;
|
||||
$warningButtonActiveBorderColor: scale-color(
|
||||
$warningButtonBg,
|
||||
$lightness: 30%
|
||||
) !default;
|
||||
$warningButtonFocusShadow: 0 0 0 1px
|
||||
scale-color($warningButtonBg, $lightness: 30%) !default;
|
||||
|
||||
@@ -478,7 +510,9 @@ $cardSubTitleFontWeight: 100 !default;
|
||||
$cardSubTitleColor: $shade100 !default;
|
||||
$cardContentPadding: 1.25rem 0 !default;
|
||||
$cardFooterPadding: 1.25rem 0 0 0 !default;
|
||||
$cardShadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14),
|
||||
$cardShadow:
|
||||
0 2px 1px -1px rgba(0, 0, 0, 0.2),
|
||||
0 1px 1px 0 rgba(0, 0, 0, 0.14),
|
||||
0 1px 3px 0 rgba(0, 0, 0, 0.12) !default;
|
||||
|
||||
//editor
|
||||
@@ -644,8 +678,10 @@ $contrastMessageIconColor: $contrastButtonTextColor !default;
|
||||
//overlays
|
||||
$overlayContentBorder: 1px solid $shade600 !default;
|
||||
$overlayContentBg: $panelContentBg !default;
|
||||
$overlayContainerShadow: 0px 11px 15px -7px rgba(0, 0, 0, 0.2),
|
||||
0px 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 9px 46px 8px rgba(0, 0, 0, 0.12) !default;
|
||||
$overlayContainerShadow:
|
||||
0px 11px 15px -7px rgba(0, 0, 0, 0.2),
|
||||
0px 24px 38px 3px rgba(0, 0, 0, 0.14),
|
||||
0px 9px 46px 8px rgba(0, 0, 0, 0.12) !default;
|
||||
|
||||
//dialog
|
||||
$dialogHeaderBg: $shade800 !default;
|
||||
@@ -719,8 +755,10 @@ $submenuHeaderBorderRadius: 0 !default;
|
||||
$submenuHeaderFontWeight: 0 !default;
|
||||
$overlayMenuBg: $menuBg !default;
|
||||
$overlayMenuBorder: 1px solid $shade600 !default;
|
||||
$overlayMenuShadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2),
|
||||
0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12) !default;
|
||||
$overlayMenuShadow:
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.2),
|
||||
0 4px 5px 0 rgba(0, 0, 0, 0.14),
|
||||
0 1px 10px 0 rgba(0, 0, 0, 0.12) !default;
|
||||
$verticalMenuPadding: 0.25rem 0 !default;
|
||||
$menuSeparatorMargin: 0.25rem 0 !default;
|
||||
|
||||
@@ -887,10 +925,23 @@ $imagePreviewActionIconFontSize: 1.5rem !default;
|
||||
$imagePreviewActionIconBorderRadius: 50% !default;
|
||||
|
||||
:root {
|
||||
font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, Segoe UI, Twemoji Country Flags, Roboto, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
|
||||
font-family:
|
||||
"Source Sans Pro",
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
Segoe UI,
|
||||
Twemoji Country Flags,
|
||||
Roboto,
|
||||
Arial,
|
||||
sans-serif,
|
||||
Apple Color Emoji,
|
||||
Segoe UI Emoji,
|
||||
Segoe UI Symbol;
|
||||
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
|
||||
font-variation-settings: normal;
|
||||
--font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, Segoe UI, Twemoji Country Flags, Roboto, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
|
||||
--font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, Segoe UI,
|
||||
Twemoji Country Flags, Roboto, Arial, sans-serif, Apple Color Emoji,
|
||||
Segoe UI Emoji, Segoe UI Symbol;
|
||||
--font-feature-settings: "cv02", "cv03", "cv04", "cv11";
|
||||
--surface-a: #{$shade800};
|
||||
--surface-b: #{$shade900};
|
||||
|
@@ -5,16 +5,21 @@ $primaryLightestColor: rgba(255, 237, 0, 0.1) !default;
|
||||
$primaryTextColor: #030712 !default;
|
||||
|
||||
$highlightBg: rgba($primaryColor, 0.16) !default;
|
||||
$highlightTextColor: rgba(255,255,255,0.87) !default;
|
||||
$highlightTextColor: rgba(255, 255, 255, 0.87) !default;
|
||||
$highlightFocusBg: rgba($primaryColor, 0.24) !default;
|
||||
|
||||
@import '../_variables';
|
||||
@import './_fonts';
|
||||
@import '../../../../theme-base/_components';
|
||||
@import '../_extensions';
|
||||
@import "../_variables";
|
||||
@import "./_fonts";
|
||||
@import "../../../../theme-base/_components";
|
||||
@import "../_extensions";
|
||||
|
||||
:root {
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
@@ -150,9 +155,15 @@ $highlightFocusBg: rgba($primaryColor, 0.24) !default;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
}
|
||||
|
||||
.fc.fc-unthemed .fc-toolbar .fc-button.fc-dayGridMonth-button.fc-button-active,
|
||||
.fc.fc-unthemed .fc-toolbar .fc-button.fc-timeGridWeek-button.fc-button-active,
|
||||
.fc.fc-unthemed .fc-toolbar .fc-button.fc-timeGridDay-button.fc-button-active {
|
||||
.fc.fc-unthemed
|
||||
.fc-toolbar
|
||||
.fc-button.fc-dayGridMonth-button.fc-button-active,
|
||||
.fc.fc-unthemed
|
||||
.fc-toolbar
|
||||
.fc-button.fc-timeGridWeek-button.fc-button-active,
|
||||
.fc.fc-unthemed
|
||||
.fc-toolbar
|
||||
.fc-button.fc-timeGridDay-button.fc-button-active {
|
||||
background: map-get($colors, "htwk-yellow"); /*#93c5fd*/
|
||||
border-color: map-get($colors, "htwk-yellow"); /*#93c5fd*/
|
||||
color: map-get($colors, "htwk-schwarz"); /*#1c2127*/
|
||||
@@ -460,6 +471,9 @@ $highlightFocusBg: rgba($primaryColor, 0.24) !default;
|
||||
|
||||
.fc.fc-theme-standard .fc-highlight {
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background: rgba(map-get($colors, "htwk-yellow"), 0.16); /*rgba(147, 197, 253, 0.16)*/
|
||||
background: rgba(
|
||||
map-get($colors, "htwk-yellow"),
|
||||
0.16
|
||||
); /*rgba(147, 197, 253, 0.16)*/
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,8 @@
|
||||
@mixin focused-ring($ring-color) {
|
||||
box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px $ring-color, 0 1px 2px 0 rgba(0, 0, 0, 1.0);
|
||||
box-shadow:
|
||||
0 0 0 2px #ffffff,
|
||||
0 0 0 4px $ring-color,
|
||||
0 1px 2px 0 rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
@layer primevue {
|
||||
@@ -9,13 +12,19 @@
|
||||
|
||||
.p-selectbutton > .p-button,
|
||||
.p-togglebutton.p-button {
|
||||
transition: background-color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
background-color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
|
||||
.p-accordion {
|
||||
.p-accordion-header {
|
||||
.p-accordion-header-link {
|
||||
transition: background-color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
background-color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +33,10 @@
|
||||
.p-tabview-nav {
|
||||
li {
|
||||
.p-tabview-nav-link {
|
||||
transition: background-color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
background-color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +46,10 @@
|
||||
.p-tabmenu-nav {
|
||||
.p-tabmenuitem {
|
||||
.p-menuitem-link {
|
||||
transition: background-color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
background-color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +127,12 @@
|
||||
|
||||
.p-picklist-buttons .p-button,
|
||||
.p-orderlist-controls .p-button {
|
||||
transition: opacity $transitionDuration, background-color $transitionDuration, color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration;
|
||||
transition:
|
||||
opacity $transitionDuration,
|
||||
background-color $transitionDuration,
|
||||
color $transitionDuration,
|
||||
border-color $transitionDuration,
|
||||
box-shadow $transitionDuration;
|
||||
}
|
||||
|
||||
.p-steps {
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -4,17 +4,22 @@ $primaryDarkColor: #002d67 !default;
|
||||
$primaryDarkerColor: #022541 !default;
|
||||
$primaryTextColor: #ffffff !default;
|
||||
|
||||
$highlightBg: #EFF6FF !default;
|
||||
$highlightBg: #eff6ff !default;
|
||||
$highlightTextColor: $primaryDarkerColor !default;
|
||||
$highlightFocusBg: rgba($primaryColor, .24) !default;
|
||||
$highlightFocusBg: rgba($primaryColor, 0.24) !default;
|
||||
|
||||
@import '../_variables';
|
||||
@import './_fonts';
|
||||
@import '../../../../theme-base/_components';
|
||||
@import '../_extensions';
|
||||
@import "../_variables";
|
||||
@import "./_fonts";
|
||||
@import "../../../../theme-base/_components";
|
||||
@import "../_extensions";
|
||||
|
||||
:root {
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
@@ -139,9 +144,15 @@ $highlightFocusBg: rgba($primaryColor, .24) !default;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
}
|
||||
|
||||
.fc.fc-unthemed .fc-toolbar .fc-button.fc-dayGridMonth-button.fc-button-active,
|
||||
.fc.fc-unthemed .fc-toolbar .fc-button.fc-timeGridWeek-button.fc-button-active,
|
||||
.fc.fc-unthemed .fc-toolbar .fc-button.fc-timeGridDay-button.fc-button-active {
|
||||
.fc.fc-unthemed
|
||||
.fc-toolbar
|
||||
.fc-button.fc-dayGridMonth-button.fc-button-active,
|
||||
.fc.fc-unthemed
|
||||
.fc-toolbar
|
||||
.fc-button.fc-timeGridWeek-button.fc-button-active,
|
||||
.fc.fc-unthemed
|
||||
.fc-toolbar
|
||||
.fc-button.fc-timeGridDay-button.fc-button-active {
|
||||
background: map-get($colors, "primary"); /*#93c5fd*/
|
||||
border-color: map-get($colors, "primary"); /*#93c5fd*/
|
||||
color: $primaryTextColor; /*#1c2127*/
|
||||
@@ -449,6 +460,9 @@ $highlightFocusBg: rgba($primaryColor, .24) !default;
|
||||
|
||||
.fc.fc-theme-standard .fc-highlight {
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background: rgba(map-get($colors, "primary"), 0.16); /*rgba(147, 197, 253, 0.16)*/
|
||||
background: rgba(
|
||||
map-get($colors, "primary"),
|
||||
0.16
|
||||
); /*rgba(147, 197, 253, 0.16)*/
|
||||
}
|
||||
}
|
||||
|
@@ -1,22 +1,35 @@
|
||||
@use 'sass:color';
|
||||
@use "sass:color";
|
||||
|
||||
$primaryColor: #00944c !default;
|
||||
$primaryLightColor: color.scale($primaryColor, $lightness: 10%, $saturation: -10%) !default;
|
||||
$primaryLightColor: color.scale(
|
||||
$primaryColor,
|
||||
$lightness: 10%,
|
||||
$saturation: -10%
|
||||
) !default;
|
||||
$primaryDarkColor: color.scale($primaryColor, $lightness: -40%) !default;
|
||||
$primaryDarkerColor: color.scale($primaryColor, $lightness: -80%) !default;
|
||||
$primaryTextColor: #ffffff !default;
|
||||
|
||||
$highlightBg: color.scale($primaryColor, $lightness: 90%, $saturation: -80%) !default;
|
||||
$highlightBg: color.scale(
|
||||
$primaryColor,
|
||||
$lightness: 90%,
|
||||
$saturation: -80%
|
||||
) !default;
|
||||
$highlightTextColor: $primaryDarkerColor !default;
|
||||
$highlightFocusBg: rgba($primaryColor, .24) !default;
|
||||
$highlightFocusBg: rgba($primaryColor, 0.24) !default;
|
||||
|
||||
@import '../_variables';
|
||||
@import './_fonts';
|
||||
@import '../../../../theme-base/_components';
|
||||
@import '../_extensions';
|
||||
@import "../_variables";
|
||||
@import "./_fonts";
|
||||
@import "../../../../theme-base/_components";
|
||||
@import "../_extensions";
|
||||
|
||||
:root {
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
@@ -152,9 +165,15 @@ $highlightFocusBg: rgba($primaryColor, .24) !default;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
}
|
||||
|
||||
.fc.fc-unthemed .fc-toolbar .fc-button.fc-dayGridMonth-button.fc-button-active,
|
||||
.fc.fc-unthemed .fc-toolbar .fc-button.fc-timeGridWeek-button.fc-button-active,
|
||||
.fc.fc-unthemed .fc-toolbar .fc-button.fc-timeGridDay-button.fc-button-active {
|
||||
.fc.fc-unthemed
|
||||
.fc-toolbar
|
||||
.fc-button.fc-dayGridMonth-button.fc-button-active,
|
||||
.fc.fc-unthemed
|
||||
.fc-toolbar
|
||||
.fc-button.fc-timeGridWeek-button.fc-button-active,
|
||||
.fc.fc-unthemed
|
||||
.fc-toolbar
|
||||
.fc-button.fc-timeGridDay-button.fc-button-active {
|
||||
background: map-get($colors, "primary"); /*#93c5fd*/
|
||||
border-color: map-get($colors, "primary"); /*#93c5fd*/
|
||||
color: $primaryTextColor; /*#1c2127*/
|
||||
@@ -462,6 +481,9 @@ $highlightFocusBg: rgba($primaryColor, .24) !default;
|
||||
|
||||
.fc.fc-theme-standard .fc-highlight {
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background: rgba(map-get($colors, "primary"), 0.16); /*rgba(147, 197, 253, 0.16)*/
|
||||
background: rgba(
|
||||
map-get($colors, "primary"),
|
||||
0.16
|
||||
); /*rgba(147, 197, 253, 0.16)*/
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -22,12 +22,13 @@ export async function fetchRoomOccupancy(
|
||||
to_date: string,
|
||||
): Promise<RoomOccupancyList> {
|
||||
var roomOccupancyList: RoomOccupancyList = new RoomOccupancyList(
|
||||
new Date(), 0, 0, []
|
||||
new Date(),
|
||||
0,
|
||||
0,
|
||||
[],
|
||||
);
|
||||
|
||||
await fetch(
|
||||
"/api/schedule/rooms?from=" + from_date + "&to=" + to_date,
|
||||
)
|
||||
await fetch("/api/schedule/rooms?from=" + from_date + "&to=" + to_date)
|
||||
.then((response) => {
|
||||
return response.arrayBuffer();
|
||||
})
|
||||
|
@@ -104,7 +104,7 @@ const actions = computed(() => [
|
||||
label: t("calendarLink.toHTWKalendar"),
|
||||
icon: "pi pi-home",
|
||||
command: forwardToHTWKalendar,
|
||||
}
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
|
@@ -17,10 +17,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import FullCalendar from "@fullcalendar/vue3";
|
||||
import { computed, ComputedRef, inject, Ref, ref, watch } from "vue";
|
||||
import { CalendarOptions, DatesSetArg, EventClickArg } from "@fullcalendar/core";
|
||||
import {
|
||||
CalendarOptions,
|
||||
DatesSetArg,
|
||||
EventClickArg,
|
||||
} from "@fullcalendar/core";
|
||||
import allLocales from "@fullcalendar/core/locales-all";
|
||||
import dayGridPlugin from "@fullcalendar/daygrid";
|
||||
import interactionPlugin from "@fullcalendar/interaction";
|
||||
@@ -55,7 +58,6 @@ const toggle = (info: EventClickArg) => {
|
||||
op.value.hide();
|
||||
return;
|
||||
} else {
|
||||
|
||||
clickedEvent.value = {
|
||||
title: info.event._def.title,
|
||||
start: start,
|
||||
@@ -66,11 +68,8 @@ const toggle = (info: EventClickArg) => {
|
||||
};
|
||||
op.value.show(info.jsEvent);
|
||||
op.value.target = info.el;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const selectedToken = computed(() => props.token);
|
||||
|
||||
@@ -79,8 +78,7 @@ const date: Ref<Date> = ref(new Date());
|
||||
|
||||
const { data: calendar } = useQuery({
|
||||
queryKey: ["userCalendar", selectedToken],
|
||||
queryFn: () =>
|
||||
fetchICalendarEvents(selectedToken.value),
|
||||
queryFn: () => fetchICalendarEvents(selectedToken.value),
|
||||
select: (data) => {
|
||||
return data;
|
||||
},
|
||||
@@ -175,20 +173,22 @@ watch(mobilePage, () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<FullCalendar id="overlay-mount-point" ref="fullCalendar" :options="calendarOptions" >
|
||||
<FullCalendar
|
||||
id="overlay-mount-point"
|
||||
ref="fullCalendar"
|
||||
:options="calendarOptions"
|
||||
>
|
||||
</FullCalendar>
|
||||
|
||||
<OverlayPanel ref="op" >
|
||||
<OverlayPanel ref="op">
|
||||
<div>
|
||||
<h3>{{ clickedEvent.title }}</h3>
|
||||
<p>Location: {{ clickedEvent.location }}</p>
|
||||
<p>Start: {{ clickedEvent.start?.toLocaleString()}}</p>
|
||||
<p>Start: {{ clickedEvent.start?.toLocaleString() }}</p>
|
||||
<p>End: {{ clickedEvent.end?.toLocaleString() }}</p>
|
||||
<p>Notes: {{ clickedEvent.notes }}</p>
|
||||
</div>
|
||||
</OverlayPanel>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
@@ -63,7 +63,7 @@ onMounted(() => {
|
||||
class="p-button-rounded w-full md:w-auto"
|
||||
style="margin-right: 1rem"
|
||||
:severity="isDark ? 'warning' : 'success'"
|
||||
@click="toggleTheme();"
|
||||
@click="toggleTheme()"
|
||||
>
|
||||
<i v-if="isDark" class="pi pi-sun"></i>
|
||||
<i v-else class="pi pi-moon"></i>
|
||||
|
@@ -68,7 +68,14 @@ updateLocale(localeStore().locale);
|
||||
<template #value="slotProps">
|
||||
<div v-if="slotProps.value" class="flex align-items-center">
|
||||
<div class="mr-2 flag">{{ displayIcon(slotProps.value) }}</div>
|
||||
<div style="font-family: 'Twemoji Country Flags', 'Helvetica', 'Comic Sans', serif;">{{ displayCountry(slotProps.value) }}</div>
|
||||
<div
|
||||
style="
|
||||
font-family: "Twemoji Country Flags",
|
||||
"Helvetica", "Comic Sans", serif;
|
||||
"
|
||||
>
|
||||
{{ displayCountry(slotProps.value) }}
|
||||
</div>
|
||||
</div>
|
||||
<span v-else>
|
||||
{{ slotProps.placeholder }}
|
||||
|
@@ -67,7 +67,7 @@ const items = computed(() => [
|
||||
label: t("roomFinderPage.roomSchedule") + " (offline)",
|
||||
icon: "pi pi-fw pi-ban",
|
||||
route: "/rooms/occupancy/offline",
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -140,7 +140,9 @@ function handleDarkModeToggled(isDarkVar: boolean) {
|
||||
</template>
|
||||
<template #end>
|
||||
<div class="flex align-items-stretch justify-content-center">
|
||||
<DarkModeSwitcher @dark-mode-toggled="handleDarkModeToggled"></DarkModeSwitcher>
|
||||
<DarkModeSwitcher
|
||||
@dark-mode-toggled="handleDarkModeToggled"
|
||||
></DarkModeSwitcher>
|
||||
<LocaleSwitcher></LocaleSwitcher>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -181,9 +181,7 @@ const calendarOptions: ComputedRef<CalendarOptions> = computed(() => ({
|
||||
borderColor: event.showFree
|
||||
? "var(--htwk-gruen-600)"
|
||||
: "var(--htwk-grau-60-600)",
|
||||
textColor: event.showFree
|
||||
? "var(--green-50)"
|
||||
: "white",
|
||||
textColor: event.showFree ? "var(--green-50)" : "white",
|
||||
title: event.showFree
|
||||
? t("roomFinderPage.available")
|
||||
: t("roomFinderPage.occupied"),
|
||||
|
@@ -79,7 +79,11 @@ const selectedRoom = computed(() => props.room);
|
||||
*/
|
||||
function transformData(data: RoomOccupancyList) {
|
||||
const events = data
|
||||
.decodeOccupancy(selectedRoom.value, new Date(currentDateFrom.value), new Date(currentDateTo.value))
|
||||
.decodeOccupancy(
|
||||
selectedRoom.value,
|
||||
new Date(currentDateFrom.value),
|
||||
new Date(currentDateTo.value),
|
||||
)
|
||||
.map((event, index) => ({
|
||||
id: index,
|
||||
event: event,
|
||||
@@ -92,7 +96,7 @@ const { data: occupations } = useQuery({
|
||||
queryFn: () =>
|
||||
fetchRoomOccupancy(
|
||||
new Date(currentDateFrom.value).toISOString(),
|
||||
new Date(currentDateTo.value).toISOString()
|
||||
new Date(currentDateTo.value).toISOString(),
|
||||
),
|
||||
select: (data) => transformData(data),
|
||||
enabled: () => selectedRoom.value !== "" && currentDateFrom.value !== "",
|
||||
@@ -188,9 +192,7 @@ const calendarOptions: ComputedRef<CalendarOptions> = computed(() => ({
|
||||
color: event.event.free
|
||||
? "var(--htwk-gruen-500)"
|
||||
: "var(--htwk-grau-60-500)",
|
||||
textColor: event.event.free
|
||||
? "var(--green-50)"
|
||||
: "white",
|
||||
textColor: event.event.free ? "var(--green-50)" : "white",
|
||||
title: event.event.stub
|
||||
? t("roomFinderPage.stub")
|
||||
: event.event.free
|
||||
|
@@ -23,7 +23,6 @@ export function formatYearMonthDay(date: Date): string {
|
||||
return date.toISOString().split("T")[0].replace(/-/g, "");
|
||||
}
|
||||
|
||||
|
||||
export function removeTZ(date: Date): Date {
|
||||
return new Date(date.getTime() + date.getTimezoneOffset() * 60000)
|
||||
return new Date(date.getTime() + date.getTimezoneOffset() * 60000);
|
||||
}
|
@@ -18,12 +18,9 @@ import { expect, test } from "vitest";
|
||||
import { exportedForTesting } from "@/helpers/ical.ts";
|
||||
import { CalendarComponent } from "ical";
|
||||
|
||||
|
||||
// colorizeEvents has only the function to colorize the events that are passed to it
|
||||
test("colorizeEventsSameSummary", () => {
|
||||
|
||||
const events: CalendarComponent[] =
|
||||
[
|
||||
const events: CalendarComponent[] = [
|
||||
{
|
||||
type: "VEVENT",
|
||||
summary: "Operations Research",
|
||||
@@ -34,17 +31,14 @@ test("colorizeEventsSameSummary", () => {
|
||||
},
|
||||
];
|
||||
|
||||
expect(exportedForTesting.colorizeEvents(
|
||||
events
|
||||
)
|
||||
).toEqual([{ summary: "Operations Research", color: "var(--htwk-rot-200)" },{ summary: "Operations Research", color: "var(--htwk-rot-200)" }]);
|
||||
}
|
||||
);
|
||||
expect(exportedForTesting.colorizeEvents(events)).toEqual([
|
||||
{ summary: "Operations Research", color: "var(--htwk-rot-200)" },
|
||||
{ summary: "Operations Research", color: "var(--htwk-rot-200)" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("colorizeEventsDifferentSummary", () => {
|
||||
|
||||
const events: CalendarComponent[] =
|
||||
[
|
||||
const events: CalendarComponent[] = [
|
||||
{
|
||||
type: "VEVENT",
|
||||
summary: "Algorithmische Mathematik",
|
||||
@@ -55,17 +49,14 @@ test("colorizeEventsDifferentSummary", () => {
|
||||
},
|
||||
];
|
||||
|
||||
expect(exportedForTesting.colorizeEvents(
|
||||
events
|
||||
)
|
||||
).toEqual([{ summary: "Algorithmische Mathematik", color: "var(--htwk-rot-200)" },{ summary: "Funktionale Programmierung", color: "var(--htwk-gruen-300)" }]);
|
||||
}
|
||||
);
|
||||
|
||||
expect(exportedForTesting.colorizeEvents(events)).toEqual([
|
||||
{ summary: "Algorithmische Mathematik", color: "var(--htwk-rot-200)" },
|
||||
{ summary: "Funktionale Programmierung", color: "var(--htwk-gruen-300)" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("filterEventsDistinct", () => {
|
||||
const events: CalendarComponent[] =
|
||||
[
|
||||
const events: CalendarComponent[] = [
|
||||
{
|
||||
type: "VEVENT",
|
||||
summary: "Operations Research",
|
||||
@@ -76,15 +67,13 @@ test("filterEventsDistinct", () => {
|
||||
},
|
||||
];
|
||||
|
||||
expect(exportedForTesting.filterEventsDistinct(
|
||||
events
|
||||
)
|
||||
).toEqual([{ type: "VEVENT", summary: "Operations Research" }]);
|
||||
expect(exportedForTesting.filterEventsDistinct(events)).toEqual([
|
||||
{ type: "VEVENT", summary: "Operations Research" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("filterEventsDistinctDifferentSummary", () => {
|
||||
const events: CalendarComponent[] =
|
||||
[
|
||||
const events: CalendarComponent[] = [
|
||||
{
|
||||
type: "VEVENT",
|
||||
summary: "Algorithmische Mathematik",
|
||||
@@ -95,16 +84,11 @@ test("filterEventsDistinctDifferentSummary", () => {
|
||||
},
|
||||
];
|
||||
|
||||
expect(exportedForTesting.filterEventsDistinct(
|
||||
events
|
||||
)
|
||||
).toEqual(events);
|
||||
expect(exportedForTesting.filterEventsDistinct(events)).toEqual(events);
|
||||
});
|
||||
|
||||
|
||||
test("extractedColorizedEvents", () => {
|
||||
const events: CalendarComponent[] =
|
||||
[
|
||||
const events: CalendarComponent[] = [
|
||||
{
|
||||
type: "VEVENT",
|
||||
summary: "Operations Research",
|
||||
@@ -115,15 +99,13 @@ test("extractedColorizedEvents", () => {
|
||||
},
|
||||
];
|
||||
|
||||
expect(exportedForTesting.extractedColorizedEvents(
|
||||
events
|
||||
)
|
||||
).toEqual([{ summary: "Operations Research", color: "var(--htwk-rot-200)" }]);
|
||||
expect(exportedForTesting.extractedColorizedEvents(events)).toEqual([
|
||||
{ summary: "Operations Research", color: "var(--htwk-rot-200)" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("extractedColorizedEventsDifferentSummary", () => {
|
||||
const events: CalendarComponent[] =
|
||||
[
|
||||
const events: CalendarComponent[] = [
|
||||
{
|
||||
type: "VEVENT",
|
||||
summary: "Algorithmische Mathematik",
|
||||
@@ -134,8 +116,8 @@ test("extractedColorizedEventsDifferentSummary", () => {
|
||||
},
|
||||
];
|
||||
|
||||
expect(exportedForTesting.extractedColorizedEvents(
|
||||
events
|
||||
)
|
||||
).toEqual([{ summary: "Algorithmische Mathematik", color: "var(--htwk-rot-200)" },{ summary: "Funktionale Programmierung", color: "var(--htwk-gruen-300)" }]);
|
||||
expect(exportedForTesting.extractedColorizedEvents(events)).toEqual([
|
||||
{ summary: "Algorithmische Mathematik", color: "var(--htwk-rot-200)" },
|
||||
{ summary: "Funktionale Programmierung", color: "var(--htwk-gruen-300)" },
|
||||
]);
|
||||
});
|
@@ -23,7 +23,7 @@ import { CalendarComponent } from "ical";
|
||||
* @param color Color code for the event
|
||||
*/
|
||||
export interface ColorDistinctionEvent {
|
||||
summary: string;
|
||||
summary: string | undefined;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@@ -32,13 +32,15 @@ export interface ColorDistinctionEvent {
|
||||
* @param icalData iCal data to parse
|
||||
* @returns Array of calendar components
|
||||
*/
|
||||
export function parseICalData(icalData: string | undefined): CalendarComponent[] {
|
||||
export function parseICalData(
|
||||
icalData: string | undefined,
|
||||
): CalendarComponent[] {
|
||||
if (icalData === undefined || !icalData) {
|
||||
return [];
|
||||
} else {
|
||||
const jCalData = ICAL.parse(icalData);
|
||||
const comp = new ICAL.Component(jCalData);
|
||||
const vEvents = comp.getAllSubcomponents('vevent');
|
||||
const vEvents = comp.getAllSubcomponents("vevent");
|
||||
const colorDistinctionEvents = extractedColorizedEvents(vEvents);
|
||||
|
||||
return vEvents.map((vevent: CalendarComponent) => {
|
||||
@@ -50,7 +52,9 @@ export function parseICalData(icalData: string | undefined): CalendarComponent[]
|
||||
end: event.endDate.toJSDate(),
|
||||
notes: event.description,
|
||||
allDay: event.startDate.isDate,
|
||||
color: colorDistinctionEvents.find((e: ColorDistinctionEvent) => e.summary === event.summary)?.color,
|
||||
color: colorDistinctionEvents.find(
|
||||
(e: ColorDistinctionEvent) => e.summary === event.summary,
|
||||
)?.color,
|
||||
id: event.uid,
|
||||
location: event.location,
|
||||
};
|
||||
@@ -63,32 +67,37 @@ export function parseICalData(icalData: string | undefined): CalendarComponent[]
|
||||
* @param vEvents Array of calendar components
|
||||
* @returns Array of objects with event name and color
|
||||
*/
|
||||
function extractedColorizedEvents(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
|
||||
function extractedColorizedEvents(
|
||||
vEvents: CalendarComponent[],
|
||||
): ColorDistinctionEvent[] {
|
||||
return colorizeEvents(filterEventsDistinct(vEvents));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filters out duplicate events
|
||||
* @param vEvents Array of calendar components
|
||||
* @returns Array of calendar components without duplicates
|
||||
*/
|
||||
function filterEventsDistinct(vEvents: CalendarComponent[]): CalendarComponent[] {
|
||||
return vEvents.filter((vevent: CalendarComponent, index: number, self: CalendarComponent[]) => {
|
||||
return self.findIndex((v) => {
|
||||
function filterEventsDistinct(
|
||||
vEvents: CalendarComponent[],
|
||||
): CalendarComponent[] {
|
||||
return vEvents.filter(
|
||||
(vevent: CalendarComponent, index: number, self: CalendarComponent[]) => {
|
||||
return (
|
||||
self.findIndex((v) => {
|
||||
return v.summary === vevent.summary;
|
||||
}) === index;
|
||||
});
|
||||
}) === index
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assigns a color to each event
|
||||
* @param vEvents Array of calendar components
|
||||
* @returns Array of objects with event name and color
|
||||
*/
|
||||
function colorizeEvents(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
|
||||
|
||||
return vEvents.map((vevent: CalendarComponent) => {
|
||||
const colors: string[] = [
|
||||
"var(--htwk-rot-200)",
|
||||
@@ -101,16 +110,19 @@ function colorizeEvents(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
|
||||
"var(--htwk-dunkelblau-200)",
|
||||
"var(--htwk-rot-400)",
|
||||
"var(--htwk-gruen-400)",
|
||||
"var(--htwk-blau-200)"
|
||||
"var(--htwk-blau-200)",
|
||||
];
|
||||
|
||||
const randomColor = colors[vEvents.findIndex((e: CalendarComponent) => {
|
||||
return e.summary === vevent.summary?? "";
|
||||
}) % colors.length];
|
||||
const randomColor =
|
||||
colors[
|
||||
vEvents.findIndex((e: CalendarComponent) => {
|
||||
return e.summary === vevent.summary;
|
||||
}) % colors.length
|
||||
];
|
||||
|
||||
return {
|
||||
summary: vevent.summary?? "",
|
||||
color: randomColor
|
||||
summary: vevent.summary,
|
||||
color: randomColor,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -118,5 +130,5 @@ function colorizeEvents(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
|
||||
export const exportedForTesting = {
|
||||
extractedColorizedEvents,
|
||||
filterEventsDistinct,
|
||||
colorizeEvents
|
||||
colorizeEvents,
|
||||
};
|
@@ -10,7 +10,7 @@
|
||||
"privacy": "privacy",
|
||||
"english": "English",
|
||||
"german": "German",
|
||||
"japanese" : "Japanese",
|
||||
"japanese": "Japanese",
|
||||
"courseSelection": {
|
||||
"headline": "welcome to HTWKalender",
|
||||
"winterSemester": "winter semester",
|
||||
|
@@ -26,41 +26,15 @@
|
||||
"金曜日",
|
||||
"土曜日"
|
||||
],
|
||||
"dayNamesMin": [
|
||||
"日",
|
||||
"月",
|
||||
"火",
|
||||
"水",
|
||||
"木",
|
||||
"金",
|
||||
"土"
|
||||
],
|
||||
"dayNamesShort": [
|
||||
"日",
|
||||
"月",
|
||||
"火",
|
||||
"水",
|
||||
"木",
|
||||
"金",
|
||||
"土"
|
||||
],
|
||||
"dayNamesMin": ["日", "月", "火", "水", "木", "金", "土"],
|
||||
"dayNamesShort": ["日", "月", "火", "水", "木", "金", "土"],
|
||||
"emptyFilterMessage": "オプションなし",
|
||||
"emptyMessage": "結果なし",
|
||||
"emptySearchMessage": "該当なし",
|
||||
"emptySelectionMessage": "選択なし",
|
||||
"endsWith": "終わる",
|
||||
"equals": "等しい",
|
||||
"fileSizeTypes": [
|
||||
"B",
|
||||
"KB",
|
||||
"MB",
|
||||
"GB",
|
||||
"TB",
|
||||
"PB",
|
||||
"EB",
|
||||
"ZB",
|
||||
"YB"
|
||||
],
|
||||
"fileSizeTypes": ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],
|
||||
"filter": "フィルター",
|
||||
"firstDayOfWeek": 0,
|
||||
"gt": "超える",
|
||||
|
@@ -31,7 +31,7 @@ import Card from "primevue/card";
|
||||
import DataView from "primevue/dataview";
|
||||
import Dialog from "primevue/dialog";
|
||||
import Slider from "primevue/slider";
|
||||
import OverlayPanel from 'primevue/overlaypanel';
|
||||
import OverlayPanel from "primevue/overlaypanel";
|
||||
import ToggleButton from "primevue/togglebutton";
|
||||
import "primeicons/primeicons.css";
|
||||
import "primeflex/primeflex.css";
|
||||
@@ -57,14 +57,14 @@ import Calendar from "primevue/calendar";
|
||||
import i18n from "./i18n";
|
||||
import { VueQueryPlugin } from "@tanstack/vue-query";
|
||||
import { polyfillCountryFlagEmojis } from "country-flag-emoji-polyfill";
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
||||
|
||||
polyfillCountryFlagEmojis();
|
||||
|
||||
const app = createApp(App);
|
||||
const pinia = createPinia();
|
||||
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
|
||||
app.use(VueQueryPlugin, {
|
||||
queryClientConfig: {
|
||||
|
@@ -21,18 +21,18 @@ import { addHours, addMinutes, interval, subHours } from "date-fns";
|
||||
import { toZonedTime } from "date-fns-tz";
|
||||
|
||||
const testListStart = new Date("2022-01-01T00:00:00Z");
|
||||
var testList : RoomOccupancyList; //= RoomOccupancyList.fromJSON({});
|
||||
var alternating : Uint8Array = new Uint8Array(Array(4).fill(0xF0));
|
||||
var booked : Uint8Array = new Uint8Array(Array(4).fill(0xFF));
|
||||
var empty : Uint8Array = new Uint8Array(Array(4).fill(0x00));
|
||||
var counting : Uint8Array = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
|
||||
var testList: RoomOccupancyList; //= RoomOccupancyList.fromJSON({});
|
||||
var alternating: Uint8Array = new Uint8Array(Array(4).fill(0xf0));
|
||||
var booked: Uint8Array = new Uint8Array(Array(4).fill(0xff));
|
||||
var empty: Uint8Array = new Uint8Array(Array(4).fill(0x00));
|
||||
var counting: Uint8Array = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
|
||||
|
||||
const localTimezone = "Europe/Berlin";
|
||||
|
||||
describe("RoomOccupancyList", () => {
|
||||
beforeEach(() => {
|
||||
alternating = new Uint8Array(Array(4).fill(0xF0));
|
||||
booked = new Uint8Array(Array(4).fill(0xFF));
|
||||
alternating = new Uint8Array(Array(4).fill(0xf0));
|
||||
booked = new Uint8Array(Array(4).fill(0xff));
|
||||
empty = new Uint8Array(Array(4).fill(0x00));
|
||||
counting = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
|
||||
testList = RoomOccupancyList.fromJSON({
|
||||
@@ -55,8 +55,8 @@ describe("RoomOccupancyList", () => {
|
||||
{
|
||||
name: "COUNTING",
|
||||
occupancy: new Binary(counting, 0),
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -66,12 +66,7 @@ describe("RoomOccupancyList", () => {
|
||||
const rooms = testList["getRooms"]();
|
||||
|
||||
// assert
|
||||
expect(rooms).toEqual([
|
||||
"BOOKED",
|
||||
"EMPTY",
|
||||
"ALTERNATING",
|
||||
"COUNTING"
|
||||
]);
|
||||
expect(rooms).toEqual(["BOOKED", "EMPTY", "ALTERNATING", "COUNTING"]);
|
||||
});
|
||||
|
||||
test("get empty rooms", () => {
|
||||
@@ -80,7 +75,7 @@ describe("RoomOccupancyList", () => {
|
||||
start: testListStart,
|
||||
granularity: 60,
|
||||
blocks: 32,
|
||||
rooms: []
|
||||
rooms: [],
|
||||
});
|
||||
|
||||
// act
|
||||
@@ -89,7 +84,7 @@ describe("RoomOccupancyList", () => {
|
||||
// assert
|
||||
expect(rooms).toEqual([]);
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe("decodeOccupancy", () => {
|
||||
test("generate stubs for missing room", () => {
|
||||
@@ -109,8 +104,8 @@ describe("RoomOccupancyList", () => {
|
||||
end: "2022-01-01T08:00:00.000Z",
|
||||
rooms: "MISSING",
|
||||
free: true,
|
||||
stub: true
|
||||
}
|
||||
stub: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -131,8 +126,8 @@ describe("RoomOccupancyList", () => {
|
||||
end: "2021-12-31T19:00:00.000Z",
|
||||
rooms: "BOOKED",
|
||||
free: true,
|
||||
stub: true
|
||||
}
|
||||
stub: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -151,48 +146,41 @@ describe("RoomOccupancyList", () => {
|
||||
end: "2022-01-01T08:00:00.000Z",
|
||||
rooms: "BOOKED",
|
||||
free: false,
|
||||
stub: false
|
||||
}
|
||||
stub: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("sliceOccupancy", () => {
|
||||
test.each([
|
||||
booked,
|
||||
empty,
|
||||
alternating
|
||||
])("getCompleteOccupancy of %j", (occupancy) => {
|
||||
test.each([booked, empty, alternating])(
|
||||
"getCompleteOccupancy of %j",
|
||||
(occupancy) => {
|
||||
// arrange
|
||||
const startTime = new Date(testList.start);
|
||||
const endTime = new Date(addHours(startTime, 32));
|
||||
const sliceInterval = interval(startTime, endTime);
|
||||
|
||||
// act
|
||||
const sliced = testList["sliceOccupancy"](
|
||||
sliceInterval,
|
||||
occupancy
|
||||
)
|
||||
const sliced = testList["sliceOccupancy"](sliceInterval, occupancy);
|
||||
|
||||
// assert
|
||||
expect(sliced).toEqual({
|
||||
decodeSliceStart: startTime,
|
||||
decodeSlice: new Uint8Array(occupancy),
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test("throws start out of bounds", () => {
|
||||
// arrange
|
||||
const startTime = new Date(subHours(testList.start,1));
|
||||
const startTime = new Date(subHours(testList.start, 1));
|
||||
const endTime = new Date(addHours(startTime, 32));
|
||||
const sliceInterval = interval(startTime, endTime);
|
||||
|
||||
// act and assert
|
||||
expect(() => {
|
||||
testList["sliceOccupancy"](
|
||||
sliceInterval,
|
||||
alternating
|
||||
)
|
||||
testList["sliceOccupancy"](sliceInterval, alternating);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
@@ -204,10 +192,7 @@ describe("RoomOccupancyList", () => {
|
||||
|
||||
// act and assert
|
||||
expect(() => {
|
||||
testList["sliceOccupancy"](
|
||||
sliceInterval,
|
||||
alternating
|
||||
)
|
||||
testList["sliceOccupancy"](sliceInterval, alternating);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
@@ -218,10 +203,7 @@ describe("RoomOccupancyList", () => {
|
||||
const sliceInterval = interval(startTime, endTime);
|
||||
|
||||
// act
|
||||
const sliced = testList["sliceOccupancy"](
|
||||
sliceInterval,
|
||||
counting
|
||||
)
|
||||
const sliced = testList["sliceOccupancy"](sliceInterval, counting);
|
||||
|
||||
// assert
|
||||
expect(sliced).toEqual({
|
||||
@@ -237,14 +219,11 @@ describe("RoomOccupancyList", () => {
|
||||
const sliceInterval = interval(startTime, endTime);
|
||||
|
||||
// act
|
||||
const sliced = testList["sliceOccupancy"](
|
||||
sliceInterval,
|
||||
counting
|
||||
)
|
||||
const sliced = testList["sliceOccupancy"](sliceInterval, counting);
|
||||
|
||||
// assert
|
||||
expect(sliced).toEqual({
|
||||
decodeSliceStart: addHours(testListStart,8),
|
||||
decodeSliceStart: addHours(testListStart, 8),
|
||||
decodeSlice: new Uint8Array([0x01]),
|
||||
});
|
||||
});
|
||||
@@ -257,7 +236,7 @@ describe("RoomOccupancyList", () => {
|
||||
start: testListStart,
|
||||
granularity: 60,
|
||||
blocks: 0,
|
||||
rooms: []
|
||||
rooms: [],
|
||||
});
|
||||
|
||||
// act
|
||||
@@ -272,7 +251,9 @@ describe("RoomOccupancyList", () => {
|
||||
const testInterval = testList["getOccupancyInterval"]();
|
||||
|
||||
// assert
|
||||
expect(testInterval).toEqual(interval(testListStart, addHours(testListStart, 32)));
|
||||
expect(testInterval).toEqual(
|
||||
interval(testListStart, addHours(testListStart, 32)),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -284,7 +265,7 @@ describe("RoomOccupancyList", () => {
|
||||
new Uint8Array([]),
|
||||
testListStart,
|
||||
15,
|
||||
"Raum"
|
||||
"Raum",
|
||||
);
|
||||
|
||||
// assert
|
||||
@@ -298,7 +279,7 @@ describe("RoomOccupancyList", () => {
|
||||
booked,
|
||||
testListStart,
|
||||
15,
|
||||
"BOOKED"
|
||||
"BOOKED",
|
||||
);
|
||||
|
||||
// assert
|
||||
@@ -308,8 +289,8 @@ describe("RoomOccupancyList", () => {
|
||||
end: addHours(testListStart, 8).toISOString(),
|
||||
rooms: "BOOKED",
|
||||
free: false,
|
||||
stub: false
|
||||
}
|
||||
stub: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -320,7 +301,7 @@ describe("RoomOccupancyList", () => {
|
||||
empty,
|
||||
testListStart,
|
||||
15,
|
||||
"BOOKED"
|
||||
"BOOKED",
|
||||
);
|
||||
|
||||
// assert
|
||||
@@ -334,7 +315,7 @@ describe("RoomOccupancyList", () => {
|
||||
alternating,
|
||||
new Date("2024-01-01T00:00:00Z"),
|
||||
15,
|
||||
"ALTERNATING"
|
||||
"ALTERNATING",
|
||||
);
|
||||
|
||||
// assert
|
||||
@@ -344,29 +325,29 @@ describe("RoomOccupancyList", () => {
|
||||
end: "2024-01-01T01:00:00.000Z",
|
||||
rooms: "ALTERNATING",
|
||||
free: false,
|
||||
stub: false
|
||||
stub: false,
|
||||
},
|
||||
{
|
||||
start: "2024-01-01T02:00:00.000Z",
|
||||
end: "2024-01-01T03:00:00.000Z",
|
||||
rooms: "ALTERNATING",
|
||||
free: false,
|
||||
stub: false
|
||||
stub: false,
|
||||
},
|
||||
{
|
||||
start: "2024-01-01T04:00:00.000Z",
|
||||
end: "2024-01-01T05:00:00.000Z",
|
||||
rooms: "ALTERNATING",
|
||||
free: false,
|
||||
stub: false
|
||||
stub: false,
|
||||
},
|
||||
{
|
||||
start: "2024-01-01T06:00:00.000Z",
|
||||
end: "2024-01-01T07:00:00.000Z",
|
||||
rooms: "ALTERNATING",
|
||||
free: false,
|
||||
stub: false
|
||||
}
|
||||
stub: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -381,7 +362,7 @@ describe("RoomOccupancyList", () => {
|
||||
const stubEvents = RoomOccupancyList["generateStubEvents"](
|
||||
"ROOM",
|
||||
startTime,
|
||||
endTime
|
||||
endTime,
|
||||
);
|
||||
|
||||
// assert
|
||||
@@ -397,7 +378,7 @@ describe("RoomOccupancyList", () => {
|
||||
const stubEvents = RoomOccupancyList["generateStubEvents"](
|
||||
"ROOM",
|
||||
startTime,
|
||||
endTime
|
||||
endTime,
|
||||
);
|
||||
|
||||
// assert
|
||||
@@ -413,7 +394,7 @@ describe("RoomOccupancyList", () => {
|
||||
const stubEvents = RoomOccupancyList["generateStubEvents"](
|
||||
"ROOM",
|
||||
startTime,
|
||||
endTime
|
||||
endTime,
|
||||
);
|
||||
|
||||
// assert
|
||||
@@ -466,7 +447,7 @@ describe("RoomOccupancyList", () => {
|
||||
rooms: "ROOM",
|
||||
free: true,
|
||||
stub: true,
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -479,7 +460,7 @@ describe("RoomOccupancyList", () => {
|
||||
const stubEvents = RoomOccupancyList["generateStubEvents"](
|
||||
"ROOM",
|
||||
startTime,
|
||||
endTime
|
||||
endTime,
|
||||
);
|
||||
|
||||
// assert
|
||||
@@ -490,7 +471,7 @@ describe("RoomOccupancyList", () => {
|
||||
rooms: "ROOM",
|
||||
free: true,
|
||||
stub: true,
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -501,10 +482,13 @@ describe("RoomOccupancyList", () => {
|
||||
const startTime = new Date("2022-01-01T20:00:00Z");
|
||||
|
||||
// act
|
||||
const shiftedTime = RoomOccupancyList["shiftTimeForwardInsideWorkday"](startTime);
|
||||
const shiftedTime =
|
||||
RoomOccupancyList["shiftTimeForwardInsideWorkday"](startTime);
|
||||
|
||||
// assert
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(new Date("2022-01-02T00:00:00Z"));
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(
|
||||
new Date("2022-01-02T00:00:00Z"),
|
||||
);
|
||||
});
|
||||
|
||||
test("don't shift time on the same day", () => {
|
||||
@@ -512,10 +496,13 @@ describe("RoomOccupancyList", () => {
|
||||
const startTime = new Date("2022-01-02T01:00:00Z");
|
||||
|
||||
// act
|
||||
const shiftedTime = RoomOccupancyList["shiftTimeForwardInsideWorkday"](startTime);
|
||||
const shiftedTime =
|
||||
RoomOccupancyList["shiftTimeForwardInsideWorkday"](startTime);
|
||||
|
||||
// assert
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(new Date("2022-01-02T02:00:00Z"));
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(
|
||||
new Date("2022-01-02T02:00:00Z"),
|
||||
);
|
||||
});
|
||||
|
||||
test("don't shift if already inside workday", () => {
|
||||
@@ -523,10 +510,13 @@ describe("RoomOccupancyList", () => {
|
||||
const startTime = new Date("2022-01-02T12:30:00Z");
|
||||
|
||||
// act
|
||||
const shiftedTime = RoomOccupancyList["shiftTimeForwardInsideWorkday"](startTime);
|
||||
const shiftedTime =
|
||||
RoomOccupancyList["shiftTimeForwardInsideWorkday"](startTime);
|
||||
|
||||
// assert
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(new Date("2022-01-02T13:30:00Z"));
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(
|
||||
new Date("2022-01-02T13:30:00Z"),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -536,10 +526,13 @@ describe("RoomOccupancyList", () => {
|
||||
const startTime = new Date("2022-01-02T05:30:00Z");
|
||||
|
||||
// act
|
||||
const shiftedTime = RoomOccupancyList["shiftTimeBackwardInsideWorkday"](startTime);
|
||||
const shiftedTime =
|
||||
RoomOccupancyList["shiftTimeBackwardInsideWorkday"](startTime);
|
||||
|
||||
// assert
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(new Date("2022-01-01T23:59:59.999Z"));
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(
|
||||
new Date("2022-01-01T23:59:59.999Z"),
|
||||
);
|
||||
});
|
||||
|
||||
test("don't shift time on the same day", () => {
|
||||
@@ -547,10 +540,13 @@ describe("RoomOccupancyList", () => {
|
||||
const startTime = new Date("2022-01-02T22:00:00Z");
|
||||
|
||||
// act
|
||||
const shiftedTime = RoomOccupancyList["shiftTimeBackwardInsideWorkday"](startTime);
|
||||
const shiftedTime =
|
||||
RoomOccupancyList["shiftTimeBackwardInsideWorkday"](startTime);
|
||||
|
||||
// assert
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(new Date("2022-01-02T23:00:00Z"));
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(
|
||||
new Date("2022-01-02T23:00:00Z"),
|
||||
);
|
||||
});
|
||||
|
||||
test("don't shift if already inside workday", () => {
|
||||
@@ -558,10 +554,13 @@ describe("RoomOccupancyList", () => {
|
||||
const startTime = new Date("2022-01-02T12:30:00Z");
|
||||
|
||||
// act
|
||||
const shiftedTime = RoomOccupancyList["shiftTimeBackwardInsideWorkday"](startTime);
|
||||
const shiftedTime =
|
||||
RoomOccupancyList["shiftTimeBackwardInsideWorkday"](startTime);
|
||||
|
||||
// assert
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(new Date("2022-01-02T13:30:00Z"));
|
||||
expect(toZonedTime(shiftedTime, localTimezone)).toEqual(
|
||||
new Date("2022-01-02T13:30:00Z"),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -582,7 +581,11 @@ describe("RoomOccupancyList", () => {
|
||||
const startTime = new Date("2022-06-02T12:30:00Z");
|
||||
|
||||
// act
|
||||
const shiftedTime = RoomOccupancyList["setTimeOfDay"](startTime, {hours: 23, minutes: 59, seconds: 59});
|
||||
const shiftedTime = RoomOccupancyList["setTimeOfDay"](startTime, {
|
||||
hours: 23,
|
||||
minutes: 59,
|
||||
seconds: 59,
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(shiftedTime).toEqual(new Date("2022-06-02T21:59:59Z"));
|
||||
@@ -593,7 +596,11 @@ describe("RoomOccupancyList", () => {
|
||||
const startTime = new Date("2022-01-02T12:30:00Z");
|
||||
|
||||
// act
|
||||
const shiftedTime = RoomOccupancyList["setTimeOfDay"](startTime, {hours: 13, minutes: 30, seconds: 0});
|
||||
const shiftedTime = RoomOccupancyList["setTimeOfDay"](startTime, {
|
||||
hours: 13,
|
||||
minutes: 30,
|
||||
seconds: 0,
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(shiftedTime).toEqual(new Date("2022-01-02T12:30:00Z"));
|
||||
@@ -647,5 +654,4 @@ describe("RoomOccupancyList", () => {
|
||||
expect(shiftedTime).toEqual(new Date("2022-06-01:22:00Z"));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -16,13 +16,31 @@
|
||||
|
||||
import { Binary } from "bson";
|
||||
import { AnonymizedOccupancy } from "./event";
|
||||
import { Duration, NormalizedInterval, add, addDays, addMinutes, clamp, differenceInMinutes, eachDayOfInterval, endOfDay, interval, isAfter, isBefore, isEqual, max, min, startOfDay, subDays } from "date-fns";
|
||||
import {
|
||||
Duration,
|
||||
NormalizedInterval,
|
||||
add,
|
||||
addDays,
|
||||
addMinutes,
|
||||
clamp,
|
||||
differenceInMinutes,
|
||||
eachDayOfInterval,
|
||||
endOfDay,
|
||||
interval,
|
||||
isAfter,
|
||||
isBefore,
|
||||
isEqual,
|
||||
max,
|
||||
min,
|
||||
startOfDay,
|
||||
subDays,
|
||||
} from "date-fns";
|
||||
import { fromZonedTime, toZonedTime } from "date-fns-tz";
|
||||
|
||||
/// The start time of the day. 07:00
|
||||
const START_OF_WORKDAY : Duration = {hours: 7};
|
||||
const START_OF_WORKDAY: Duration = { hours: 7 };
|
||||
/// The end time of the day. 20:00
|
||||
const END_OF_WORKDAY : Duration = {hours: 20};
|
||||
const END_OF_WORKDAY: Duration = { hours: 20 };
|
||||
/// The timezone of the data (Leipzig)
|
||||
const TIMEZONE = "Europe/Berlin";
|
||||
|
||||
@@ -32,8 +50,8 @@ const TIMEZONE = "Europe/Berlin";
|
||||
*/
|
||||
class RoomOccupancy {
|
||||
constructor(
|
||||
public name : string,
|
||||
public occupancy : Binary,
|
||||
public name: string,
|
||||
public occupancy: Binary,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -46,17 +64,17 @@ class RoomOccupancy {
|
||||
*/
|
||||
export class RoomOccupancyList {
|
||||
constructor(
|
||||
public start : Date,
|
||||
public granularity : number,
|
||||
public blocks : number,
|
||||
public rooms : RoomOccupancy[],
|
||||
public start: Date,
|
||||
public granularity: number,
|
||||
public blocks: number,
|
||||
public rooms: RoomOccupancy[],
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get a list of all rooms encoded in this occupancy list.
|
||||
* @returns a list of room names.
|
||||
*/
|
||||
public getRooms() : string[] {
|
||||
public getRooms(): string[] {
|
||||
return this.rooms.map((room) => room.name);
|
||||
}
|
||||
|
||||
@@ -67,7 +85,11 @@ export class RoomOccupancyList {
|
||||
* @param to the end of the time range.
|
||||
* @returns a list of AnonymizedEventDTO objects representing the occupancy of the room.
|
||||
*/
|
||||
public decodeOccupancy(room : string, from : Date, to : Date) : AnonymizedOccupancy[] {
|
||||
public decodeOccupancy(
|
||||
room: string,
|
||||
from: Date,
|
||||
to: Date,
|
||||
): AnonymizedOccupancy[] {
|
||||
const roomOccupancy = this.rooms.find((r) => r.name === room);
|
||||
|
||||
if (roomOccupancy === undefined) {
|
||||
@@ -77,23 +99,41 @@ export class RoomOccupancyList {
|
||||
const occupancyList = [];
|
||||
|
||||
// Get start and end of decoded time range (within encoded list and requested range)
|
||||
let decodeInterval = interval(clamp(from, this.getOccupancyInterval()), clamp(to, this.getOccupancyInterval()));
|
||||
let decodeInterval = interval(
|
||||
clamp(from, this.getOccupancyInterval()),
|
||||
clamp(to, this.getOccupancyInterval()),
|
||||
);
|
||||
|
||||
let {decodeSliceStart, decodeSlice} = this.sliceOccupancy(
|
||||
let { decodeSliceStart, decodeSlice } = this.sliceOccupancy(
|
||||
decodeInterval,
|
||||
roomOccupancy.occupancy.buffer
|
||||
roomOccupancy.occupancy.buffer,
|
||||
);
|
||||
|
||||
// Decode the occupancy data
|
||||
occupancyList.push(...RoomOccupancyList.decodeOccupancyData(new Uint8Array(decodeSlice), decodeSliceStart, this.granularity, room));
|
||||
occupancyList.push(
|
||||
...RoomOccupancyList.decodeOccupancyData(
|
||||
new Uint8Array(decodeSlice),
|
||||
decodeSliceStart,
|
||||
this.granularity,
|
||||
room,
|
||||
),
|
||||
);
|
||||
|
||||
// add stub events for the time before and after the decoded time range
|
||||
if (!isEqual(from, decodeInterval.start)) {
|
||||
occupancyList.push(...RoomOccupancyList.generateStubEvents(room, from, decodeInterval.start));
|
||||
occupancyList.push(
|
||||
...RoomOccupancyList.generateStubEvents(
|
||||
room,
|
||||
from,
|
||||
decodeInterval.start,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!isEqual(to, decodeInterval.end)) {
|
||||
occupancyList.push(...RoomOccupancyList.generateStubEvents(room, decodeInterval.end, to));
|
||||
occupancyList.push(
|
||||
...RoomOccupancyList.generateStubEvents(room, decodeInterval.end, to),
|
||||
);
|
||||
}
|
||||
|
||||
return occupancyList;
|
||||
@@ -106,10 +146,16 @@ export class RoomOccupancyList {
|
||||
* @returns a new occupancy byte array with the starting time of the first byte
|
||||
* @throws an error, if the selected time range is outside of the occupancy list.
|
||||
*/
|
||||
private sliceOccupancy(decodeInterval : NormalizedInterval, occupancy : Uint8Array) : {decodeSliceStart: Date, decodeSlice: Uint8Array} {
|
||||
private sliceOccupancy(
|
||||
decodeInterval: NormalizedInterval,
|
||||
occupancy: Uint8Array,
|
||||
): { decodeSliceStart: Date; decodeSlice: Uint8Array } {
|
||||
// Calculate the slice of bytes, that are needed to decode the requested time range
|
||||
// Note: differenceInMinutes calculates (left - right)
|
||||
let minutesFromStart = differenceInMinutes(decodeInterval.start, this.start);
|
||||
let minutesFromStart = differenceInMinutes(
|
||||
decodeInterval.start,
|
||||
this.start,
|
||||
);
|
||||
let minutesToEnd = differenceInMinutes(decodeInterval.end, this.start);
|
||||
|
||||
let firstByte = Math.floor(minutesFromStart / this.granularity / 8);
|
||||
@@ -117,13 +163,18 @@ export class RoomOccupancyList {
|
||||
|
||||
// check if firstByte and lastByte are within the bounds of the occupancy array and throw an error if not
|
||||
if (
|
||||
firstByte < 0 || firstByte >= occupancy.length ||
|
||||
lastByte < 0 || lastByte > occupancy.length
|
||||
firstByte < 0 ||
|
||||
firstByte >= occupancy.length ||
|
||||
lastByte < 0 ||
|
||||
lastByte > occupancy.length
|
||||
) {
|
||||
throw new Error("Requested time range is outside of the occupancy list.");
|
||||
}
|
||||
|
||||
let decodeSliceStart = addMinutes(this.start, firstByte * 8 * this.granularity);
|
||||
let decodeSliceStart = addMinutes(
|
||||
this.start,
|
||||
firstByte * 8 * this.granularity,
|
||||
);
|
||||
let decodeSlice = occupancy.buffer.slice(firstByte, lastByte);
|
||||
|
||||
return { decodeSliceStart, decodeSlice: new Uint8Array(decodeSlice) };
|
||||
@@ -133,8 +184,11 @@ export class RoomOccupancyList {
|
||||
* Get the decoded time interval within the current occupancy list.
|
||||
* @returns the interval of the occupancy list.
|
||||
*/
|
||||
private getOccupancyInterval() : NormalizedInterval<Date> {
|
||||
return interval(this.start, addMinutes(this.start, this.granularity * this.blocks));
|
||||
private getOccupancyInterval(): NormalizedInterval<Date> {
|
||||
return interval(
|
||||
this.start,
|
||||
addMinutes(this.start, this.granularity * this.blocks),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,9 +199,14 @@ export class RoomOccupancyList {
|
||||
* @param room the room name.
|
||||
* @returns a list of AnonymizedOccupancy objects representing the occupancy of the room.
|
||||
*/
|
||||
public static decodeOccupancyData(occupancy : Uint8Array, start : Date, granularity : number, room : string) : AnonymizedOccupancy[] {
|
||||
public static decodeOccupancyData(
|
||||
occupancy: Uint8Array,
|
||||
start: Date,
|
||||
granularity: number,
|
||||
room: string,
|
||||
): AnonymizedOccupancy[] {
|
||||
let occupancyList = [];
|
||||
let firstOccupancyBit : number | null = null;
|
||||
let firstOccupancyBit: number | null = null;
|
||||
|
||||
// Iterate over all bytes that are in the array
|
||||
for (let byte_i = 0; byte_i < occupancy.length; byte_i++) {
|
||||
@@ -155,7 +214,7 @@ export class RoomOccupancyList {
|
||||
|
||||
// Iterate over all bits in the current byte
|
||||
for (let bit_i = 0; bit_i < 8; bit_i++) {
|
||||
let isOccupied = (byte & (1 << (7-bit_i))) !== 0;
|
||||
let isOccupied = (byte & (1 << (7 - bit_i))) !== 0;
|
||||
|
||||
if (firstOccupancyBit === null && isOccupied) {
|
||||
firstOccupancyBit = byte_i * 8 + bit_i;
|
||||
@@ -164,13 +223,15 @@ export class RoomOccupancyList {
|
||||
let endTime = addMinutes(start, (byte_i * 8 + bit_i) * granularity);
|
||||
|
||||
// add event between start and end of a block of boolean true values
|
||||
occupancyList.push(new AnonymizedOccupancy(
|
||||
occupancyList.push(
|
||||
new AnonymizedOccupancy(
|
||||
startTime.toISOString(),
|
||||
endTime.toISOString(),
|
||||
room,
|
||||
false,
|
||||
false,
|
||||
));
|
||||
),
|
||||
);
|
||||
|
||||
firstOccupancyBit = null;
|
||||
}
|
||||
@@ -182,13 +243,15 @@ export class RoomOccupancyList {
|
||||
let startTime = addMinutes(start, firstOccupancyBit * granularity);
|
||||
let endTime = addMinutes(start, occupancy.length * 8 * granularity);
|
||||
|
||||
occupancyList.push(new AnonymizedOccupancy(
|
||||
occupancyList.push(
|
||||
new AnonymizedOccupancy(
|
||||
startTime.toISOString(),
|
||||
endTime.toISOString(),
|
||||
room,
|
||||
false,
|
||||
false,
|
||||
));
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return occupancyList;
|
||||
@@ -202,7 +265,11 @@ export class RoomOccupancyList {
|
||||
* @param to The end time within the specified end day.
|
||||
* @returns a list of AnonymizedEventDTO objects, from start to end.
|
||||
*/
|
||||
public static generateStubEvents(rooms : string, from : Date, to : Date) : AnonymizedOccupancy[] {
|
||||
public static generateStubEvents(
|
||||
rooms: string,
|
||||
from: Date,
|
||||
to: Date,
|
||||
): AnonymizedOccupancy[] {
|
||||
from = RoomOccupancyList.shiftTimeForwardInsideWorkday(from);
|
||||
to = RoomOccupancyList.shiftTimeBackwardInsideWorkday(to);
|
||||
|
||||
@@ -210,9 +277,15 @@ export class RoomOccupancyList {
|
||||
return [];
|
||||
}
|
||||
|
||||
return eachDayOfInterval({start: from, end: to}).map((day) => {
|
||||
let startTime = max([from, RoomOccupancyList.setTimeOfDay(day, START_OF_WORKDAY)]);
|
||||
let endTime = min([to, RoomOccupancyList.setTimeOfDay(day, END_OF_WORKDAY)]);
|
||||
return eachDayOfInterval({ start: from, end: to }).map((day) => {
|
||||
let startTime = max([
|
||||
from,
|
||||
RoomOccupancyList.setTimeOfDay(day, START_OF_WORKDAY),
|
||||
]);
|
||||
let endTime = min([
|
||||
to,
|
||||
RoomOccupancyList.setTimeOfDay(day, END_OF_WORKDAY),
|
||||
]);
|
||||
|
||||
return new AnonymizedOccupancy(
|
||||
startTime.toISOString(),
|
||||
@@ -230,13 +303,15 @@ export class RoomOccupancyList {
|
||||
* @param json the JS object to read from.
|
||||
* @returns a RoomOccupancyList object.
|
||||
*/
|
||||
public static fromJSON(json : any) : RoomOccupancyList {
|
||||
public static fromJSON(json: any): RoomOccupancyList {
|
||||
return new RoomOccupancyList(
|
||||
json.start,
|
||||
json.granularity,
|
||||
json.blocks,
|
||||
json.rooms.map((room : any) => new RoomOccupancy(room.name, room.occupancy)
|
||||
));
|
||||
json.rooms.map(
|
||||
(room: any) => new RoomOccupancy(room.name, room.occupancy),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,11 +320,11 @@ export class RoomOccupancyList {
|
||||
* @param date the date time to check if in bounds.
|
||||
* @returns the shifted time.
|
||||
*/
|
||||
private static shiftTimeForwardInsideWorkday(date : Date) : Date {
|
||||
private static shiftTimeForwardInsideWorkday(date: Date): Date {
|
||||
// if the time of date is after the end of the workday
|
||||
if (isAfter(date, RoomOccupancyList.setTimeOfDay(date, END_OF_WORKDAY))) {
|
||||
// shift the time to the start of the next day
|
||||
return RoomOccupancyList.startOfDay(addDays(date,1));
|
||||
return RoomOccupancyList.startOfDay(addDays(date, 1));
|
||||
} else {
|
||||
return date;
|
||||
}
|
||||
@@ -261,11 +336,13 @@ export class RoomOccupancyList {
|
||||
* @param date the date time to check if in bounds.
|
||||
* @returns the shifted time.
|
||||
*/
|
||||
private static shiftTimeBackwardInsideWorkday(date : Date) : Date {
|
||||
private static shiftTimeBackwardInsideWorkday(date: Date): Date {
|
||||
// if the time of date is before the start of the workday
|
||||
if (isBefore(date, RoomOccupancyList.setTimeOfDay(date, START_OF_WORKDAY))) {
|
||||
if (
|
||||
isBefore(date, RoomOccupancyList.setTimeOfDay(date, START_OF_WORKDAY))
|
||||
) {
|
||||
// shift the time to the end of the previous day
|
||||
return RoomOccupancyList.endOfDay(subDays(date,1));
|
||||
return RoomOccupancyList.endOfDay(subDays(date, 1));
|
||||
} else {
|
||||
return date;
|
||||
}
|
||||
@@ -277,7 +354,7 @@ export class RoomOccupancyList {
|
||||
* @param time the time as Duration after 00:00.
|
||||
* @returns new date with changed time values.
|
||||
*/
|
||||
private static setTimeOfDay(date : Date, time : Duration) : Date {
|
||||
private static setTimeOfDay(date: Date, time: Duration): Date {
|
||||
return add(RoomOccupancyList.startOfDay(date), time);
|
||||
}
|
||||
|
||||
@@ -286,7 +363,7 @@ export class RoomOccupancyList {
|
||||
* @param date
|
||||
* @returns the start of the day.
|
||||
*/
|
||||
private static startOfDay(date : Date) : Date {
|
||||
private static startOfDay(date: Date): Date {
|
||||
const dateInLocalTimezone = toZonedTime(date, TIMEZONE);
|
||||
return fromZonedTime(startOfDay(dateInLocalTimezone), TIMEZONE);
|
||||
}
|
||||
@@ -296,10 +373,8 @@ export class RoomOccupancyList {
|
||||
* @param date
|
||||
* @returns the end of the day.
|
||||
*/
|
||||
private static endOfDay(date : Date) : Date {
|
||||
private static endOfDay(date: Date): Date {
|
||||
const dateInLocalTimezone = toZonedTime(date, TIMEZONE);
|
||||
return fromZonedTime(endOfDay(dateInLocalTimezone), TIMEZONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -129,8 +129,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
/>
|
||||
</template>
|
||||
<template #body="slotProps">
|
||||
<div class="flex flex-column sm:flex-row justify-content-between flex-1 column-gap-4 mx-2 md:mx-4">
|
||||
<p class="flex-1 align-self-stretch sm:align-self-center my-2">{{ slotProps.data.room }}</p>
|
||||
<div
|
||||
class="flex flex-column sm:flex-row justify-content-between flex-1 column-gap-4 mx-2 md:mx-4"
|
||||
>
|
||||
<p class="flex-1 align-self-stretch sm:align-self-center my-2">
|
||||
{{ slotProps.data.room }}
|
||||
</p>
|
||||
<Button
|
||||
:label="$t('freeRooms.viewOccupancy')"
|
||||
icon="pi pi-hourglass"
|
||||
|
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import CalendarViewer from "@/components/CalendarViewer.vue";
|
||||
import DynamicPage from "@/view/DynamicPage.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
@@ -12,7 +11,7 @@ import tokenStore from "@/store/tokenStore.ts";
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
const toast = useToast();
|
||||
|
||||
const token = ref(tokenStore().token || "" as string );
|
||||
const token = ref(tokenStore().token || ("" as string));
|
||||
|
||||
// parse token from query parameter
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
@@ -46,7 +45,6 @@ onMounted(() => {
|
||||
loadCalendar();
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -69,13 +67,9 @@ onMounted(() => {
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<CalendarViewer
|
||||
:token="tokenStore().token"
|
||||
/>
|
||||
<CalendarViewer :token="tokenStore().token" />
|
||||
</template>
|
||||
</DynamicPage>
|
||||
</DynamicPage>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
2
frontend/src/vite-env.d.ts
vendored
2
frontend/src/vite-env.d.ts
vendored
@@ -16,4 +16,4 @@
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module 'ical.js';
|
||||
declare module "ical.js";
|
||||
|
@@ -21,7 +21,7 @@
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [
|
||||
|
@@ -17,63 +17,64 @@
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { VitePWA } from 'vite-plugin-pwa';
|
||||
import basicSsl from '@vitejs/plugin-basic-ssl'
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
import basicSsl from "@vitejs/plugin-basic-ssl";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
basicSsl(),
|
||||
VitePWA({
|
||||
mode: 'development',
|
||||
base: '/',
|
||||
injectRegister: 'auto',
|
||||
includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'mask-icon.svg'],
|
||||
mode: "development",
|
||||
base: "/",
|
||||
injectRegister: "auto",
|
||||
includeAssets: ["favicon.ico", "apple-touch-icon.png", "mask-icon.svg"],
|
||||
manifest: {
|
||||
name: 'HTWKalender',
|
||||
short_name: 'HTWKalender',
|
||||
description: 'Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.',
|
||||
theme_color: '#FFFFFF',
|
||||
background_color: '#FFFFFF',
|
||||
display: 'standalone',
|
||||
start_url: '/',
|
||||
name: "HTWKalender",
|
||||
short_name: "HTWKalender",
|
||||
description:
|
||||
"Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.",
|
||||
theme_color: "#FFFFFF",
|
||||
background_color: "#FFFFFF",
|
||||
display: "standalone",
|
||||
start_url: "/",
|
||||
icons: [
|
||||
{
|
||||
src: "/pwa-192x192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png",
|
||||
purpose: "any"
|
||||
purpose: "any",
|
||||
},
|
||||
{
|
||||
src: "/pwa-512x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
purpose: "any"
|
||||
purpose: "any",
|
||||
},
|
||||
{
|
||||
src: "/pwa-maskable-192x192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png",
|
||||
purpose: "maskable"
|
||||
purpose: "maskable",
|
||||
},
|
||||
{
|
||||
src: "/pwa-maskable-512x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
purpose: "maskable"
|
||||
}
|
||||
purpose: "maskable",
|
||||
},
|
||||
],
|
||||
},
|
||||
registerType: 'autoUpdate',
|
||||
registerType: "autoUpdate",
|
||||
workbox: {
|
||||
globPatterns: ['**/*.{js,css,html,ico,png,svg,json,vue,txt,woff2}'],
|
||||
globPatterns: ["**/*.{js,css,html,ico,png,svg,json,vue,txt,woff2}"],
|
||||
cleanupOutdatedCaches: true,
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: /^https?.*/,
|
||||
handler: 'NetworkFirst',
|
||||
handler: "NetworkFirst",
|
||||
options: {
|
||||
cacheName: 'https-calls',
|
||||
cacheName: "https-calls",
|
||||
expiration: {
|
||||
maxEntries: 150,
|
||||
maxAgeSeconds: 30 * 12 * 60 * 60, // 1 month
|
||||
@@ -86,11 +87,12 @@ export default defineConfig({
|
||||
devOptions: {
|
||||
enabled: true,
|
||||
/* when using generateSW the PWA plugin will switch to classic */
|
||||
type: 'module',
|
||||
navigateFallback: 'index.html',
|
||||
type: "module",
|
||||
navigateFallback: "index.html",
|
||||
suppressWarnings: true,
|
||||
}
|
||||
})],
|
||||
},
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
@@ -112,14 +114,14 @@ export default defineConfig({
|
||||
},
|
||||
esbuild: {
|
||||
supported: {
|
||||
'top-level-await': true
|
||||
"top-level-await": true,
|
||||
},
|
||||
},
|
||||
optimizeDeps: {
|
||||
esbuildOptions: {
|
||||
supported: {
|
||||
'top-level-await': true
|
||||
}
|
||||
"top-level-await": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@@ -1,11 +1,14 @@
|
||||
// vitest.config.ts
|
||||
import {mergeConfig} from 'vite'
|
||||
import {defineConfig} from 'vitest/config'
|
||||
import viteConfig from './vite.config'
|
||||
import { mergeConfig } from "vite";
|
||||
import { defineConfig } from "vitest/config";
|
||||
import viteConfig from "./vite.config";
|
||||
|
||||
export default mergeConfig(viteConfig, defineConfig({
|
||||
export default mergeConfig(
|
||||
viteConfig,
|
||||
defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
globalSetup: './vitest.global-setup.ts',
|
||||
globalSetup: "./vitest.global-setup.ts",
|
||||
},
|
||||
}))
|
||||
}),
|
||||
);
|
||||
|
@@ -1,3 +1,3 @@
|
||||
export const setup = () => {
|
||||
process.env.TZ = 'UTC'
|
||||
}
|
||||
process.env.TZ = "UTC";
|
||||
};
|
||||
|
Reference in New Issue
Block a user