Added some colors to the notes and basic support for displaying the colors on the main list Added a toggle to disable the fancy text editor and just use a basic textarea Added some mobile styles with much better support for smaller screens Added tag suggestions based on user input, excluding tags from current note, only using tags user has put into system Cleaned and refactored a bunch of stuff
213 lines
4.9 KiB
Vue
213 lines
4.9 KiB
Vue
<template>
|
|
<div>
|
|
|
|
|
|
<div class="ui equal width grid">
|
|
|
|
<!-- mobile search menu -->
|
|
<div class="ui mobile only row">
|
|
<!-- Small screen new note button -->
|
|
<div class="ui four wide column">
|
|
<div @click="createNote" class="ui fluid green icon button">
|
|
<i class="plus icon"></i>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ui twelve wide column">
|
|
<div class="ui form">
|
|
<input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- search menu -->
|
|
<div class="ui large screen only row">
|
|
|
|
<div class="ui two wide column">
|
|
<div @click="createNote" class="ui fluid green button">
|
|
<i class="plus icon"></i>
|
|
New Note
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ui five wide column">
|
|
<div class="ui form">
|
|
<input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ui row">
|
|
|
|
<!-- tags display -->
|
|
<div class="ui two wide large screen only column">
|
|
<div class="ui basic fluid button" @click="reset">Reset</div>
|
|
<div class="ui divider"></div>
|
|
<div class="ui clickable basic fluid large label" v-for="tag in commonTags" @click="toggleTagFilter(tag.id)"
|
|
:class="{ 'green':(searchTags.includes(tag.id)) }">
|
|
{{ucWords(tag.text)}} <div class="detail">{{tag.usages}}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Note title cards -->
|
|
<div class="ui fourteen wide computer sixteen wide mobile column">
|
|
<h2>Notes ({{notes.length}})</h2>
|
|
<div v-if="notes !== null">
|
|
<note-title-display-card
|
|
v-for="note in notes"
|
|
:onClick="openNote"
|
|
:data="note"
|
|
:key="note.id + note.color"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<input-notes v-if="activeNoteId1 != null" :noteid="activeNoteId1" :position="activeNote1Position" />
|
|
<input-notes v-if="activeNoteId2 != null" :noteid="activeNoteId2" :position="activeNote2Position" />
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
import axios from 'axios';
|
|
|
|
export default {
|
|
name: 'SearchBar',
|
|
components: {
|
|
'input-notes': require('./InputNotes.vue').default,
|
|
'note-title-display-card': require('./NoteTitleDisplayCard.vue').default,
|
|
},
|
|
data () {
|
|
return {
|
|
initComponent: true,
|
|
commonTags: [],
|
|
searchTerm: '',
|
|
searchTags: [],
|
|
notes: [],
|
|
searchDebounce: null,
|
|
|
|
//Currently open notes in app
|
|
activeNoteId1: null,
|
|
activeNoteId2: null,
|
|
//Position determines how note is Positioned
|
|
activeNote1Position: 0,
|
|
activeNote2Position: 0
|
|
}
|
|
},
|
|
beforeMount(){
|
|
this.$bus.$on('close_active_note', position => {
|
|
this.closeNote(position)
|
|
})
|
|
},
|
|
mounted() {
|
|
this.search()
|
|
},
|
|
methods: {
|
|
openNote(id){
|
|
|
|
//Do not open same note twice
|
|
if(this.activeNoteId1 == id || this.activeNoteId2 == id){
|
|
return;
|
|
}
|
|
|
|
//1 note open
|
|
if(this.activeNoteId1 == null && this.activeNoteId2 == null){
|
|
this.activeNoteId1 = id
|
|
this.activeNote1Position = 0 //Middel of page
|
|
return
|
|
}
|
|
//2 notes open
|
|
if(this.activeNoteId1 != null && this.activeNoteId2 == null){
|
|
this.activeNoteId2 = id
|
|
this.activeNote1Position = 1 //Right side of page
|
|
this.activeNote2Position = 2 //Left side of page
|
|
return
|
|
}
|
|
},
|
|
closeNote(position){
|
|
//One note open, close that note
|
|
if(position == 0){
|
|
this.activeNoteId1 = null
|
|
this.activeNoteId2 = null
|
|
}
|
|
//Right note closed, thats 1
|
|
if(position == 1){
|
|
this.activeNoteId1 = null
|
|
}
|
|
if(position == 2){
|
|
this.activeNoteId2 = null
|
|
}
|
|
|
|
this.activeNote1Position = 0
|
|
this.activeNote2Position = 0
|
|
|
|
this.search()
|
|
},
|
|
toggleTagFilter(tagId){
|
|
|
|
if(this.searchTags.includes(tagId)){
|
|
this.searchTags.splice( this.searchTags.indexOf(tagId) , 1);
|
|
} else {
|
|
this.searchTags.push(tagId)
|
|
}
|
|
|
|
this.search()
|
|
},
|
|
search(){
|
|
let postData = {
|
|
searchQuery: this.searchTerm,
|
|
searchTags: this.searchTags
|
|
}
|
|
//Perform search
|
|
let vm = this
|
|
axios.post('/api/notes/search', postData).
|
|
then(response => {
|
|
console.log('Notes and Tags')
|
|
console.log(response.data)
|
|
|
|
vm.commonTags = response.data.tags
|
|
vm.notes = response.data.notes
|
|
})
|
|
},
|
|
searchKeyUp(){
|
|
let vm = this
|
|
clearTimeout(vm.searchDebounce)
|
|
vm.searchDebounce = setTimeout(() => {
|
|
vm.search()
|
|
}, 300)
|
|
},
|
|
createNote(event){
|
|
const title = ''
|
|
let vm = this
|
|
|
|
axios.post('/api/notes/create', {title})
|
|
.then(response => {
|
|
|
|
if(response.data && response.data.id){
|
|
vm.openNote(response.data.id)
|
|
}
|
|
})
|
|
},
|
|
ucWords(str){
|
|
return (str + '')
|
|
.replace(/^(.)|\s+(.)/g, function ($1) {
|
|
return $1.toUpperCase()
|
|
})
|
|
},
|
|
reset(){
|
|
this.searchTerm = ''
|
|
this.searchTags = []
|
|
this.search()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style type="text/css" scoped>
|
|
.detail {
|
|
float: right;
|
|
}
|
|
</style> |