This repository has been archived by the owner on Jan 12, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
Rewrite suggestion #49
Open
chrillewoodz
wants to merge
2
commits into
Viczei:master
Choose a base branch
from
chrillewoodz:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+829
−0
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
62 changes: 62 additions & 0 deletions
62
src/components/swipe-cards/shared/components/card.component.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
.card-wrapper { | ||
width: 100%; | ||
height: 100%; | ||
} | ||
|
||
:host { | ||
transition: transform 1s ease; | ||
position: absolute; | ||
border-radius: 2px; | ||
border: 1px solid white; | ||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !important; | ||
transition: transform 0.2s ease; | ||
background-color: white; | ||
touch-action: none !important; | ||
} | ||
|
||
:host(.card-heap) { | ||
transition: transform 1s ease; | ||
display: block; | ||
position: absolute; | ||
background-color: white; | ||
box-shadow: 0 0 0 rgba(0, 0, 0, 0) !important; | ||
transform: perspective(400px) translate3d(0, 30px, -30px); | ||
visibility: hidden; | ||
} | ||
|
||
:host(.card-heap):nth-child(1) { | ||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !important; | ||
z-index:3; | ||
visibility: visible; | ||
transform: perspective(400px) translate3d(0, 0px, 0px); | ||
} | ||
|
||
:host(.card-heap):nth-child(2) { | ||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !important; | ||
z-index:2; | ||
visibility: visible; | ||
transform: perspective(400px) translate3d(0, 30px, -30px); | ||
} | ||
|
||
:host(.card-heap):nth-child(3) { | ||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !important; | ||
z-index:1; | ||
visibility: visible; | ||
transform: perspective(400px) translate3d(0, 60px, -60px); | ||
} | ||
|
||
:host .card-overlay { | ||
transform: translateZ(0); | ||
opacity: 0; | ||
border-radius: 2px; | ||
position: absolute; | ||
width: 100%; | ||
height: 10px; | ||
top: 0; | ||
left: 0; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
overflow: hidden; | ||
color: white; | ||
} |
4 changes: 4 additions & 0 deletions
4
src/components/swipe-cards/shared/components/card.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<div class="card-wrapper"> | ||
<ng-content></ng-content> | ||
<div #overlay class="card-overlay"></div> | ||
</div> |
255 changes: 255 additions & 0 deletions
255
src/components/swipe-cards/shared/components/card.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
import { | ||
AfterViewChecked, | ||
ChangeDetectionStrategy, | ||
ChangeDetectorRef, | ||
Component, | ||
ElementRef, | ||
EventEmitter, | ||
HostBinding, | ||
HostListener, | ||
Input, | ||
OnDestroy, | ||
OnInit, | ||
Output, | ||
Renderer2, | ||
ViewChild | ||
} from '@angular/core'; | ||
|
||
import {Subscription} from 'rxjs/Subscription'; | ||
import 'rxjs/add/operator/filter'; | ||
|
||
import {SwipeCardsApi} from '@components/swipe-cards/shared/services/swipe-cards-api.service'; | ||
|
||
@Component({ | ||
moduleId: module.id, | ||
selector: 'card', | ||
templateUrl: './card.component.html', | ||
styleUrls: ['./card.component.css'], | ||
changeDetection: ChangeDetectionStrategy.OnPush | ||
}) | ||
|
||
export class CardComponent implements AfterViewChecked, OnInit, OnDestroy { | ||
@Input() card: any; | ||
@Input() cardElement: any; | ||
@Input() position: number; | ||
@Input() beforeSwipeAction: (event: any) => boolean; | ||
|
||
@Input() set config(config) { | ||
|
||
if (config) { | ||
this._config = config; | ||
} | ||
} | ||
|
||
@Input() set orientation(value: string) { | ||
this._orientation = value || 'xy'; | ||
} | ||
|
||
get config() { | ||
return this._config; | ||
} | ||
|
||
get orientation() { | ||
return this._orientation; | ||
} | ||
|
||
@Output() onLike: EventEmitter<any> = new EventEmitter<any>(); | ||
@Output() onDislike: EventEmitter<any> = new EventEmitter<any>(); | ||
@Output() onRelease: EventEmitter<any> = new EventEmitter<any>(); | ||
@Output() onSwipe: EventEmitter<any> = new EventEmitter<any>(); | ||
@Output() onAbort: EventEmitter<any> = new EventEmitter<any>(); | ||
@Output() onDisallowed: EventEmitter<any> = new EventEmitter<any>(); | ||
@Output() onSpecial: EventEmitter<any> = new EventEmitter<any>(); | ||
@Output() removeCard: EventEmitter<any> = new EventEmitter<any>(); | ||
@ViewChild('overlay') overlay: ElementRef; | ||
|
||
public releaseRadius: any; | ||
public released: Boolean = false; | ||
public element: HTMLElement; | ||
|
||
public direction: any = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
|
||
private _config: any; | ||
private _orientation = 'xy'; | ||
|
||
private swipeActionSubscription: Subscription; | ||
|
||
@HostBinding('class.card-heap') isCardHeapClass = true; | ||
|
||
@HostListener('pan', ['$event']) | ||
onPan(event: any) { | ||
|
||
if (!this.config.fixed && !this.released && this.position === 0) { | ||
this.onSwipeCb(event); | ||
} | ||
} | ||
|
||
@HostListener('panend', ['$event']) | ||
onPanEnd(event: any) { | ||
|
||
if (!this.config.fixed && !this.released && this.position === 0) { | ||
|
||
if ((this._orientation === 'x' && (this.releaseRadius.x < event.deltaX || this.releaseRadius.x * -1 > event.deltaX)) || (this._orientation === 'y' && (this.releaseRadius.y < event.deltaY || this.releaseRadius.y * -1 > event.deltaY)) || ((this.releaseRadius.x < event.deltaX || this.releaseRadius.x * -1 > event.deltaX) || (this.releaseRadius.y < event.deltaY || this.releaseRadius.y * -1 > event.deltaY))) { | ||
this.onReleaseCb(event); | ||
} | ||
else { | ||
this.onAbortCb(event); | ||
} | ||
} | ||
} | ||
|
||
constructor( | ||
private cd: ChangeDetectorRef, | ||
protected el: ElementRef, | ||
private renderer: Renderer2, | ||
private swipeCardsApi: SwipeCardsApi | ||
) {} | ||
|
||
ngOnInit() { | ||
|
||
this.element = this.el.nativeElement; | ||
|
||
this.swipeActionSubscription = this.swipeCardsApi.swipeAction$ | ||
.filter(() => this.position === 0) | ||
.subscribe((options: any) => { | ||
|
||
if (this.beforeSwipeAction) { | ||
|
||
const canProceedWithAction: boolean = this.beforeSwipeAction({action: options.action, card: this.card}); | ||
|
||
if (canProceedWithAction) { | ||
this.onAction(options.action, options.direction); | ||
} | ||
else { | ||
this.onDisallowed.emit({action: options.action, card: this.card}); | ||
} | ||
} | ||
else { | ||
this.onAction(options.action, options.direction); | ||
} | ||
} | ||
); | ||
} | ||
|
||
ngAfterViewChecked() { | ||
|
||
if (this.element.parentElement) { | ||
|
||
const height = this.element.parentElement.clientHeight; | ||
const width = this.element.parentElement.clientWidth; | ||
|
||
this.renderer.setStyle(this.element, 'height', height + 'px'); | ||
this.renderer.setStyle(this.element, 'width', width + 'px'); | ||
|
||
this.releaseRadius = { | ||
x: width / 4, | ||
y: height / 4 | ||
}; | ||
} | ||
} | ||
|
||
ngOnDestroy() { | ||
this.swipeActionSubscription.unsubscribe(); | ||
} | ||
|
||
translate(params: any) { | ||
|
||
if (!this.config.fixed) { | ||
this.renderer.setStyle(this.element, 'transition', 'transform ' + (params.time || 0) + 's ease'); | ||
this.renderer.setStyle(this.element, 'webkitTransform', `translate3d(${(params.x && (!this._orientation || this._orientation.indexOf('x') !== -1) ? (params.x) : 0)}px, ${(params.y && (!this._orientation || this._orientation.indexOf('y') !== -1) ? (params.y) : 0)}px, 0) rotate(${params.rotate || 0}deg)`); | ||
} | ||
} | ||
|
||
onSwipeCb(event: any) { | ||
|
||
const like = (this.orientation === 'y' && event.deltaY < 0) || (this.orientation !== 'y' && event.deltaX > 0); | ||
const opacity = (event.distance < 0 ? event.distance * -1 : event.distance) * 0.5 / this.element.offsetWidth; | ||
|
||
if (!!this.config.overlay) { | ||
|
||
this.renderer.setStyle(this.overlay.nativeElement, 'transition', 'opacity 0s ease'); | ||
this.renderer.setStyle(this.overlay.nativeElement, 'opacity', opacity.toString()); | ||
this.renderer.setStyle(this.overlay.nativeElement, 'background-color', this.config.overlay[like ? 'like' : 'dislike'].backgroundColor); | ||
} | ||
|
||
this.translate({ | ||
x: event.deltaX, | ||
y: event.deltaY, | ||
rotate: ((event.deltaX * 20) / this.element.clientWidth) | ||
}); | ||
|
||
this.onSwipe.emit(event); | ||
} | ||
|
||
onAbortCb(event: any): void { | ||
|
||
if (!!this.config.overlay) { | ||
this.renderer.setStyle(this.overlay.nativeElement, 'transition', 'opacity 0.2s ease'); | ||
this.renderer.setStyle(this.overlay.nativeElement, 'opacity', '0'); | ||
} | ||
|
||
this.translate({ | ||
x: 0, | ||
y: 0, | ||
rotate: 0, | ||
time: 0.2 | ||
}); | ||
|
||
this.onAbort.emit(event); | ||
} | ||
|
||
onReleaseCb(event: any): void { | ||
|
||
this.released = true; | ||
|
||
const like = (this.orientation === 'y' && event.deltaY < 0) || (this.orientation !== 'y' && event.deltaX > 0); | ||
|
||
if (this.beforeSwipeAction) { | ||
|
||
const canProceedWithAction: boolean = this.beforeSwipeAction({action: like ? 'like' : 'dislike', card: this.card}); | ||
|
||
if (canProceedWithAction) { | ||
this.onAction(like ? 'like' : 'dislike', like ? 'right' : 'left'); | ||
} | ||
else { | ||
this.onDisallowed.emit({action: like ? 'like' : 'dislike', card: this.card}); | ||
} | ||
} | ||
else { | ||
this.onAction(like ? 'like' : 'dislike', like ? 'right' : 'left'); | ||
} | ||
|
||
this.onRelease.emit(event); | ||
} | ||
|
||
onAction(action: string, direction: string): void { | ||
|
||
const el = this.element; | ||
const x = (el.offsetWidth + el.clientWidth) * (direction === 'right' ? 1 : -1); | ||
const y = (el.offsetHeight + el.clientHeight) * (direction === 'right' ? -1 : 1); | ||
|
||
this.translate({ | ||
x: x, | ||
y: y, | ||
rotate: (x * 20) / el.clientWidth, | ||
time: 0.8 | ||
}); | ||
|
||
this.renderer.setStyle(this.overlay.nativeElement, 'transition', 'opacity 0.4s ease'); | ||
this.renderer.setStyle(this.overlay.nativeElement, 'opacity', '0.5'); | ||
this.renderer.setStyle(this.overlay.nativeElement, 'background-color', this.config.overlay[action].backgroundColor); | ||
|
||
switch (action) { | ||
case 'like': this.onLike.emit({like: true, card: this.card}); break; | ||
case 'dislike': this.onDislike.emit({like: false, card: this.card}); break; | ||
case 'special': this.onSpecial.emit({special: true, card: this.card}); break; | ||
} | ||
|
||
setTimeout(() => { | ||
this.removeCard.emit(this.card); | ||
}, 200); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/components/swipe-cards/shared/components/card.module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import {NgModule} from '@angular/core'; | ||
import {CommonModule} from '@angular/common'; | ||
|
||
import {CardComponent} from './card.component'; | ||
|
||
@NgModule({ | ||
imports: [ | ||
CommonModule | ||
], | ||
exports: [ | ||
CardComponent | ||
], | ||
declarations: [ | ||
CardComponent | ||
] | ||
}) | ||
|
||
export class CardModule {} |
25 changes: 25 additions & 0 deletions
25
src/components/swipe-cards/shared/directives/action.directive.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import {Directive, Input, HostListener} from '@angular/core'; | ||
|
||
import {SwipeCardsApi} from '@components/swipe-cards/shared/services/swipe-cards-api.service'; | ||
|
||
@Directive({ | ||
selector: '[swipeCardsAction]' | ||
}) | ||
|
||
export class ActionDirective { | ||
@Input() action: string; | ||
@Input() direction: string; | ||
@Input() beforeSwipeAction: () => boolean; | ||
|
||
constructor(private swipeCardsApi: SwipeCardsApi) {} | ||
|
||
@HostListener('click') | ||
swipeCard(): void { | ||
|
||
this.swipeCardsApi.swipe({ | ||
action: this.action, | ||
beforeSwipeAction: this.beforeSwipeAction, | ||
direction: this.direction | ||
}); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the use of the 'special' action? It seems to have no behaviors in the components apart from sending a callback with the card element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's supposed to be like a "super like" or whatever you want it to be. I've got some ideas how we can make this better, by instead of having like/dislike etc we have left/right/top/bottom swipes instead. And then you can decide on your own what you want each direction to do. This would make it really easy to customise the behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now it only fires from a button using a directive. That's why you can't see any behaviour attached to it, it basically just changes the overlay color.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you mean, so the special is just an example and we can add for example left, top, ... etc actions
It's indeed more logical than a like or dislike which would not always be the use of a tinder card even if the most common
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the plan is to make left/right/top/bottom actions, wouldn't it be better to make action and direction the same argument for the function?
And treat "like" as a "right" and "dislike" as a "left", in order to prevent regressions for current behaviors.
I don't really see the advantages of the "special", if it's needed to change the overlay component, i think it's already possible through the config input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we specify exactly what we want to do it'll be easier to understand. The action should indeed be left, right etc. instead of like/dislike. I don't think we need to think a lot about regression since the repo isn't that big yet. Now we have the chance to make it right :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes i think too that we should specify a bit all this. I also had plans for the future by adding a drag and drop system to cards (tinder cards beeing a drag and drop system)
I did begin a work on the branch card-grid