Added a modal window
This commit is contained in:
94
src/components/Modal.vue
Normal file
94
src/components/Modal.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div
|
||||
class="modal"
|
||||
:class="{hidden: !active}"
|
||||
>
|
||||
<div class="bg" @click="close" />
|
||||
<div class="window">
|
||||
<div class="close" @click="close">×</div>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
active: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.active = true;
|
||||
},
|
||||
close() {
|
||||
this.active = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.modal {
|
||||
position: fixed;
|
||||
transition: all .4s;
|
||||
|
||||
.bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(90, 90, 90, 0.28);
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.window {
|
||||
z-index: 1000;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 16px;
|
||||
border-radius: 16px;
|
||||
background: $lighter;
|
||||
color: $dark;
|
||||
width: 340px;
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $max-width) {
|
||||
.modal {
|
||||
.window {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
top: unset;
|
||||
box-sizing: border-box;
|
||||
border-radius: 16px 16px 0 0;
|
||||
transform: translate(0, 0);
|
||||
transition: transform .4s;
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
.window {
|
||||
opacity: 1;
|
||||
transform: translate(0, 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -5,15 +5,16 @@
|
||||
v-model="newCategory"
|
||||
placeholder="New category"
|
||||
@keypress.enter="addCategory"
|
||||
@mouseenter="newCategory=''"
|
||||
@mouseenter="newCategory = ''"
|
||||
@mouseleave="blurInput"
|
||||
/>
|
||||
<div class="categories">
|
||||
<div
|
||||
class="category"
|
||||
v-for="category in categories" :key="category"
|
||||
:style="{background: stringToColor(category)}"
|
||||
:class="{selected: selectedCategory===category}"
|
||||
v-for="category in categories"
|
||||
:key="category"
|
||||
:style="{ background: stringToColor(category) }"
|
||||
:class="{ selected: selectedCategory === category }"
|
||||
@click="selectCategory(category)"
|
||||
>
|
||||
{{ category }}
|
||||
@@ -75,7 +76,7 @@ export default {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid $light;
|
||||
//border-bottom: 1px solid $light;
|
||||
height: 48px;
|
||||
background: $dark;
|
||||
display: flex;
|
||||
@@ -89,20 +90,21 @@ export default {
|
||||
padding: 4px 12px;
|
||||
width: 32px;
|
||||
box-sizing: border-box;
|
||||
transition: width .6s;
|
||||
transition: width 0.6s;
|
||||
|
||||
&:hover {
|
||||
width: 220px
|
||||
width: 220px;
|
||||
}
|
||||
}
|
||||
|
||||
.categories {
|
||||
display: flex;
|
||||
margin-left: 32px;
|
||||
overflow-x: scroll;
|
||||
|
||||
.category {
|
||||
margin-right: 16px;
|
||||
border: 3px solid transparent;
|
||||
border: 3px solid $dark;
|
||||
|
||||
&.selected {
|
||||
border: 3px double $dark;
|
||||
@@ -110,4 +112,10 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $max-width) {
|
||||
.category-bar {
|
||||
padding: 0 0 0 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
$dark-blue: #05263B;
|
||||
$misty-blue: #AEB8C4;
|
||||
$blue-grotto: #163B50;
|
||||
$slate: #9CA6B8;
|
||||
|
||||
$dark: $blue-grotto;
|
||||
$darker: $dark-blue;
|
||||
$light: $slate;
|
||||
$lighter: $misty-blue;
|
||||
$dark: #1f1f1f;
|
||||
$darker: #121212;
|
||||
$light: rgb(219, 219, 219);
|
||||
$lighter: white;
|
||||
|
||||
|
||||
$max-width: 1024px;
|
||||
@@ -4,6 +4,7 @@
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-size: 16px;
|
||||
|
||||
color: $light;
|
||||
background: $darker;
|
||||
@@ -13,12 +14,24 @@
|
||||
input, button {
|
||||
border: none;
|
||||
border-radius: 16px;
|
||||
|
||||
&::placeholder {
|
||||
color: $dark;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.category {
|
||||
border-radius: 16px;
|
||||
padding: 4px 12px;
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: $darker;
|
||||
|
||||
span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,69 @@
|
||||
<template>
|
||||
<div
|
||||
class="task"
|
||||
:class="{active: task.running}"
|
||||
>
|
||||
<div class="task" :class="{ active: task.running }">
|
||||
<div class="time">
|
||||
{{ formattedTime }}
|
||||
</div>
|
||||
<div class="toggle-state">
|
||||
<div v-if="task.running" @click="stopTask">
|
||||
<img src="@/assets/pause.svg">
|
||||
<img src="@/assets/pause.svg" />
|
||||
</div>
|
||||
<div v-else @click="startTask">
|
||||
<img src="@/assets/play.svg">
|
||||
<img src="@/assets/play.svg" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="name">
|
||||
{{ task.name }}
|
||||
</div>
|
||||
<div class="spacer"/>
|
||||
<div
|
||||
v-if="task.category"
|
||||
class="category"
|
||||
:style="{ background: stringToColor(task.category) }"
|
||||
>
|
||||
{{ task.category }}
|
||||
<span @click="removeCategory">×</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="select-category"
|
||||
>
|
||||
Assign Category
|
||||
<CategoryDropdown
|
||||
|
||||
<div class="optional-break">
|
||||
<div class="name">
|
||||
{{ task.name }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="task.category"
|
||||
class="category"
|
||||
:style="{ background: stringToColor(task.category) }"
|
||||
>
|
||||
{{ task.category }}
|
||||
<span @click="removeCategory">×</span>
|
||||
</div>
|
||||
<div v-else class="select-category" @click="$refs.categorySelect.open">
|
||||
Assign Category
|
||||
<!-- <CategoryDropdown
|
||||
class="dropdown"
|
||||
@selected="assignCategory"
|
||||
/>
|
||||
/> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="delete"
|
||||
@click="removeTask"
|
||||
>
|
||||
<img src="@/assets/trash.svg">
|
||||
<Modal ref="categorySelect" class="modal">
|
||||
<div class="title">Assign Category</div>
|
||||
<div
|
||||
v-for="category in categories"
|
||||
:key="category"
|
||||
class="category"
|
||||
:style="{ background: stringToColor(category) }"
|
||||
@click="assignCategory(category)"
|
||||
>
|
||||
{{ category }}
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<div class="delete" @click="removeTask">
|
||||
<img src="@/assets/trash.svg" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import toColor from '@/stringToColor';
|
||||
|
||||
import CategoryDropdown from './CategoryDropdown.vue';
|
||||
// import CategoryDropdown from './CategoryDropdown.vue';
|
||||
import Modal from '@/components/Modal.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CategoryDropdown,
|
||||
// CategoryDropdown,
|
||||
Modal,
|
||||
},
|
||||
props: {
|
||||
task: Object,
|
||||
@@ -73,9 +83,13 @@ export default {
|
||||
},
|
||||
assignCategory(category) {
|
||||
this.$store.commit('assignCategory', { name: this.task.name, category });
|
||||
this.$refs.categorySelect.close();
|
||||
},
|
||||
removeCategory() {
|
||||
this.$store.commit('assignCategory', { name: this.task.name, category: undefined });
|
||||
this.$store.commit('assignCategory', {
|
||||
name: this.task.name,
|
||||
category: undefined,
|
||||
});
|
||||
},
|
||||
stringToColor(str) {
|
||||
return toColor(str);
|
||||
@@ -106,6 +120,9 @@ export default {
|
||||
|
||||
return `${days}d ${hours}h ${mins}m`;
|
||||
},
|
||||
...mapState({
|
||||
categories: (state) => state.categories,
|
||||
}),
|
||||
},
|
||||
mounted() {
|
||||
setInterval(() => {
|
||||
@@ -118,12 +135,12 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.task {
|
||||
color: $lighter;
|
||||
height: 42px;
|
||||
min-height: 42px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.time {
|
||||
width: 124px;
|
||||
min-width: 104px;
|
||||
}
|
||||
|
||||
.toggle-state {
|
||||
@@ -146,37 +163,54 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.spacer {
|
||||
.optional-break {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.select-category {
|
||||
position: relative;
|
||||
color: $darker;
|
||||
color: $light;
|
||||
background: $dark;
|
||||
padding: 4px 12px;
|
||||
border-radius: 16px;
|
||||
cursor: pointer;
|
||||
|
||||
.dropdown {
|
||||
display: none;
|
||||
}
|
||||
// .dropdown {
|
||||
// display: none;
|
||||
// }
|
||||
|
||||
&:hover {
|
||||
.dropdown {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
// &:hover {
|
||||
// .dropdown {
|
||||
// display: block;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
.delete {
|
||||
margin-left: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal {
|
||||
.category {
|
||||
margin-top: 12px;
|
||||
border-radius: 24px !important;
|
||||
padding: 12px 24px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
from {opacity: .3;}
|
||||
to {opacity: 1;}
|
||||
from {
|
||||
opacity: 0.3;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.task.active {
|
||||
@@ -184,4 +218,16 @@ export default {
|
||||
animation: pulse 1s infinite alternate;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $max-width) {
|
||||
.task {
|
||||
min-height: 64px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.optional-break {
|
||||
flex-direction: column;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -55,6 +55,7 @@ export default {
|
||||
.task-list {
|
||||
max-width: $max-width;
|
||||
margin: 32px auto;
|
||||
padding: 0 8px;
|
||||
|
||||
.add-task {
|
||||
width: 100%;
|
||||
|
||||
Reference in New Issue
Block a user