Adding everything to get started on cycle tracking and maybe avid habit clone
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="page-container" v-on:scroll="onScroll">
|
||||
<div class="page-container">
|
||||
|
||||
<div class="ui grid" ref="content">
|
||||
|
||||
<div class="sixteen wide column">
|
||||
<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
|
||||
<!-- :class="{ 'sixteen wide column':showOneColumn 'sixteen wide column':!showOneColumn}" -->
|
||||
|
||||
<div class="ui stackable grid">
|
||||
|
||||
@@ -33,15 +33,6 @@
|
||||
Active Sessions {{ $store.getters.getActiveSessions }}
|
||||
</span>
|
||||
|
||||
<div class="ui right floated basic shrinking icon button" v-on:click="toggleTitleView()" v-if="$store.getters.totals && $store.getters.totals['totalNotes'] > 0">
|
||||
<span v-if="titleView">
|
||||
<i class="th icon"></i> Tiles
|
||||
</span>
|
||||
<span v-if="!titleView">
|
||||
<i class="list icon"></i> List
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="eight wide column" v-if="showClear">
|
||||
@@ -107,7 +98,19 @@
|
||||
</h3>
|
||||
|
||||
<!-- Go to one wide column, do not do this on mobile interface -->
|
||||
<div :class="{'one-column':( showOneColumn() )}">
|
||||
<div :class="{'one-column':( showOneColumn), 'floating-list':( isFloatingList ), 'hidden-floating-list':(collapseFloatingList)}" v-on:scroll="onScroll">
|
||||
|
||||
|
||||
<div class="ui basic fitted right aligned segment" v-if="isFloatingList">
|
||||
<div class="ui small basic green left floated button" v-on:click="closeAllNotes()" v-if="openNotes.length > 1">
|
||||
<i class="times circle outline icon"></i>
|
||||
Close All
|
||||
</div>
|
||||
<div class="ui small green button" v-on:click="collapseFloatingList = true">
|
||||
<i class="caret square left outline icon"></i>
|
||||
Hide Menu
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- render each section based on notes in set -->
|
||||
<div v-for="section,index in noteSections" v-if="section.length > 0" class="note-card-section">
|
||||
@@ -120,8 +123,8 @@
|
||||
:ref="'note-'+note.id"
|
||||
:onClick="openNote"
|
||||
:data="note"
|
||||
:title-view="titleView"
|
||||
:currently-open="activeNoteId1 == note.id"
|
||||
:title-view="titleView || isFloatingList"
|
||||
:currently-open="openNotes.includes(note.id)"
|
||||
:key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
||||
/>
|
||||
</div>
|
||||
@@ -149,13 +152,21 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<note-input-panel
|
||||
v-if="activeNoteId1 != null"
|
||||
:key="activeNoteId1"
|
||||
:noteid="activeNoteId1"
|
||||
:url-data="$route.params"
|
||||
/>
|
||||
<div class="show-hidden-note-list-button" v-if="collapseFloatingList" v-on:click="collapseFloatingList = false">
|
||||
<i class="caret square right outline icon"></i>
|
||||
</div>
|
||||
|
||||
<!-- flexbox note container evenly spaces open notes -->
|
||||
<div class="note-panel-container" :class="{ 'note-panel-fullwidth':collapseFloatingList}" v-if="openNotes.length">
|
||||
<note-input-panel
|
||||
v-for="noteId in openNotes"
|
||||
v-if="noteId != null"
|
||||
:key="noteId"
|
||||
:noteid="noteId"
|
||||
:url-data="$route.params"
|
||||
:open-notes="openNotes.length"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -165,7 +176,7 @@
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'SearchBar',
|
||||
name: 'NotesPage',
|
||||
components: {
|
||||
|
||||
'note-input-panel': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'),
|
||||
@@ -186,6 +197,8 @@
|
||||
searchResultsCount: 0,
|
||||
searchTags: [],
|
||||
notes: [],
|
||||
openNotes: [],
|
||||
collapseFloatingList: false,
|
||||
highlights: [],
|
||||
searchDebounce: null,
|
||||
fastFilters: {},
|
||||
@@ -247,35 +260,34 @@
|
||||
|
||||
this.$io.on('new_note_created', noteId => {
|
||||
|
||||
//Do not update note if its open
|
||||
if(this.activeNoteId1 != noteId){
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
this.updateSingleNote(noteId, false)
|
||||
}
|
||||
// Push new note to top of list and animate
|
||||
this.updateSingleNote(noteId)
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
})
|
||||
|
||||
this.$io.on('note_attribute_modified', noteId => {
|
||||
|
||||
const drawFocus = !this.openNotes.includes(parseInt(noteId))
|
||||
this.updateSingleNote(noteId, drawFocus)
|
||||
|
||||
//Do not update note if its open
|
||||
if(this.activeNoteId1 != noteId){
|
||||
if(this.openNotes.includes(parseInt(noteId))){
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
this.updateSingleNote(noteId, false)
|
||||
}
|
||||
})
|
||||
|
||||
//Update title cards when new note text is saved
|
||||
this.$io.on('new_note_text_saved', ({noteId, hash}) => {
|
||||
|
||||
//Do not update note if its open
|
||||
if(this.activeNoteId1 != noteId){
|
||||
this.updateSingleNote(noteId, true)
|
||||
}
|
||||
const drawFocus = !this.openNotes.includes(parseInt(noteId))
|
||||
this.updateSingleNote(noteId, drawFocus)
|
||||
})
|
||||
|
||||
this.$bus.$on('update_single_note', (noteId) => {
|
||||
//Do not update note if its open
|
||||
if(this.activeNoteId1 != noteId){
|
||||
this.updateSingleNote(noteId)
|
||||
}
|
||||
|
||||
const drawFocus = !this.openNotes.includes(parseInt(noteId))
|
||||
this.updateSingleNote(noteId, drawFocus)
|
||||
|
||||
})
|
||||
|
||||
//Update totals for app
|
||||
@@ -283,19 +295,7 @@
|
||||
|
||||
//Close note event
|
||||
this.$bus.$on('close_active_note', ({noteId, modified}) => {
|
||||
|
||||
if(modified){
|
||||
console.log('Just closed Note -> ' + noteId + ', modified -> ', modified)
|
||||
}
|
||||
|
||||
//A note has been closed
|
||||
if(this.$route.fullPath != '/notes'){
|
||||
this.$router.push('/notes')
|
||||
}
|
||||
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
//Focus and animate if modified
|
||||
this.updateSingleNote(noteId, modified)
|
||||
this.closeNote(noteId, modified)
|
||||
})
|
||||
|
||||
this.$bus.$on('note_deleted', (noteId) => {
|
||||
@@ -347,6 +347,8 @@
|
||||
}
|
||||
})
|
||||
|
||||
// Window scroll needed when scrolling full page.
|
||||
// second scroll event added on note-list for floating view scroll detection
|
||||
window.addEventListener('scroll', this.onScroll)
|
||||
|
||||
//Close notes when back button is pressed
|
||||
@@ -355,8 +357,6 @@
|
||||
//update note on visibility change
|
||||
// document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
||||
|
||||
//Find previously stored notes, cache for 20 hours, load them and compare
|
||||
|
||||
},
|
||||
beforeDestroy(){
|
||||
window.removeEventListener('scroll', this.onScroll)
|
||||
@@ -375,9 +375,9 @@
|
||||
},
|
||||
mounted() {
|
||||
|
||||
//Open note on load if ID is set
|
||||
//Open note on PAGE LOAD if ID is set
|
||||
if(this.$route.params.id > 1){
|
||||
this.activeNoteId1 = this.$route.params.id
|
||||
this.openNote(this.$route.params.id)
|
||||
}
|
||||
|
||||
//Loads initial batch and tags
|
||||
@@ -386,18 +386,21 @@
|
||||
},
|
||||
watch: {
|
||||
'$route.params.id': function(id){
|
||||
//Open note on ID, null id will close note
|
||||
this.activeNoteId1 = id
|
||||
this.openNote(id)
|
||||
},
|
||||
'$route' (to, from) {
|
||||
|
||||
|
||||
// Reload the notes if returning to this page
|
||||
if(to.fullPath == '/notes' && !from.fullPath.includes('/notes/open/')){
|
||||
|
||||
this.reset()
|
||||
}
|
||||
|
||||
// Close all notes if returning to /notes page
|
||||
if(to.fullPath == '/notes' && from.fullPath.includes('/notes/open/')){
|
||||
this.closeAllNotes()
|
||||
}
|
||||
|
||||
//Lookup tags set in URL
|
||||
if(to.params.tag && this.$store.getters.totals && this.$store.getters.totals['tags'][to.params.tag]){
|
||||
|
||||
@@ -410,30 +413,96 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleTitleView(){
|
||||
this.titleView = !this.titleView
|
||||
computed: {
|
||||
isFloatingList(){
|
||||
|
||||
//If note 1 or 2 is open, show floating column
|
||||
return (this.openNotes.length > 0)
|
||||
|
||||
},
|
||||
showOneColumn(){
|
||||
|
||||
return this.$store.getters.getIsUserOnMobile
|
||||
|
||||
//If note 1 or 2 is open, show one column. Or if the user is on mobile
|
||||
return (this.activeNoteId1 != null || this.activeNoteId2 != null) &&
|
||||
!this.$store.getters.getIsUserOnMobile
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openNote(id, event = null){
|
||||
|
||||
//
|
||||
|
||||
const intId = parseInt(id)
|
||||
if(this.openNotes.includes(intId)){
|
||||
|
||||
console.log('Open already open note?')
|
||||
|
||||
// const openIndex = this.openNotes.indexOf(intId)
|
||||
// if(openIndex != -1){
|
||||
// console.log('Open note and remove it ', intId + ' on index ' + openIndex)
|
||||
// this.openNotes.splice(openIndex, 1)
|
||||
// }
|
||||
// this.$bus.$emit('close_note_by_id', intId)
|
||||
return
|
||||
}
|
||||
|
||||
//Don't open note if a link is clicked in display card
|
||||
if(event && event.target && event.target.nodeName){
|
||||
const nodeClick = event.target.nodeName
|
||||
if(nodeClick == 'A'){ return }
|
||||
}
|
||||
|
||||
//Open note if a link was not clicked
|
||||
this.$router.push('/notes/open/'+id)
|
||||
// Push note to stack if not open
|
||||
if(Number.isInteger(intId) && !this.openNotes.includes(intId)){
|
||||
this.openNotes.push(intId)
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
// change route if open ID is not the same as current ID
|
||||
if(this.$route.params.id != id){
|
||||
console.log('Open note, change route -> route id ' + this.$route.params.id + ' note id ->' + id + ', ' +(this.$route.params.id == id))
|
||||
this.$router.push('/notes/open/'+id)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
return
|
||||
},
|
||||
closeNote(noteId, modified){
|
||||
|
||||
console.log('close note', this.$route.fullPath)
|
||||
|
||||
const openIndex = this.openNotes.indexOf(noteId)
|
||||
if(openIndex != -1){
|
||||
console.log('Removing note id ', noteId + ' on index ' + openIndex)
|
||||
this.openNotes.splice(openIndex, 1)
|
||||
}
|
||||
|
||||
// //A note has been closed
|
||||
// if(this.$route.fullPath != '/notes'){
|
||||
// this.$router.push('/notes')
|
||||
// }
|
||||
if(this.openNotes.length == 0 && this.$route.fullPath != '/notes'){
|
||||
this.$router.push('/notes')
|
||||
}
|
||||
|
||||
if(modified){
|
||||
console.log('Just closed Note -> ' + noteId + ', modified -> ', modified)
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
//Focus and animate if modified
|
||||
this.updateSingleNote(noteId, modified)
|
||||
}
|
||||
|
||||
console.log('closeNote(): Open notes length ', this.openNotes.length)
|
||||
},
|
||||
closeAllNotes(){
|
||||
console.log('Close all notes ------------')
|
||||
for (let i = this.openNotes.length - 1; i >= 0; i--) {
|
||||
console.log('Close all notes -> ' + this.openNotes[i])
|
||||
this.closeNote(this.openNotes[i])
|
||||
}
|
||||
console.log('----------------')
|
||||
},
|
||||
toggleTagFilter(tagId){
|
||||
|
||||
this.searchTags = [tagId]
|
||||
@@ -489,7 +558,6 @@
|
||||
}
|
||||
|
||||
this.lastVisibilityState = document.visibilityState
|
||||
|
||||
},
|
||||
// @TODO Don't even trigger this if the note wasn't changed
|
||||
updateSingleNote(noteId, focuseAndAnimate = true){
|
||||
@@ -525,6 +593,7 @@
|
||||
return
|
||||
}
|
||||
|
||||
// if old note data and new note data exists
|
||||
if(note && newNote){
|
||||
|
||||
//go through each prop and update it with new values
|
||||
@@ -533,7 +602,7 @@
|
||||
})
|
||||
|
||||
//Push new note to front if its modified or we want it to
|
||||
if( focuseAndAnimate || note.updated != newNote.updated ){
|
||||
if( note.updated != newNote.updated ){
|
||||
|
||||
// Find note, in section, move to front
|
||||
Object.keys(this.noteSections).forEach( key => {
|
||||
@@ -547,6 +616,9 @@
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
if( focuseAndAnimate ){
|
||||
this.$nextTick( () => {
|
||||
//Trigger close animation on note
|
||||
this.$refs['note-'+noteId][0].justClosed()
|
||||
@@ -833,18 +905,133 @@
|
||||
padding: 15px 0 0;
|
||||
}
|
||||
.loading-section {
|
||||
position: fixed;
|
||||
bottom: 40px;
|
||||
padding: 0 10px;
|
||||
right: 5px;
|
||||
box-shadow: 0 1px 3px 0 #656565;
|
||||
color: var(--main-accent);
|
||||
box-shadow: 0 1px 3px 0 var(--main-accent);
|
||||
border-radius: 6px;
|
||||
background-color: var(--small_element_bg_color);
|
||||
opacity: 0.9;
|
||||
font-size: 0.7em;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin: 15px 0;
|
||||
}
|
||||
.floating-list {
|
||||
z-index: 1000;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 25%;
|
||||
height: 100vh;
|
||||
background-color: var(--small_element_bg_color);
|
||||
padding: 15px 5px 0px 10px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
-ms-overflow-style: none; /* Internet Explorer 10+ */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
background-color: var(--border_color);
|
||||
}
|
||||
.floating-list::-webkit-scrollbar {
|
||||
display: none; /* Safari and Chrome */
|
||||
}
|
||||
.note-panel-container {
|
||||
position: fixed;
|
||||
width: 75%;
|
||||
height: 100vh;
|
||||
background: gray;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
|
||||
z-index: 1000;
|
||||
}
|
||||
.note-panel-fullwidth {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.note-panel-container > div {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
.hidden-floating-list {
|
||||
left: -1000px !important;
|
||||
}
|
||||
.show-hidden-note-list-button {
|
||||
position: fixed;
|
||||
top: 25px;
|
||||
left: 0;
|
||||
min-width: 45px;
|
||||
background-color: var(--main-accent);
|
||||
color: var(--text_color);
|
||||
display: block;
|
||||
z-index: 1100;
|
||||
cursor: pointer;
|
||||
border-bottom-right-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
padding: 8px 0px 8px 13px;
|
||||
text-align: left;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
@media (min-width:320px) { /* smartphones, iPhone, portrait 480x320 phones */
|
||||
.floating-list {
|
||||
left: -1000px;
|
||||
}
|
||||
.note-panel-container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@media (min-width:481px) { /* portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */
|
||||
.floating-list {
|
||||
left: 0px;
|
||||
}
|
||||
.note-panel-container {
|
||||
width: 75%;
|
||||
}
|
||||
}
|
||||
@media (min-width:641px) { /* portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones */
|
||||
|
||||
}
|
||||
@media (min-width:961px) { /* tablet, landscape iPad, lo-res laptops ands desktops */
|
||||
|
||||
}
|
||||
@media (min-width:1025px) { /* big landscape tablets, laptops, and desktops */
|
||||
|
||||
}
|
||||
@media (min-width:1281px) { /* hi-res laptops and desktops */
|
||||
|
||||
}
|
||||
@media (min-width:2000px) { /* BIG hi-res laptops and desktops */
|
||||
.floating-list {
|
||||
left: 180px;
|
||||
width: calc(30% - 180px);
|
||||
}
|
||||
.note-panel-container {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.master-note-edit {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
background: var(--small_element_bg_color);
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.master-note-edit + .master-note-edit {
|
||||
border-left: 2px solid var(--main-accent);
|
||||
border-left: 5px solid var(--border_color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user