feat:Change styles on dashboard, add animations

This commit is contained in:
Daniel Blumrich
2022-09-08 11:58:57 +00:00
committed by Thea Schöbl
parent 0d755bcbd3
commit 605aa1b782
12 changed files with 252 additions and 126 deletions

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2022 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Animation, AnimationController} from '@ionic/angular';
import {NgZone} from '@angular/core';
export class DashboardCollapse {
collapseAnimation: Animation;
nextFrame: number;
constructor(
private animationControl: AnimationController,
private zone: NgZone,
scrollContainer: HTMLElement,
toolbar: HTMLElement,
schedule: HTMLElement,
) {
this.zone
.runOutsideAngular(async () => {
this.collapseAnimation = this.animationControl
.create()
.duration(1000)
.addAnimation([
this.animationControl
.create()
.addElement(toolbar)
.fromTo('transform', 'translateY(0)', 'translateY(-32px)'),
this.animationControl
.create()
.addElement(toolbar.querySelector(':scope > ion-img')!)
.fromTo('transform', 'scale(1)', 'scale(0.35)'),
this.animationControl
.create()
.addElement(schedule)
.fromTo(
'transform',
'translateY(0) scaleY(1)',
'translateY(-75px) scaleY(0.8)',
),
this.animationControl
.create()
.addElement(schedule.querySelectorAll(':scope > a > *'))
.fromTo('transform', 'scaleY(1)', `scaleY(${1 / 0.8})`),
]);
this.collapseAnimation.progressStart(true, 0);
const element = scrollContainer;
let pos = element.scrollTop;
const animate = () => {
if (pos !== element.scrollTop) {
pos = element.scrollTop;
this.collapseAnimation.progressStep(element.scrollTop / 172);
}
this.nextFrame = requestAnimationFrame(animate);
};
this.nextFrame = requestAnimationFrame(animate);
})
.then();
}
destroy() {
cancelAnimationFrame(this.nextFrame);
}
}

View File

