mirror of
https://github.com/CaramelFur/Picsur.git
synced 2026-05-07 10:07:29 +02:00
improve speeddial
This commit is contained in:
@@ -2,13 +2,22 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { FabComponent } from './normal/fab.component';
|
||||
import { SpeedDialOptionDirective } from './speed-dial/speed-dial-option.directive';
|
||||
import { SpeedDialComponent } from './speed-dial/speed-dial.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [FabComponent, SpeedDialComponent],
|
||||
imports: [CommonModule, MatIconModule, MatButtonModule],
|
||||
declarations: [FabComponent, SpeedDialComponent, SpeedDialOptionDirective],
|
||||
imports: [CommonModule, MatIconModule, MatButtonModule, MatTooltipModule],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
exports: [FabComponent, SpeedDialComponent],
|
||||
exports: [
|
||||
FabComponent,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
SpeedDialComponent,
|
||||
SpeedDialOptionDirective,
|
||||
],
|
||||
})
|
||||
export class FabModule {}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div class="fabholder">
|
||||
<div class="fab-wrapper">
|
||||
<button
|
||||
mat-fab
|
||||
[color]="color"
|
||||
class="fabposition fullanimate mat-elevation-z6"
|
||||
class="fab-position fullanimate mat-elevation-z6"
|
||||
(click)="onClick()"
|
||||
aria-label=""
|
||||
>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Directive, Host, Optional } from '@angular/core';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
|
||||
@Directive({
|
||||
selector: 'speed-dial (button[mat-mini-fab], button[mat-fab])',
|
||||
})
|
||||
export class SpeedDialOptionDirective {
|
||||
constructor(@Host() @Optional() test?: MatTooltip) {
|
||||
if (test) test.position = 'left';
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,13 @@ import {
|
||||
|
||||
export const SpeedDialAnimation = trigger('speedDialAnimation', [
|
||||
transition(':enter', [
|
||||
query('button', [
|
||||
query('[mat-mini-fab]', [
|
||||
style({ transform: 'scale(0)' }),
|
||||
stagger(-50, [animate(100, style({ transform: 'scale(1)' }))]),
|
||||
]),
|
||||
]),
|
||||
transition(':leave', [
|
||||
query('button', [
|
||||
query('[mat-mini-fab]', [
|
||||
style({ transform: 'scale(1)' }),
|
||||
stagger(50, [animate(150, style({ transform: 'scale(0)' }))]),
|
||||
]),
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
<div class="fabholder">
|
||||
<div class="fab-wrapper">
|
||||
<div
|
||||
class="fabposition"
|
||||
class="fab-position"
|
||||
(mouseenter)="enter()"
|
||||
(mouseleave)="leave()"
|
||||
[class.speeddial-is-open]="isOpen"
|
||||
[class.speed-dial-is-open]="isOpen"
|
||||
>
|
||||
<div class="speeddial-options" [@speedDialAnimation] (@speedDialAnimation.done)="done()" *ngIf="isOpen">
|
||||
<button mat-mini-fab color="primary">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<button mat-mini-fab color="primary">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button class="pog" mat-mini-fab color="primary">
|
||||
<mat-icon>filter_list</mat-icon>
|
||||
</button>
|
||||
<div
|
||||
class="speed-dial-options"
|
||||
[@speedDialAnimation]
|
||||
(@speedDialAnimation.start)="animStart()"
|
||||
(@speedDialAnimation.done)="animDone()"
|
||||
*ngIf="isOpen"
|
||||
>
|
||||
<ng-content select="[mat-mini-fab]"></ng-content>
|
||||
</div>
|
||||
|
||||
<button
|
||||
mat-fab
|
||||
[color]="color"
|
||||
class="fullanimate mat-elevation-z6"
|
||||
class="speed-dial-main-button fullanimate mat-elevation-z6"
|
||||
[matTooltip]="tooltip"
|
||||
[matTooltipDisabled]="!isOpen"
|
||||
(click)="click()"
|
||||
aria-label=""
|
||||
>
|
||||
<mat-icon
|
||||
[class.icon-rotate]="iconHover === undefined"
|
||||
[class.icon-main]="iconHover !== undefined"
|
||||
class="icon-main"
|
||||
fontSet="material-icons-outlined"
|
||||
[aria-label]="ariaLabel"
|
||||
>
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
.mat-button-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.icon-main {
|
||||
opacity: 1;
|
||||
}
|
||||
.icon-hover {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.speeddial-is-open {
|
||||
.icon-main {
|
||||
opacity: 0;
|
||||
}
|
||||
.icon-hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.icon-rotate {
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.speeddial-options {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
|
||||
& > * {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
@@ -1,44 +1,77 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, Input, Output } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { SpeedDialAnimation } from './speed-dial.animation';
|
||||
|
||||
@Component({
|
||||
selector: 'speed-dial',
|
||||
templateUrl: './speed-dial.component.html',
|
||||
styleUrls: ['./speed-dial.component.scss'],
|
||||
animations: [SpeedDialAnimation],
|
||||
})
|
||||
export class SpeedDialComponent {
|
||||
@Input('aria-label') ariaLabel: string = 'Floating Action Button';
|
||||
|
||||
@Input('icon') icon: string = 'add';
|
||||
@Input('icon-hover') iconHover: string | undefined;
|
||||
@Input('icon-hover') iconHover: string = 'close';
|
||||
@Input('color') color: string = 'accent';
|
||||
@Input('open-on-hover') openOnHover: boolean = true;
|
||||
@Input('open-on-hover') openOnHover: boolean = false;
|
||||
@Input('tooltip') tooltip: string;
|
||||
|
||||
@Output('main-click') clickEmitter = new Subject<void>();
|
||||
|
||||
public isOpen = false;
|
||||
|
||||
private isAnimating = true;
|
||||
private wantsOpen = false;
|
||||
private _isAnimating = false;
|
||||
private _wantsOpen = false;
|
||||
|
||||
constructor() {}
|
||||
private set isAnimating(val: boolean) {
|
||||
this._isAnimating = val;
|
||||
if (val === false && this._wantsOpen !== this.isOpen) {
|
||||
this.isOpen = this._wantsOpen;
|
||||
}
|
||||
}
|
||||
|
||||
private set wantsOpen(val: boolean) {
|
||||
this._wantsOpen = val;
|
||||
if (!this._isAnimating) {
|
||||
this.isOpen = val;
|
||||
}
|
||||
}
|
||||
|
||||
click() {
|
||||
this.isOpen = !this.isOpen;
|
||||
if (this._isAnimating) return;
|
||||
|
||||
this.wantsOpen = !this._wantsOpen;
|
||||
|
||||
if (this._wantsOpen === false) {
|
||||
this.clickEmitter.next();
|
||||
}
|
||||
}
|
||||
|
||||
enter() {
|
||||
if (this.openOnHover) {
|
||||
this.isOpen = true;
|
||||
this.wantsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
leave() {
|
||||
if (this.openOnHover) {
|
||||
this.isOpen = false;
|
||||
this.wantsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
done() {
|
||||
console.log('done');
|
||||
animStart() {
|
||||
this.isAnimating = true;
|
||||
}
|
||||
|
||||
animDone() {
|
||||
this.isAnimating = false;
|
||||
}
|
||||
|
||||
open() {
|
||||
this.wantsOpen = true;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.wantsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,7 @@
|
||||
<copy-field label="Rst" [value]="imageLinks.rst"></copy-field>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button
|
||||
mat-raised-button
|
||||
class="m-1"
|
||||
color="accent"
|
||||
(click)="downloadImage()"
|
||||
>
|
||||
<button mat-raised-button class="m-1" color="accent" (click)="download()">
|
||||
Download
|
||||
</button>
|
||||
|
||||
@@ -45,4 +40,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<speed-dial></speed-dial>
|
||||
<speed-dial
|
||||
icon="menu"
|
||||
icon-hover="download"
|
||||
tooltip="Download the image"
|
||||
[open-on-hover]="true"
|
||||
(main-click)="download()"
|
||||
#speedDial
|
||||
>
|
||||
<button
|
||||
mat-mini-fab
|
||||
matTooltip="Close menu"
|
||||
color="primary"
|
||||
(click)="speedDial.close()"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<button mat-mini-fab matTooltip="Info about the action" color="primary">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button mat-mini-fab matTooltip="Info about the action" color="primary">
|
||||
<mat-icon>filter_list</mat-icon>
|
||||
</button>
|
||||
</speed-dial>
|
||||
|
||||
@@ -35,7 +35,7 @@ export class ViewComponent implements OnInit {
|
||||
this.imageLinks = this.imageService.CreateImageLinksFromID(id);
|
||||
}
|
||||
|
||||
downloadImage() {
|
||||
download() {
|
||||
this.utilService.downloadFile(this.imageLinks.source);
|
||||
}
|
||||
|
||||
|
||||
72
frontend/src/scss/fab.scss
Normal file
72
frontend/src/scss/fab.scss
Normal file
@@ -0,0 +1,72 @@
|
||||
@use "../node_modules/bootstrap/scss/bootstrap-grid.scss" as bs;
|
||||
|
||||
// Fabs
|
||||
.fab-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.fab-position {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
z-index: 8;
|
||||
|
||||
@include bs.media-breakpoint-down(xxl) {
|
||||
right: 4rem;
|
||||
}
|
||||
|
||||
@include bs.media-breakpoint-down(xl) {
|
||||
right: 2rem;
|
||||
}
|
||||
|
||||
@include bs.media-breakpoint-up(xl) {
|
||||
bottom: 4rem;
|
||||
}
|
||||
|
||||
@include bs.media-breakpoint-up(xxl) {
|
||||
transform: translateX(3rem);
|
||||
}
|
||||
}
|
||||
|
||||
.speed-dial-options {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
|
||||
padding-bottom: 1rem;
|
||||
|
||||
[mat-mini-fab] {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.speed-dial-main-button {
|
||||
mat-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-main {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.icon-hover {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%) rotate(-45deg);
|
||||
}
|
||||
|
||||
.speed-dial-is-open {
|
||||
.icon-main {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
}
|
||||
.icon-hover {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
@use "./material/material-theme.scss";
|
||||
@use "./fixes.scss";
|
||||
@use "./personal.scss";
|
||||
@use "./fab.scss";
|
||||
@use "./snackbar.scss";
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
@use "../node_modules/bootstrap/scss/bootstrap-grid.scss" as bs;
|
||||
|
||||
// Create white border around content
|
||||
.content-border {
|
||||
border-radius: 20px;
|
||||
@@ -48,34 +46,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Fabs
|
||||
.fabholder {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
& .fabposition {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
z-index: 8;
|
||||
|
||||
@include bs.media-breakpoint-down(xxl) {
|
||||
right: 4rem;
|
||||
}
|
||||
|
||||
@include bs.media-breakpoint-down(xl) {
|
||||
right: 2rem;
|
||||
}
|
||||
|
||||
@include bs.media-breakpoint-up(xl) {
|
||||
bottom: 4rem;
|
||||
}
|
||||
|
||||
@include bs.media-breakpoint-up(xxl) {
|
||||
transform: translateX(3rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Anim
|
||||
|
||||
.container,
|
||||
|
||||
Reference in New Issue
Block a user