New design (#14)
This commit is contained in:
180
src/App.vue
180
src/App.vue
@ -1,84 +1,101 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<nav class="navbar is-dark" role="navigation" aria-label="main navigation" v-if="user.authenticated">
|
||||
<div class="container">
|
||||
<div class="navbar-brand">
|
||||
<router-link :to="{name: 'home'}" class="navbar-item logo">
|
||||
<img src="images/logo-full-white.svg"/>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="navbar-menu">
|
||||
<div class="navbar-end">
|
||||
<router-link :to="{name: 'listTeams'}" class="navbar-item">
|
||||
<span class="icon is-small">
|
||||
<icon icon="users"/>
|
||||
</span>
|
||||
Teams
|
||||
</router-link>
|
||||
<router-link :to="{name: 'newNamespace'}" class="navbar-item">
|
||||
<span class="icon is-small">
|
||||
<icon icon="layer-group"/>
|
||||
</span>
|
||||
New Namespace
|
||||
</router-link>
|
||||
<span class="navbar-item">{{user.infos.username}}</span>
|
||||
<span class="navbar-item image">
|
||||
<img :src="gravatar()" class="is-rounded" alt=""/>
|
||||
</span>
|
||||
<a v-on:click="logout()" class="navbar-item is-right logout-icon">
|
||||
<span class="icon is-medium">
|
||||
<icon icon="sign-out-alt" size="2x"/>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="navbar is-dark is-fixed-top" role="navigation" aria-label="main navigation" v-if="user.authenticated">
|
||||
<div class="navbar-brand">
|
||||
<router-link :to="{name: 'home'}" class="navbar-item logo">
|
||||
<img src="/images/logo-full-white.svg"/>
|
||||
</router-link>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="column is-centered container">
|
||||
<div class="box shadow" v-if="user.authenticated">
|
||||
<div class="columns">
|
||||
<div class="column is-3">
|
||||
<aside class="menu namespaces-lists">
|
||||
<p class="menu-label" v-if="loading">Loading...</p>
|
||||
<template v-for="n in namespaces">
|
||||
<div :key="n.id">
|
||||
<router-link :to="{name: 'editNamespace', params: {id: n.id} }" class="nsettings" v-if="n.id > 0">
|
||||
<span class="icon">
|
||||
<icon icon="cog"/>
|
||||
</span>
|
||||
</router-link>
|
||||
<router-link :to="{ name: 'newList', params: { id: n.id} }" class="is-success nsettings" :key="n.id + 'newList'" v-if="n.id > 0">
|
||||
<span class="icon">
|
||||
<icon icon="plus"/>
|
||||
</span>
|
||||
</router-link>
|
||||
<div class="menu-label">
|
||||
{{n.name}}
|
||||
</div>
|
||||
<div v-if="user.authenticated">
|
||||
<a @click="mobileMenuActive = true" class="mobilemenu-show-button" v-if="!mobileMenuActive"><icon icon="bars"></icon></a>
|
||||
<a @click="mobileMenuActive = false" class="mobilemenu-hide-button" v-if="mobileMenuActive"><icon icon="times"></icon></a>
|
||||
<div class="app-container">
|
||||
<div class="namespace-container" :class="{'is-active': mobileMenuActive}">
|
||||
<div class="menu top-menu">
|
||||
<ul class="menu-list user">
|
||||
<li>
|
||||
<img :src="gravatar()" class="is-rounded" alt=""/>
|
||||
<span class="username">{{user.infos.username}}</span>
|
||||
<a @click="logout()" class="logout-icon">
|
||||
<span class="icon is-medium">
|
||||
<icon icon="power-off" size="2x"/>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="menu top-menu">
|
||||
<ul class="menu-list">
|
||||
<li>
|
||||
<router-link :to="{ name: 'home'}">
|
||||
<span class="icon">
|
||||
<icon icon="calendar"/>
|
||||
</span>
|
||||
Overview
|
||||
</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link :to="{ name: 'listTeams'}">
|
||||
<span class="icon">
|
||||
<icon icon="users"/>
|
||||
</span>
|
||||
Teams
|
||||
</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link :to="{ name: 'newNamespace'}">
|
||||
<span class="icon">
|
||||
<icon icon="layer-group"/>
|
||||
</span>
|
||||
New Namespace
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<aside class="menu namespaces-lists">
|
||||
<div class="spinner" :class="{ 'is-loading': loading}"></div>
|
||||
<template v-for="n in namespaces">
|
||||
<div :key="n.id">
|
||||
<router-link v-tooltip.right="'Settings'" :to="{name: 'editNamespace', params: {id: n.id} }" class="nsettings" v-if="n.id > 0">
|
||||
<span class="icon">
|
||||
<icon icon="cog"/>
|
||||
</span>
|
||||
</router-link>
|
||||
<router-link v-tooltip="'Add a new list in the ' + n.name + ' namespace'" :to="{ name: 'newList', params: { id: n.id} }" class="nsettings" :key="n.id + 'newList'" v-if="n.id > 0">
|
||||
<span class="icon">
|
||||
<icon icon="plus"/>
|
||||
</span>
|
||||
</router-link>
|
||||
<div class="menu-label">
|
||||
{{n.name}}
|
||||
</div>
|
||||
<ul class="menu-list" :key="n.id + 'child'">
|
||||
<li v-for="l in n.lists" :key="l.id">
|
||||
<router-link :to="{ name: 'showList', params: { id: l.id} }">{{l.title}}</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</aside>
|
||||
</div>
|
||||
<div class="column is-9">
|
||||
<router-view/>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="menu-list" :key="n.id + 'child'">
|
||||
<li v-for="l in n.lists" :key="l.id">
|
||||
<router-link :to="{ name: 'showList', params: { id: l.id} }">{{l.title}}</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="container has-text-centered">
|
||||
<div class="column is-4 is-offset-4">
|
||||
<img src="images/logo-full.svg"/>
|
||||
<router-view/>
|
||||
</div>
|
||||
<div class="app-content" :class="{'fullpage-overlay': fullpage}">
|
||||
<a class="mobile-overlay" v-if="mobileMenuActive" @click="mobileMenuActive = false"></a>
|
||||
<transition name="fade">
|
||||
<router-view/>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<notifications position="bottom left" />
|
||||
<div v-else>
|
||||
<div class="container has-text-centered">
|
||||
<div class="column is-4 is-offset-4">
|
||||
<img src="/images/logo-full.svg"/>
|
||||
<router-view/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<notifications position="bottom left" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -96,6 +113,8 @@
|
||||
user: auth.user,
|
||||
loading: false,
|
||||
namespaces: [],
|
||||
mobileMenuActive: false,
|
||||
fullpage: false,
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
@ -119,7 +138,7 @@
|
||||
},
|
||||
watch: {
|
||||
// call the method again if the route changes
|
||||
'$route': 'loadNamespacesIfNeeded'
|
||||
'$route': 'doStuffAfterRoute'
|
||||
},
|
||||
methods: {
|
||||
logout() {
|
||||
@ -129,14 +148,14 @@
|
||||
return 'https://www.gravatar.com/avatar/' + this.user.infos.avatar + '?s=50'
|
||||
},
|
||||
loadNamespaces() {
|
||||
this.loading = true
|
||||
this.namespaces = []
|
||||
const cancel = message.setLoading(this)
|
||||
HTTP.get(`namespaces`, {headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}})
|
||||
.then(response => {
|
||||
this.$set(this, 'namespaces', response.data)
|
||||
this.loading = false
|
||||
cancel()
|
||||
})
|
||||
.catch(e => {
|
||||
cancel()
|
||||
this.handleError(e)
|
||||
})
|
||||
},
|
||||
@ -145,8 +164,15 @@
|
||||
this.loadNamespaces()
|
||||
}
|
||||
},
|
||||
doStuffAfterRoute(e) {
|
||||
this.fullpage = false;
|
||||
this.loadNamespacesIfNeeded(e)
|
||||
this.mobileMenuActive = false
|
||||
},
|
||||
setFullPage() {
|
||||
this.fullpage = true;
|
||||
},
|
||||
handleError(e) {
|
||||
this.loading = false
|
||||
message.error(e, this)
|
||||
}
|
||||
},
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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)
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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;
|
||||
|
@ -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>
|
@ -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>
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
||||
|
24
src/main.js
24
src/main.js
@ -30,6 +30,11 @@ import { faUser } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faLock } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faPen } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faTimes } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faTachometerAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faCalendar } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faBars } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faPowerOff } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faTimesCircle } from '@fortawesome/free-regular-svg-icons'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
|
||||
library.add(faSignOutAlt)
|
||||
@ -45,9 +50,28 @@ library.add(faUser)
|
||||
library.add(faLock)
|
||||
library.add(faPen)
|
||||
library.add(faTimes)
|
||||
library.add(faTachometerAlt)
|
||||
library.add(faCalendar)
|
||||
library.add(faTimesCircle)
|
||||
library.add(faBars)
|
||||
library.add(faPowerOff)
|
||||
|
||||
Vue.component('icon', FontAwesomeIcon)
|
||||
|
||||
// Tooltip
|
||||
import VTooltip from 'v-tooltip'
|
||||
Vue.use(VTooltip)
|
||||
|
||||
// Set focus
|
||||
Vue.directive('focus', {
|
||||
// When the bound element is inserted into the DOM...
|
||||
inserted: function (el) {
|
||||
// Focus the element
|
||||
el.focus()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// Check the user's auth status when the app starts
|
||||
auth.checkAuth()
|
||||
|
||||
|
109
src/styles/_tooltip.scss
Normal file
109
src/styles/_tooltip.scss
Normal file
@ -0,0 +1,109 @@
|
||||
.tooltip {
|
||||
display: block !important;
|
||||
z-index: 10000;
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
|
||||
.tooltip-inner {
|
||||
background: $dark;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
padding: 5px 10px 5px;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
position: absolute;
|
||||
margin: 5px;
|
||||
border-color: $dark;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&[x-placement^="top"] {
|
||||
margin-bottom: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 5px 0 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
bottom: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="bottom"] {
|
||||
margin-top: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 0 5px 5px 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
top: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="right"] {
|
||||
margin-left: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 5px 5px 0;
|
||||
border-left-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
left: -5px;
|
||||
top: calc(50% - 5px);
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="left"] {
|
||||
margin-right: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-top-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
right: -5px;
|
||||
top: calc(50% - 5px);
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.popover {
|
||||
.popover-inner {
|
||||
background: $light;
|
||||
color: $dark;
|
||||
padding: 24px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 5px 30px rgba(black, .1);
|
||||
}
|
||||
|
||||
.popover-arrow {
|
||||
border-color: $light;
|
||||
}
|
||||
}
|
||||
|
||||
&[aria-hidden='true'] {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity .15s, visibility .15s;
|
||||
}
|
||||
|
||||
&[aria-hidden='false'] {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity .15s;
|
||||
}
|
||||
}
|
26
src/styles/_variables.scss
Normal file
26
src/styles/_variables.scss
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
$black: hsl(0, 0%, 4%) !default
|
||||
|
||||
$orange: #ff851b;
|
||||
$green: #00CE6E;
|
||||
$blue: #5974d9;
|
||||
$red: #ff4136;
|
||||
$primary: #198CFF !default;
|
||||
$dark: lighten($black, 8);
|
||||
|
||||
$info-invert: #fff;
|
||||
$family-sans-serif: 'Open Sans', Helvetica, Arial, sans-serif;
|
||||
$thickness: 1px;
|
||||
$pagination-current-border: darken($primary, 5);
|
||||
$navbar-item-active-color: $primary;
|
||||
$dropdown-content-shadow: none;
|
||||
$navbar-dropdown-boxed-shadow: $dropdown-content-shadow;
|
||||
$bulmaswatch-import-font: false !default;
|
||||
|
||||
$vikunja-font: 'Quicksand', sans-serif;
|
||||
$vikunja-light-text: darken(#fff, 10%);
|
||||
$vikunja-blue: #7F23FF;// #7F23FF; // #5974d9
|
||||
$vikunja-green: #4DB788;
|
||||
$navbar-padding: 1.5em;
|
||||
|
||||
$transition: 150ms ease;
|
58
src/styles/fancycheckbox.scss
Normal file
58
src/styles/fancycheckbox.scss
Normal file
@ -0,0 +1,58 @@
|
||||
|
||||
// Fancy Checkboxes
|
||||
.fancycheckbox {
|
||||
display: inline-block;
|
||||
padding-right: 5px;
|
||||
padding-top: 3px;
|
||||
|
||||
.check {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
margin: auto;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
transform: translate3d(0, 0, 0);
|
||||
|
||||
&:hover svg {
|
||||
stroke: $primary;
|
||||
}
|
||||
|
||||
svg {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke: #c8ccd4;
|
||||
stroke-width: 1.5;
|
||||
transform: translate3d(0, 0, 0);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
path {
|
||||
stroke-dasharray: 60;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
polyline {
|
||||
stroke-dasharray: 22;
|
||||
stroke-dashoffset: 66;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked + .check svg {
|
||||
stroke: $primary;
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked + .check svg path {
|
||||
stroke-dashoffset: 60;
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked + .check svg polyline {
|
||||
stroke-dashoffset: 42;
|
||||
transition: all 0.2s linear;
|
||||
transition-delay: 0.15s;
|
||||
}
|
||||
}
|
57
src/styles/fullpage.scss
Normal file
57
src/styles/fullpage.scss
Normal file
@ -0,0 +1,57 @@
|
||||
.fullpage{
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
padding: 15vh 20vh;
|
||||
background: $vikunja-blue;
|
||||
color: $vikunja-light-text;
|
||||
font-size: 2em;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
padding: 20vw 10vw;
|
||||
}
|
||||
|
||||
input{
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 3px solid darken($vikunja-blue, 10);
|
||||
color: $vikunja-light-text;
|
||||
padding: 1em 0.5em;
|
||||
font-size: 1.5em;
|
||||
border-radius: 0;
|
||||
|
||||
&::placeholder{
|
||||
color: $vikunja-light-text;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
font-size: 1em;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
h3{
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: fixed;
|
||||
top: 5vh;
|
||||
right: 6vh;
|
||||
color: $vikunja-light-text;
|
||||
}
|
||||
|
||||
.small{
|
||||
margin-top: 1em;
|
||||
font-size: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.fullpage-overlay{
|
||||
z-index: 6 !important;
|
||||
}
|
312
src/styles/general.scss
Normal file
312
src/styles/general.scss
Normal file
@ -0,0 +1,312 @@
|
||||
|
||||
/* Logo */
|
||||
.logo {
|
||||
|
||||
padding-left: 2rem !important;
|
||||
|
||||
img {
|
||||
max-height: 3rem !important;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Buttons icons */
|
||||
.button .icon.is-small {
|
||||
margin-right: 0.05rem !important;
|
||||
}
|
||||
|
||||
/* menu buttons */
|
||||
.button-bottom {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.navbar-menu .navbar-item .icon{
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
||||
.navbar{
|
||||
z-index: 4 !important;
|
||||
}
|
||||
|
||||
.app-container{
|
||||
min-height: calc(100vh - 65px);
|
||||
@media screen and (max-width: $tablet) {
|
||||
padding-top: $navbar-height + 0.75rem;
|
||||
}
|
||||
|
||||
.namespace-container{
|
||||
background: $vikunja-blue;
|
||||
box-shadow: 0 0 1em darken(#fff, 30%);
|
||||
z-index: 3;
|
||||
color: $vikunja-light-text;
|
||||
padding: 0;
|
||||
transition: all $transition;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: $navbar-height + 0.75rem;
|
||||
overflow-x: auto;
|
||||
width: 17vw;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
padding: 0 0 1em;
|
||||
left: -147vw;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 70vw;
|
||||
z-index: 5;
|
||||
|
||||
&.is-active {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.namespaces-lists{
|
||||
border-top: 1px solid darken($vikunja-blue, 6);
|
||||
}
|
||||
|
||||
.menu{
|
||||
.menu-label {
|
||||
font-size: 1em;
|
||||
font-weight: 400;
|
||||
min-height: 2.5em;
|
||||
padding-top: $navbar-padding * 0.3;
|
||||
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nsettings{
|
||||
vertical-align: middle;
|
||||
float: right;
|
||||
margin-left: 0.5rem;
|
||||
min-width: 2.648em;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
font-weight: bold;
|
||||
font-family: $vikunja-font;
|
||||
}
|
||||
|
||||
.menu-label,.nsettings,.menu-list a{
|
||||
color: $vikunja-light-text;
|
||||
}
|
||||
|
||||
.menu-label{
|
||||
padding-left: $navbar-padding;
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
li {
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
a {
|
||||
padding-left: $navbar-padding * 2;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
|
||||
.icon {
|
||||
height: 1rem;
|
||||
vertical-align: middle;
|
||||
padding-bottom: 4px;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
&.router-link-exact-active {
|
||||
background: darken($vikunja-blue, 5%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: darken($vikunja-blue, 3%);
|
||||
}
|
||||
}
|
||||
|
||||
&.user{
|
||||
padding: 0 0.5em 1em 1em;
|
||||
border-bottom: 1px solid #6d04ff;
|
||||
|
||||
li{
|
||||
height: auto;
|
||||
}
|
||||
|
||||
img.is-rounded{
|
||||
border-radius: 100%;
|
||||
vertical-align: middle;
|
||||
margin-top: -20px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.username{
|
||||
font-family: $vikunja-font;
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
padding-left: 0.5em;
|
||||
margin-top: 20px;
|
||||
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: calc(100% - 103px - 1em);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a.logout-icon{
|
||||
float: right;
|
||||
width: 53px;
|
||||
margin-top: 15px;
|
||||
|
||||
&:hover, &:focus{
|
||||
color: lighten($light, 80);
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-menu {
|
||||
margin: $navbar-padding 0;
|
||||
|
||||
.menu-list a {
|
||||
padding-left: $navbar-padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app-content{
|
||||
padding: $navbar-height + 1.5rem 1.5em 0 1.5em;
|
||||
z-index: 2;
|
||||
background: url('../public/images/llama-upside-down.svg') no-repeat top right darken(#fff, 4);
|
||||
margin-left: 17vw;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
margin-left: 0;
|
||||
padding-top: 1.5em;
|
||||
min-height: calc(100vh - 4rem);
|
||||
}
|
||||
|
||||
.card{
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobilemenu-hide-button,.mobilemenu-show-button{
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 5;
|
||||
font-weight: bold;
|
||||
font-size: 2em;
|
||||
color: $light;
|
||||
&:hover, &:focus{
|
||||
color: $light;
|
||||
}
|
||||
}
|
||||
|
||||
.mobilemenu-hide-button{
|
||||
color: $dark;
|
||||
&:hover, &:focus{
|
||||
color: $dark;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-overlay{
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(250,250,250,0.8);
|
||||
z-index: 4;
|
||||
opacity: 0;
|
||||
transition: all $transition;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
.mobilemenu-hide-button{
|
||||
display: block;
|
||||
top: 1vh;
|
||||
right: 4vh;
|
||||
}
|
||||
|
||||
.mobilemenu-show-button{
|
||||
display: block;
|
||||
top: 1vh;
|
||||
left: 4vh;
|
||||
}
|
||||
|
||||
.mobile-overlay{
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.navbar.is-dark .navbar-brand > .navbar-item{
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Logout-icon */
|
||||
.logout-icon {
|
||||
margin-right: 0.85em !important;
|
||||
}
|
||||
|
||||
/* Loading spinner */
|
||||
.loader-container {
|
||||
&.is-loading {
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
&:after {
|
||||
@include loader;
|
||||
position: absolute;
|
||||
top: calc(50% - 2.5em);
|
||||
left: calc(50% - 2.5em);
|
||||
width: 5em;
|
||||
height: 5em;
|
||||
border-width: 0.25em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.spinner{
|
||||
&.is-loading {
|
||||
pointer-events: none;
|
||||
&:after {
|
||||
@include loader;
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
margin-left: calc(50% - 1em);
|
||||
position: absolute;
|
||||
margin-top: 1em;
|
||||
z-index: 999;
|
||||
border-width: 0.25em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notifications{
|
||||
left: 0.5em !important;
|
||||
bottom: 1em !important;
|
||||
|
||||
.notification-wrapper .notification{
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
border-top-width: 0;
|
||||
border-right-width: 0;
|
||||
border-bottom-width: 0;
|
||||
border-left-width: 0.4em;
|
||||
}
|
||||
}
|
||||
|
||||
.button-right{
|
||||
float: right;
|
||||
}
|
101
src/styles/tasks.scss
Normal file
101
src/styles/tasks.scss
Normal file
@ -0,0 +1,101 @@
|
||||
.settings{
|
||||
float: right;
|
||||
color: rgb(74, 74, 74);
|
||||
}
|
||||
|
||||
.tasks {
|
||||
margin-top: 1rem;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
max-width: 80vw;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
&.short {
|
||||
max-width: 53vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&.noborder{
|
||||
margin: 1rem -0.5rem;
|
||||
}
|
||||
|
||||
.task {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
border-bottom: 1px solid darken(#fff, 10%);
|
||||
|
||||
label{
|
||||
width: 96%;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
|
||||
.tasktext {
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
width: 94%;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
width: 89%;
|
||||
}
|
||||
|
||||
&.done{
|
||||
text-decoration: line-through;
|
||||
color: $grey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.settings{
|
||||
float: right;
|
||||
width: 4%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.task:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.taskedit{
|
||||
min-height: calc(100% - 1rem);
|
||||
margin-top: 1rem;
|
||||
|
||||
.reminder-input{
|
||||
margin: 0;
|
||||
|
||||
&.overdue input{
|
||||
color: $red;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $red;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 90%;
|
||||
border: none;
|
||||
|
||||
&:focus {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
src/styles/teams.scss
Normal file
25
src/styles/teams.scss
Normal file
@ -0,0 +1,25 @@
|
||||
ul.teams{
|
||||
padding: 0;
|
||||
margin-left: 0;
|
||||
overflow: hidden;
|
||||
|
||||
li{
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid $border;
|
||||
|
||||
a{
|
||||
color: #363636;
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
|
||||
&:hover{
|
||||
background: darken(#fff, 2%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li:last-child{
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
230
src/styles/theme.scss
Normal file
230
src/styles/theme.scss
Normal file
@ -0,0 +1,230 @@
|
||||
@import url('/fonts/fonts.css');
|
||||
@import 'variables';
|
||||
@import "../../node_modules/bulma/bulma";
|
||||
|
||||
*, *:hover, *:active, *:focus{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button {
|
||||
transition: all $transition;
|
||||
border: 0;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
height: 2.648em;
|
||||
|
||||
box-shadow: 0.3em 0.3em 1em lighten($dark, 75);
|
||||
&.is-hovered,
|
||||
&:hover {
|
||||
box-shadow: 0.6em 0.6em 1em lighten($dark, 75);
|
||||
}
|
||||
|
||||
&.is-active,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&:focus,
|
||||
&:focus:not(:active) {
|
||||
box-shadow: 0.1em 0.1em 0.7em lighten($dark, 75) !important;
|
||||
}
|
||||
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
|
||||
&.is-#{$name} {
|
||||
box-shadow: 0.3em 0.3em 1em lighten($color, 30);
|
||||
|
||||
&.is-hovered,
|
||||
&:hover {
|
||||
box-shadow: 0.6em 0.6em 1em lighten($color, 30);
|
||||
}
|
||||
|
||||
&.is-active,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&:focus,
|
||||
&:focus:not(:active) {
|
||||
box-shadow: 0.1em 0.1em 0.7em lighten($color, 30) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.noshadow{
|
||||
&,
|
||||
&.is-hovered,
|
||||
&:hover,
|
||||
&.is-active,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&:focus,
|
||||
&:focus:not(:active) {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input,
|
||||
.textarea {
|
||||
transition: all $transition;
|
||||
box-shadow: none;
|
||||
|
||||
&.is-active,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
$color-invert: nth($pair, 2);
|
||||
|
||||
&.is-#{$name} {
|
||||
&.is-active,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&:focus,
|
||||
&:focus:not(:active) {
|
||||
border-color: darken($color, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select:after {
|
||||
margin-top: -0.575em;
|
||||
}
|
||||
|
||||
.select select {
|
||||
border-width: $thickness;
|
||||
|
||||
&:not([multiple]) {
|
||||
height: calc(2.25em + #{$thickness});
|
||||
}
|
||||
|
||||
&.is-active,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&:focus,
|
||||
&:focus:not(:active) {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.field.has-addons {
|
||||
.control .select select {
|
||||
height: 2.25em;
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
border: $thickness solid $border;
|
||||
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
|
||||
&.is-#{$name} {
|
||||
border-color: darken($color, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress {
|
||||
border-radius: $radius-large;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: rgba($grey-lighter, 0.075);
|
||||
border-radius: $radius;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.card-image {
|
||||
img {
|
||||
border-radius: $radius $radius 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
box-shadow: none;
|
||||
border-bottom: 1px solid $grey-lighter;
|
||||
border-radius: $radius $radius 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.box,.card{
|
||||
border: $thickness solid $border;
|
||||
box-shadow: 0.3em 0.3em 0.8em darken($light, 6);
|
||||
}
|
||||
|
||||
.message {
|
||||
.message-body {
|
||||
border: $thickness solid;
|
||||
}
|
||||
}
|
||||
|
||||
.hero {
|
||||
.navbar {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
$color-invert: nth($pair, 2);
|
||||
|
||||
&.is-#{$name} {
|
||||
.navbar {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include touch {
|
||||
.navbar-menu {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar {
|
||||
z-index: 2;
|
||||
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
$color-invert: nth($pair, 2);
|
||||
|
||||
&.is-#{$name} {
|
||||
border-color: darken($color, 5);
|
||||
}
|
||||
}
|
||||
.navbar-dropdown {
|
||||
box-shadow: $navbar-dropdown-boxed-shadow;
|
||||
top: 101%;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-link,
|
||||
.pagination-next,
|
||||
.pagination-previous {
|
||||
border-width: $thickness;
|
||||
}
|
||||
|
||||
body {
|
||||
background: url('../public/images/llama.svg') no-repeat bottom left fixed darken(#fff, 4);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
font-family: $vikunja-font;
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
.bigbuttons{
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.control.has-icons-left .icon, .control.has-icons-right .icon {
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.buttonright {
|
||||
margin-right: 0.5rem;
|
||||
}
|
268
src/vikunja.scss
268
src/vikunja.scss
@ -1,263 +1,9 @@
|
||||
*, *:hover, *:active, *:focus{
|
||||
outline: none;
|
||||
}
|
||||
@import 'styles/theme';
|
||||
@import 'styles/general';
|
||||
|
||||
@import '../node_modules/bulmaswatch/lumen/variables';
|
||||
@import "../node_modules/bulma/bulma";
|
||||
@import '../node_modules/bulmaswatch/lumen/overrides';
|
||||
@import 'styles/tasks';
|
||||
@import 'styles/teams';
|
||||
@import 'styles/fullpage';
|
||||
|
||||
@import url('/fonts/fonts.css');
|
||||
|
||||
*, *:focus, *:active{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
body {
|
||||
background: url('../public/images/llama.svg') no-repeat bottom right fixed darken(#fff, 7%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
font-family: 'Quicksand', sans-serif;
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
/* Logout-icon */
|
||||
.logout-icon {
|
||||
margin-right: 0.85em !important;
|
||||
}
|
||||
|
||||
/* Logo */
|
||||
.logo {
|
||||
|
||||
padding-left: 2rem !important;
|
||||
|
||||
img {
|
||||
max-height: 3rem !important;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Buttons icons */
|
||||
.button .icon.is-small {
|
||||
margin-right: 0.05rem !important;
|
||||
}
|
||||
|
||||
/* List active link */
|
||||
.menu-list a.router-link-active{
|
||||
background: darken(#fff, 5%);
|
||||
}
|
||||
|
||||
/* menu buttons */
|
||||
.button-bottom {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.navbar-menu .navbar-item .icon{
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
||||
/* Namespaces list */
|
||||
.namespaces-lists{
|
||||
.menu-label {
|
||||
font-size: 1em;
|
||||
font-weight: 400;
|
||||
min-height: 2.5em;
|
||||
padding-top: 0.3em;
|
||||
}
|
||||
|
||||
/* Namespace settings */
|
||||
.nsettings{
|
||||
vertical-align: middle;
|
||||
float: right;
|
||||
margin-left: 0.5rem;
|
||||
min-width: 2.648em;
|
||||
color: rgb(74, 74, 74);
|
||||
}
|
||||
}
|
||||
|
||||
.bigbuttons{
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.card{
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.buttonright {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.tasks.noborder{
|
||||
margin: 1rem -0.5rem;
|
||||
}
|
||||
|
||||
.tasks {
|
||||
margin-top: 1rem;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
|
||||
.task {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
border-bottom: 1px solid darken(#fff, 10%);
|
||||
|
||||
label{
|
||||
width: 96%;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
|
||||
.tasktext {
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.settings{
|
||||
float: right;
|
||||
width: 4%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.task:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.taskedit{
|
||||
min-height: calc(100% - 1rem);
|
||||
margin-top: 1rem;
|
||||
|
||||
.subtasks {
|
||||
input {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.button {
|
||||
float:right;
|
||||
}
|
||||
}
|
||||
|
||||
.reminder-input{
|
||||
margin: 0;
|
||||
|
||||
&.overdue input{
|
||||
color: $red;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $red;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 90%;
|
||||
border: none;
|
||||
|
||||
&:focus {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.settings{
|
||||
float: right;
|
||||
color: rgb(74, 74, 74);
|
||||
}
|
||||
|
||||
.column.container {
|
||||
padding:0;
|
||||
|
||||
.box.shadow {
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: 2px 2px 5px lighten(#000, 85%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Loading spinner */
|
||||
.loader-container {
|
||||
&.is-loading {
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
&:after {
|
||||
@include loader;
|
||||
position: absolute;
|
||||
top: calc(50% - 2.5em);
|
||||
left: calc(50% - 2.5em);
|
||||
width: 5em;
|
||||
height: 5em;
|
||||
border-width: 0.25em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fancy Checkboxes
|
||||
.fancycheckbox {
|
||||
display: inline-block;
|
||||
padding-right: 5px;
|
||||
padding-top: 3px;
|
||||
|
||||
.check {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
margin: auto;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
transform: translate3d(0, 0, 0);
|
||||
|
||||
&:hover svg {
|
||||
stroke: $primary;
|
||||
}
|
||||
|
||||
svg {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke: #c8ccd4;
|
||||
stroke-width: 1.5;
|
||||
transform: translate3d(0, 0, 0);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
path {
|
||||
stroke-dasharray: 60;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
polyline {
|
||||
stroke-dasharray: 22;
|
||||
stroke-dashoffset: 66;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked + .check svg {
|
||||
stroke: $primary;
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked + .check svg path {
|
||||
stroke-dashoffset: 60;
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked + .check svg polyline {
|
||||
stroke-dashoffset: 42;
|
||||
transition: all 0.2s linear;
|
||||
transition-delay: 0.15s;
|
||||
}
|
||||
}
|
||||
@import 'styles/fancycheckbox';
|
||||
@import 'styles/tooltip';
|
Reference in New Issue
Block a user