This repository has been archived on 2025-10-10. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ToToday.app/src/components/TaskComp.vue
Guz e6d036784f feat(taskList): created task list and improved task component
Created the Task List component to handle and render the Task components dynamically;

Improved Task component to now be able to delete itself from the list / added task controls;

Task's state now are saved in LocalStorage;

Added animations to Task Components;
2022-01-29 11:46:57 -03:00

299 lines
5.0 KiB
Vue

<template>
<li :id="`task${id}`" :class="`${newTask ? 'newTask ' : ''}task`">
<div class="taskInfo">
<label
class="checkbox"
:for="`checkboxInput${id}`"
@click="changeState()"
>
<input :id="`checkboxInput${id}`" type="checkbox" :checked="checked" />
<div class="icons animate">
<IconChecked class="checkedIcon" />
<IconUnchecked class="uncheckedIcon" />
</div>
</label>
<div class="info">
<h1>{{ title }}</h1>
<p>{{ description }}</p>
</div>
</div>
<nav class="controls">
<button class="deleteButton" @click="deleteTask()">
<IconTrash class="trashIcon" />
</button>
</nav>
</li>
</template>
<script lang="js">
import Vue from 'vue';
import sm from '~/libs/storageManagement';
export default Vue.extend({
name: 'TaskComp',
props: {
id: {
type: Number,
required: true,
},
title: {
type: String,
default: 'Task Title',
},
description: {
type: String,
default: 'Task short description',
},
checked: {
type: Boolean,
default: false,
},
newTask: {
type: Boolean,
default: false,
}
},
methods: {
changeState() {
const state = document.querySelector(`input#checkboxInput${this.id}`)?.checked;
const tasks = sm.get('tasks');
tasks[this.id].checked = state;
sm.set('tasks', tasks);
},
deleteTask() {
const localTasks = sm.get('tasks');
localTasks.splice(this.id, 1);
sm.set('tasks', localTasks);
}
}
});
</script>
<style lang="scss">
@import '~assets/styles/_variables.scss';
@import '~assets/styles/_mixins.scss';
$checked-color: $green0;
$unchecked-color: $begonia-red0;
.newTask {
animation-delay: 0s !important;
}
@for $i from 1 through 100 {
.task#task#{$i} {
animation-delay: #{$i * 0.2}s;
}
}
.task {
.light-mode & {
background-color: $blue0;
color: $independence-gray0;
}
.dark-mode & {
background-color: $eerie-black0;
color: $dark-primary;
}
border-radius: 20px;
margin-top: 5%;
padding: 10px;
display: flex;
align-items: center;
justify-content: space-between;
padding-right: 5%;
opacity: 0;
transform: translateY(50%);
animation: enter 0.5s ease-out;
animation-fill-mode: forwards;
@keyframes enter {
from {
opacity: 0;
transform: translateY(50%);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.taskInfo {
display: flex;
text-align: left;
align-items: center;
width: 100%;
.checkbox {
padding: 1%;
padding-right: 2%;
input {
display: none;
}
input[type='checkbox']:checked + .icons {
animation: iconAnim 1s;
.checkedIcon {
display: inline-block;
}
.uncheckedIcon {
display: none;
}
.checkedIcon *,
.uncheckedIcon * {
.light-mode & {
@include colorFadeAnim(
$unchecked-color,
$checked-color,
1s,
'checkLight'
);
stroke: $checked-color;
}
.dark-mode & {
@include colorFadeAnim(
$unchecked-color,
$checked-color,
1s,
'checkDark'
);
stroke: $checked-color;
}
}
}
input[type='checkbox']:not(:checked) + .icons {
animation: iconAnimReverse 1s;
.checkedIcon {
display: none;
}
.uncheckedIcon {
display: inline-block;
}
.checkedIcon *,
.uncheckedIcon * {
.light-mode & {
@include colorFadeAnim(
$checked-color,
$unchecked-color,
1s,
'uncheckLight'
);
stroke: $unchecked-color;
}
.dark-mode & {
@include colorFadeAnim(
$checked-color,
$unchecked-color,
1s,
'uncheckDark'
);
stroke: $unchecked-color;
}
}
}
.icons {
@include center;
$bg-color: #00000080;
background-color: $bg-color;
margin: 2px;
padding: 2px;
border-radius: 50%;
.checkedIcon *,
.uncheckedIcon * {
.light-mode & {
stroke: $unchecked-color;
}
.dark-mode & {
stroke: $unchecked-color;
}
}
}
@keyframes iconAnim {
from {
transform: rotate(0) scale(1);
}
5% {
transform: rotate(0) scale(0.7);
}
50% {
transform: rotate(360deg) scale(1.2);
}
90% {
transform: scale(1.2);
}
to {
transform: scale(1);
}
}
@keyframes iconAnimReverse {
from {
transform: rotate(0) scale(1);
}
5% {
transform: rotate(0) scale(0.7);
}
50% {
transform: rotate(-360deg) scale(1);
}
to {
transform: rotate(-360deg) scale(1);
}
}
}
.info {
display: inline-block;
h1 {
font-size: 1.2em;
margin: 0;
}
p {
font-family: $secondary-font;
font-size: 0.8em;
margin: 0;
}
}
}
.controls {
opacity: 0;
@media (pointer: none), (pointer: coarse) {
opacity: 0.5;
}
transition: opacity 0.2s;
button {
background-color: transparent;
padding: 1px;
border: 0;
cursor: pointer;
}
.trashIcon {
* {
transition: stroke 0.2s;
}
&:hover * {
stroke: $unchecked-color;
}
}
}
&:hover .controls {
opacity: 1;
}
}
</style>