* Adjusted theme colors to add more contrast on white theme while making black more OLED friendly
* Links now get an underline on hover * Cleaned up CSS variable names, added another theme color for more control * Cleaned up unused CSS, removed scrollbars popping up, tons of other little UI tweaks * Renamed shared notes to inbox * Tweaked form display, seperated login and create accouts * Put login/sign up form on home page * Created more legitimate marketing for home page * Tons up updates to note page and note input panel * Better support for two users editing a note * MUCH better diff handling, web sockets restore notes with unsaved diffs * Moved all squire text modifier functions into a mixin class * It now says saving when closing a note * Lots of cleanup and better handiling of events on mount and destroy * Scroll behavior modified to load notes when closer to bottom of page * Pretty decent shared notes and sharable link support * Updated help text * Search now includes tag suggestions and attachment suggestions * Cleaned up scratch pad a ton, allow for users to create new scratch pads * Created a 404 Page and a Shared note page * So many other small improvements. Oh my god, what is wrong with me, not doing commits!?
This commit is contained in:
@@ -7,27 +7,19 @@
|
||||
<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
|
||||
|
||||
<div class="ui stackable grid">
|
||||
|
||||
<div class="six wide column" v-if="$store.getters.totals && $store.getters.totals['totalNotes']">
|
||||
<search-input />
|
||||
</div>
|
||||
|
||||
<div class="ten wide column"
|
||||
:class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">
|
||||
<div class="ten wide column" :class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">
|
||||
|
||||
<div class="ui basic button shrinking"
|
||||
v-on:click="updateFastFilters(3)"
|
||||
v-if="$store.getters.totals && ($store.getters.totals['sharedToNotes'] > 0 || $store.getters.totals['sharedFromNotes'] > 0)"
|
||||
v-if="$store.getters.totals && ($store.getters.totals['youGotMailCount'] > 0)"
|
||||
style="position: relative;">
|
||||
<i class="green mail icon"></i>Shared Notes
|
||||
<span class="floating ui green label" v-if="$store.getters.totals['unreadNotes'] > 0">
|
||||
{{ $store.getters.totals['unreadNotes'] }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="ui basic button shrinking" v-on:click="updateFastFilters(2)" v-if="$store.getters.totals && $store.getters.totals['archivedNotes'] > 0">
|
||||
<i class="green archive icon"></i>Archived
|
||||
<!-- <span>{{ $store.getters.totals['archivedNotes'] }}</span> -->
|
||||
</div>
|
||||
|
||||
<div class="ui basic icon button shrinking" v-on:click="updateFastFilters(4)" v-if="$store.getters.totals && $store.getters.totals['trashedNotes'] > 0">
|
||||
<i class="trash alternate outline icon"></i>
|
||||
<i class="green mail icon"></i>Inbox
|
||||
+{{ $store.getters.totals['youGotMailCount'] }}
|
||||
</div>
|
||||
|
||||
<tag-display
|
||||
@@ -42,12 +34,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="six wide column">
|
||||
<search-input
|
||||
v-on:tagClick="tagId => toggleTagFilter(tagId)"
|
||||
v-if="$store.getters.totals && $store.getters.totals['totalNotes']" />
|
||||
</div>
|
||||
|
||||
<div class="eight wide column" v-if="showClear">
|
||||
<!-- <fast-filters /> -->
|
||||
<span class="ui fluid green button" @click="reset">
|
||||
@@ -75,7 +61,7 @@
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide column" v-if="fastFilters['onlyShowTrashed'] == 1">
|
||||
<h2 >Trash
|
||||
<h2>Trash
|
||||
<span>({{ $store.getters.totals['trashedNotes'] }})</span>
|
||||
<div class="ui right floated basic button" data-tooltip="This doesn't work yet">
|
||||
<i class="poo storm icon"></i>
|
||||
@@ -88,6 +74,25 @@
|
||||
<h2>Shared Notes</h2>
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide column" v-if="tagSuggestions.length > 0">
|
||||
<h5 class="ui tiny dividing header"><i class="green tags icon"></i> Tags ({{ tagSuggestions.length }})</h5>
|
||||
<div class="ui clickable green label" v-for="tag in tagSuggestions" v-on:click="tagId => toggleTagFilter(tag.id)">
|
||||
<i class="tag icon"></i>
|
||||
{{ tag.text }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- found attachments -->
|
||||
<div class="sixteen wide column" v-if="foundAttachments.length > 0">
|
||||
<h5 class="ui tiny dividing header"><i class="green folder open outline icon"></i> Files ({{ foundAttachments.length }})</h5>
|
||||
<attachment-display
|
||||
v-for="item in foundAttachments"
|
||||
:item="item"
|
||||
:key="item.id"
|
||||
:search-params="{}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Note title card display -->
|
||||
<div class="sixteen wide column">
|
||||
|
||||
@@ -123,18 +128,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- found attachments -->
|
||||
<div class="sixteen wide column" v-if="foundAttachments.length > 0">
|
||||
<h4><i class="folder open outline icon"></i> Found in Files ({{ foundAttachments.length }})</h4>
|
||||
<attachment-display
|
||||
v-for="item in foundAttachments"
|
||||
:item="item"
|
||||
:key="item.id"
|
||||
:search-params="{}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -170,7 +163,7 @@
|
||||
data () {
|
||||
return {
|
||||
initComponent: true,
|
||||
commonTags: [],
|
||||
tagSuggestions:[],
|
||||
searchTerm: '',
|
||||
searchResultsCount: 0,
|
||||
searchTags: [],
|
||||
@@ -191,13 +184,6 @@
|
||||
//Clear button is not visible
|
||||
showClear: false,
|
||||
initialPostData: null,
|
||||
currentPostData: null,
|
||||
|
||||
containsNormalNotes: 0,
|
||||
containsPinnednotes: 0,
|
||||
containsTextResults: 0,
|
||||
// containsTagResults: 0,
|
||||
// containsAttachmentResults: 0,
|
||||
|
||||
//Currently open notes in app
|
||||
activeNoteId1: null,
|
||||
@@ -214,8 +200,8 @@
|
||||
sectionData: {
|
||||
'pinned': ['thumbtack', 'Pinned'],
|
||||
'archived': ['archive', 'Archived'],
|
||||
'shared': ['envelope outline', 'Received Notes'],
|
||||
'sent': ['paper plane outline', 'Shared Notes'],
|
||||
'shared': ['envelope outline', 'Inbox'],
|
||||
'sent': ['paper plane outline', 'Sent Notes'],
|
||||
'notes': ['file','Notes'],
|
||||
'highlights': ['paragraph', 'Found In Text'],
|
||||
'trashed': ['poop', 'Trashed Notes'],
|
||||
@@ -275,13 +261,12 @@
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
|
||||
//Close note event
|
||||
this.$bus.$on('close_active_note', ({position, noteId, modified}) => {
|
||||
this.$bus.$on('close_active_note', ({noteId, modified}) => {
|
||||
|
||||
this.closeNote()
|
||||
if(modified){
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
this.updateSingleNote(parseInt(noteId))
|
||||
}
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
//Focus and animate if modified
|
||||
this.updateSingleNote(parseInt(noteId), modified)
|
||||
})
|
||||
|
||||
this.$bus.$on('note_deleted', (noteId) => {
|
||||
@@ -295,15 +280,12 @@
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
this.$bus.$on('update_fast_filters', newFilter => {
|
||||
this.fastFilters = newFilter
|
||||
//Fast filters always return all the results and tags
|
||||
this.search(true, this.batchSize, false).then( () => {
|
||||
// return
|
||||
})
|
||||
this.$bus.$on('update_fast_filters', filterIndex => {
|
||||
|
||||
this.updateFastFilters(filterIndex)
|
||||
})
|
||||
|
||||
//Event to update search from other areas
|
||||
@@ -312,8 +294,18 @@
|
||||
this.search(true, this.batchSize)
|
||||
.then( () => {
|
||||
|
||||
console.log('Search attachments disabled for now')
|
||||
// this.searchAttachments()
|
||||
this.searchAttachments()
|
||||
|
||||
const postData = {
|
||||
'tagText':this.searchTerm.trim()
|
||||
}
|
||||
|
||||
this.tagSuggestions = []
|
||||
axios.post('/api/tag/suggest', postData)
|
||||
.then( response => {
|
||||
|
||||
this.tagSuggestions = response.data
|
||||
})
|
||||
|
||||
// return
|
||||
})
|
||||
@@ -365,6 +357,9 @@
|
||||
|
||||
//Loads initial batch and tags
|
||||
this.reset()
|
||||
|
||||
// this.search(true, this.firstLoadBatchSize, false)
|
||||
// .then( r => this.search(false, this.batchSize, true))
|
||||
},
|
||||
methods: {
|
||||
toggleTitleView(){
|
||||
@@ -390,7 +385,7 @@
|
||||
if(this.activeNoteId1 == null){
|
||||
this.activeNoteId1 = id
|
||||
this.activeNote1Position = 0 //Middel of page
|
||||
this.$router.push('/notes/open/'+this.activeNoteId1)
|
||||
this.$router.push('/notes/open/'+this.activeNoteId1).catch(e => { console.log(e) })
|
||||
return
|
||||
}
|
||||
},
|
||||
@@ -417,24 +412,18 @@
|
||||
clearTimeout(this.loadingBatchTimeout)
|
||||
this.loadingBatchTimeout = setTimeout(() => {
|
||||
|
||||
//Distance to bottom of page
|
||||
const bottomOfWindow =
|
||||
Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop)
|
||||
+ window.innerHeight
|
||||
//Detect distance scrolled down the page
|
||||
const scrolledDown = window.pageYOffset + window.innerHeight
|
||||
//Get height of div to properly detect scroll distance down
|
||||
const height = document.getElementById('app').scrollHeight
|
||||
|
||||
//height of page
|
||||
const offsetHeight = this.$refs.content.clientHeight
|
||||
|
||||
//Determine percentage down the page
|
||||
const percentageDown = Math.round( (bottomOfWindow/offsetHeight)*100 )
|
||||
|
||||
//If greater than 80 of the way down the page, load the next batch
|
||||
if(percentageDown >= 65 && this.scrollLoadEnabled){
|
||||
//Load if less than 500px from the bottom
|
||||
if(((height - scrolledDown) < 500) && this.scrollLoadEnabled && !this.loadingInProgress){
|
||||
|
||||
this.search(false, this.batchSize, true)
|
||||
}
|
||||
|
||||
}, 50)
|
||||
}, 30)
|
||||
|
||||
|
||||
return
|
||||
@@ -491,7 +480,10 @@
|
||||
noteId = parseInt(noteId)
|
||||
|
||||
//Find local note, if it exists; continue
|
||||
|
||||
let note = null
|
||||
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0] && this.$refs['note-'+noteId][0].note){
|
||||
note = this.$refs['note-'+noteId][0].note
|
||||
}
|
||||
|
||||
//Lookup one note using passed in ID
|
||||
const postData = {
|
||||
@@ -508,60 +500,62 @@
|
||||
|
||||
//Pull note data out of note set
|
||||
let newNote = results.data.notes[0]
|
||||
let foundNote = false
|
||||
|
||||
if(newNote === undefined){
|
||||
return
|
||||
}
|
||||
|
||||
//Find Just updated note and modify all its attributes
|
||||
Object.keys(this.noteSections).forEach(key => {
|
||||
if(note && newNote){
|
||||
|
||||
this.noteSections[key].forEach( (note,index) => {
|
||||
//Don't move notes that were not changed
|
||||
if(note.updated == newNote.updated){
|
||||
return
|
||||
}
|
||||
|
||||
if(note.id == noteId){
|
||||
foundNote = true
|
||||
//go through each prop and update it with new values
|
||||
Object.keys(newNote).forEach(prop => {
|
||||
note[prop] = newNote[prop]
|
||||
})
|
||||
|
||||
//Don't move notes that were not changed
|
||||
if(note.updated == newNote.updated){
|
||||
// return
|
||||
}
|
||||
//Push new note to front if its modified
|
||||
if(focuseAndAnimate){
|
||||
|
||||
//Compare note tags, if they changed, reload tags
|
||||
if(newNote.tag_count != note.tag_count){
|
||||
|
||||
}
|
||||
|
||||
//go through each prop and update it with new values
|
||||
Object.keys(newNote).forEach(prop => {
|
||||
note[prop] = newNote[prop]
|
||||
})
|
||||
|
||||
//Remove note from location and push to front
|
||||
this.noteSections[key].splice(index, 1)
|
||||
this.noteSections[key].unshift(note)
|
||||
|
||||
this.$nextTick( () => {
|
||||
|
||||
//Trigger close animation on note
|
||||
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0] && focuseAndAnimate){
|
||||
this.$refs['note-'+noteId][0].justClosed()
|
||||
// Find note, in section, move to front
|
||||
Object.keys(this.noteSections).forEach( key => {
|
||||
this.noteSections[key].forEach( (searchNote, index) => {
|
||||
if(searchNote.id == noteId){
|
||||
//Remove note from location and push to front
|
||||
this.noteSections[key].splice(index, 1)
|
||||
this.noteSections[key].unshift(note)
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
this.$nextTick( () => {
|
||||
//Trigger close animation on note
|
||||
this.$refs['note-'+noteId][0].justClosed()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//New notes don't exist in list, push them to the front
|
||||
if(!foundNote){
|
||||
if(note == null){
|
||||
this.noteSections.notes.unshift(newNote)
|
||||
//Trigger close animation on note
|
||||
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
||||
this.$refs['note-'+noteId][0].justClosed()
|
||||
}
|
||||
}
|
||||
|
||||
//Trigger section rebuild
|
||||
this.rebuildNoteCategorise()
|
||||
})
|
||||
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Notes') })
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
this.$bus.$emit('notification', 'Failed to Update Note')
|
||||
})
|
||||
},
|
||||
searchAttachments(){
|
||||
axios.post('/api/attachment/textsearch', {'searchTerm':this.searchTerm})
|
||||
@@ -570,13 +564,13 @@
|
||||
})
|
||||
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Attachments') })
|
||||
},
|
||||
search(showLoading = true, notesInNextLoad = null, mergeExisting = false){
|
||||
search(showLoading = true, notesInNextLoad = 10, mergeExisting = false){
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
//Don't double load note batches
|
||||
if(this.loadingInProgress){
|
||||
console.log('Loading in progress, cancel operation')
|
||||
return resolve()
|
||||
console.log('Loading already in progress')
|
||||
return resolve(false)
|
||||
}
|
||||
|
||||
//Reset a lot of stuff if we are not merging batches
|
||||
@@ -585,7 +579,6 @@
|
||||
this.noteSections[key] = []
|
||||
})
|
||||
this.batchOffset = 0 // Reset batch offset if we are not merging note batches
|
||||
// this.commonTags = [] //Don't reset tags, if search returns tags, they will be set
|
||||
}
|
||||
this.searchResultsCount = 0
|
||||
|
||||
@@ -628,11 +621,6 @@
|
||||
//Enable or disable scroll loading
|
||||
this.scrollLoadEnabled = response.data.notes.length > 0
|
||||
|
||||
//Mush the two new sets of data together (set will be empty is reset is on)
|
||||
// if(response.data.tags.length > 0){
|
||||
// this.commonTags = response.data.tags
|
||||
// }
|
||||
|
||||
if(response.data.total > 0){
|
||||
this.searchResultsCount = response.data.total
|
||||
}
|
||||
@@ -742,33 +730,22 @@
|
||||
this.scrollLoadEnabled = true
|
||||
this.searchTerm = ''
|
||||
this.searchTags = []
|
||||
this.tagSuggestions = []
|
||||
this.fastFilters = {}
|
||||
this.updateFastFilters(5)
|
||||
this.foundAttachments = [] //Remove all attachments
|
||||
this.$bus.$emit('reset_fast_filters')
|
||||
|
||||
//Load initial batch, then tags, then other batch
|
||||
this.search(true, this.firstLoadBatchSize)
|
||||
.then( () => {
|
||||
//Load a larger batch once first batch has loaded
|
||||
return this.search(false, this.batchSize, true)
|
||||
})
|
||||
this.$bus.$emit('reset_fast_filters')
|
||||
this.updateFastFilters(5) //This loads notes
|
||||
|
||||
},
|
||||
updateFastFilters(index){
|
||||
|
||||
//clear out tags
|
||||
this.searchTags = []
|
||||
this.tagSuggestions = []
|
||||
this.loadingInProgress = false
|
||||
this.searchTerm = ''
|
||||
this.$bus.$emit('reset_fast_filters')
|
||||
|
||||
//A little hacky, brings user to notes page then filters on click
|
||||
if(this.$route.name != 'Note Page'){
|
||||
this.$router.push('/notes')
|
||||
setTimeout( () => {
|
||||
this.updateFastFilters(index)
|
||||
}, 500 )
|
||||
}
|
||||
this.$bus.$emit('reset_fast_filters') //Clear out search
|
||||
|
||||
const options = [
|
||||
'withLinks', // 'Only Show Notes with Links'
|
||||
@@ -782,7 +759,10 @@
|
||||
let filter = {}
|
||||
filter[options[index]] = 1
|
||||
|
||||
this.$bus.$emit('update_fast_filters', filter)
|
||||
this.fastFilters = filter
|
||||
//Fetch First batch of notes with new filter
|
||||
this.search(true, this.firstLoadBatchSize, false)
|
||||
.then( r => this.search(false, this.batchSize, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user