Skip to content

Show task for current note only #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion client/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,22 @@ export default {
mounted: function() {
SharedBuefy.notifications = this.$buefy.toast;
SharedBuefy.dialog = this.$buefy.dialog;
},
provide() {
const global = {};
Object.defineProperty(global, "taskList", {
enumerable: true,
get: () => this.taskList
});
return { global };
},
data() {
return {
global: {},
taskList: []
};
}
}
};
</script>

<style lang="sass">
Expand Down
35 changes: 34 additions & 1 deletion client/src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</template>

<script lang="ts">
import { Vue, Component, Watch } from 'vue-property-decorator';
import { Vue, Component, Watch, Inject } from 'vue-property-decorator';
import * as CodeMirror from 'codemirror';
import _ from 'lodash';

Expand Down Expand Up @@ -53,6 +53,8 @@ import eventHub from '../services/eventHub';
}
})
export default class Editor extends Vue {
@Inject()
private global: any;
public editor!: CodeMirror.Editor;
public value!: string;

Expand Down Expand Up @@ -83,12 +85,30 @@ export default class Editor extends Vue {
this.editor = CodeMirror.fromTextArea(tagElement, this.config);

this.editor.on('changes', _.throttle(() => {
this.generateTaskList();
this.$emit('valChanged', this.editor.getValue());
}, 500, {trailing: true, leading: false}));

this.handleValueUpdate(true);
}

generateTaskList() {
// Get task list for today
const data = this.editor.getValue();
const regex = /- \[( |x)\] (.+)/gm;
let m: any;
let completed = false;
this.global.taskList.splice(0)
while ((m = regex.exec(data)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
completed = m[1] === "x";
this.global.taskList.push({ completed, name: m[2], index: m['index'] });
}
}

created() {
eventHub.$on('focusEditor', this.focus);
}
Expand Down Expand Up @@ -143,6 +163,19 @@ export default class Editor extends Vue {
this.editor.setCursor(cursor);
});
}

@Watch('global.taskList')
onTaskListChanged() {
const data = this.editor.getValue();
let newData = data
this.global.taskList.forEach((task: any) => {
let c = task.completed ? 'x' : ' ';
newData = newData.substr(0, task.index + 3) + c + newData.substr(task.index + 4);
})
if (newData !== data) {
this.editor.setValue(newData);
}
}
}
</script>

Expand Down
17 changes: 4 additions & 13 deletions client/src/components/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,7 @@
</b-tooltip>
</div>
</div>
<div class="level-item alt-button" v-if="sidebar.tasks.length">
<b-dropdown aria-role="list">
<b-tooltip label="Tasks" position="is-bottom" slot="trigger" role="button">
<b-icon icon="tasks"></b-icon>
</b-tooltip>
<b-dropdown-item custom v-for="task of sidebar.tasks" v-bind:key="task.uuid">
<SimpleTask :task="task"></SimpleTask>
</b-dropdown-item>
</b-dropdown>
</div>
<Tasks></Tasks>
<div class="level-item alt-button">
<div @click="goToSearch()">
<b-tooltip label="Search notes" position="is-bottom">
Expand Down Expand Up @@ -109,11 +100,11 @@ import {NoteService} from '../services/notes';

import {IHeaderOptions} from '../interfaces';

import SimpleTask from './SimpleTask.vue';
import Tasks from './Tasks.vue';

