Skip to content

Commit 0278717

Browse files
committed
feat(tasks): add tasks module
1 parent 28a28c0 commit 0278717

File tree

10 files changed

+804
-0
lines changed

10 files changed

+804
-0
lines changed

src/tasks/components/task-form.scss

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
$root-font-size: 16px !default;
2+
3+
@function strip-unit($value) {
4+
@return $value / ($value * 0 + 1);
5+
}
6+
@function em($value, $base: $root-font-size) {
7+
$value: strip-unit($value);
8+
9+
@if $value == 0 {
10+
@return $value;
11+
}
12+
13+
@return $value / strip-unit($base) * 1em;
14+
}
15+
@function rem($value) {
16+
$value: strip-unit($value);
17+
18+
@if $value == 0 {
19+
@return $value;
20+
}
21+
22+
@return $value / strip-unit($root-font-size) * 1rem;
23+
}
24+
$breakpoints: (
25+
small : 0,
26+
medium : 740px,
27+
large : 980px,
28+
xlarge : 1300px
29+
) !default;
30+
$breakpoint-prefixes: (
31+
small : sm-,
32+
medium : md-,
33+
large : lg-,
34+
xlarge : xl-
35+
) !default;
36+
37+
@function media-query-width($value) {
38+
@if map-has-key($breakpoints, $value) {
39+
$value: map-get($breakpoints, $value);
40+
}
41+
42+
@if $value == 0 {
43+
@return $value;
44+
}
45+
@return em($value);
46+
}
47+
@mixin media-query($min: null, $max: null, $orientation: null, $pixel-ratio: null, $type: 'screen') {
48+
$query: $type;
49+
50+
@if $pixel-ratio {
51+
$query: $query + ' and (min-resolution: #{$pixel-ratio * 1dppx})';
52+
}
53+
54+
@if $min {
55+
$min-width: media-query-width($min);
56+
@if $min-width > 0 {
57+
$query: $query + ' and (min-width: #{$min-width})';
58+
}
59+
}
60+
61+
@if $max {
62+
$max-width: media-query-width($max) - .01em;
63+
$query: $query + ' and (max-width: #{$max-width})';
64+
}
65+
66+
@if $orientation {
67+
$query: $query + ' and (orientation: #{$orientation})';
68+
}
69+
70+
@media #{$query} {
71+
@content;
72+
}
73+
}
74+
75+
.task-form {
76+
margin: 40px 0 10px;
77+
78+
@include media-query(540) {
79+
margin: 80px 0 20px;
80+
}
81+
}
82+
83+
.task-form-input {
84+
outline: none;
85+
border: 0;
86+
border-bottom: 1px dotted #666;
87+
border-radius: 0;
88+
padding: 0 0 5px 0;
89+
width: 100%;
90+
height: 50px;
91+
font-family: inherit;
92+
font-size: rem(24px);
93+
font-weight: 300;
94+
color: #fff;
95+
background: transparent;
96+
97+
@include media-query(540) {
98+
height: 61px;
99+
font-size: rem(32px);
100+
}
101+
102+
&::placeholder {
103+
color: #999;
104+
opacity: 1; // firefox native placeholder style has opacity < 1
105+
}
106+
107+
&:focus::placeholder {
108+
color: #777;
109+
opacity: 1;
110+
}
111+
112+
// webkit input doesn't inherit font-smoothing from ancestors
113+
-webkit-font-smoothing: antialiased;
114+
115+
// remove `x`
116+
&::-ms-clear {
117+
display: none;
118+
}
119+
}

src/tasks/components/task-form.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Component, ViewEncapsulation, ChangeDetectionStrategy, EventEmitter, Output } from '@angular/core';
2+
3+
@Component({
4+
selector: 'task-form',
5+
encapsulation: ViewEncapsulation.None,
6+
changeDetection: ChangeDetectionStrategy.OnPush,
7+
template:`
8+
<form class="task-form" (ngSubmit)="submit()" novalidate>
9+
<input type="text"
10+
class="task-form-input"
11+
placeholder="What needs to be done?"
12+
name="title"
13+
[(ngModel)]="title"
14+
(keyup.escape)="clear()"
15+
autocomplete="off"
16+
autoFocus
17+
required>
18+
</form>
19+
`,
20+
styleUrls: ['./task-form.css']
21+
})
22+
export class TaskFormComponent {
23+
title: string = '';
24+
25+
@Output() createTask: EventEmitter<any> = new EventEmitter<any>(false);
26+
27+
clear(): void {
28+
this.title = '';
29+
}
30+
31+
submit(): void {
32+
const title: string = this.title.trim();
33+
if (title.length) {
34+
this.createTask.emit(title);
35+
}
36+
this.clear();
37+
}
38+
}

