* Made splash page dark and updated description
* Cleaned up unused things * Updated squire which had a comment typo update...thats it * Background color picker has matching colors and styles to text color picker * Added new black theme * Moved search to main page, show it on mobile and added options to push things to notes from search with experimental tag searching * Added active note menu buttons based on cursor location in text * Added more instant updating if app is open in two locations for the same user Scratch Pad and home page update with new notes and new text in real time
This commit is contained in:
parent
67b218329b
commit
e87e8513bc
@ -10,13 +10,16 @@
|
|||||||
<meta name="theme-color" content="#000" />
|
<meta name="theme-color" content="#000" />
|
||||||
<link rel="manifest" href="/api/static/assets/manifest.json">
|
<link rel="manifest" href="/api/static/assets/manifest.json">
|
||||||
|
|
||||||
<title>Solid Scribe - A Note Taking Website</title>
|
<title>Solid Scribe - An easy, encrypted Note App</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<!-- placeholder data for scrapers with no JS -->
|
<!-- placeholder data for scrapers with no JS -->
|
||||||
<style>
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #212221;
|
||||||
|
color: #aeaeae;
|
||||||
|
}
|
||||||
.centered {
|
.centered {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@ -37,7 +40,8 @@
|
|||||||
<div class="centered">
|
<div class="centered">
|
||||||
<img class="logo" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo - if you can read this your connection is really slow">
|
<img class="logo" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo - if you can read this your connection is really slow">
|
||||||
<h1>Solid Scribe</h1>
|
<h1>Solid Scribe</h1>
|
||||||
<h3>Loading...</h3>
|
<h3>An easy, encrypted Note App</h3>
|
||||||
|
<h4>Loading...</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="scrape-info">
|
<div class="scrape-info">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app" :class="{ 'night-mode':($store.getters.getIsNightMode) }">
|
<div id="app" :class="{ 'night-mode':($store.getters.getIsNightMode == 2) }">
|
||||||
|
|
||||||
<global-site-menu />
|
<global-site-menu />
|
||||||
|
|
||||||
@ -30,7 +30,6 @@ export default {
|
|||||||
//Puts token into state on page load
|
//Puts token into state on page load
|
||||||
let token = localStorage.getItem('loginToken')
|
let token = localStorage.getItem('loginToken')
|
||||||
let username = localStorage.getItem('username')
|
let username = localStorage.getItem('username')
|
||||||
let masterKey = localStorage.getItem('masterKey')
|
|
||||||
|
|
||||||
// const socket = io({ path:'/socket' });
|
// const socket = io({ path:'/socket' });
|
||||||
const socket = this.$io
|
const socket = this.$io
|
||||||
@ -45,13 +44,14 @@ export default {
|
|||||||
this.$store.commit('detectIsUserOnMobile')
|
this.$store.commit('detectIsUserOnMobile')
|
||||||
|
|
||||||
//Set color theme based on local storage
|
//Set color theme based on local storage
|
||||||
if(localStorage.getItem('nightMode') == 'true'){
|
const themeNumber = localStorage.getItem('nightMode')
|
||||||
this.$store.commit('toggleNightMode')
|
if(themeNumber != null){
|
||||||
|
this.$store.commit('toggleNightMode', themeNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Put user data into global store on load
|
//Put user data into global store on load
|
||||||
if(token){
|
if(token){
|
||||||
this.$store.commit('setLoginToken', {token, username, masterKey})
|
this.$store.commit('setLoginToken', {token, username})
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -392,7 +392,7 @@ function createElement ( doc, tag, props, children ) {
|
|||||||
|
|
||||||
function fixCursor ( node, root ) {
|
function fixCursor ( node, root ) {
|
||||||
// In Webkit and Gecko, block level elements are collapsed and
|
// In Webkit and Gecko, block level elements are collapsed and
|
||||||
// unfocussable if they have no content. To remedy this, a <BR> must be
|
// unfocusable if they have no content. To remedy this, a <BR> must be
|
||||||
// inserted. In Opera and IE, we just need a textnode in order for the
|
// inserted. In Opera and IE, we just need a textnode in order for the
|
||||||
// cursor to appear.
|
// cursor to appear.
|
||||||
var self = root.__squire__;
|
var self = root.__squire__;
|
||||||
@ -2615,6 +2615,8 @@ function Squire ( root, config ) {
|
|||||||
this.setConfig( config );
|
this.setConfig( config );
|
||||||
|
|
||||||
root.setAttribute( 'contenteditable', 'true' );
|
root.setAttribute( 'contenteditable', 'true' );
|
||||||
|
// Grammarly breaks the editor, *sigh*
|
||||||
|
root.setAttribute( 'data-gramm', 'false' );
|
||||||
|
|
||||||
// Remove Firefox's built-in controls
|
// Remove Firefox's built-in controls
|
||||||
try {
|
try {
|
||||||
|
@ -64,8 +64,8 @@
|
|||||||
return {
|
return {
|
||||||
allStyles:{ 'noteText':null,'noteBackground':null, 'noteIcon':null, 'iconColor':null },
|
allStyles:{ 'noteText':null,'noteBackground':null, 'noteIcon':null, 'iconColor':null },
|
||||||
blankStyle:{ 'noteText':null,'noteBackground':null, 'noteIcon':null, 'iconColor':null },
|
blankStyle:{ 'noteText':null,'noteBackground':null, 'noteIcon':null, 'iconColor':null },
|
||||||
colors: [
|
colors: [null,
|
||||||
"#ffebee","#ffcdd2","#ef9a9a","#e57373","#ef5350","#f44336","#e53935","#d32f2f","#c62828","#b71c1c","#fce4ec","#f8bbd0","#f48fb1","#f06292","#ec407a","#e91e63","#d81b60","#c2185b","#ad1457","#880e4f","#f3e5f5","#e1bee7","#ce93d8","#ba68c8","#ab47bc","#9c27b0","#8e24aa","#7b1fa2","#6a1b9a","#4a148c","#ede7f6","#d1c4e9","#b39ddb","#9575cd","#7e57c2","#673ab7","#5e35b1","#512da8","#4527a0","#311b92","#e8eaf6","#c5cae9","#9fa8da","#7986cb","#5c6bc0","#3f51b5","#3949ab","#303f9f","#283593","#1a237e","#e3f2fd","#bbdefb","#90caf9","#64b5f6","#42a5f5","#2196f3","#1e88e5","#1976d2","#1565c0","#0d47a1","#e1f5fe","#b3e5fc","#81d4fa","#4fc3f7","#29b6f6","#03a9f4","#039be5","#0288d1","#0277bd","#01579b","#e0f7fa","#b2ebf2","#80deea","#4dd0e1","#26c6da","#00bcd4","#00acc1","#0097a7","#00838f","#006064","#e0f2f1","#b2dfdb","#80cbc4","#4db6ac","#26a69a","#009688","#00897b","#00796b","#00695c","#004d40","#e8f5e9","#c8e6c9","#a5d6a7","#81c784","#66bb6a","#4caf50","#43a047","#388e3c","#2e7d32","#1b5e20","#f1f8e9","#dcedc8","#c5e1a5","#aed581","#9ccc65","#8bc34a","#7cb342","#689f38","#558b2f","#33691e","#f9fbe7","#f0f4c3","#e6ee9c","#dce775","#d4e157","#cddc39","#c0ca33","#afb42b","#9e9d24","#827717","#fffde7","#fff9c4","#fff59d","#fff176","#ffee58","#ffeb3b","#fdd835","#fbc02d","#f9a825","#f57f17","#fff8e1","#ffecb3","#ffe082","#ffd54f","#ffca28","#ffc107","#ffb300","#ffa000","#ff8f00","#ff6f00","#fff3e0","#ffe0b2","#ffcc80","#ffb74d","#ffa726","#ff9800","#fb8c00","#f57c00","#ef6c00","#e65100","#fbe9e7","#ffccbc","#ffab91","#ff8a65","#ff7043","#ff5722","#f4511e","#e64a19","#d84315","#bf360c","#efebe9","#d7ccc8","#bcaaa4","#a1887f","#8d6e63","#795548","#6d4c41","#5d4037","#4e342e","#3e2723","#fafafa","#f5f5f5","#eeeeee","#e0e0e0","#bdbdbd","#9e9e9e","#757575","#616161","#424242","#212121","#eceff1","#cfd8dc","#b0bec5","#90a4ae","#78909c","#607d8b","#546e7a","#455a64","#37474f","#263238","#ffffff","#000000"],
|
'rgb(67,67,67)','rgb(102,102,102)','rgb(153,153,153)','rgb(183,183,183)','rgb(204,204,204)','rgb(217,217,217)','rgb(239,239,239)','rgb(243,243,243)','rgb(255,255,255)','rgb(152,0,0)','rgb(255,0,0)','rgb(255,153,0)','rgb(255,255,0)','rgb(0,255,0)','rgb(0,255,255)','rgb(74,134,232)','rgb(0,0,255)','rgb(153,0,255)','rgb(255,0,255)','rgb(230,184,175)','rgb(244,204,204)','rgb(252,229,205)','rgb(255,242,204)','rgb(217,234,211)','rgb(208,224,227)','rgb(201,218,248)','rgb(207,226,243)','rgb(217,210,233)','rgb(234,209,220)','rgb(221,126,107)','rgb(234,153,153)','rgb(249,203,156)','rgb(255,229,153)','rgb(182,215,168)','rgb(162,196,201)','rgb(164,194,244)','rgb(159,197,232)','rgb(180,167,214)','rgb(213,166,189)','rgb(204,65,37)','rgb(224,102,102)','rgb(246,178,107)','rgb(255,217,102)','rgb(147,196,125)','rgb(118,165,175)','rgb(109,158,235)','rgb(111,168,220)','rgb(142,124,195)','rgb(194,123,160)','rgb(166,28,0)','rgb(204,0,0)','rgb(230,145,56)','rgb(241,194,50)','rgb(106,168,79)','rgb(69,129,142)','rgb(60,120,216)','rgb(61,133,198)','rgb(103,78,167)','rgb(166,77,121)','rgb(133,32,12)','rgb(153,0,0)','rgb(180,95,6)','rgb(191,144,0)','rgb(56,118,29)','rgb(19,79,92)','rgb(17,85,204)','rgb(11,83,148)','rgb(53,28,117)','rgb(116,27,71)','rgb(91,15,0)','rgb(102,0,0)','rgb(120,63,4)','rgb(127,96,0)','rgb(39,78,19)','rgb(12,52,61)','rgb(28,69,135)','rgb(7,55,99)','rgb(32,18,77)','rgb(76,17,48)'],
|
||||||
icons: ['ambulance','anchor','balance scale','bath','bed','beer','bell','bell slash','bell slash outline','bicycle','binoculars','birthday cake','blind','bomb','book','bookmark','briefcase','building','car','coffee','crosshairs','dollar sign','eye','eye slash','fighter jet','fire','fire extinguisher','flag','flag checkered','flask','gamepad','gavel','gift','glass martini','globe','graduation cap','h square','heart','heart outline','heartbeat','home','hospital','hospital outline','image','image outline','images','images outline','industry','info','info circle','key','leaf','lemon','lemon outline','life ring','life ring outline','lightbulb','lightbulb outline','location arrow','low vision','magnet','male','map','map outline','map marker','map marker alternate','map pin','map signs','medkit','money bill alternate','money bill alternate outline','motorcycle','music','newspaper','newspaper outline','paw','phone','phone square','phone volume','plane','plug','plus','plus square','plus square outline','print','recycle','road','rocket','search','search minus','search plus','ship','shopping bag','shopping basket','shopping cart','shower','street view','subway','suitcase','tag','tags','taxi','thumbtack','ticket alternate','tint','train','tree','trophy','truck','tty','umbrella','university','utensil spoon','utensils','wheelchair','wifi','wrench']
|
icons: ['ambulance','anchor','balance scale','bath','bed','beer','bell','bell slash','bell slash outline','bicycle','binoculars','birthday cake','blind','bomb','book','bookmark','briefcase','building','car','coffee','crosshairs','dollar sign','eye','eye slash','fighter jet','fire','fire extinguisher','flag','flag checkered','flask','gamepad','gavel','gift','glass martini','globe','graduation cap','h square','heart','heart outline','heartbeat','home','hospital','hospital outline','image','image outline','images','images outline','industry','info','info circle','key','leaf','lemon','lemon outline','life ring','life ring outline','lightbulb','lightbulb outline','location arrow','low vision','magnet','male','map','map outline','map marker','map marker alternate','map pin','map signs','medkit','money bill alternate','money bill alternate outline','motorcycle','music','newspaper','newspaper outline','paw','phone','phone square','phone volume','plane','plug','plus','plus square','plus square outline','print','recycle','road','rocket','search','search minus','search plus','ship','shopping bag','shopping basket','shopping cart','shower','street view','subway','suitcase','tag','tags','taxi','thumbtack','ticket alternate','tint','train','tree','trophy','truck','tty','umbrella','university','utensil spoon','utensils','wheelchair','wifi','wrench']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -84,15 +84,12 @@
|
|||||||
|
|
||||||
this.colors.forEach((color,i) => {
|
this.colors.forEach((color,i) => {
|
||||||
|
|
||||||
if(i%20 <= 10){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let mod = (i % 10)+1 //1 - 10
|
let mod = (i % 10)+1 //1 - 10
|
||||||
let lines = [3, 5, 8, 9, 10]
|
let lines = [3, 5, 8, 9, 10]
|
||||||
if(lines.includes(mod)){
|
// if(lines.includes(mod)){
|
||||||
reduced.push(color)
|
reduced.push(color)
|
||||||
}
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
reduced.push("#000")
|
reduced.push("#000")
|
||||||
@ -110,6 +107,11 @@
|
|||||||
//Set not background to color that was chosen
|
//Set not background to color that was chosen
|
||||||
this.allStyles.noteBackground = inColor
|
this.allStyles.noteBackground = inColor
|
||||||
|
|
||||||
|
if(inColor == null){
|
||||||
|
this.$emit('changeColor', this.allStyles)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//Automatically select note text color
|
//Automatically select note text color
|
||||||
|
|
||||||
// Convert hex color to RGB - http://gist.github.com/983661
|
// Convert hex color to RGB - http://gist.github.com/983661
|
||||||
@ -148,16 +150,18 @@
|
|||||||
<style type="text/css" scoped>
|
<style type="text/css" scoped>
|
||||||
.icon-button {
|
.icon-button {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
width: 14.2%;
|
width: calc(10% - 7px);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
}
|
}
|
||||||
.color-button {
|
.color-button {
|
||||||
height: 50px;
|
display: inline-block;
|
||||||
width: 20%;
|
width: calc(10% - 7px);
|
||||||
display: block;
|
height: 30px;
|
||||||
|
border-radius: 30px;
|
||||||
|
box-shadow: 0px 1px 3px 0px #3e3e3e;
|
||||||
|
margin: 7px 7px 0 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
float: left;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -125,7 +125,6 @@
|
|||||||
<i class="open folder outline icon"></i>
|
<i class="open folder outline icon"></i>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="two wide center aligned bottom aligned column">
|
<div class="two wide center aligned bottom aligned column">
|
||||||
@ -138,7 +137,6 @@
|
|||||||
<i class="green moon outline icon"></i>
|
<i class="green moon outline icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<search-input v-if="loggedIn && mobile"></search-input>
|
|
||||||
<!-- mobile create note button -->
|
<!-- mobile create note button -->
|
||||||
<span v-if="loggedIn">
|
<span v-if="loggedIn">
|
||||||
<span v-if="!disableNewNote" @click="createNote" class="ui large green compact icon button">
|
<span v-if="!disableNewNote" @click="createNote" class="ui large green compact icon button">
|
||||||
@ -199,11 +197,11 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="menu-section" v-if="loggedIn">
|
<div class="menu-section" v-if="loggedIn">
|
||||||
<router-link v-if="loggedIn" exact-active-class="active" class="menu-item menu-button" to="/quick">
|
<router-link v-if="loggedIn" exact-active-class="active" class="menu-item menu-button" to="/quick">
|
||||||
<i class="paper plane outline icon"></i>Quick Note
|
<i class="sticky note outline icon"></i>Scratch Pad
|
||||||
</router-link>
|
</router-link>
|
||||||
</div> -->
|
</div>
|
||||||
|
|
||||||
<div class="menu-section" v-if="!loggedIn">
|
<div class="menu-section" v-if="!loggedIn">
|
||||||
<router-link v-if="!loggedIn" class="menu-item menu-button" exact-active-class="active" to="/">
|
<router-link v-if="!loggedIn" class="menu-item menu-button" exact-active-class="active" to="/">
|
||||||
@ -217,10 +215,12 @@
|
|||||||
|
|
||||||
<div class="menu-section">
|
<div class="menu-section">
|
||||||
<div v-on:click="toggleNightMode" class="menu-item menu-button">
|
<div v-on:click="toggleNightMode" class="menu-item menu-button">
|
||||||
<span v-if="$store.getters.getIsNightMode">
|
<span v-if="$store.getters.getIsNightMode == 0">
|
||||||
|
<i class="moon outline icon"></i>Black Theme</span>
|
||||||
|
<span v-if="$store.getters.getIsNightMode == 1">
|
||||||
|
<i class="moon outline icon"></i>Night Theme</span>
|
||||||
|
<span v-if="$store.getters.getIsNightMode == 2">
|
||||||
<i class="moon outline icon"></i>Light Theme</span>
|
<i class="moon outline icon"></i>Light Theme</span>
|
||||||
<span v-else>
|
|
||||||
<i class="moon outline icon"></i>Dark Theme</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -257,7 +257,7 @@
|
|||||||
},
|
},
|
||||||
data: function(){
|
data: function(){
|
||||||
return {
|
return {
|
||||||
version: '2.1.0',
|
version: '2.1.2',
|
||||||
username: '',
|
username: '',
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
mobile: false,
|
mobile: false,
|
||||||
@ -329,7 +329,7 @@
|
|||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
||||||
if(response.data && response.data.id){
|
if(response.data && response.data.id){
|
||||||
this.$router.push('/notes/open/'+response.data.id)
|
// this.$router.push('/notes/open/'+response.data.id)
|
||||||
this.$bus.$emit('open_note', response.data.id)
|
this.$bus.$emit('open_note', response.data.id)
|
||||||
this.disableNewNote = false
|
this.disableNewNote = false
|
||||||
}
|
}
|
||||||
@ -380,7 +380,7 @@
|
|||||||
location.reload(true)
|
location.reload(true)
|
||||||
},
|
},
|
||||||
getVersionIcon(){
|
getVersionIcon(){
|
||||||
const icons = ['cat','crow','dog','dove','dragon','fish','frog','hippo','horse','kiwi bird','otter','spider']
|
const icons = ['cat','crow','dog','dove','dragon','fish','frog','hippo','horse','kiwi bird','otter','spider', 'smile', 'robot', 'hat wizard', 'microchip', 'atom', 'grin tongue squint', 'radiation']
|
||||||
const index = ( parseInt(this.version.replace(/\./g,'')) % (icons.length))
|
const index = ( parseInt(this.version.replace(/\./g,'')) % (icons.length))
|
||||||
return icons[index]
|
return icons[index]
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="loading-container">
|
<div class="loading-container">
|
||||||
<svg version="1.1" id="L6" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
<svg version="1.1" id="L6" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||||
<rect fill="none" :stroke="$store.getters.getIsNightMode?'#FFF':'#16ab39'" stroke-width="4" x="25" y="25" width="50" height="50" rx="5">
|
<rect fill="none" :stroke="$store.getters.getIsNightMode > 0 ? '#FFF':'#16ab39'" stroke-width="4" x="25" y="25" width="50" height="50" rx="5">
|
||||||
<animateTransform
|
<animateTransform
|
||||||
attributeName="transform"
|
attributeName="transform"
|
||||||
dur="0.5s"
|
dur="0.5s"
|
||||||
@ -12,7 +12,7 @@
|
|||||||
attributeType="XML"
|
attributeType="XML"
|
||||||
begin="rectBox.end"/>
|
begin="rectBox.end"/>
|
||||||
</rect>
|
</rect>
|
||||||
<rect x="25" y="25" :fill="$store.getters.getIsNightMode?'#FFF':'#16ab39'" width="50" height="50">
|
<rect x="25" y="25" :fill="$store.getters.getIsNightMode > 0 ? '#FFF':'#16ab39'" width="50" height="50">
|
||||||
<animate
|
<animate
|
||||||
attributeName="height"
|
attributeName="height"
|
||||||
dur="1.3s"
|
dur="1.3s"
|
||||||
|
@ -21,25 +21,25 @@
|
|||||||
|
|
||||||
<div class="edit-divide"></div>
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="toggleList('ul')" data-tooltip="Task List" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="toggleList('ul')" data-tooltip="Task List" data-position="bottom center" data-inverted :class="{'edit-active':activeToDo}">
|
||||||
<i class="tasks icon"></i>
|
<i class="tasks icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="edit-button" v-on:click="toggleList('ol')" data-tooltip="Numbered List" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="toggleList('ol')" data-tooltip="Numbered List" data-position="bottom center" data-inverted :class="{'edit-active':activeList}">
|
||||||
<i class="list ol icon"></i>
|
<i class="list ol icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="colorpicker = true" data-tooltip="Text Color" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="colorpicker = true" data-tooltip="Text Color" data-position="bottom center" data-inverted :style="{'color':activeColor}">
|
||||||
<i class="palette icon"></i>
|
<i class="palette icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="toggleBold()" data-tooltip="Bold" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="toggleBold()" data-tooltip="Bold" data-position="bottom center" data-inverted :class="{'edit-active':activeBold}">
|
||||||
<i class="bold icon"></i>
|
<i class="bold icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="toggleItalic()" data-tooltip="Quote" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="toggleItalic()" data-tooltip="Quote" data-position="bottom center" data-inverted :class="{'edit-active':activeQuote}">
|
||||||
<i class="quote left icon"></i>
|
<i class="quote left icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="edit-button" v-on:click="modifyFont('1.4em')" data-tooltip="Title" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="modifyFont('1.4em')" data-tooltip="Title" data-position="bottom center" data-inverted :class="{'edit-active':activeTitle}">
|
||||||
<i class="text height icon"></i>
|
<i class="text height icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="edit-button" v-on:click="editor.increaseQuoteLevel()" data-tooltip="Indent" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="editor.increaseQuoteLevel()" data-tooltip="Indent" data-position="bottom center" data-inverted>
|
||||||
@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
<div class="edit-divide"></div>
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/colors`)" data-tooltip="Note Color" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/colors`)" data-tooltip="Note Color" data-position="bottom center" data-inverted :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
|
||||||
<i class="paint brush icon"></i>
|
<i class="paint brush icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)" data-tooltip="Tags" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)" data-tooltip="Tags" data-position="bottom center" data-inverted>
|
||||||
@ -112,7 +112,7 @@
|
|||||||
|
|
||||||
<div class="bottom-edit-menu"></div>
|
<div class="bottom-edit-menu"></div>
|
||||||
|
|
||||||
<div class="input-container-wrapper" :class="{ 'side-menu-open':sideMenuOpen, 'size-down':(sizeDown == true)}" >
|
<div class="input-container-wrapper" :class="{ 'side-menu-open':sideMenuOpen, 'size-down':(sizeDown == true),}" :style="{ 'background-color':styleObject['noteBackground'] }">
|
||||||
|
|
||||||
<!-- Squire box grows -->
|
<!-- Squire box grows -->
|
||||||
<div class="note-wrapper" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
|
<div class="note-wrapper" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
|
||||||
@ -142,11 +142,6 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- && this.$store.getters.getIsUserOnMobile -->
|
|
||||||
<span class="note-status-indicator" v-on:click="save()" v-if="statusText != 'Saved' && $store.getters.getIsUserOnMobile">
|
|
||||||
<div class="ui green button">{{statusText}}</div>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- color picker -->
|
<!-- color picker -->
|
||||||
@ -298,6 +293,14 @@
|
|||||||
images: false,
|
images: false,
|
||||||
options: false,
|
options: false,
|
||||||
colorpicker: false,
|
colorpicker: false,
|
||||||
|
|
||||||
|
//active button states
|
||||||
|
activeBold: false,
|
||||||
|
activeQuote: false,
|
||||||
|
activeTitle: false,
|
||||||
|
activeList: false,
|
||||||
|
activeToDo: false,
|
||||||
|
activeColor: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -383,7 +386,7 @@
|
|||||||
this.setText(this.noteText)
|
this.setText(this.noteText)
|
||||||
|
|
||||||
this.lastNoteHash = this.hashString(this.getText())
|
this.lastNoteHash = this.hashString(this.getText())
|
||||||
console.log('hash on load', this.lastNoteHash)
|
// console.log('hash on load', this.lastNoteHash)
|
||||||
|
|
||||||
//focus on open, not on mobile, thats annoying
|
//focus on open, not on mobile, thats annoying
|
||||||
if(!this.$store.getters.getIsUserOnMobile){
|
if(!this.$store.getters.getIsUserOnMobile){
|
||||||
@ -398,6 +401,41 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Change button states on editor when element is active
|
||||||
|
//eg; Bold button turns green when on bold text
|
||||||
|
this.editor.addEventListener('pathChange', e => {
|
||||||
|
|
||||||
|
//Reset all button states
|
||||||
|
this.activeBold = false
|
||||||
|
this.activeTitle = false
|
||||||
|
this.activeQuote = false
|
||||||
|
this.activeList = false
|
||||||
|
this.activeToDo = false
|
||||||
|
this.activeColor = null
|
||||||
|
|
||||||
|
let colors = e.path.match(/\d+/g)
|
||||||
|
if(colors && colors.length == 3){
|
||||||
|
this.activeColor=`rgb(${colors.join(',')})`
|
||||||
|
}
|
||||||
|
|
||||||
|
//@ TODO - Update this to match all elements, like color and bold
|
||||||
|
// index of and then the specific thing might more indexOf('B'), indexOf('I'), etc
|
||||||
|
|
||||||
|
let element = e.path.split('>').pop()
|
||||||
|
switch (element) {
|
||||||
|
case 'B': this.activeBold = true; break;
|
||||||
|
case 'I': this.activeQuote = true; break;
|
||||||
|
case 'SPAN.size[fontSize=1.4em]': this.activeTitle = true; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parent = e.path.split('>').shift()
|
||||||
|
switch (parent) {
|
||||||
|
case 'OL': this.activeList = true; break;
|
||||||
|
case 'UL': this.activeToDo = true; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
//Click Event - Open links when clicked in editor or toggle checks
|
//Click Event - Open links when clicked in editor or toggle checks
|
||||||
this.editor.addEventListener('click', e => {
|
this.editor.addEventListener('click', e => {
|
||||||
|
|
||||||
@ -1003,17 +1041,17 @@
|
|||||||
|
|
||||||
this.statusText = ''
|
this.statusText = ''
|
||||||
|
|
||||||
this.diffText()
|
// this.diffText()
|
||||||
|
|
||||||
//Each note, save after 5 seconds, focus lost or 30 characters typed.
|
//Each note, save after 15 seconds, focus lost or 30 characters typed.
|
||||||
clearTimeout(this.editDebounce)
|
clearTimeout(this.editDebounce)
|
||||||
this.editDebounce = setTimeout(() => {
|
this.editDebounce = setTimeout(() => {
|
||||||
this.save()
|
this.save()
|
||||||
}, 5000)
|
}, 15 * 1000)
|
||||||
|
|
||||||
//Save after 30 keystrokes
|
//Save after 50 keystrokes
|
||||||
this.keyPressesCounter = (this.keyPressesCounter + 1)
|
this.keyPressesCounter = (this.keyPressesCounter + 1)
|
||||||
if(this.keyPressesCounter > 30){
|
if(this.keyPressesCounter > 50){
|
||||||
this.keyPressesCounter = 0
|
this.keyPressesCounter = 0
|
||||||
this.save()
|
this.save()
|
||||||
}
|
}
|
||||||
@ -1048,7 +1086,7 @@
|
|||||||
'hash': currentHash,
|
'hash': currentHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Save Hash', currentHash)
|
// console.log('Save Hash', currentHash)
|
||||||
|
|
||||||
this.statusText = 'Saving'
|
this.statusText = 'Saving'
|
||||||
axios.post('/api/note/update', postData).then( response => {
|
axios.post('/api/note/update', postData).then( response => {
|
||||||
@ -1148,8 +1186,8 @@
|
|||||||
setupWebSockets(){
|
setupWebSockets(){
|
||||||
|
|
||||||
this.$io.on('new_note_text_saved', ({noteId, hash}) => {
|
this.$io.on('new_note_text_saved', ({noteId, hash}) => {
|
||||||
console.log('Current hash', this.lastNoteHash)
|
// console.log('Current hash', this.lastNoteHash)
|
||||||
console.log('Incoming Hash', hash)
|
// console.log('Incoming Hash', hash)
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -1255,6 +1293,10 @@
|
|||||||
.edit-button:hover {
|
.edit-button:hover {
|
||||||
background-color: var(--menu-accent);
|
background-color: var(--menu-accent);
|
||||||
}
|
}
|
||||||
|
.edit-active {
|
||||||
|
background-color: #21BA45;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
.edit-divide {
|
.edit-divide {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background-color: var(--menu-accent);
|
background-color: var(--menu-accent);
|
||||||
@ -1313,7 +1355,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
background: var(--background_color);
|
/*background: var(--background_color);*/
|
||||||
/*opacity: 0.;*/
|
/*opacity: 0.;*/
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="note-title-display-card"
|
<div class="note-title-display-card"
|
||||||
:style="{'background-color':color, 'color':fontColor, 'border-color':color }"
|
:style="{'background-color':color, 'color':fontColor, 'border-color':color }"
|
||||||
:class="{'currently-open':currentlyOpen, 'bgboy':triggerClosedAnimation}"
|
:class="{'currently-open':currentlyOpen, 'bgboy':triggerClosedAnimation, 'title-view':titleView }"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|
||||||
<!-- Show title and snippet below it -->
|
<!-- Show title and snippet below it -->
|
||||||
<div class="overflow-hidden note-card-text" @click="cardClicked">
|
<div class="overflow-hidden note-card-text" @click="cardClicked" v-if="!titleView">
|
||||||
|
|
||||||
<span class="subtext" v-if="note.shareUsername">
|
<span class="subtext" v-if="note.shareUsername">
|
||||||
Shared by {{ note.shareUsername }}
|
Shared by {{ note.shareUsername }}
|
||||||
@ -62,13 +62,17 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="titleView" class="single-line-text" @click="cardClicked">
|
||||||
|
<span class="title-line" v-if="note.title.length > 0">{{ note.title }}<br></span>
|
||||||
|
<span class="sub-line" v-if="note.subtext.length > 0">{{ removeHtml(note.subtext) }}</span>
|
||||||
|
<span v-if="note.title.length == 0 && note.title.length == 0">Empty Note</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Toolbar on the bottom -->
|
<!-- Toolbar on the bottom -->
|
||||||
<div class="tool-bar" @click.self="cardClicked">
|
<div class="tool-bar" @click.self="cardClicked" v-if="!titleView">
|
||||||
<div class="icon-bar">
|
<div class="icon-bar">
|
||||||
|
|
||||||
<!-- <span v-if="note.pinned == 1" data-position="top left" data-tooltip="Pinned" data-inverted>
|
<!-- <span v-if="note.pinned == 1" data-position="top left" data-tooltip="Pinned" data-inverted>
|
||||||
<i class="green pin icon"></i>
|
<i class="green pin icon"></i>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="note.archived == 1" data-position="top left" data-tooltip="Archived" data-inverted>
|
<span v-if="note.archived == 1" data-position="top left" data-tooltip="Archived" data-inverted>
|
||||||
@ -113,9 +117,8 @@
|
|||||||
<img v-for="thumb in getThumbs" class="tiny-thumb" :src="`/api/static/thumb_${thumb}`">
|
<img v-for="thumb in getThumbs" class="tiny-thumb" :src="`/api/static/thumb_${thumb}`">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<side-slide-menu v-if="showTagSlideMenu" v-on:close="toggleTags(false)" :full-shadow="true" :skip-history="true">
|
<side-slide-menu v-if="showTagSlideMenu" v-on:close="toggleTags(false)" :full-shadow="true" :skip-history="true">
|
||||||
<div class="ui basic segment">
|
<div class="ui basic segment">
|
||||||
<note-tag-edit :noteId="note.id" :key="'display-tags-for-note-'+note.id"/>
|
<note-tag-edit :noteId="note.id" :key="'display-tags-for-note-'+note.id"/>
|
||||||
@ -136,7 +139,7 @@
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NoteTitleDisplayCard',
|
name: 'NoteTitleDisplayCard',
|
||||||
props: [ 'onClick', 'data', 'currentlyOpen', 'textResults', 'attachmentResults', 'tagResults' ],
|
props: [ 'onClick', 'data', 'currentlyOpen', 'textResults', 'attachmentResults', 'tagResults', 'titleView' ],
|
||||||
components: {
|
components: {
|
||||||
'delete-button': require('@/components/NoteDeleteButtonComponent.vue').default,
|
'delete-button': require('@/components/NoteDeleteButtonComponent.vue').default,
|
||||||
'note-tag-edit': require('@/components/NoteTagEdit.vue').default,
|
'note-tag-edit': require('@/components/NoteTagEdit.vue').default,
|
||||||
@ -148,6 +151,17 @@
|
|||||||
this.beenClicked = true
|
this.beenClicked = true
|
||||||
this.onClick(this.note.id)
|
this.onClick(this.note.id)
|
||||||
},
|
},
|
||||||
|
removeHtml(string){
|
||||||
|
if(string == undefined || string == null || string.length == 0){
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return string
|
||||||
|
.replace(/&[[#A-Za-z0-9]+A-Za-z0-9]+;/g,' ') //Rip out all HTML entities
|
||||||
|
.replace(/<[^>]+>/g, ' ') //Rip out all HTML tags
|
||||||
|
.replace(/\s+/g, ' ') //Remove all whitespace
|
||||||
|
.trim()
|
||||||
|
},
|
||||||
cleanHighlight(text){
|
cleanHighlight(text){
|
||||||
//Basically just remove whitespace
|
//Basically just remove whitespace
|
||||||
let updated = text.replace(/ /g, '').replace(/<br>/g,'')
|
let updated = text.replace(/ /g, '').replace(/<br>/g,'')
|
||||||
@ -395,6 +409,27 @@
|
|||||||
.note-title-display-card:hover {
|
.note-title-display-card:hover {
|
||||||
box-shadow: 0px 2px 2px 1px rgba(210, 211, 211, 0.8);
|
box-shadow: 0px 2px 2px 1px rgba(210, 211, 211, 0.8);
|
||||||
}
|
}
|
||||||
|
.note-title-display-card.title-view {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 10px;
|
||||||
|
max-width: none;
|
||||||
|
box-shadow: 0px 0px 1px 1px rgba(210, 211, 211, 0.46);
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-line-text {
|
||||||
|
width: calc(100% - 25px);
|
||||||
|
margin: 5px 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.title-line {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.2em;
|
||||||
|
padding: 0 20px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-bar {
|
.icon-bar {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 5px 10px 0;
|
padding: 5px 10px 0;
|
||||||
|
@ -8,45 +8,69 @@
|
|||||||
}
|
}
|
||||||
.floating-button {
|
.floating-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 7px;
|
||||||
top: 4px;
|
top: 4px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
.floating-note-options {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
top: 35px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.floating-note-options > .segment {
|
||||||
|
border-top: none;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<template>
|
<template>
|
||||||
<span>
|
<span v-on:mouseenter="extraMenuHover = true" v-on:mouseleave="extraMenuHover = false">
|
||||||
|
|
||||||
<div class="ui form" v-if="!$store.getters.getIsUserOnMobile">
|
<div class="ui form">
|
||||||
<!-- normal search menu -->
|
<!-- normal search menu -->
|
||||||
<div class="ui left icon fluid input">
|
<div class="ui left icon fluid input">
|
||||||
<input ref="desktopSearch" v-model="searchTerm" @keyup.enter="search" placeholder="Search Notes and Files" />
|
<input ref="desktopSearch" v-on:blur="focused = false" v-on:focus="focused = true" v-model="searchTerm" @keydown="onKeyDown" @keyup="onKeyUp" placeholder="Search or Start Typing New Note" />
|
||||||
<i class="search icon"></i>
|
<i class="search icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="floating-button" v-if="searchTerm.length > 0 && !searched">
|
|
||||||
|
<div class="floating-button" v-if="searchTerm.length > 0 && !searched && searchTerm.indexOf(' ') == -1">
|
||||||
<div class="ui green compact button" v-on:click="search()">Search</div>
|
<div class="ui green compact button" v-on:click="search()">Search</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="floating-button" v-if="searchTerm.length > 0 && searched">
|
<div class="floating-button" v-if="searchTerm.length > 0 && searched">
|
||||||
<div class="ui grey compact button" v-on:click="clear()">Clear</div>
|
<div class="ui grey compact button" v-on:click="clear()">Clear</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="floating-button" v-if="!searched && searchTerm.length > 0 && searchTerm.indexOf(' ') != -1">
|
||||||
|
<div class="ui grey compact button" v-on:click="searchTerm = ''">Clear</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Only show button on mobile -->
|
<div class="floating-note-options"
|
||||||
<span class="ui basic icon button" v-on:click="openFloatingSearch" v-if="$store.getters.getIsUserOnMobile">
|
v-if="(searchTerm.indexOf(' ') != -1 || tagSuggestions.length > 0) && (extraMenuHover)">
|
||||||
<i class="green search icon"></i>
|
<div class="ui segment">
|
||||||
</span>
|
<div class="ui very compact grid" v-if="searchTerm.indexOf(' ') != -1">
|
||||||
|
<div class="eight wide column">
|
||||||
|
<div class="ui green compact shrinking button" v-on:click="pushToNewNote()">
|
||||||
|
<i class="plus icon"></i>A New Note
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="eight wide right aligned column">
|
||||||
|
<div class="ui green compact shrinking button" v-on:click="pushToQuickNote()">
|
||||||
|
<i class="sticky note outline icon"></i>The Scratch Pad
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="fixed-search" v-if="showFixedSearch">
|
<div class="ui very compact grid" v-if="tagSuggestions.length > 0">
|
||||||
<div class="ui raised segment">
|
<div class="sixteen wide column">
|
||||||
<h2 class="ui center aligned header">Search!</h2>
|
<div class="ui clickable green label" v-for="tag in tagSuggestions" v-on:click="tagClick(tag.id)">
|
||||||
<div class="ui form">
|
<i class="tag icon"></i>
|
||||||
<div class="ui left icon fluid input">
|
{{ tag.text }}
|
||||||
<input
|
</div>
|
||||||
ref="fixedSearch"
|
</div>
|
||||||
v-model="searchTerm"
|
</div>
|
||||||
@keyup.enter="search"
|
|
||||||
v-on:blur="showFixedSearch = false"
|
|
||||||
placeholder="Press Enter to Search" />
|
|
||||||
<i class="search icon"></i>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -57,13 +81,19 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
data: function(){
|
data: function(){
|
||||||
return {
|
return {
|
||||||
searchTerm: '',
|
searchTerm:'',
|
||||||
showFixedSearch: false,
|
|
||||||
searched: false,
|
searched: false,
|
||||||
|
|
||||||
|
tagSuggestions: [],
|
||||||
|
tagSearchDebounce: null,
|
||||||
|
|
||||||
|
extraMenuHover: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeCreate: function(){
|
beforeCreate: function(){
|
||||||
@ -73,36 +103,105 @@
|
|||||||
//search clear
|
//search clear
|
||||||
this.$bus.$on('reset_fast_filters', () => {
|
this.$bus.$on('reset_fast_filters', () => {
|
||||||
this.searchTerm = ''
|
this.searchTerm = ''
|
||||||
|
this.tagSuggestions = []
|
||||||
})
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openFloatingSearch(){
|
tagClick(tagId){
|
||||||
this.showFixedSearch = !this.showFixedSearch
|
|
||||||
|
|
||||||
if(this.showFixedSearch){
|
this.$emit('tagClick', tagId)
|
||||||
this.$nextTick( () => {
|
this.tagSuggestions = []
|
||||||
this.searchTerm = ''
|
this.searchTerm = ''
|
||||||
this.$refs.fixedSearch.focus()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
clear(){
|
clear(){
|
||||||
this.searched = false
|
this.searched = false
|
||||||
this.searchTerm = ''
|
this.searchTerm = ''
|
||||||
|
this.tagSuggestions = []
|
||||||
if(!this.$store.getters.getIsUserOnMobile){
|
if(!this.$store.getters.getIsUserOnMobile){
|
||||||
this.$refs.desktopSearch.focus()
|
this.$refs.desktopSearch.focus()
|
||||||
}
|
}
|
||||||
this.$bus.$emit('note_reload')
|
this.$bus.$emit('note_reload')
|
||||||
},
|
},
|
||||||
|
pushToQuickNote(){
|
||||||
|
|
||||||
|
const text = this.searchTerm
|
||||||
|
this.searchTerm = ''
|
||||||
|
this.tagSuggestions = []
|
||||||
|
|
||||||
|
axios.post('/api/quick-note/update', { 'pushText':text.trim() } )
|
||||||
|
.then( response => {
|
||||||
|
|
||||||
|
//Open Quick Note
|
||||||
|
if(response.data && response.data.id){
|
||||||
|
this.$router.push('/notes/open/'+response.data.id)
|
||||||
|
this.$bus.$emit('open_note', response.data.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Update The Scratch Pad') })
|
||||||
|
},
|
||||||
|
pushToNewNote(){
|
||||||
|
|
||||||
|
const text = this.searchTerm
|
||||||
|
this.searchTerm = ''
|
||||||
|
this.tagSuggestions = []
|
||||||
|
|
||||||
|
axios.post('/api/note/create', { text })
|
||||||
|
.then(response => {
|
||||||
|
|
||||||
|
if(response.data && response.data.id){
|
||||||
|
this.$router.push('/notes/open/'+response.data.id)
|
||||||
|
this.$bus.$emit('open_note', response.data.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => { this.$bus.$emit('notification', 'Failed to create note') })
|
||||||
|
},
|
||||||
|
onKeyUp(event){
|
||||||
|
//Search Tags
|
||||||
|
const postData = {
|
||||||
|
'tagText':this.searchTerm.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(this.tagSearchDebounce)
|
||||||
|
|
||||||
|
if(this.searchTerm.length == 0){
|
||||||
|
this.tagSuggestions = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tagSearchDebounce = setTimeout(() => {
|
||||||
|
this.tagSuggestions = []
|
||||||
|
axios.post('/api/tag/suggest', postData)
|
||||||
|
.then( response => {
|
||||||
|
|
||||||
|
this.tagSuggestions = response.data
|
||||||
|
})
|
||||||
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Get Suggested Tags') })
|
||||||
|
}, 800)
|
||||||
|
},
|
||||||
|
onKeyDown(event){
|
||||||
|
|
||||||
|
//Commant + Enter
|
||||||
|
if((event.metaKey || event.ctrlKey) && event.keyCode == 13 ){
|
||||||
|
this.pushToQuickNote()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event.keyCode == 13){
|
||||||
|
this.search()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
search(){
|
search(){
|
||||||
this.searched = true
|
this.searched = true
|
||||||
if(this.$store.getters.getIsUserOnMobile){
|
|
||||||
this.$refs.fixedSearch.blur()
|
|
||||||
}
|
|
||||||
if(!this.$store.getters.getIsUserOnMobile){
|
|
||||||
this.$refs.desktopSearch.focus()
|
this.$refs.desktopSearch.focus()
|
||||||
|
//Blur after search on mobile
|
||||||
|
if(this.$store.getters.getIsUserOnMobile){
|
||||||
|
this.$refs.desktopSearch.blur()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$bus.$emit('update_search_term', this.searchTerm)
|
this.$bus.$emit('update_search_term', this.searchTerm)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,14 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'HelpPage'
|
name: 'HelpPage',
|
||||||
|
props:[ 'message' ],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
items: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
@ -31,10 +31,16 @@
|
|||||||
v-on:tagClick="tagId => toggleTagFilter(tagId)"
|
v-on:tagClick="tagId => toggleTagFilter(tagId)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div class="ui basic shrinking icon button" v-on:click="toggleTitleView()">
|
||||||
|
<i v-if="titleView" class="th icon"></i>
|
||||||
|
<i v-if="!titleView" class="bars icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="six wide column" v-if="!$store.getters.getIsUserOnMobile">
|
</div>
|
||||||
|
|
||||||
|
<div class="six wide column">
|
||||||
<search-input
|
<search-input
|
||||||
|
v-on:tagClick="tagId => toggleTagFilter(tagId)"
|
||||||
v-if="$store.getters.totals && $store.getters.totals['totalNotes']" />
|
v-if="$store.getters.totals && $store.getters.totals['totalNotes']" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -49,9 +55,16 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 v-if="searchTerm.length > 0 && !loadingInProgress">
|
<div class="sixteen wide column" v-if="searchTerm.length > 0 && !loadingInProgress">
|
||||||
|
<h2 class="ui header">
|
||||||
|
<div class="content">
|
||||||
{{ searchResultsCount.toLocaleString() }} notes with keyword "{{ searchTerm }}"
|
{{ searchResultsCount.toLocaleString() }} notes with keyword "{{ searchTerm }}"
|
||||||
|
<div v-if="searchResultsCount == 0" class="sub header">
|
||||||
|
Search can only find key words. Try a single word search.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2 v-if="fastFilters['withLinks'] == 1">Notes with Links</h2>
|
<h2 v-if="fastFilters['withLinks'] == 1">Notes with Links</h2>
|
||||||
<h2 v-if="fastFilters['withTags'] == 1">Notes with Tags</h2>
|
<h2 v-if="fastFilters['withTags'] == 1">Notes with Tags</h2>
|
||||||
@ -81,6 +94,7 @@
|
|||||||
:ref="'note-'+note.id"
|
:ref="'note-'+note.id"
|
||||||
:onClick="openNote"
|
:onClick="openNote"
|
||||||
:data="note"
|
:data="note"
|
||||||
|
:title-view="titleView"
|
||||||
:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
|
:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
|
||||||
:key="note.id + note.color + note.note_highlights.length + note.attachment_highlights.length + ' -' + note.tag_highlights.length + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
:key="note.id + note.color + note.note_highlights.length + note.attachment_highlights.length + ' -' + note.tag_highlights.length + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
||||||
/>
|
/>
|
||||||
@ -152,6 +166,7 @@
|
|||||||
highlights: [],
|
highlights: [],
|
||||||
searchDebounce: null,
|
searchDebounce: null,
|
||||||
fastFilters: {},
|
fastFilters: {},
|
||||||
|
titleView: false,
|
||||||
|
|
||||||
//Load up notes in batches
|
//Load up notes in batches
|
||||||
firstLoadBatchSize: 10, //First set of rapidly loaded notes
|
firstLoadBatchSize: 10, //First set of rapidly loaded notes
|
||||||
@ -207,10 +222,18 @@
|
|||||||
|
|
||||||
this.$parent.loginGateway()
|
this.$parent.loginGateway()
|
||||||
|
|
||||||
|
this.$io.on('new_note_created', noteId => {
|
||||||
|
//Do not update note if its open
|
||||||
|
if(this.activeNoteId1 != noteId){
|
||||||
|
this.updateSingleNote(parseInt(noteId))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//Update title cards when new note text is saved
|
||||||
this.$io.on('new_note_text_saved', ({noteId, hash}) => {
|
this.$io.on('new_note_text_saved', ({noteId, hash}) => {
|
||||||
//Do not update note if its open
|
//Do not update note if its open
|
||||||
if(this.activeNoteId1 != noteId){
|
if(this.activeNoteId1 != noteId){
|
||||||
console.log('notePage: update display of note ', noteId)
|
this.updateSingleNote(parseInt(noteId))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -237,6 +260,7 @@
|
|||||||
this.noteSections[key].forEach( (note, index) => {
|
this.noteSections[key].forEach( (note, index) => {
|
||||||
if(note.id == noteId){
|
if(note.id == noteId){
|
||||||
this.noteSections[key].splice(index,1)
|
this.noteSections[key].splice(index,1)
|
||||||
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -312,6 +336,9 @@
|
|||||||
this.reset()
|
this.reset()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
toggleTitleView(){
|
||||||
|
this.titleView = !this.titleView
|
||||||
|
},
|
||||||
showOneColumn(){
|
showOneColumn(){
|
||||||
|
|
||||||
return this.$store.getters.getIsUserOnMobile
|
return this.$store.getters.getIsUserOnMobile
|
||||||
@ -328,32 +355,13 @@
|
|||||||
if(nodeClick == 'A'){ return }
|
if(nodeClick == 'A'){ return }
|
||||||
}
|
}
|
||||||
|
|
||||||
//Do not open same note twice
|
|
||||||
if(this.activeNoteId1 == id || this.activeNoteId2 == id){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//1 note open
|
//1 note open
|
||||||
if(this.activeNoteId1 == null && this.activeNoteId2 == null){
|
if(this.activeNoteId1 == null){
|
||||||
this.activeNoteId1 = id
|
this.activeNoteId1 = id
|
||||||
this.activeNote1Position = 0 //Middel of page
|
this.activeNote1Position = 0 //Middel of page
|
||||||
this.$router.push('/notes/open/'+this.activeNoteId1)
|
this.$router.push('/notes/open/'+this.activeNoteId1)
|
||||||
return
|
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
|
|
||||||
}
|
|
||||||
//2 notes open
|
|
||||||
if(this.activeNoteId2 != null && this.activeNoteId1 == null){
|
|
||||||
this.activeNoteId1 = id
|
|
||||||
this.activeNote1Position = 2 //Right side of page
|
|
||||||
this.activeNote2Position = 1 //Left side of page
|
|
||||||
return
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
closeNote(position){
|
closeNote(position){
|
||||||
//One note open, close that note
|
//One note open, close that note
|
||||||
@ -448,10 +456,6 @@
|
|||||||
if(this.$refs.note1 && this.$refs.note1.currentNoteId == noteIdToClose){
|
if(this.$refs.note1 && this.$refs.note1.currentNoteId == noteIdToClose){
|
||||||
// this.$refs.note1.close()
|
// this.$refs.note1.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.$refs.note2 && this.$refs.note2.currentNoteId == noteIdToClose){
|
|
||||||
//this.$refs.note2.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
visibiltyChangeAction(event){
|
visibiltyChangeAction(event){
|
||||||
@ -475,6 +479,9 @@
|
|||||||
// @TODO Don't even trigger this if the note wasn't changed
|
// @TODO Don't even trigger this if the note wasn't changed
|
||||||
updateSingleNote(noteId){
|
updateSingleNote(noteId){
|
||||||
|
|
||||||
|
//Find local note, if it exists; continue
|
||||||
|
|
||||||
|
|
||||||
//Lookup one note using passed in ID
|
//Lookup one note using passed in ID
|
||||||
const postData = {
|
const postData = {
|
||||||
searchQuery: this.searchTerm,
|
searchQuery: this.searchTerm,
|
||||||
@ -484,8 +491,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Note data must be fetched, then sorted into existing note data
|
||||||
|
|
||||||
axios.post('/api/note/search', postData)
|
axios.post('/api/note/search', postData)
|
||||||
.then(results => {
|
.then(results => {
|
||||||
|
|
||||||
@ -526,6 +532,7 @@
|
|||||||
|
|
||||||
this.$nextTick( () => {
|
this.$nextTick( () => {
|
||||||
|
|
||||||
|
//Trigger close animation on note
|
||||||
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
||||||
this.$refs['note-'+noteId][0].justClosed()
|
this.$refs['note-'+noteId][0].justClosed()
|
||||||
}
|
}
|
||||||
|
@ -4,31 +4,27 @@
|
|||||||
|
|
||||||
<div class="ui sixteen wide column">
|
<div class="ui sixteen wide column">
|
||||||
<h2 class="ui header">
|
<h2 class="ui header">
|
||||||
<i class="paper plane outline icon"></i>
|
<i class="sticky note outline icon"></i>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
Quick
|
The Scratch Pad
|
||||||
<div class="sub header">Rapidly save text</div>
|
<div class="sub header">One place to put random junk</div>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sixteen wide middle aligned column">
|
<div class="sixteen wide middle aligned column">
|
||||||
|
|
||||||
<div class="ui compact basic button"
|
<div class="ui compact basic right floated button shrinking" v-if="!showNewNoteConfirm" v-on:click="showNewNoteConfirm = true">
|
||||||
v-on:click="enterToSubmit = !enterToSubmit">
|
<i class="sync alternate reload icon"></i>
|
||||||
<i v-if="enterToSubmit" class="green toggle on icon"></i>
|
New Quick Note
|
||||||
<i v-else class="toggle off icon"></i>
|
|
||||||
|
|
||||||
<span v-if="enterToSubmit">Save after Enter press</span>
|
|
||||||
<span v-else>CTRL + Enter to Save</span>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="showNewNoteConfirm" class="ui compact basic right floated button shrinking" v-on:click="showNewNoteConfirm = false">
|
||||||
<div class="ui compact basic button"
|
<i class="close icon"></i>
|
||||||
v-on:click="pasteToSubmit = !pasteToSubmit">
|
Cancel
|
||||||
<i v-if="pasteToSubmit" class="green check circle outline icon"></i>
|
</div>
|
||||||
<i v-else class="circle outline icon"></i>
|
<div v-if="showNewNoteConfirm" class="ui compact basic right floated button shrinking" v-on:click="newQuickNote()">
|
||||||
Save after Pasting
|
<i class="green thumbs up icon"></i>
|
||||||
|
Confirm
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -41,25 +37,28 @@
|
|||||||
ref="fastInput"
|
ref="fastInput"
|
||||||
v-model="newText"
|
v-model="newText"
|
||||||
v-on:keydown="checkKeyup"
|
v-on:keydown="checkKeyup"
|
||||||
v-on:paste="onPaste"
|
|
||||||
placeholder="Push to the top of the quick note."
|
placeholder="Push to the top of the quick note."
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div v-on:click="appendQuickNote" class="ui green button">Save</div>
|
<div v-on:click="appendQuickNote" class="ui green button">Save (Enter)</div>
|
||||||
<div v-if="quickNoteId" class="ui right floated basic button" v-on:click="$router.push('/attachments/note/'+quickNoteId)">
|
<div v-if="quickNoteId" class="ui right floated basic button" v-on:click="$router.push('/attachments/note/'+quickNoteId)">
|
||||||
<i class="folder open outline icon"></i>
|
<i class="folder open outline icon"></i>
|
||||||
Files
|
Files
|
||||||
</div>
|
</div>
|
||||||
<div v-if="quickNoteId" v-on:click="openNoteEdit" class="ui right floated basic button">
|
<div v-if="quickNoteId" v-on:click="openNoteEdit" class="ui right floated basic button">
|
||||||
<i class="file outline icon"></i>
|
<i class="file outline icon"></i>
|
||||||
Edit
|
Open Note
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="fun" v-html="savedQuickNoteText"></div>
|
<div class="one wide column"></div>
|
||||||
|
<div class="fourteen wide column">
|
||||||
|
<div class="note-card-text" v-html="savedQuickNoteText"></div>
|
||||||
|
</div>
|
||||||
|
<div class="one wide column"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -79,8 +78,7 @@
|
|||||||
newText: '',
|
newText: '',
|
||||||
savedQuickNoteText: '',
|
savedQuickNoteText: '',
|
||||||
quickNoteId: null,
|
quickNoteId: null,
|
||||||
pasteToSubmit: true,
|
showNewNoteConfirm: false,
|
||||||
enterToSubmit: true,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeCreate: function(){
|
beforeCreate: function(){
|
||||||
@ -89,6 +87,16 @@
|
|||||||
//
|
//
|
||||||
this.$parent.loginGateway()
|
this.$parent.loginGateway()
|
||||||
},
|
},
|
||||||
|
beforeMount(){
|
||||||
|
|
||||||
|
this.$io.on('new_note_created', noteId => {
|
||||||
|
this.getQuickNote()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$io.on('new_note_text_saved', ({noteId, hash}) => {
|
||||||
|
this.getQuickNote()
|
||||||
|
})
|
||||||
|
},
|
||||||
mounted: function(){
|
mounted: function(){
|
||||||
|
|
||||||
if(this.$refs.fastInput){
|
if(this.$refs.fastInput){
|
||||||
@ -107,6 +115,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
newQuickNote(){
|
||||||
|
|
||||||
|
this.showNewNoteConfirm = false
|
||||||
|
|
||||||
|
axios.post('/api/quick-note/new')
|
||||||
|
.then( ({data}) => {
|
||||||
|
this.savedQuickNoteText = ''
|
||||||
|
this.quickNoteId = ''
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
openNoteEdit(){
|
openNoteEdit(){
|
||||||
this.$router.push({'path':'/notes/open/'+this.quickNoteId})
|
this.$router.push({'path':'/notes/open/'+this.quickNoteId})
|
||||||
},
|
},
|
||||||
@ -119,14 +138,7 @@
|
|||||||
element.style.height = (element.scrollHeight + padding) +'px';
|
element.style.height = (element.scrollHeight + padding) +'px';
|
||||||
|
|
||||||
//Enter Key submits by default
|
//Enter Key submits by default
|
||||||
if(event.keyCode == 13 && this.enterToSubmit == true){
|
if(event.keyCode == 13){
|
||||||
this.appendQuickNote()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//Alternate submit
|
|
||||||
//If command+enter or control+enter is pressed, submit
|
|
||||||
if((event.metaKey || event.ctrlKey) && [13].includes(event.keyCode) && this.enterToSubmit == false){
|
|
||||||
this.appendQuickNote()
|
this.appendQuickNote()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -142,28 +154,17 @@
|
|||||||
this.newText = '' //Clear text area
|
this.newText = '' //Clear text area
|
||||||
this.$refs.fastInput.style.height = 'auto' //Back to normal size
|
this.$refs.fastInput.style.height = 'auto' //Back to normal size
|
||||||
|
|
||||||
this.savedQuickNoteText = results.data.text
|
|
||||||
this.quickNoteId = results.data.id
|
|
||||||
})
|
})
|
||||||
.catch(error => { this.$bus.$emit('notification', 'Failed to Update Quick Note') })
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Update Quick Note') })
|
||||||
},
|
},
|
||||||
getQuickNote (){
|
getQuickNote(){
|
||||||
axios.post('/api/quick-note/get')
|
axios.post('/api/quick-note/get')
|
||||||
.then( results => {
|
.then( ({data}) => {
|
||||||
this.savedQuickNoteText = results.data.text
|
this.savedQuickNoteText = data.text
|
||||||
this.quickNoteId = results.data.id
|
this.quickNoteId = data.id
|
||||||
})
|
})
|
||||||
.catch(error => { this.$bus.$emit('notification', 'Failed to Fetch Quick Note') })
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Fetch Quick Note') })
|
||||||
},
|
},
|
||||||
onPaste(event){
|
|
||||||
|
|
||||||
if(this.pasteToSubmit == true){
|
|
||||||
setTimeout( () => {
|
|
||||||
this.appendQuickNote()
|
|
||||||
}, 10)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
@ -60,7 +60,7 @@ export default new Router({
|
|||||||
{
|
{
|
||||||
path: '/quick',
|
path: '/quick',
|
||||||
name: 'Quick',
|
name: 'Quick',
|
||||||
meta: {title:'Quick'},
|
meta: {title:'Scratch Pad'},
|
||||||
component: QuickPage
|
component: QuickPage
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -41,38 +41,61 @@ export default new Vuex.Store({
|
|||||||
state.token = null
|
state.token = null
|
||||||
state.username = null
|
state.username = null
|
||||||
},
|
},
|
||||||
toggleNightMode(state){
|
toggleNightMode(state, pastTheme){
|
||||||
|
|
||||||
//Toggle state and save to local storage
|
const themes = {
|
||||||
state.nightMode = !(state.nightMode)
|
'white':{
|
||||||
localStorage.setItem('nightMode', state.nightMode)
|
|
||||||
|
|
||||||
//Default theme colors
|
|
||||||
let themeColors = {
|
|
||||||
'background_color': '#fff',
|
'background_color': '#fff',
|
||||||
'text_color': '#3d3d3d',
|
'text_color': '#3d3d3d',
|
||||||
'outline_color': 'rgba(34,36,38,0.15)',
|
'outline_color': 'rgba(34,36,38,0.15)',
|
||||||
'border_color': 'rgba(34,36,38,0.20)',
|
'border_color': 'rgba(34,36,38,0.20)',
|
||||||
'menu-accent': '#cecece',
|
'menu-accent': '#cecece',
|
||||||
'menu-text': '#5e6268',
|
'menu-text': '#5e6268',
|
||||||
}
|
},
|
||||||
//Night mode colors
|
'black':{
|
||||||
if(state.nightMode){
|
'background_color': '#000',
|
||||||
themeColors = {
|
'text_color': '#FFF',
|
||||||
|
'outline_color': '#FFF',
|
||||||
|
'border_color': 'rgba(255, 255, 255, 0.70)',
|
||||||
|
'menu-accent': '#626262',
|
||||||
|
'menu-text': '#d9d9d9',
|
||||||
|
},
|
||||||
|
'night':{
|
||||||
'background_color': '#000',
|
'background_color': '#000',
|
||||||
'text_color': '#a98457',
|
'text_color': '#a98457',
|
||||||
'outline_color': '#a98457',
|
'outline_color': '#a98457',
|
||||||
'border_color': 'rgba(255, 255, 255, 0.31)',
|
'border_color': 'rgba(255, 255, 255, 0.31)',
|
||||||
|
|
||||||
'menu-accent': '#626262',
|
'menu-accent': '#626262',
|
||||||
'menu-text': '#d9d9d9',
|
'menu-text': '#d9d9d9',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Catch values not in set
|
||||||
|
|
||||||
|
|
||||||
|
const totalThemes = Object.keys(themes).length
|
||||||
|
state.nightMode++
|
||||||
|
if(state.nightMode > totalThemes-1){
|
||||||
|
state.nightMode = 0
|
||||||
}
|
}
|
||||||
|
if(pastTheme != null){
|
||||||
|
state.nightMode = pastTheme
|
||||||
|
}
|
||||||
|
|
||||||
|
//Final catch for numbers
|
||||||
|
if(Number.isInteger(parseInt(state.nightMode)) == false){
|
||||||
|
state.nightMode = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTheme = Object.keys(themes)[state.nightMode]
|
||||||
|
|
||||||
|
//Toggle state and save to local storage
|
||||||
|
localStorage.setItem('nightMode', state.nightMode)
|
||||||
|
|
||||||
//Go through each color and set CSS variable
|
//Go through each color and set CSS variable
|
||||||
let root = document.documentElement
|
let root = document.documentElement
|
||||||
Object.keys(themeColors).forEach( attribute => {
|
Object.keys( themes[currentTheme] ).forEach( attribute => {
|
||||||
root.style.setProperty('--'+attribute, themeColors[attribute])
|
root.style.setProperty('--'+attribute, themes[currentTheme][attribute])
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
detectIsUserOnMobile(state){
|
detectIsUserOnMobile(state){
|
||||||
|
@ -139,8 +139,8 @@ app.use(function(req, res, next){
|
|||||||
|
|
||||||
// Test Area
|
// Test Area
|
||||||
// -> right here
|
// -> right here
|
||||||
let UserTest = require('@models/User')
|
// let UserTest = require('@models/User')
|
||||||
let NoteTest = require('@models/Note')
|
// let NoteTest = require('@models/Note')
|
||||||
// UserTest.keyPairTest()
|
// UserTest.keyPairTest()
|
||||||
// .then( ({testUserId, masterKey}) => NoteTest.test(testUserId, masterKey))
|
// .then( ({testUserId, masterKey}) => NoteTest.test(testUserId, masterKey))
|
||||||
// .then( message => { console.log(message) })
|
// .then( message => { console.log(message) })
|
||||||
|
@ -24,7 +24,7 @@ Note.test = (userId, masterKey) => {
|
|||||||
|
|
||||||
let testNoteId = 0
|
let testNoteId = 0
|
||||||
|
|
||||||
Note.create(userId, '','', masterKey)
|
Note.create(null, userId, '','', masterKey)
|
||||||
.then(newNoteId => {
|
.then(newNoteId => {
|
||||||
|
|
||||||
console.log('Test: Create Note - Pass')
|
console.log('Test: Create Note - Pass')
|
||||||
@ -164,7 +164,7 @@ Note.encryptEveryNote = (userId, masterKey) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Returns insertedId of new note
|
//Returns insertedId of new note
|
||||||
Note.create = (userId, noteTitle, noteText, masterKey) => {
|
Note.create = (io, userId, noteTitle = '', noteText = '', masterKey) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
if(userId == null || userId < 10){ reject('User Id required to create note') }
|
if(userId == null || userId < 10){ reject('User Id required to create note') }
|
||||||
@ -173,6 +173,9 @@ Note.create = (userId, noteTitle, noteText, masterKey) => {
|
|||||||
const salt = cs.createSmallSalt()
|
const salt = cs.createSmallSalt()
|
||||||
const snippetSalt = cs.createSmallSalt()
|
const snippetSalt = cs.createSmallSalt()
|
||||||
|
|
||||||
|
const snippetObj = JSON.stringify([noteTitle, noteText.substring(0, 500)])
|
||||||
|
const snippet = cs.encrypt(masterKey, snippetSalt, snippetObj)
|
||||||
|
|
||||||
const textObject = JSON.stringify([noteTitle, noteText])
|
const textObject = JSON.stringify([noteTitle, noteText])
|
||||||
const encryptedText = cs.encrypt(masterKey, salt, textObject)
|
const encryptedText = cs.encrypt(masterKey, salt, textObject)
|
||||||
|
|
||||||
@ -183,10 +186,15 @@ Note.create = (userId, noteTitle, noteText, masterKey) => {
|
|||||||
const rawTextId = rows[0].insertId
|
const rawTextId = rows[0].insertId
|
||||||
|
|
||||||
return db.promise()
|
return db.promise()
|
||||||
.query('INSERT INTO note (user_id, note_raw_text_id, created, quick_note, snippet_salt) VALUES (?,?,?,?,?)',
|
.query('INSERT INTO note (user_id, note_raw_text_id, created, quick_note, snippet, snippet_salt) VALUES (?,?,?,?,?,?)',
|
||||||
[userId, rawTextId, created, 0, snippetSalt])
|
[userId, rawTextId, created, 0, snippet, snippetSalt])
|
||||||
})
|
})
|
||||||
.then((rows, fields) => {
|
.then((rows, fields) => {
|
||||||
|
|
||||||
|
if(io){
|
||||||
|
io.to(userId).emit('new_note_created', rows[0].insertId)
|
||||||
|
}
|
||||||
|
|
||||||
// Indexing is done on save
|
// Indexing is done on save
|
||||||
resolve(rows[0].insertId) //Only return the new note ID when creating a new note
|
resolve(rows[0].insertId) //Only return the new note ID when creating a new note
|
||||||
})
|
})
|
||||||
|
@ -5,45 +5,76 @@ let Note = require('@models/Note')
|
|||||||
let QuickNote = module.exports = {}
|
let QuickNote = module.exports = {}
|
||||||
|
|
||||||
|
|
||||||
QuickNote.get = (userId) => {
|
QuickNote.get = (userId, masterKey) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
db.promise()
|
db.promise()
|
||||||
.query(`
|
.query(`
|
||||||
SELECT note.id, text FROM note
|
SELECT note.id FROM note WHERE quick_note = 1 AND user_id = ? LIMIT 1
|
||||||
JOIN note_raw_text ON (note_raw_text.id = note.note_raw_text_id)
|
|
||||||
WHERE quick_note = 1 AND user_id = ? LIMIT 1
|
|
||||||
`, [userId])
|
`, [userId])
|
||||||
.then((rows, fields) => {
|
.then((rows, fields) => {
|
||||||
|
|
||||||
//Quick Note is set, return note text
|
//Quick Note is set, return note text
|
||||||
if(rows[0].length == 1){
|
if(rows[0][0] != undefined){
|
||||||
resolve({
|
let noteId = rows[0][0].id
|
||||||
id: rows[0][0].id,
|
Note.get(userId, noteId, masterKey)
|
||||||
text: rows[0][0].text
|
.then( noteObject => {
|
||||||
|
return resolve(noteObject)
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
return resolve(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve({
|
|
||||||
id: null,
|
|
||||||
text: 'Enter something to create a quick note.'
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickNote.update = (userId, pushText) => {
|
QuickNote.newNote = (userId) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
db.promise().query('UPDATE note SET quick_note = 0 WHERE quick_note = 1 AND user_id = ?',[userId])
|
||||||
|
.then((rows, fields) => {
|
||||||
|
resolve(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
QuickNote.makeUrlLink = (inputText) => {
|
||||||
|
var replacedText, replacePattern1, replacePattern2, replacePattern3;
|
||||||
|
|
||||||
|
//URLs starting with http://, https://, or ftp://
|
||||||
|
replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
|
||||||
|
replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');
|
||||||
|
|
||||||
|
//URLs starting with "www." (without // before it, or it'd re-link the ones done above).
|
||||||
|
replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
|
||||||
|
replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');
|
||||||
|
|
||||||
|
//Change email addresses to mailto:: links.
|
||||||
|
replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
|
||||||
|
replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
|
||||||
|
|
||||||
|
return replacedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuickNote.update = (io, userId, pushText, masterKey) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
let finalId = null
|
||||||
|
let finalText = ''
|
||||||
|
|
||||||
//Process pushText, split at \n (new lines), put <p> tags around each new line
|
//Process pushText, split at \n (new lines), put <p> tags around each new line
|
||||||
let broken = '<blockquote>' +
|
let broken = '<p>' +
|
||||||
pushText.split(/\r?\n/).map( (line, index) => {
|
pushText.split(/\r?\n/).map( (line, index) => {
|
||||||
|
|
||||||
let clean = line
|
let clean = line
|
||||||
.replace(/&[#A-Za-z0-9]+;/g,'') //Rip out all HTML entities
|
.replace(/&[#A-Za-z0-9]+;/g,'') //Rip out all HTML entities
|
||||||
.replace(/<[^>]+>/g, '') //Rip out all HTML tags
|
.replace(/<[^>]+>/g, '') //Rip out all HTML tags
|
||||||
|
|
||||||
|
//Turn links into actual linx
|
||||||
|
clean = QuickNote.makeUrlLink(clean)
|
||||||
|
|
||||||
if(clean == ''){ clean = ' ' }
|
if(clean == ''){ clean = ' ' }
|
||||||
let newLine = ''
|
let newLine = ''
|
||||||
if(index > 0){ newLine = '<br>' }
|
if(index > 0){ newLine = '<br>' }
|
||||||
@ -51,51 +82,31 @@ QuickNote.update = (userId, pushText) => {
|
|||||||
//Return line wrapped in p tags
|
//Return line wrapped in p tags
|
||||||
return `${newLine}<span>${clean}</span>`
|
return `${newLine}<span>${clean}</span>`
|
||||||
|
|
||||||
}).join('') + '</blockquote>'
|
}).join('') + '</p><p><br></p>'
|
||||||
|
|
||||||
db.promise()
|
QuickNote.get(userId, masterKey)
|
||||||
.query(`
|
.then(noteObject => {
|
||||||
SELECT note.id, text, color, pinned, archived
|
|
||||||
FROM note
|
|
||||||
JOIN note_raw_text ON (note_raw_text.id = note.note_raw_text_id)
|
|
||||||
WHERE quick_note = 1 AND user_id = ? LIMIT 1
|
|
||||||
`, [userId])
|
|
||||||
.then((rows, fields) => {
|
|
||||||
|
|
||||||
//Quick Note is set, push it the front of existing note
|
if(noteObject == null){
|
||||||
if(rows[0].length == 1){
|
|
||||||
|
|
||||||
let d = rows[0][0] //Get row data
|
finalText += broken
|
||||||
|
|
||||||
//Push old text behind fresh new text
|
return Note.create(io, userId, 'Quick Note', finalText, masterKey)
|
||||||
let newText = broken +''+ d.text
|
.then(insertedId => {
|
||||||
|
finalId = insertedId
|
||||||
//Save that, then return the new text
|
return db.promise().query('UPDATE note SET quick_note = 1 WHERE id = ? AND user_id = ?',[insertedId, userId])
|
||||||
Note.update(null, userId, d.id, newText, '', d.color, d.pinned, d.archived)
|
|
||||||
.then( saveResults => {
|
|
||||||
resolve({
|
|
||||||
id:d.id,
|
|
||||||
text:newText
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//Create a new note with the quick text submitted.
|
finalText += (broken + noteObject.text)
|
||||||
Note.create(userId, broken, 1)
|
finalId = noteObject.id
|
||||||
.then( insertId => {
|
return Note.update(io, userId, noteObject.id, finalText, noteObject.title, noteObject.color, noteObject.pinned, noteObject.archived, null, masterKey)
|
||||||
resolve({
|
|
||||||
id:insertId,
|
|
||||||
text:broken
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.log)
|
.then( saveResults => {
|
||||||
|
return resolve(true)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
//Lookup quick note,
|
|
||||||
|
|
||||||
//Note.create(userId, 'Quick Note', 1)
|
|
||||||
|
|
||||||
}
|
}
|
@ -176,16 +176,24 @@ Tag.suggest = (userId, noteId, tagText) => {
|
|||||||
tagText += '%'
|
tagText += '%'
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
db.promise()
|
|
||||||
.query(`SELECT text FROM note_tag
|
let params = [userId, tagText]
|
||||||
|
let query = `SELECT tag.id, text FROM note_tag
|
||||||
JOIN tag ON note_tag.tag_id = tag.id
|
JOIN tag ON note_tag.tag_id = tag.id
|
||||||
WHERE note_tag.user_id = ?
|
WHERE note_tag.user_id = ?
|
||||||
AND tag.text LIKE ?
|
AND tag.text LIKE ?`
|
||||||
AND note_tag.tag_id NOT IN (
|
|
||||||
SELECT note_tag.tag_id FROM note_tag WHERE note_tag.note_id = ?
|
if(noteId && noteId > 0){
|
||||||
)
|
params.push(noteId)
|
||||||
GROUP BY text
|
query += `AND note_tag.tag_id NOT IN
|
||||||
LIMIT 6`, [userId, tagText, noteId])
|
(SELECT note_tag.tag_id FROM note_tag WHERE note_tag.note_id = ?)`
|
||||||
|
}
|
||||||
|
|
||||||
|
query += ` GROUP BY text, id LIMIT 6`
|
||||||
|
|
||||||
|
|
||||||
|
db.promise()
|
||||||
|
.query(query, params)
|
||||||
.then((rows, fields) => {
|
.then((rows, fields) => {
|
||||||
resolve(rows[0]) //Return new ID
|
resolve(rows[0]) //Return new ID
|
||||||
})
|
})
|
||||||
|
@ -34,7 +34,7 @@ router.post('/delete', function (req, res) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.post('/create', function (req, res) {
|
router.post('/create', function (req, res) {
|
||||||
Notes.create(userId, req.body.title, req.body.text, masterKey)
|
Notes.create(req.io, userId, req.body.title, req.body.text, masterKey)
|
||||||
.then( id => res.send({id}) )
|
.then( id => res.send({id}) )
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -2,12 +2,15 @@ var express = require('express')
|
|||||||
var router = express.Router()
|
var router = express.Router()
|
||||||
|
|
||||||
let QuickNote = require('@models/QuickNote');
|
let QuickNote = require('@models/QuickNote');
|
||||||
|
|
||||||
let userId = null
|
let userId = null
|
||||||
|
let masterKey = null
|
||||||
|
|
||||||
// middleware that is specific to this router
|
// middleware that is specific to this router
|
||||||
router.use(function setUserId (req, res, next) {
|
router.use(function setUserId (req, res, next) {
|
||||||
if(userId = req.headers.userId){
|
if(userId = req.headers.userId){
|
||||||
userId = req.headers.userId
|
userId = req.headers.userId
|
||||||
|
masterKey = req.headers.masterKey
|
||||||
}
|
}
|
||||||
|
|
||||||
next()
|
next()
|
||||||
@ -15,19 +18,19 @@ router.use(function setUserId (req, res, next) {
|
|||||||
|
|
||||||
//Get quick note text
|
//Get quick note text
|
||||||
router.post('/get', function (req, res) {
|
router.post('/get', function (req, res) {
|
||||||
QuickNote.get(userId)
|
QuickNote.get(userId, masterKey)
|
||||||
.then( data => res.send(data) )
|
.then( data => res.send(data) )
|
||||||
})
|
})
|
||||||
|
|
||||||
//Push text to quick note
|
//Push text to quick note
|
||||||
router.post('/update', function (req, res) {
|
router.post('/update', function (req, res) {
|
||||||
QuickNote.update(userId, req.body.pushText)
|
QuickNote.update(req.io, userId, req.body.pushText, masterKey)
|
||||||
.then( data => res.send(data) )
|
.then( data => res.send(data) )
|
||||||
})
|
})
|
||||||
|
|
||||||
//Change quick note to a new note
|
//Push text to quick note
|
||||||
router.post('/change', function (req, res) {
|
router.post('/new', function (req, res) {
|
||||||
QuickNote.change(userId, req.body.noteId)
|
QuickNote.newNote(userId)
|
||||||
.then( data => res.send(data) )
|
.then( data => res.send(data) )
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user