@Component({
components: {
SimpleTask,
Tasks
},
props: {
options: {
Expand Down Expand Up @@ -229,4 +220,4 @@ export default class Header extends Vue {
color: #888;
cursor: unset;
}
</style>
</style>
52 changes: 52 additions & 0 deletions client/src/components/TaskItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<template>
<div class="field">
<b-checkbox v-model="task.completed" @input="updateTask">
{{ this.task.name }}
</b-checkbox>
</div>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import { Inject } from "vue-property-decorator";

import SidebarInst from "../services/sidebar";

@Component({
props: {
task: {
type: Object,
required: true
},
index: {
type: Number,
required: true
}
}
})
export default class TaskItem extends Vue {
public task: any;
public index: any;
public sidebar = SidebarInst;
public completed: Boolean = false;

@Inject()
public global: any;

public async updateTask() {
this.global.taskList.splice(this.index, 1, this.task);
}
}
</script>

<style>
.level-item > .dropdown > .dropdown-menu {
width: 300px;
}

.level-item > .dropdown > .dropdown-menu > .dropdown-content {
max-height: 400px;
overflow-y: auto;
}
</style>
44 changes: 44 additions & 0 deletions client/src/components/Tasks.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<template>
<div class="level-item alt-button">
<b-dropdown aria-role="list">
<b-tooltip
label="Tasks"
position="is-bottom"
slot="trigger"
role="button"
>
<b-icon icon="tasks"></b-icon>
</b-tooltip>
<b-dropdown-item
custom
v-for="(task, idx) in global.taskList"
:key="task.index"
>
<task-item :task="task" :index="idx"></task-item>
</b-dropdown-item>
<div class="no-tasks" v-if="!global.taskList.length">No tasks found</div>
</b-dropdown>
</div>
</template>

<script lang="ts">
import { Vue, Component, Inject, Watch } from "vue-property-decorator";
import _ from "lodash";

import TaskItem from "./TaskItem.vue";

@Component({
components: { TaskItem }
})
export default class Tasks extends Vue {
@Inject()
public global: any;
}
</script>

<style scoped>
.no-tasks {
margin-left: 1em;
color: black;
}
</style>
94 changes: 94 additions & 0 deletions client/src/components/UnsavedForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<template>
<transition>
<div v-if="isActive" class="dialog modal is-active">
<div class="modal-background" @click="cancel('outside')" />
<div class="modal-card animation-content">
<header class="modal-card-head">
<p class="modal-card-title">Unsaved Content</p>
</header>

<section class="modal-card-body is-flex">
<div class="media">
<div class="media-left">
<b-icon
icon="alert"
type="is-warning"
:both="true"
size="is-large"
/>
</div>
<div class="media-content">
<p>
<template>
<div>
You have unsaved changes changes. What would you like to do?
</div>
</template>
</p>
</div>
</div>
</section>

<footer class="modal-card-foot">
<b-button ref="cancelButton" @click="cancel('button')"
>Cancel</b-button
>
<b-button type="is-warning" ref="discardButton" @click="discard"
>Discard</b-button
>
<b-button
type="is-primary"
ref="saveButton"
class="is-focused"
@click="save"
>Save &amp; Continue</b-button
>
</footer>
</div>
</div>
</transition>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";

@Component
export default class UnsavedForm extends Vue {
public isActive: boolean = false;

mounted() {
this.isActive = true;
if (typeof window !== "undefined") {
document.addEventListener("keyup", this.keyPress);
}
}

beforeDestroy() {
if (typeof window !== "undefined") {
document.removeEventListener("keyup", this.keyPress);
}
}

keyPress({ key }: any) {
if (key == "Enter") {
this.save();
}
}

cancel() {
this.$emit("cancel");
this.$emit("close");
}

discard() {
this.$emit("close");
this.$emit("discard");
}

save() {
this.$emit("close");
this.$emit("save");
}
}
</script>
30 changes: 21 additions & 9 deletions client/src/views/Day.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {INote} from '../interfaces';

import Editor from '@/components/Editor.vue';
import Header from '@/components/Header.vue';
import UnsavedForm from '@/components/UnsavedForm.vue';

import {IHeaderOptions} from '../interfaces';

Expand Down Expand Up @@ -159,7 +160,9 @@ export default class Day extends Vue {
const updatedDay = Object.assign(this.day, {data: this.modifiedText});
try {
const res = await NoteService.saveDay(updatedDay);
this.text = this.modifiedText;
if (!this.sidebar.autoSave) {
this.text = this.modifiedText;
}
this.day.uuid = res.uuid;

// Update the indicators
Expand Down Expand Up @@ -254,14 +257,23 @@ export default class Day extends Vue {
}

async unsavedDialog(next: Function) {
this.$buefy.dialog.confirm({
title: "Unsaved Content",
message: "Are you sure you want to discard the unsaved content?",
confirmText: "Discard",
type: "is-warning",
hasIcon: true,
onConfirm: () => next(),
onCancel: () => next(false)
this.$buefy.modal.open({
parent: this,
component: UnsavedForm,
hasModalCard: true,
trapFocus: true,
events: {
cancel: () => {
next(false);
},
discard: () => {
next();
},
save: () => {
this.saveDay();
next();
}
}
});
}
}
Expand Down
Loading