feat(inputs): Created inputs to the user create custom tasks.

Created inputs for task and sub-tasks (`Task/TaskInput.vue`, `SubTask/SubTaskInput.vue`), enabling the creation of custom tasks and sub-tasks;

Removed debug buttons.
This commit is contained in:
Guz
2022-02-01 11:44:04 -03:00
parent e522c42a8d
commit 35c85fd3de
10 changed files with 540 additions and 48 deletions

View File

@@ -95,7 +95,6 @@ export default Vue.extend({
background-color: transparent;
}
font: inherit;
width: 20px;
height: 20px;
border: 5px solid currentColor;
@@ -107,6 +106,7 @@ export default Vue.extend({
}
.description {
font-family: $secondary-font;
margin: 1px 0;
}
}

View File

@@ -0,0 +1,171 @@
<template>
<div class="alignInputContainerSubTask">
<div class="subTaskInputContainer">
<button class="addTask" @click="addSubTask(parent)">
<IconAdd class="addIcon" />
</button>
<form class="subTaskInput">
<input
id="newSubTaskInputName"
class="subTaskNameInput"
type="text"
name="subTaskNameInput"
placeholder="Sub-Task Title..."
maxlength="50"
@keypress.enter="addSubTask(parent)"
/>
</form>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import sm from '~/libs/storageManagement';
export default Vue.extend({
name: 'SubTaskInput',
props: {
parent: {
type: Number,
required: true,
},
},
methods: {
addSubTask: (parentId: number) => {
if (sm.get('tasks') === undefined) sm.add('tasks', []);
const titleInput = document.querySelector(
'input#newSubTaskInputName'
) as HTMLInputElement;
const newTitle = titleInput.value;
if (!newTitle || newTitle === '') {
if (!titleInput.className.includes(' warnTitle'))
titleInput.className += ' warnTitle';
(
document.querySelector(
'input#newSubTaskInputName'
) as HTMLInputElement
).className = titleInput.className;
setTimeout(() => {
(
document.querySelector(
'input#newSubTaskInputName'
) as HTMLInputElement
).className = titleInput.className.replace(' warnTitle', '');
}, 1500);
return;
}
const subTaskItem: SubTask = {
description: newTitle,
checked: false,
};
const localTasks: Task[] = sm.get('tasks');
const parentTask = localTasks[parentId];
if (!parentTask.subTasks) parentTask.subTasks = [];
parentTask.subTasks.push(subTaskItem);
localTasks[parentId] = parentTask;
sm.set('tasks', localTasks);
(
document.querySelector('input#newSubTaskInputName') as HTMLInputElement
).value = '';
},
},
});
</script>
<style lang="scss">
@import '~assets/styles/_variables.scss';
@import '~assets/styles/_mixins.scss';
.alignInputContainerSubTask {
@include center;
justify-content: left;
&,
* {
transition: all 0.2s;
}
*::placeholder {
transition: all 0.2s;
}
.subTaskInputContainer {
@include center;
width: 100%;
.addTask {
$bg-color: #00000080;
background-color: $bg-color;
margin: 2px;
margin-right: 2%;
padding: 1px;
border-radius: 50%;
border: 0px;
@include center;
.addIcon {
padding: 2px;
}
&:active {
transform: scale(0.5);
}
.light-mode & * {
stroke: $sky3;
}
&:hover * {
stroke: $sky0;
}
}
.subTaskInput {
text-align: left;
width: 100%;
.subTaskNameInput {
font-family: $secondary-font;
height: 1.5em;
width: 90%;
border: 0;
border-radius: 10px;
padding: 5px 10px;
.light-mode & {
background-color: $blue0;
color: $independence-gray0;
&::placeholder {
color: $independence-gray1;
}
}
.dark-mode & {
background-color: $eerie-black0;
color: $dark-primary;
&::placeholder {
color: $dark-secondary;
}
}
.warnTitle {
&::placeholder {
color: $unchecked-color !important;
}
}
}
}
}
}
</style>

View File

@@ -11,7 +11,7 @@
:checked="subTask.checked"
/>
</ul>
<button @click="addSubTask(parent)">Add subtask</button>
<SubTaskInput :parent="parent" />
</div>
</span>
</template>
@@ -20,11 +20,6 @@
import Vue from 'vue';
import sm from '~/libs/storageManagement';
const subTaskItem: SubTask = {
description: 'Task',
checked: false,
};
export default Vue.extend({
name: 'SubTasks',
props: {
@@ -55,23 +50,6 @@ export default Vue.extend({
this.preventAnim = false;
}, 1000);
},
methods: {
addSubTask: (parentId: number) => {
if (sm.get('tasks') === undefined) sm.add('tasks', []);
const localTasks: Task[] = sm.get('tasks');
const parentTask = localTasks[parentId];
if (!parentTask.subTasks) parentTask.subTasks = [];
subTaskItem.description = `Description sub task ${parentTask.subTasks.length}`;
parentTask.subTasks.push(subTaskItem);
localTasks[parentId] = parentTask;
sm.set('tasks', localTasks);
},
},
});
</script>

View File

@@ -337,6 +337,7 @@ export default Vue.extend({
.info {
display: inline-block;
text-overflow: ellipsis;
h1 {
font-size: 1.2em;
@@ -347,6 +348,7 @@ export default Vue.extend({
font-family: $secondary-font;
font-size: 0.8em;
margin: 0;
white-space: pre-wrap;
}
}
}

View File

@@ -0,0 +1,329 @@
<template>
<div class="alignInputContainer">
<div class="taskInputContainer">
<button class="addTask" @click="addTask()">
<IconAdd class="addIcon" />
</button>
<form class="taskInputs">
<div class="taskNameInputContainer">
<input
id="newTaskInputName"
class="taskNameInput"
type="text"
name="TaskNameInput"
placeholder="Task Title..."
maxlength="28"
@keypress.enter="addTask()"
/>
</div>
<div class="taskDescriptionInputContainer">
<textarea
id="newTaskInputDescription"
class="taskDescriptionInput"
name="TaskDescriptionInput"
placeholder="Task Description..."
maxlength="150"
></textarea>
</div>
</form>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import sm from '~/libs/storageManagement';
export default Vue.extend({
name: 'TaskInput',
methods: {
addTask: () => {
if (sm.get('tasks') === undefined) sm.add('tasks', []);
const titleInput = document.querySelector(
'input#newTaskInputName'
) as HTMLInputElement;
const newTitle = titleInput.value;
const newDescription = (
document.querySelector(
'textarea#newTaskInputDescription'
) as HTMLTextAreaElement
).value;
if (!newTitle || newTitle === '') {
if (!titleInput.className.includes(' warnTitle'))
titleInput.className += ' warnTitle';
(
document.querySelector('input#newTaskInputName') as HTMLInputElement
).className = titleInput.className;
setTimeout(() => {
(
document.querySelector('input#newTaskInputName') as HTMLInputElement
).className = titleInput.className.replace(' warnTitle', '');
}, 1500);
return;
}
const taskItem: Task = {
title: newTitle,
description: newDescription || '',
checked: false,
newTask: true,
autoCheck: true,
subTasks: [],
};
const localTasks: Task[] = sm.get('tasks');
localTasks.push(taskItem);
sm.set('tasks', localTasks);
(
document.querySelector('input#newTaskInputName') as HTMLInputElement
).value = '';
(
document.querySelector(
'textarea#newTaskInputDescription'
) as HTMLInputElement
).value = '';
},
},
});
</script>
<style lang="scss">
@import '~assets/styles/_variables.scss';
@import '~assets/styles/_mixins.scss';
.alignInputContainer {
@include center;
@media not screen and (pointer: none), (pointer: coarse) {
&:not(:hover),
.taskInputContainer *:not(:focus-within) {
.taskInputContainer {
animation: shrink 0.5s forwards;
@keyframes shrink {
from {
padding: 5px 10px;
margin: 10px 0;
transform: scale(100%);
width: 100%;
}
to {
padding: 0px 25%;
margin: 0px 0;
transform: scale(60%);
width: 0%;
}
}
.taskInputs {
animation: hideInputs 0.5s forwards;
@keyframes hideInputs {
from {
transform: translateX(0%);
opacity: 1;
width: 100%;
}
to {
transform: translateX(25%);
opacity: 0;
width: 0%;
}
}
}
}
}
&:hover {
.taskInputContainer {
animation: expand 0.5s forwards;
@keyframes expand {
from {
padding: 0px 25%;
margin: 0px 0;
transform: scale(60%);
width: 0%;
}
to {
padding: 5px 10px;
margin: 10px 0;
transform: scale(100%);
width: 100%;
}
}
.taskInputs {
animation: showInputs 0.5s forwards;
@keyframes showInputs {
from {
transform: translateX(25%);
opacity: 0;
width: 0%;
}
to {
transform: translateX(0%);
opacity: 1;
width: 100%;
}
}
}
}
}
}
.taskInputContainer {
&,
* {
transition: all 0.2s;
}
*::placeholder {
transition: all 0.2s;
}
.light-mode & {
background-color: $blue0;
color: $independence-gray0;
}
.dark-mode & {
background-color: $eerie-black0;
color: $dark-primary;
}
border-radius: 20px;
@include center;
@media (pointer: none), (pointer: coarse) {
padding: 5px 10px;
margin: 10px 0;
width: 100%;
}
.addTask {
$bg-color: #00000080;
background-color: $bg-color;
margin: 2px;
margin-right: 2%;
padding: 1px;
border-radius: 50%;
border: 0px;
@include center;
.addIcon {
padding: 2px;
}
&:active {
transform: scale(0.5);
}
.light-mode & * {
stroke: $sky3;
}
&:hover * {
stroke: $sky0;
}
}
.taskInputs {
text-align: left;
.taskNameInputContainer,
.taskDescriptionInputContainer {
width: 100%;
input,
textarea {
width: 90%;
border: 0;
border-radius: 10px;
text-overflow: ellipsis;
.light-mode & {
color: $independence-gray0;
&::placeholder {
color: $independence-gray1;
}
}
.dark-mode & {
color: $dark-primary;
&::placeholder {
color: $dark-secondary;
}
}
background-color: transparent;
&:hover,
&:focus {
padding: 5px 10px;
.light-mode & {
background-color: $blue2;
&::placeholder {
color: $independence-gray0;
}
}
.dark-mode & {
background-color: $dark-background;
&::placeholder {
color: $dark-primary;
}
}
}
}
}
.taskNameInputContainer {
.taskNameInput {
font-family: $main-font;
font-size: 1.2em;
}
& .taskNameInput:focus,
& .taskNameInput:hover {
margin-bottom: 10px;
}
.warnTitle {
&::placeholder {
color: $unchecked-color !important;
}
}
}
.taskDescriptionInputContainer {
.taskDescriptionInput {
overflow: auto;
white-space: pre-wrap;
font-family: $secondary-font;
font-size: 0.85em;
&:focus {
height: 5em;
resize: vertical;
}
&:not(:focus) {
overflow: hidden;
height: 1em !important;
resize: none;
}
}
& .taskDescriptionInput:focus,
& .taskDescriptionInput:hover {
margin-top: 10px;
}
}
}
}
}
</style>

View File

@@ -12,7 +12,6 @@
/>
</ul>
<ProgressBar />
<button @click="addTask()">Add tasks</button>
</div>
</template>
@@ -20,15 +19,6 @@
import Vue from 'vue';
import sm from '~/libs/storageManagement';
const taskItem: Task = {
title: 'Task 00',
description: 'Task',
checked: false,
newTask: true,
autoCheck: true,
subTasks: [],
};
export default Vue.extend({
data() {
return {
@@ -49,19 +39,6 @@ export default Vue.extend({
this.list = sm.get('tasks') ? sm.get('tasks') : [];
});
},
methods: {
addTask: () => {
if (sm.get('tasks') === undefined) sm.add('tasks', []);
const localTasks: Task[] = sm.get('tasks');
taskItem.title = `Title Task ${localTasks.length}`;
taskItem.description = `Description Task ${localTasks.length}`;
localTasks.push(taskItem);
sm.set('tasks', localTasks);
},
},
});
</script>

View File

@@ -0,0 +1,30 @@
<template>
<svg
width="24"
height="24"
stroke-width="1.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 12H12M16 12H12M12 12V8M12 12V16"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'IconAdd',
});
</script>

View File

@@ -7,6 +7,7 @@
</div>
<div>
<TaskList />
<TaskInput />
</div>
<PageFooter />
</main>

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 12H12M16 12H12M12 12V8M12 12V16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 433 B