src/tasks/components/task-item.scss

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
task-item {
2+
$root-font-size: 16px !default;
3+
$breakpoints: (
4+
small : 0,
5+
medium : 740px,
6+
large : 980px,
7+
xlarge : 1300px
8+
) !default;
9+
10+
$breakpoint-prefixes: (
11+
small : sm-,
12+
medium : md-,
13+
large : lg-,
14+
xlarge : xl-
15+
) !default;
16+
17+
@function strip-unit($value) {
18+
@return $value / ($value * 0 + 1);
19+
}
20+
@function em($value, $base: $root-font-size) {
21+
$value: strip-unit($value);
22+
23+
@if $value == 0 {
24+
@return $value;
25+
}
26+
27+
@return $value / strip-unit($base) * 1em;
28+
}
29+
@function rem($value) {
30+
$value: strip-unit($value);
31+
32+
@if $value == 0 {
33+
@return $value;
34+
}
35+
36+
@return $value / strip-unit($root-font-size) * 1rem;
37+
}
38+
@function media-query-width($value) {
39+
@if map-has-key($breakpoints, $value) {
40+
$value: map-get($breakpoints, $value);
41+
}
42+
43+
@if $value == 0 {
44+
@return $value;
45+
}
46+
@return em($value);
47+
}
48+
@mixin media-query($min: null, $max: null, $orientation: null, $pixel-ratio: null, $type: 'screen') {
49+
$query: $type;
50+
51+
@if $pixel-ratio {
52+
$query: $query + ' and (min-resolution: #{$pixel-ratio * 1dppx})';
53+
}
54+
55+
@if $min {
56+
$min-width: media-query-width($min);
57+
@if $min-width > 0 {
58+
$query: $query + ' and (min-width: #{$min-width})';
59+
}
60+
}
61+
62+
@if $max {
63+
$max-width: media-query-width($max) - .01em;
64+
$query: $query + ' and (max-width: #{$max-width})';
65+
}
66+
67+
@if $orientation {
68+
$query: $query + ' and (orientation: #{$orientation})';
69+
}
70+
71+
@media #{$query} {
72+
@content;
73+
}
74+
}
75+
@mixin button-base {
76+
&[disabled] {
77+
cursor: default;
78+
}
79+
80+
display: inline-block;
81+
text-align: center;
82+
text-decoration: none;
83+
}
84+
85+
//=====================================
86+
// TASK-ITEM
87+
//=====================================
88+
.task-item {
89+
display: flex;
90+
outline: none;
91+
border-bottom: 1px dotted #666;
92+
height: 60px;
93+
overflow: hidden;
94+
color: #fff;
95+
font-size: rem(18px);
96+
font-weight: 300;
97+
98+
@include media-query(540) {
99+
font-size: rem(24px);
100+
}
101+
}
102+
103+
.task-item-editing {
104+
border-bottom: 1px dotted #ccc;
105+
}
106+
107+
108+
109+
//=====================================
110+
// CELLS
111+
//-------------------------------------
112+
.cell {
113+
&:first-child,
114+
&:last-child {
115+
display: flex;
116+
flex: 0 0 auto;
117+
align-items: center;
118+
}
119+
120+
&:first-child {
121+
padding-right: 20px;
122+
}
123+
124+
&:nth-child(2) {
125+
flex: 1;
126+
padding-right: 30px;
127+
overflow: hidden;
128+
}
129+
}
130+
131+
//=====================================
132+
// ICON BUTTONS
133+
//-------------------------------------
134+
.task-item-button {
135+
@include button-base;
136+
margin-left: 5px;
137+
outline: none;
138+
border: 0;
139+
border-radius: 100px;
140+
padding: 0;
141+
width: 40px;
142+
height: 40px;
143+
overflow: hidden;
144+
background: #2a2a2a;
145+
transform: translate(0, 0);
146+
147+
&:first-child {
148+
margin: 0;
149+
}
150+
}
151+
152+
.icon {
153+
line-height: 40px !important;
154+
color: #555;
155+
156+
.task-item-button:hover & {
157+
color: #999;
158+
}
159+
}
160+
161+
.icon-active {
162+
&, .task-item-button:hover & {
163+
color: #85bf6b;
164+
}
165+
}
166+
167+
//=====================================
168+
// TITLE : STATIC
169+
//-------------------------------------
170+
@keyframes fade-title {
171+
from { color: #fff; }
172+
to { color: #666; }
173+
}
174+
175+
@keyframes strike-title {
176+
from { width: 0; }
177+
to { width: 100%; }
178+
}
179+
180+
.task-item-title {
181+
display: inline-block;
182+
position: relative;
183+
max-width: 100%;
184+
line-height: 60px;
185+
outline: none;
186+
overflow: hidden;
187+
text-overflow: ellipsis;
188+
white-space: nowrap;
189+
190+
&:after {
191+
position: absolute;
192+
left: 0;
193+
bottom: 0;
194+
border-top: 2px solid #85bf6b;
195+
width: 0;
196+
height: 46%;
197+
content: '';
198+
}
199+
200+
.task-item-completed & {
201+
color: #666;
202+
}
203+
204+
.task-item-completed &:after {
205+
width: 100%;
206+
}
207+
208+
.task-item-completed.task-item--status-updated & {
209+
animation: fade-title 120ms ease-in-out;
210+
}
211+
212+
.task-item-completed.task-item--status-updated &:after {
213+
animation: strike-title 180ms ease-in-out;
214+
}
215+
}
216+
217+
//=====================================
218+
// TITLE : INPUT
219+
//-------------------------------------
220+
.task-item-input {
221+
outline: none;
222+
border: 0;
223+
padding: 0;
224+
width: 100%;
225+
height: 60px;
226+
color: inherit;
227+
font: inherit;
228+
background: transparent;
229+
230+
// remove `x`
231+
&::-ms-clear {
232+
display: none;
233+
}
234+
}
235+
}

0 commit comments

Comments
 (0)