@@ -0,0 +1,47 @@
/*!
* Copyright (C) 2022 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
@import '../../../theme/util/mixins';
@include ion-md-down {
ion-toolbar, .logo, .schedule, .schedule > a > * {
will-change: transform;
}
.logo {
transform-origin: center right;
}
.schedule {
> a {
> * {
transform-origin: center;
}
> ion-label:first-child {
transform-origin: bottom;
}
> ion-label:last-child {
transform-origin: top;
}
> ion-icon:first-child {
transform-origin: top;
}
}
}
}

View File

@@ -1,54 +1,57 @@
<!--
~ Copyright (C) 2022 StApps
~ This program is free software: you can redistribute it and/or modify it
~ under the terms of the GNU General Public License as published by the Free
~ Software Foundation, version 3.
~ This program is free software: you can redistribute it and/or modify it
~ under the terms of the GNU General Public License as published by the Free
~ Software Foundation, version 3.
~
~ This program is distributed in the hope that it will be useful, but WITHOUT
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
~ more details.
~ This program is distributed in the hope that it will be useful, but WITHOUT
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
~ more details.
~
~ You should have received a copy of the GNU General Public License along with
~ this program. If not, see <https://www.gnu.org/licenses/>.
~ You should have received a copy of the GNU General Public License along with
~ this program. If not, see <https://www.gnu.org/licenses/>.
-->
<ion-header>
<div class="schedule">
<a [routerLink]="['/schedule/recurring']">
<ion-icon size="40" weight="300" name="grid_view"></ion-icon>
<ion-label>{{ 'schedule.recurring' | translate }}</ion-label>
</a>
<a
*ngIf="nextEvent && nextEvent.event"
[routerLink]="['/data-detail', nextEvent.event.uid]"
class="schedule-item-button"
>
<ion-label>{{ 'dashboard.schedule.title' | translate }}</ion-label>
<ion-label>
{{ nextEvent.dates | nextDateInList | amDateFormat: 'll, HH:mm' }}
{{ 'timeSuffix' | translate }}
</ion-label>
<ion-label>{{ nextEvent.event.name }}</ion-label>
</a>
<a
*ngIf="!nextEvent || !nextEvent.event"
[routerLink]="['/schedule/recurring']"
class="schedule-item-button"
>
<ion-label>{{ 'dashboard.schedule.title' | translate }}</ion-label>
<ion-label>{{ 'dashboard.schedule.noEvent' | translate }}</ion-label>
<ion-label>{{ 'dashboard.schedule.noEventLink' | translate }}</ion-label>
</a>
</div>
<ion-toolbar #toolbar class="ion-hide-md-up">
<ion-label slot="start">{{
'dashboard.header.title' | daytimeKey | translate
}}</ion-label>
<ion-img src="assets/imgs/logo.png" class="logo"></ion-img>
</ion-toolbar>
</ion-header>
<div #schedule class="schedule">
<a [routerLink]="['/schedule/recurring']">
<ion-icon size="40" weight="300" name="grid_view"></ion-icon>
<ion-label>{{ 'schedule.recurring' | translate }}</ion-label>
</a>
<a
*ngIf="nextEvent && nextEvent.event"
[routerLink]="['/data-detail', nextEvent.event.uid]"
class="schedule-item-button"
>
<ion-label>{{ 'dashboard.schedule.title' | translate }}</ion-label>
<ion-label>
{{ nextEvent.dates | nextDateInList | amDateFormat: 'll, HH:mm' }}
{{ 'timeSuffix' | translate }}
</ion-label>
<ion-label>{{ nextEvent.event.name }}</ion-label>
</a>
<a
*ngIf="!nextEvent || !nextEvent.event"
[routerLink]="['/schedule/recurring']"
class="schedule-item-button"
>
<ion-label>{{ 'dashboard.schedule.title' | translate }}</ion-label>
<ion-label>{{ 'dashboard.schedule.noEvent' | translate }}</ion-label>
<ion-label>{{ 'dashboard.schedule.noEventLink' | translate }}</ion-label>
</a>
</div>
<ion-content>
<div class="scrollable-container">
<stapps-navigation-section></stapps-navigation-section>
<stapps-search-section></stapps-search-section>
<stapps-news-section></stapps-news-section>
<stapps-mensa-section></stapps-mensa-section>
<stapps-favorites-section></stapps-favorites-section>
</div>
<ion-content fullscreen="true" #ionContent>
<stapps-navigation-section></stapps-navigation-section>
<stapps-search-section></stapps-search-section>
<stapps-news-section></stapps-news-section>
<stapps-mensa-section></stapps-mensa-section>
<stapps-favorites-section></stapps-favorites-section>
</ion-content>

View File

@@ -1,23 +1,28 @@
/*!
* Copyright (C) 2022 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
@import '../../../theme/util/mixins';
:host ion-header {
z-index: 1;
}
:host ion-toolbar:last-of-type {
--padding-top: var(--spacing-md);
--padding-bottom: 0;
--padding-bottom: var(--spacing-md);
z-index: -1;
ion-icon {
margin-right: var(--spacing-sm);
@@ -38,65 +43,27 @@
aspect-ratio: 1/1;
object-position: right;
margin-left: auto;
margin-right: var(--spacing-sm);
@include phoneLandscape {
width: auto;
height: 50px;
}
@include phonePortraitSmall {
width: auto;
height: 50px;
}
margin-right: 0;
}
}
ion-content {
--background: var(--ion-color-light);
--overflow: hidden;
.scrollable-container {
overflow: hidden auto;
height: 100%;
padding-top: 122px;
@media (max-width: 440px) {
padding-top: 140px;
}
@include ion-md-up {
padding-top: 0;
padding-bottom: 122px;
}
}
@include phoneLandscape {
--overflow: hidden auto;
.scrollable-container {
overflow: initial;
height: initial;
padding-top: 0;
padding-bottom: 0;
}
}
}
.schedule {
position: fixed;
width: 100%;
z-index: 3;
background: var(--ion-color-primary);
display: flex;
justify-content: space-between;
gap: var(--spacing-md);
padding: var(--spacing-sm) var(--spacing-sm) var(--spacing-xl);
padding: var(--spacing-sm);
padding-top: 0;
@include ion-md-up {
position: unset;
width: unset;
z-index: unset;
height: calc(var(--tablet-top-bar-height) + (2 * var(--spacing-xl)));
margin: 0;
padding: var(--spacing-xl);
@@ -113,22 +80,25 @@ ion-content {
}
a:first-child {
border: 2px solid var(--ion-color-primary-tint);
text-align: center;
flex: 0 0 auto;
aspect-ratio: 1;
box-sizing: content-box;
max-height: 60px;
overflow: hidden;
border: 2px solid var(--ion-color-primary-tint);
@include phoneLandscape {
height: auto;
}
}
a:first-child {
justify-content: space-around;
align-items: center;
gap: var(--spacing-sm);
ion-icon {
margin: auto auto var(--spacing-xs);
}
ion-label {
margin: 0 auto auto;
font-size: var(--font-size-xxs);
font-weight: var(--font-weight-semi-bold);
}
@@ -142,6 +112,7 @@ ion-content {
flex: 1 1 65%;
background: var(--linear-gradient);
justify-content: center;
z-index: 1;
@include ion-md-up {
flex: 1 1 100%;
@@ -156,10 +127,12 @@ ion-content {
font-weight: var(--font-weight-bold);
line-height: 1.4;
}
ion-label:first-child {
text-transform: uppercase;
color: var(--ion-color-secondary);
}
ion-label:nth-child(2n) {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-semi-bold);
@@ -173,6 +146,7 @@ ion-content {
&.section-extended {
padding-right: 0;
ion-icon[name='edit'] {
margin-right: var(--spacing-md);
}
@@ -232,6 +206,7 @@ ion-searchbar {
input {
padding: var(--spacing-lg);
}
ion-icon {
left: auto;
right: var(--spacing-lg);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 StApps
* Copyright (C) 2022 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -12,7 +12,14 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Component, OnInit, OnDestroy} from '@angular/core';
import {
Component,
ElementRef,
NgZone,
OnDestroy,
OnInit,
ViewChild,
} from '@angular/core';
import {Router} from '@angular/router';
import {Location} from '@angular/common';
import {Subscription} from 'rxjs';
@@ -22,11 +29,18 @@ import {SplashScreen} from '@capacitor/splash-screen';
import {DataRoutingService} from '../data/data-routing.service';
import {ScheduleProvider} from '../calendar/schedule.provider';
import {AnimationController, IonContent} from '@ionic/angular';
import {DashboardCollapse} from './dashboard-collapse';
// const scrollTimeline = new ScrollTimeline();
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss'],
styleUrls: [
'./dashboard.component.scss',
'/dashboard.collapse.component.scss',
],
})
export class DashboardComponent implements OnInit, OnDestroy {
/**
@@ -34,6 +48,14 @@ export class DashboardComponent implements OnInit, OnDestroy {
*/
subscriptions: Subscription[] = [];
@ViewChild('toolbar', {read: ElementRef}) toolbarRef: ElementRef;
@ViewChild('schedule', {read: ElementRef}) scheduleRef: ElementRef;
@ViewChild('ionContent') ionContentRef: IonContent;
collapseAnimation: DashboardCollapse;
/**
* UUID subscription
*/
@@ -44,6 +66,11 @@ export class DashboardComponent implements OnInit, OnDestroy {
*/
private uuids: SCUuid[];
/**
* Enable header animation
*/
isHeaderAnimated = true;
/**
* Next event in calendar
*/
@@ -66,6 +93,8 @@ export class DashboardComponent implements OnInit, OnDestroy {
private scheduleProvider: ScheduleProvider,
protected router: Router,
public location: Location,
private animationControl: AnimationController,
private zone: NgZone,
) {
this.subscriptions.push(
this.dataRoutingService.itemSelectListener().subscribe(item => {
@@ -82,6 +111,14 @@ export class DashboardComponent implements OnInit, OnDestroy {
},
);
await SplashScreen.hide();
this.collapseAnimation = new DashboardCollapse(
this.animationControl,
this.zone,
await this.ionContentRef.getScrollElement(),
this.toolbarRef.nativeElement,
this.scheduleRef.nativeElement,
);
}
async loadNextEvent() {
@@ -103,5 +140,6 @@ export class DashboardComponent implements OnInit, OnDestroy {
sub.unsubscribe();
}
this._uuidSubscription.unsubscribe();
this.collapseAnimation.destroy();
}
}

View File

@@ -17,7 +17,7 @@
:host {
display: block;
padding: var(--spacing-md) var(--spacing-md) var(--spacing-sm);
padding: var(--spacing-sm) var(--spacing-md) var(--spacing-sm);
@include ion-md-up {
padding: var(--spacing-lg) var(--spacing-xxl) var(--spacing-sm);
@@ -40,28 +40,13 @@
}
}
// TODO
&:first-of-type {
padding-top: var(--spacing-lg);
}
& > ion-label:first-child {
font-family: var(--headline-font-family);
font-size: var(--font-size-lg);
font-weight: var(--font-weight-bold);
font-stretch: condensed;
text-transform: uppercase;
margin-bottom: var(--spacing-xs);
width: 100%;
display: flex;
flex-direction: revert;
justify-content: space-between;
ion-icon {
color: var(--ion-color-medium-shade);
position: relative;
bottom: var(--spacing-sm);
margin-block: auto;
cursor: pointer;

View File

@@ -43,10 +43,10 @@ export class NewsSectionComponent extends NewsPageComponent implements OnInit {
enabled: true,
sticky: true,
},
width: 240,
width: 300,
breakpoints: {
768: {
width: 280,
width: 380,
},
},
};

View File

@@ -26,7 +26,8 @@
[(ngModel)]="searchTerm"
></ion-input>
<ion-icon
size="25"
size="35"
weight="300"
name="search"
(click)="onSubmitSearch()"
class="clickable"

View File

@@ -25,6 +25,7 @@
--padding-top: var(--spacing-xl);
--padding-bottom: var(--spacing-xl);
font-size: var(--font-size-xs);
--placeholder-font-weight: var(--font-weight-bold);
box-shadow: var(--shadow-default);
}
ion-icon {

View File

@@ -22,7 +22,6 @@
bottom: 0;
left: 0;
right: 0;
border-top: 1px solid var(--ion-color-medium);
max-height: calc(var(--ion-tabbar-height) + env(safe-area-inset-bottom));
padding-bottom: env(safe-area-inset-bottom);

View File

@@ -17,7 +17,7 @@
}
.swiper-button-prev, .swiper-button-next {
--swiper-navigation-size: 20px;
top: calc(-1 * var(--spacing-xxl));
top: calc(-1 * var(--spacing-lg));
transform: translateY(0%);
font-weight: var(--font-weight-black);
color: var(--ion-color-dark);

View File

@@ -3,7 +3,7 @@
font-weight: var(--font-weight-black);
font-stretch: condensed;
text-transform: uppercase;
margin-bottom: var(--spacing-xs);
margin-bottom: var(--spacing-sm);
width: 100%;
display: flex;