Fix bugs
This commit is contained in:
parent
e96ac49c8e
commit
e992152a75
28 changed files with 289 additions and 79 deletions
|
|
@ -7,8 +7,8 @@
|
|||
<!-- wrapper for easier styling -->
|
||||
<app-select-add
|
||||
class="select"
|
||||
[options]="modalService.active.input"
|
||||
[default]="modalService.active.input[0]"
|
||||
[options]="modalService.active.input.options"
|
||||
[default]="modalService.active.input.options[0]"
|
||||
[alwaysDropShadow]="true"
|
||||
[onlyShadowBorder]="true"
|
||||
[placeholder]="'Tag this item…'"
|
||||
|
|
@ -24,10 +24,10 @@
|
|||
<app-toggle
|
||||
[beforeText]="'This task hasn\'t been finished yet'"
|
||||
[afterText]="'Goal already accomplished'"
|
||||
[default]="false"
|
||||
[default]="!modalService.active.input.isTask"
|
||||
(value)="isDone = $event"
|
||||
></app-toggle>
|
||||
</div>
|
||||
<!-- wrapper for easier styling -->
|
||||
|
||||
<button (click)="submit()">Create</button>
|
||||
<button (click)="submit()" [disabled]="!selected">Create</button>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ export class CreateBlockComponent {
|
|||
constructor(public modalService: ModalService) {}
|
||||
|
||||
submit() {
|
||||
if (!this.selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.modalService.submit({
|
||||
selected: this.selected,
|
||||
description: this.description,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
</section>
|
||||
|
||||
<img
|
||||
*ngIf="isDragging"
|
||||
[ngClass]="isDragging ? 'active' : ''"
|
||||
src="assets/trash.svg"
|
||||
alt="trashcan"
|
||||
(pointerenter)="trashEnter()"
|
||||
|
|
@ -24,9 +24,9 @@
|
|||
(pointerup)="removeTower()"
|
||||
/>
|
||||
|
||||
<div class="double-slider-container">
|
||||
<div class="double-slider-container" [ngStyle]="{ opacity: isDragging ? '0' : '1' }">
|
||||
<app-double-slider
|
||||
*ngIf="!isDragging && dates.length >= MIN_BLOCK_COUNT_BEFORE_SHOWING_SLIDER"
|
||||
*ngIf="dates.length >= MIN_BLOCK_COUNT_BEFORE_SHOWING_SLIDER"
|
||||
[values]="dates"
|
||||
[labels]="dateLabels"
|
||||
(lowerBound)="startDate = $event"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
flex: 1 0 auto;
|
||||
|
||||
|
|
@ -28,7 +30,33 @@
|
|||
}
|
||||
}
|
||||
|
||||
@include inner-spacing(var(--medium-padding), $horizontal: true);
|
||||
max-width: 800px;
|
||||
|
||||
& > * {
|
||||
max-width: 200px;
|
||||
box-sizing: content-box;
|
||||
flex: 0 0 auto;
|
||||
|
||||
&:not(:nth-last-child(1)) {
|
||||
margin-right: var(--medium-padding);
|
||||
@media (max-width: $mobile-width) {
|
||||
margin-right: var(--small-padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
position: relative;
|
||||
|
||||
@for $i from 1 to 6 {
|
||||
& > *:first-child:nth-last-child(#{$i}),
|
||||
& > *:first-child:nth-last-child(#{$i}) ~ * {
|
||||
width: calc((100% - (#{$i} - 1) * var(--medium-padding)) / #{$i});
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
width: calc((100% - (#{$i} - 1) * var(--small-padding)) / #{$i});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.double-slider-container {
|
||||
|
|
@ -38,16 +66,25 @@
|
|||
}
|
||||
|
||||
img {
|
||||
@include square(47.33333px);
|
||||
padding: 47.3333px 0;
|
||||
margin: auto;
|
||||
@include square(48px);
|
||||
padding: 16px;
|
||||
|
||||
position: relative;
|
||||
position: absolute;
|
||||
z-index: 1500;
|
||||
bottom: 8px;
|
||||
left: 50%;
|
||||
margin: 0 !important;
|
||||
|
||||
transform: translateX(-50%) scale(0);
|
||||
|
||||
transition: transform $long-animation-time;
|
||||
|
||||
&.active {
|
||||
transform: translateX(-50%) scale(1);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
transform: translateX(-50%) scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, Input } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Page } from '../../../model/page';
|
||||
import { ModalService } from '../../../services/modal.service';
|
||||
import { DataService } from '../../../services/data.service';
|
||||
|
|
@ -20,6 +20,8 @@ export class PageComponent {
|
|||
this.updateDates();
|
||||
}
|
||||
|
||||
@Output() isDragHappening: EventEmitter<boolean> = new EventEmitter();
|
||||
|
||||
get page(): Page {
|
||||
return this._page;
|
||||
}
|
||||
|
|
@ -59,11 +61,13 @@ export class PageComponent {
|
|||
dropDrag(event: any) {
|
||||
this.page.moveTower(event);
|
||||
this.isDragging = false;
|
||||
this.isDragHappening.emit(false);
|
||||
}
|
||||
|
||||
startDrag(id: number) {
|
||||
this.draggedTowerIndex = id;
|
||||
this.isDragging = true;
|
||||
this.isDragHappening.emit(true);
|
||||
}
|
||||
|
||||
trashEnter() {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
<div class="container">
|
||||
<div class="container {{ tasks.length > 0 ? 'show-hover' : '' }}">
|
||||
<p class="header" (click)="isOpen = !isOpen">
|
||||
{{ tasks.length == 0 ? 'no' : '' }}
|
||||
<strong>
|
||||
{{ tasks.length == 0 ? '' : tasks.length }}
|
||||
</strong>
|
||||
{{ tasks.length == 1 ? 'task' : 'tasks' }}
|
||||
{{ tasks.length == 0 ? '​' : tasks.length == 1 ? 'task' : 'tasks' }}
|
||||
</p>
|
||||
<div class="all-task" #allTask [ngStyle]="{ height: (isOpen ? allTask?.scrollHeight : 0) + 'px' }">
|
||||
<p
|
||||
*ngFor="let task of tasks"
|
||||
(click)="handleClick(task)"
|
||||
[innerText]="task.description ? task.description : 'unknown'"
|
||||
></p>
|
||||
<div class="task-container" *ngFor="let task of tasks" [ngStyle]="{ color: task.color.toString() }">
|
||||
<div [ngStyle]="{ 'background-color': task.color.toString() }"></div>
|
||||
<p (click)="handleClick(task)" [innerText]="task.description ? task.description : 'unknown'"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,12 +3,20 @@
|
|||
:host {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
z-index: 100000;
|
||||
|
||||
.container {
|
||||
@include card();
|
||||
box-shadow: $shadow-border;
|
||||
padding: var(--small-padding);
|
||||
margin: var(--small-padding);
|
||||
|
||||
cursor: pointer;
|
||||
transition: box-shadow $long-animation-time;
|
||||
&.show-hover:hover {
|
||||
box-shadow: $shadow-border;
|
||||
}
|
||||
|
||||
padding: calc(var(--small-padding) / 2);
|
||||
margin: calc(var(--small-padding) / 2);
|
||||
|
||||
max-height: 30vh;
|
||||
overflow-y: auto;
|
||||
|
|
@ -18,7 +26,6 @@
|
|||
}
|
||||
|
||||
p {
|
||||
width: 100%;
|
||||
font-size: var(--medium-font-size);
|
||||
}
|
||||
|
||||
|
|
@ -29,23 +36,43 @@
|
|||
margin-top: var(--small-padding);
|
||||
}
|
||||
|
||||
width: 100%;
|
||||
height: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
transition: height $long-animation-time;
|
||||
overflow-y: hidden;
|
||||
|
||||
height: 0;
|
||||
transition: height $long-animation-time;
|
||||
|
||||
p {
|
||||
max-width: 60px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
text-align: left;
|
||||
.task-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
font-weight: bold;
|
||||
p {
|
||||
@media (min-width: $mobile-width) {
|
||||
color: inherit !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
flex: 0 0 auto;
|
||||
margin: 0 calc(var(--small-padding) / 2) 0 0;
|
||||
@include square(var(--small-padding));
|
||||
@media (max-width: $mobile-width) {
|
||||
@include square(calc(var(--small-padding) / 2));
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
text-align: left;
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
font-size: var(--small-font-size);
|
||||
}
|
||||
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
|
|||
import { Block } from '../../../../../model/block';
|
||||
import { Tower } from '../../../../../model/tower';
|
||||
import { ModalService } from '../../../../../services/modal.service';
|
||||
import { CancelService } from '../../../../../services/cancel.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tasks',
|
||||
|
|
@ -12,11 +13,25 @@ export class TasksComponent implements OnInit {
|
|||
@Input() tasks: Block[];
|
||||
@Input() tower: Tower;
|
||||
|
||||
@Input() isOpen = false;
|
||||
private _isOpen = false;
|
||||
@Input() set isOpen(value: boolean) {
|
||||
if (value) {
|
||||
this.cancelService.cancelAllExcept(this);
|
||||
}
|
||||
this._isOpen = value;
|
||||
}
|
||||
|
||||
get isOpen(): boolean {
|
||||
return this._isOpen;
|
||||
}
|
||||
|
||||
@ViewChild('allTask') allTask: ElementRef;
|
||||
|
||||
constructor(private modalService: ModalService) {}
|
||||
constructor(private modalService: ModalService, private cancelService: CancelService) {
|
||||
this.cancelService.subscribe(this, () => {
|
||||
this.isOpen = false;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
|
|
@ -39,4 +54,16 @@ export class TasksComponent implements OnInit {
|
|||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
public async addTask() {
|
||||
try {
|
||||
const { selected: tag, description, isDone } = await this.modalService.showCreateBlock({
|
||||
options: this.tower.tags,
|
||||
isTask: true
|
||||
});
|
||||
this.tower.addBlock({ tag, description, isDone });
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<input
|
||||
id="tower-name"
|
||||
type="text"
|
||||
placeholder="…"
|
||||
placeholder="name…"
|
||||
[(ngModel)]="tower.name"
|
||||
[ngStyle]="{ color: tower.baseColor.toString() }"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -11,8 +11,17 @@
|
|||
opacity: 0;
|
||||
}
|
||||
|
||||
&.cdk-drag-preview,
|
||||
&:hover {
|
||||
@media (min-width: $mobile-width) {
|
||||
div {
|
||||
.container {
|
||||
box-shadow: $shadow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.cdk-drag-preview {
|
||||
div {
|
||||
.container {
|
||||
box-shadow: $shadow;
|
||||
|
|
@ -39,7 +48,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@include inner-spacing(var(--small-padding));
|
||||
|
|
@ -52,7 +61,7 @@
|
|||
position: relative;
|
||||
|
||||
@include card();
|
||||
|
||||
overflow: hidden;
|
||||
transition: transform $short-animation-time, box-shadow $long-animation-time;
|
||||
|
||||
@include inner-spacing(var(--medium-padding));
|
||||
|
|
@ -65,7 +74,7 @@
|
|||
pointer-events: none;
|
||||
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
z-index: 2;
|
||||
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
|
@ -85,9 +94,9 @@
|
|||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
height: 56px;
|
||||
height: 48px;
|
||||
@media (max-width: $mobile-width) {
|
||||
height: 42px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
opacity: 0.33;
|
||||
|
|
@ -130,7 +139,7 @@
|
|||
}
|
||||
|
||||
input[type='text'] {
|
||||
font-size: var(--medium-font-size);
|
||||
font-size: var(--small-font-size);
|
||||
text-align: center;
|
||||
@media (min-width: $mobile-width) {
|
||||
width: 50%;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, ElementRef, Input, ViewChild } from '@angular/core';
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Tower } from '../../../../model/tower';
|
||||
import { ModalService } from '../../../../services/modal.service';
|
||||
import { Block } from '../../../../model/block';
|
||||
|
|
@ -40,7 +40,10 @@ export class TowerComponent {
|
|||
|
||||
public async addBlock() {
|
||||
try {
|
||||
const { selected: tag, description, isDone } = await this.modalService.showCreateBlock(this.tower.tags);
|
||||
const { selected: tag, description, isDone } = await this.modalService.showCreateBlock({
|
||||
options: this.tower.tags,
|
||||
isTask: false
|
||||
});
|
||||
this.tower.addBlock({ tag, description, isDone });
|
||||
} catch (e) {
|
||||
// pass
|
||||
|
|
|
|||
|
|
@ -11,8 +11,12 @@
|
|||
|
||||
<div class="page-container">
|
||||
<!-- wrapper for easier styling -->
|
||||
<app-page *ngIf="dataService.active !== null" [page]="dataService.active"></app-page>
|
||||
<app-page
|
||||
*ngIf="dataService.active !== null"
|
||||
[page]="dataService.active"
|
||||
(isDragHappening)="isDragHappening = $event"
|
||||
></app-page>
|
||||
</div>
|
||||
<!-- wrapper for easier styling -->
|
||||
|
||||
<button (click)="openSettings()">Settings</button>
|
||||
<button [ngClass]="isDragHappening ? 'transparent' : ''" (click)="openSettings()">Settings</button>
|
||||
|
|
|
|||
|
|
@ -18,4 +18,12 @@
|
|||
.page-container {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
button {
|
||||
transition: opacity $long-animation-time;
|
||||
|
||||
&.transparent {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ export class PagesComponent {
|
|||
@ViewChild('page') page: ElementRef;
|
||||
@ViewChild('bottom') bottom: ElementRef;
|
||||
|
||||
isDragHappening = false;
|
||||
|
||||
constructor(public dataService: DataService, private modalService: ModalService) {}
|
||||
|
||||
async selectPage(selected: string) {
|
||||
|
|
|
|||
|
|
@ -37,11 +37,12 @@ $slider-size: 40px;
|
|||
|
||||
transition: box-shadow $long-animation-time, transform $long-animation-time;
|
||||
|
||||
&:hover {
|
||||
box-shadow: $shadow;
|
||||
transform: translateY(-$slider-size / 2 + $line-height / 2) scale(1.1);
|
||||
@media (min-width: $mobile-width) {
|
||||
&:hover {
|
||||
box-shadow: $shadow;
|
||||
transform: translateY(-$slider-size / 2 + $line-height / 2) scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ export class DoubleSliderComponent {
|
|||
|
||||
this._values = values;
|
||||
this.calculateLabels();
|
||||
if (this._oneValue > this._otherValue) {
|
||||
this._oneValue = this.MAX - 1;
|
||||
} else {
|
||||
this._otherValue = this.MAX - 1;
|
||||
}
|
||||
|
||||
this.emitValue();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,8 +98,10 @@ $inner-padding: var(--medium-padding);
|
|||
}
|
||||
|
||||
&:hover {
|
||||
.background {
|
||||
box-shadow: $shadow;
|
||||
@media (min-width: $mobile-width) {
|
||||
.background {
|
||||
box-shadow: $shadow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core';
|
||||
import { CancelService } from '../../../services/cancel.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-select-add',
|
||||
|
|
@ -28,6 +29,12 @@ export class SelectAddComponent {
|
|||
newOption: string;
|
||||
isOpen = false;
|
||||
|
||||
constructor(private cancelService: CancelService) {
|
||||
this.cancelService.subscribe(this, () => {
|
||||
this.isOpen = false;
|
||||
});
|
||||
}
|
||||
|
||||
get otherOptions(): string[] {
|
||||
return this.options.filter(a => a !== this.selected);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ import { Color } from './color';
|
|||
|
||||
export class Block extends Base implements IBlock {
|
||||
constructor(props: IBlock) {
|
||||
// TODO: remove
|
||||
if (props.isDone === undefined) {
|
||||
props.isDone = true;
|
||||
}
|
||||
|
||||
super(props);
|
||||
|
||||
if (this.created.constructor.name !== 'Date') {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ import { ITower } from '../interfaces/persistance/tower';
|
|||
|
||||
export class Page extends Base implements IPage {
|
||||
constructor(props) {
|
||||
// TODO: remove
|
||||
if (!props.userData) {
|
||||
props.userData = {};
|
||||
}
|
||||
|
||||
super(props);
|
||||
// @ts-ignore to prevent update message
|
||||
this.__towers = this.towers.map(t => this.createTower(t));
|
||||
|
|
@ -37,7 +42,6 @@ export class Page extends Base implements IPage {
|
|||
do {
|
||||
hue = Math.random() * 360;
|
||||
} while (30 <= hue && hue <= 200);
|
||||
console.log(hue);
|
||||
|
||||
this.towers.push(
|
||||
this.createTower({
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Color } from './color';
|
|||
import { Block } from './block';
|
||||
import { Base } from './base';
|
||||
import { IBlock } from '../interfaces/persistance/block';
|
||||
import { hashCode } from '../utils/hash';
|
||||
import { hash } from '../utils/hash';
|
||||
|
||||
export class Tower extends Base implements ITower {
|
||||
constructor(props: ITower) {
|
||||
|
|
@ -46,7 +46,7 @@ export class Tower extends Base implements ITower {
|
|||
if (!this.tags.includes(block.tag)) {
|
||||
this.tags.push(block.tag);
|
||||
}
|
||||
block.color = this.baseColor.lighten(hashCode(block.tag) * 50);
|
||||
block.color = this.baseColor.lighten(hash(block.tag) * 50);
|
||||
}
|
||||
|
||||
super.update();
|
||||
|
|
|
|||
30
src/app/services/cancel.service.ts
Normal file
30
src/app/services/cancel.service.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
interface Subscriber {
|
||||
callback: () => void;
|
||||
object: object;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CancelService {
|
||||
private subscribers: Subscriber[] = [];
|
||||
|
||||
constructor() {}
|
||||
|
||||
subscribe(object: object, callback: () => void) {
|
||||
this.subscribers.push({
|
||||
object,
|
||||
callback
|
||||
});
|
||||
}
|
||||
|
||||
cancelAllExcept(except: object) {
|
||||
this.subscribers.filter(s => s.object !== except).map(s => s.callback());
|
||||
}
|
||||
|
||||
cancelAll() {
|
||||
this.subscribers.map(s => s.callback());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Tower } from '../model/tower';
|
||||
import { top } from '../utils/top';
|
||||
import { CancelService } from './cancel.service';
|
||||
|
||||
export enum ModalType {
|
||||
createBlock,
|
||||
|
|
@ -25,8 +26,13 @@ interface Modal {
|
|||
export class ModalService {
|
||||
private modalStack: Modal[] = [];
|
||||
|
||||
showCreateBlock(options: string[]): Promise<{ selected: string; description: string; isDone: boolean }> {
|
||||
return this.createPromiseAndPushToStack(options, ModalType.createBlock);
|
||||
constructor(private cancelService: CancelService) {}
|
||||
|
||||
showCreateBlock(input: {
|
||||
options: string[];
|
||||
isTask: boolean;
|
||||
}): Promise<{ selected: string; description: string; isDone: boolean }> {
|
||||
return this.createPromiseAndPushToStack(input, ModalType.createBlock);
|
||||
}
|
||||
|
||||
showEditBlock(data: {
|
||||
|
|
@ -65,6 +71,8 @@ export class ModalService {
|
|||
}
|
||||
|
||||
private createPromiseAndPushToStack(input: any, type: ModalType): Promise<any> {
|
||||
this.cancelService.cancelAll();
|
||||
|
||||
const modal = {
|
||||
input,
|
||||
type,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Page } from '../model/page';
|
||||
|
||||
const LOCAL_STORAGE_KEY = 'life-towers.data.v.2.1';
|
||||
const LOCAL_STORAGE_KEY = 'life-towers.data.v.2';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
|
|||
|
|
@ -1,14 +1,8 @@
|
|||
export const hashCode = (text: string) => {
|
||||
let hash = 0;
|
||||
if (text.length == 0) {
|
||||
return hash;
|
||||
export const hash = (text: string): number => {
|
||||
// Return number between 0 and 1.
|
||||
if (!text) {
|
||||
return 0;
|
||||
}
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const char = text.charCodeAt(i);
|
||||
hash = (hash << 5) - hash + char;
|
||||
hash = hash & hash;
|
||||
}
|
||||
|
||||
hash /= Math.pow(2, 32) - 1;
|
||||
return hash;
|
||||
const hash = Array.prototype.reduce.call(text, (hash, char) => (hash << 5) - hash + char.charCodeAt(0), 7);
|
||||
return hash / (Math.pow(2, 32) - 1);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$accent-color: #a2666f;
|
||||
$text-color: #5d576b;
|
||||
$text-color: #5d576bff;
|
||||
$light-color: #ffffff;
|
||||
|
||||
$background-gradient: linear-gradient(90deg, #fff9e077 0, #ffd6d677 100%);
|
||||
|
|
|
|||
|
|
@ -43,10 +43,35 @@ button {
|
|||
|
||||
background: transparent;
|
||||
border: 0;
|
||||
text-decoration: underline;
|
||||
|
||||
@include medium-text();
|
||||
@include jump();
|
||||
font-size: var(--large-font-size);
|
||||
$height: 2px;
|
||||
cursor: pointer;
|
||||
border-bottom: solid $height #5d576b55;
|
||||
position: relative;
|
||||
|
||||
&:disabled {
|
||||
color: #5d576b55;
|
||||
border-bottom: solid $height #5d576b33;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:not(:disabled):hover {
|
||||
&:after {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
&:after {
|
||||
content: '';
|
||||
width: 0;
|
||||
height: $height;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: calc(-1 * #{$height});
|
||||
background-color: $text-color;
|
||||
transition: width 300ms;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
|
|
|
|||
|
|
@ -60,3 +60,8 @@ img {
|
|||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
* {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue