1
0

New design (#14)

This commit is contained in:
konrad
2018-12-25 15:03:51 +00:00
committed by Gitea
parent de6104dda6
commit e094b654e2
51 changed files with 2828 additions and 551 deletions

View File

@ -4,11 +4,11 @@
<p>Click on a list or namespace on the left to get started.</p>
<p v-if="loading">Loading tasks...</p>
<h3 v-if="tasks && tasks.length > 0">Current tasks</h3>
<div class="box tasks" v-if="tasks && tasks.length > 0">
<div class="tasks" v-if="tasks && tasks.length > 0">
<div @click="gotoList(l.listID)" class="task" v-for="l in tasks" v-bind:key="l.id" v-if="!l.done">
<label v-bind:for="l.id">
<div class="fancycheckbox">
<input @change="markAsDone" type="checkbox" v-bind:id="l.id" v-bind:checked="l.done" style="display: none;" disabled>
<input type="checkbox" v-bind:id="l.id" v-bind:checked="l.done" style="display: none;" disabled>
<label v-bind:for="l.id" class="check">
<svg width="18px" height="18px" viewBox="0 0 18 18">
<path d="M1,9 L1,3.5 C1,2 2,1 3.5,1 L14.5,1 C16,1 17,2 17,3.5 L17,14.5 C17,16 16,17 14.5,17 L3.5,17 C2,17 1,16 1,14.5 L1,9 Z"></path>

View File

@ -1,5 +1,5 @@
<template>
<div class="loader-container" v-bind:class="{ 'is-loading': loading}">
<div class="loader-container" :class="{ 'is-loading': loading}">
<div class="card">
<header class="card-header">
<p class="card-header-title">
@ -12,7 +12,7 @@
<div class="field">
<label class="label" for="listtext">List Name</label>
<div class="control">
<input :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="listtext" placeholder="The list title goes here..." v-model="list.title">
<input v-focus :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="listtext" placeholder="The list title goes here..." v-model="list.title">
</div>
</div>
<div class="field">
@ -25,7 +25,7 @@
<div class="columns bigbuttons">
<div class="column">
<button @click="submit()" class="button is-success is-fullwidth" :class="{ 'is-loading': loading}">
<button @click="submit()" class="button is-primary is-fullwidth" :class="{ 'is-loading': loading}">
Save
</button>
</div>
@ -48,7 +48,7 @@
<modal
v-if="showDeleteModal"
@close="showDeleteModal = false"
v-on:submit="deleteList()">
@submit="deleteList()">
<span slot="header">Delete the list</span>
<p slot="text">Are you sure you want to delete this list and all of its contents?
<br/>This includes all tasks and <b>CANNOT BE UNDONE!</b></p>

View File

@ -1,16 +1,17 @@
<template>
<div class="content">
<div class="fullpage">
<a class="close" @click="back()">
<icon :icon="['far', 'times-circle']">
</icon>
</a>
<h3>Create a new list</h3>
<form @submit.prevent="newList">
<form @submit.prevent="newList" @keyup.esc="back()">
<div class="field is-grouped">
<p class="control has-icons-left is-expanded" v-bind:class="{ 'is-loading': loading}">
<input class="input" v-bind:class="{ 'disabled': loading}" v-model="list.title" type="text" placeholder="The list's name goes here...">
<span class="icon is-small is-left">
<icon icon="list-ol"/>
</span>
<p class="control is-expanded" :class="{ 'is-loading': loading}">
<input v-focus class="input" :class="{ 'disabled': loading}" v-model="list.title" type="text" placeholder="The list's name goes here...">
</p>
<p class="control">
<button type="submit" class="button is-success">
<button type="submit" class="button is-success noshadow">
<span class="icon is-small">
<icon icon="plus"/>
</span>
@ -43,21 +44,28 @@
router.push({name: 'home'})
}
},
created() {
this.$parent.setFullPage();
},
methods: {
newList() {
const cancel = message.setLoading(this)
HTTP.put(`namespaces/` + this.$route.params.id + `/lists`, this.list, {headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}})
.then(() => {
.then(response => {
this.$parent.loadNamespaces()
this.handleSuccess({message: 'The list was successfully created.'})
cancel()
router.push({name: 'showList', params: {id: response.data.id}})
})
.catch(e => {
cancel()
this.handleError(e)
})
},
back() {
router.go(-1)
},
handleError(e) {
message.error(e, this)
},
@ -66,8 +74,4 @@
}
}
}
</script>
<style scoped>
</style>
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="loader-container" v-bind:class="{ 'is-loading': loading}">
<div class="loader-container" :class="{ 'is-loading': loading}">
<div class="content">
<router-link :to="{ name: 'editList', params: { id: list.id } }" class="icon settings is-medium">
<icon icon="cog" size="2x"/>
@ -8,8 +8,8 @@
</div>
<form @submit.prevent="addTask()">
<div class="field is-grouped">
<p class="control has-icons-left is-expanded" v-bind:class="{ 'is-loading': loading}">
<input class="input" v-bind:class="{ 'disabled': loading}" v-model="newTask.text" type="text" placeholder="Add a new task...">
<p class="control has-icons-left is-expanded" :class="{ 'is-loading': loading}">
<input v-focus class="input" :class="{ 'disabled': loading}" v-model="newTask.text" type="text" placeholder="Add a new task...">
<span class="icon is-small is-left">
<icon icon="tasks"/>
</span>
@ -27,19 +27,19 @@
<div class="columns">
<div class="column">
<div class="box tasks" v-if="this.list.tasks && this.list.tasks.length > 0">
<div class="task" v-for="l in list.tasks" v-bind:key="l.id">
<label v-bind:for="l.id">
<div class="tasks" v-if="this.list.tasks && this.list.tasks.length > 0" :class="{'short': isTaskEdit}">
<div class="task" v-for="l in list.tasks" :key="l.id">
<label :for="l.id">
<div class="fancycheckbox">
<input @change="markAsDone" type="checkbox" v-bind:id="l.id" v-bind:checked="l.done" style="display: none;">
<label v-bind:for="l.id" class="check">
<input @change="markAsDone" type="checkbox" :id="l.id" :checked="l.done" style="display: none;">
<label :for="l.id" class="check">
<svg width="18px" height="18px" viewBox="0 0 18 18">
<path d="M1,9 L1,3.5 C1,2 2,1 3.5,1 L14.5,1 C16,1 17,2 17,3.5 L17,14.5 C17,16 16,17 14.5,17 L3.5,17 C2,17 1,16 1,14.5 L1,9 Z"></path>
<polyline points="1 9 7 14 15 4"></polyline>
</svg>
</label>
</div>
<span class="tasktext">
<span class="tasktext" :class="{ 'done': l.done}">
{{l.text}}
</span>
</label>
@ -67,7 +67,7 @@
<div class="field">
<label class="label" for="tasktext">Task Text</label>
<div class="control">
<input :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="tasktext" placeholder="The task text is here..." v-model="taskEditTask.text">
<input v-focus :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="tasktext" placeholder="The task text is here..." v-model="taskEditTask.text">
</div>
</div>
<div class="field">
@ -78,7 +78,7 @@
</div>
<b>Reminder Dates</b>
<div class="reminder-input" :class="{ 'overdue': (r < nowUnix && index !== (taskEditTask.reminderDates.length - 1))}" v-for="(r, index) in taskEditTask.reminderDates" v-bind:key="index">
<div class="reminder-input" :class="{ 'overdue': (r < nowUnix && index !== (taskEditTask.reminderDates.length - 1))}" v-for="(r, index) in taskEditTask.reminderDates" :key="index">
<flat-pickr
:class="{ 'disabled': loading}"
:disabled="loading"
@ -129,7 +129,7 @@
v-model="taskEditTask.endDate"
:config="flatPickerConfig"
id="taskduedate"
placeholder="Start date">
placeholder="End date">
</flat-pickr>
</div>
</div>
@ -141,7 +141,7 @@
<div class="column">
<input class="input" placeholder="Specify an amount..." v-model="repeatAfter.amount"/>
</div>
<div class="column">
<div class="column is-3">
<div class="select">
<select v-model="repeatAfter.type">
<option value="hours">Hours</option>
@ -157,30 +157,31 @@
<div class="field">
<label class="label" for="subtasks">Subtasks</label>
<div class="control subtasks">
<div class="tasks noborder" v-if="taskEditTask.subtasks && taskEditTask.subtasks.length > 0">
<div class="task" v-for="s in taskEditTask.subtasks" v-bind:key="s.id">
<label v-bind:for="s.id">
<div class="fancycheckbox">
<input @change="markAsDone" type="checkbox" v-bind:id="s.id" v-bind:checked="s.done" style="display: none;">
<label v-bind:for="s.id" class="check">
<svg width="18px" height="18px" viewBox="0 0 18 18">
<path d="M1,9 L1,3.5 C1,2 2,1 3.5,1 L14.5,1 C16,1 17,2 17,3.5 L17,14.5 C17,16 16,17 14.5,17 L3.5,17 C2,17 1,16 1,14.5 L1,9 Z"></path>
<polyline points="1 9 7 14 15 4"></polyline>
</svg>
</label>
</div>
<span class="tasktext">
{{s.text}}
</span>
</label>
</div>
<div class="tasks noborder" v-if="taskEditTask.subtasks && taskEditTask.subtasks.length > 0">
<div class="task" v-for="s in taskEditTask.subtasks" :key="s.id">
<label :for="s.id">
<div class="fancycheckbox">
<input @change="markAsDone" type="checkbox" :id="s.id" :checked="s.done" style="display: none;">
<label :for="s.id" class="check">
<svg width="18px" height="18px" viewBox="0 0 18 18">
<path d="M1,9 L1,3.5 C1,2 2,1 3.5,1 L14.5,1 C16,1 17,2 17,3.5 L17,14.5 C17,16 16,17 14.5,17 L3.5,17 C2,17 1,16 1,14.5 L1,9 Z"></path>
<polyline points="1 9 7 14 15 4"></polyline>
</svg>
</label>
</div>
<span class="tasktext" :class="{ 'done': s.done}">
{{s.text}}
</span>
</label>
</div>
<input :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="tasktext" placeholder="New subtask" v-model="newTask.text"/>
</div>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<input @keyup.enter="addSubtask()" :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="tasktext" placeholder="New subtask" v-model="newTask.text"/>
</div>
<div class="control">
<a class="button" @click="addSubtask()"><icon icon="plus"></icon></a>
</div>
</div>
@ -258,6 +259,7 @@
}
// This adds a new elemednt "list" to our object which contains all lists
response.data.tasks = this.sortTasks(response.data.tasks)
this.$set(this, 'list', response.data)
if (this.list.tasks === null) {
this.list.tasks = []
@ -302,21 +304,30 @@
if (task.ParentTask === this.taskEditTask.id) {
this.taskEditTask.subtasks.push(task)
}
this.list.tasks = this.sortTasks(this.list.tasks)
},
markAsDone(e) {
const cancel = message.setLoading(this)
let context = this
if (e.target.checked) {
setTimeout(doTheDone, 300); // Delay it to show the animation when marking a task as done
} else {
doTheDone() // Don't delay it when un-marking it as it doesn't have an animation the other way around
}
HTTP.post(`tasks/` + e.target.id, {done: e.target.checked}, {headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}})
.then(response => {
this.updateTaskByID(parseInt(e.target.id), response.data)
this.handleSuccess({message: 'The task was successfully ' + (e.target.checked ? 'un-' :'') + 'marked as done.'})
cancel() // To not set the spinner to loading when the request is made in less than 100ms, would lead to loading infinitly.
})
.catch(e => {
cancel()
this.handleError(e)
})
function doTheDone() {
const cancel = message.setLoading(context)
HTTP.post(`tasks/` + e.target.id, {done: e.target.checked}, {headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}})
.then(response => {
context.updateTaskByID(parseInt(e.target.id), response.data)
context.handleSuccess({message: 'The task was successfully ' + (e.target.checked ? '' : 'un-') + 'marked as done.'})
cancel() // To not set the spinner to loading when the request is made in less than 100ms, would lead to loading infinitly.
})
.catch(e => {
cancel()
context.handleError(e)
})
}
},
editTask(id) {
// Find the selected task and set it to the current object
@ -371,7 +382,6 @@
this.taskEditTask.startDate = (+ new Date(this.taskEditTask.startDate)) / 1000
this.taskEditTask.endDate = (+ new Date(this.taskEditTask.endDate)) / 1000
// remove all nulls
this.taskEditTask.reminderDates = this.removeNullsFromArray(this.taskEditTask.reminderDates)
// Make normal timestamps from js timestamps
@ -404,14 +414,12 @@
HTTP.post(`tasks/` + this.taskEditTask.id, this.taskEditTask, {headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}})
.then(response => {
response.data.dueDate = new Date(response.data.dueDate * 1000)
response.data.reminderDates = this.makeJSReminderDatesAfterUpdate(response.data.reminderDates)
// Update the task in the list
// Update the task in the list
this.updateTaskByID(this.taskEditTask.id, response.data)
// Also update the current taskedit object so the ui changes
this.$set(this, 'taskEditTask', this.fixStuffComingFromAPI(response.data))
response.data.reminderDates.push(null) // To be able to add a new one
this.$set(this, 'taskEditTask', response.data)
this.handleSuccess({message: 'The task was successfully updated.'})
cancel() // cancel the timers
})
@ -440,6 +448,7 @@
}
}
}
this.list.tasks = this.sortTasks(this.list.tasks)
},
fixStuffComingFromAPI(task) {
// Make date objects from timestamps
@ -455,8 +464,21 @@
if (task.subtasks === null) {
task.subtasks = []
}
return task
},
sortTasks(tasks) {
if (tasks === null) {
return tasks
}
return tasks.sort(function(a,b) {
if (a.done < b.done)
return -1
if (a.done > b.done)
return 1
return 0
})
},
parseDateIfNessecary(dateUnix) {
let dateobj = (+new Date(dateUnix * 1000))
if (dateobj === 0 || dateUnix === 0) {
@ -499,18 +521,6 @@
}
return array
},
makeJSReminderDatesAfterUpdate(dates) {
// Make js timestamps from normal timestamps
for (const rd in dates) {
dates[rd] = +new Date(dates[rd] * 1000)
}
if (dates == null) {
dates = []
}
dates.push(null)
return dates
},
handleError(e) {
message.error(e, this)
},

View File

@ -10,8 +10,8 @@
<slot name="text"></slot>
</div>
<div class="actions">
<button class="button is-danger is-inverted" @click="$emit('close')">Cancel</button>
<button class="button is-success is-inverted" @click="$emit('submit')">Do it!</button>
<button class="button is-danger is-inverted noshadow" @click="$emit('close')">Cancel</button>
<button class="button is-success noshadow" @click="$emit('submit')">Do it!</button>
</div>
</div>
</div>
@ -22,9 +22,6 @@
<script>
export default {
name: 'modal',
props: {
header: ''
},
mounted: function () {
document.addEventListener('keydown', (e) => {
// Close the model when escape is pressed

View File

@ -12,7 +12,7 @@
<div class="field">
<label class="label" for="namespacetext">Namespace Name</label>
<div class="control">
<input :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="namespacetext" placeholder="The namespace text is here..." v-model="namespace.name">
<input v-focus :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="namespacetext" placeholder="The namespace text is here..." v-model="namespace.name">
</div>
</div>
<div class="field">
@ -25,7 +25,7 @@
<div class="columns bigbuttons">
<div class="column">
<button @click="submit()" class="button is-success is-fullwidth" :class="{ 'is-loading': loading}">
<button @click="submit()" class="button is-primary is-fullwidth" :class="{ 'is-loading': loading}">
Save
</button>
</div>

View File

@ -1,16 +1,17 @@
<template>
<div class="content">
<div class="fullpage">
<a class="close" @click="back()">
<icon :icon="['far', 'times-circle']">
</icon>
</a>
<h3>Create a new namespace</h3>
<form @submit.prevent="newNamespace">
<form @submit.prevent="newNamespace" @keyup.esc="back()">
<div class="field is-grouped">
<p class="control has-icons-left is-expanded" v-bind:class="{ 'is-loading': loading}">
<input class="input" v-bind:class="{ 'disabled': loading}" v-model="namespace.name" type="text" placeholder="The namespace's name goes here...">
<span class="icon is-small is-left">
<icon icon="layer-group"/>
</span>
<p class="control is-expanded" v-bind:class="{ 'is-loading': loading}">
<input v-focus class="input" v-bind:class="{ 'disabled': loading}" v-model="namespace.name" type="text" placeholder="The namespace's name goes here...">
</p>
<p class="control">
<button type="submit" class="button is-success">
<button type="submit" class="button is-success noshadow">
<span class="icon is-small">
<icon icon="plus"/>
</span>
@ -19,55 +20,59 @@
</p>
</div>
</form>
<p class="small" v-tooltip.bottom="'A namespace is a collection of lists you can share and use to organize your lists with.<br/>In fact, every list belongs to a namepace.'">What's a namespace?</p>
</div>
</template>
<script>
import auth from '../../auth'
import router from '../../router'
import {HTTP} from '../../http-common'
import message from '../../message'
import auth from '../../auth'
import router from '../../router'
import {HTTP} from '../../http-common'
import message from '../../message'
export default {
name: "NewNamespace",
data() {
return {
namespace: {title: ''},
error: '',
loading: false
}
},
beforeMount() {
// Check if the user is already logged in, if so, redirect him to the homepage
if (!auth.user.authenticated) {
router.push({name: 'home'})
}
},
methods: {
newNamespace() {
export default {
name: "NewNamespace",
data() {
return {
namespace: {title: ''},
error: '',
loading: false
}
},
beforeMount() {
// Check if the user is already logged in, if so, redirect him to the homepage
if (!auth.user.authenticated) {
router.push({name: 'home'})
}
},
created() {
this.$parent.setFullPage();
},
methods: {
newNamespace() {
const cancel = message.setLoading(this)
HTTP.put(`namespaces`, this.namespace, {headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}})
.then(() => {
this.$parent.loadNamespaces()
this.handleSuccess({message: 'The namespace was successfully created.'})
HTTP.put(`namespaces`, this.namespace, {headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}})
.then(() => {
this.$parent.loadNamespaces()
this.handleSuccess({message: 'The namespace was successfully created.'})
cancel()
router.push({name: 'home'})
})
.catch(e => {
cancel()
})
.catch(e => {
cancel()
this.handleError(e)
})
},
handleError(e) {
message.error(e, this)
},
handleSuccess(e) {
message.success(e, this)
}
}
}
})
},
back() {
router.go(-1)
},
handleError(e) {
message.error(e, this)
},
handleSuccess(e) {
message.success(e, this)
}
}
}
</script>
<style scoped>
</style>

View File

@ -12,7 +12,7 @@
<div class="field">
<label class="label" for="teamtext">Team Name</label>
<div class="control">
<input :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="teamtext" placeholder="The team text is here..." v-model="team.name">
<input v-focus :class="{ 'disabled': loading}" :disabled="loading" class="input" type="text" id="teamtext" placeholder="The team text is here..." v-model="team.name">
</div>
</div>
<div class="field">
@ -276,6 +276,8 @@
.table{
border-top: 1px solid darken(#fff, 15%);
border-radius: 4px;
overflow: hidden;
td{
vertical-align: middle;

View File

@ -1,6 +1,9 @@
<template>
<div class="content loader-container" v-bind:class="{ 'is-loading': loading}">
<router-link :to="{name:'newTeam'}" class="button is-success button-right" >
<span class="icon is-small">
<icon icon="plus"/>
</span>
New Team
</router-link>
<h1>Teams</h1>
@ -57,35 +60,3 @@
}
}
</script>
<style lang="scss" scoped>
.button-right{
float: right;
}
ul.teams{
padding: 0;
margin-left: 0;
li{
list-style: none;
margin: 0;
border-bottom: 1px solid darken(#fff, 25%);
a{
color: #363636;
display: block;
padding: 0.5rem 1rem;
&:hover{
background: darken(#fff, 2%);
}
}
}
li:last-child{
border-bottom: none;
}
}
</style>

View File

@ -1,16 +1,17 @@
<template>
<div class="content">
<div class="fullpage">
<a class="close" @click="back()">
<icon :icon="['far', 'times-circle']">
</icon>
</a>
<h3>Create a new team</h3>
<form @submit.prevent="newTeam">
<form @submit.prevent="newTeam" @keyup.esc="back()">
<div class="field is-grouped">
<p class="control has-icons-left is-expanded" v-bind:class="{ 'is-loading': loading}">
<input class="input" v-bind:class="{ 'disabled': loading}" v-model="team.name" type="text" placeholder="The team's name goes here...">
<span class="icon is-small is-left">
<icon icon="users"/>
</span>
<p class="control is-expanded" v-bind:class="{ 'is-loading': loading}">
<input v-focus class="input" v-bind:class="{ 'disabled': loading}" v-model="team.name" type="text" placeholder="The team's name goes here...">
</p>
<p class="control">
<button type="submit" class="button is-success">
<button type="submit" class="button is-success noshadow">
<span class="icon is-small">
<icon icon="plus"/>
</span>
@ -43,6 +44,9 @@
router.push({name: 'home'})
}
},
created() {
this.$parent.setFullPage();
},
methods: {
newTeam() {
const cancel = message.setLoading(this)
@ -58,6 +62,9 @@
this.handleError(e)
})
},
back() {
router.go(-1)
},
handleError(e) {
message.error(e, this)
},
@ -67,7 +74,3 @@
}
}
</script>
<style scoped>
</style>

View File

@ -8,7 +8,7 @@
<form id="loginform" @submit.prevent="submit">
<div class="field">
<div class="control">
<input type="text" class="input" name="username" placeholder="Username" v-model="credentials.username" required>
<input v-focus type="text" class="input" name="username" placeholder="Username" v-model="credentials.username" required>
</div>
</div>
<div class="field">

View File

@ -5,7 +5,7 @@
<form id="form" @submit.prevent="submit" v-if="!successMessage">
<div class="field">
<div class="control">
<input type="password" class="input" name="password1" placeholder="Password" v-model="credentials.password" required>
<input v-focus type="password" class="input" name="password1" placeholder="Password" v-model="credentials.password" required>
</div>
</div>
<div class="field">

View File

@ -5,7 +5,7 @@
<form id="registerform" @submit.prevent="submit">
<div class="field">
<div class="control">
<input type="text" class="input" name="username" placeholder="Username" v-model="credentials.username" required>
<input v-focus type="text" class="input" name="username" placeholder="Username" v-model="credentials.username" required>
</div>
</div>
<div class="field">

View File

@ -5,7 +5,7 @@
<form id="loginform" @submit.prevent="submit" v-if="!isSuccess">
<div class="field">
<div class="control">
<input type="text" class="input" name="email" placeholder="Email-Adress" v-model="email" required>
<input v-focus type="text" class="input" name="email" placeholder="Email-Adress" v-model="email" required>
</div>
</div>