Compare commits

..

No commits in common. "b7d22cb7fc627433c31c31c6110bc73116a7130b" and "c972430ef437f11a12f70be8239831d42d9548fa" have entirely different histories.

25 changed files with 363 additions and 1805 deletions

View File

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9vBYgeFm2nDnj
HJ+Cq4H96adNLrynoFPs0lSxk3YMXG/mP2sXUpqT3P8S7E6QK55IyU0jtiOoYiV1
bjcTuDrQyZXrtt+Nz0A7vQxtRu8CatXSEG8Vc3y8QrcDT0HfTezHdNkuJXE8cnYv
XSgrZH+cHF996ytOA0lLJWBCHCJH5WIHj5Jziw5dHaLc4mjxSg51xjjqfzLFWQgZ
rOPF6lviAWBFux8RIXXg7nClNvEeyikdraZvVuWFgt89KhN/ePU1Xik/o6++evhT
HxBZqMQHnTp/4h5T25lPGcs0CPPX0afwNSUdPc8yspuSYNcLsWix3oROLMX6cHBa
CTBrtlLzAgMBAAECggEAIBhG7est0dQPfrmCygnVDWyO3mF/jCN0zuStavR0zZZ9
X0dvCBzzBPwnMb5Dc+PM/KcAo3/V/E/N4lVof690U4kmER94JXbfeLt79KhBGfmU
fdpF0C0e9oGaj7bCf9GgsgS0EDhJNV5vW4e4mc6AP5oVFSnIw4OOzGVgKQ61Rc/e
vaalAEz7xGbsYYh2Y43tFnNA6g/qOzs+H8e2Uv+G9mxx7EID1MG3txJJCBpeUeN5
JbHQe254IBy4Ko3+i5Tq3ziYL3WyyElCwK5PiRtAP7WNL5AqFT6Fn4L2fULwkTKL
sjPSgGxt7QHomeW+12n9bst1mOEmsz0hTGrAtIf1UQKBgQDu1u7BLdTt9H+zaOFl
XfhOR3GDZnrIs+F6VuEjdjwNEQLKvOYzGhbgDNRArSETK6f03Jvl7ZC9XYwNC836
J29fHsXVcsMJm8fq69PBSdmMXmOpRfjgALu6DYxK1vBqNQ2ToulCwiWoskKEuPUN
GwVCc/0HcvwZElWZ1UhsB5Xf9wKBgQDLXfMCtsVpfI15w8qEqRCdrCzprHSitcHJ
dCXO72+i9ygMuFtcxo7kgivT0oFUCYmt7Ex+krOlq/xbVLu4sJXWd1FDZ1IeTsIh
cuh4IhSOGJR70S4Q/DzbGUQ08Hu+4hrudaw1Y8Fod0wTERCyOIQiWBfKn3Tab3mk
X29RdGod5QKBgBig5UHaXgijm79+Yy+2vvIjf9sS6DpmAixBZTno6UxXorgRPpOq
bw1vhTueHrkBWXJwhUrycmh0iwqVWwoeoudmHvRhvybwf28EHnPiD6Lf4NsFsiI3
MSSAXSUigOwSyHGe7PrLVmLM7vsMr4hIbwRpPYBVJRXYxCb2zV8GcTgFAoGBALiV
gWhJNE1We6K1jy9xtF8oU2uU2BiHGGkdPuPgd1dXNca13lcK8c9+RwFv42q/bXOr
MpL/3IbW36qV8fzkalvK2LtxIBvaKGHrxgykAjwnGz520nUgPKww9rOGQwsydndR
3whmjrme7jGwH5NjsKrrgkyrBojs/V+wL32jSF3xAoGAPLmI5gamjEo9K25ojNxO
XjA0fIOxUz/rTPS/qYrxcluXibz8eGXDLq8/D3Q4uWDh18ZQYzWVGoN/x2Qv0srz
SHU4AyJo6+asZAe+viOhAtI81B7uM5V4oyEkPaEASPg6+do/to7SFmdcw/XM/p2v
KYVXalAeFhW0wJ4I4z6DkuU=
-----END PRIVATE KEY-----

View File

@ -1,26 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEWTCCAsGgAwIBAgIRAPWg+zwqGDC6qPGon1qGS0cwDQYJKoZIhvcNAQELBQAw
czEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSQwIgYDVQQLDBttYWJA
bWFydmluIChNYXggR2lhbGFuZWxsYSkxKzApBgNVBAMMIm1rY2VydCBtYWJAbWFy
dmluIChNYXggR2lhbGFuZWxsYSkwHhcNMjIwNjI2MTgxMDE5WhcNMjQwOTI2MTgx
MDE5WjBPMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUx
JDAiBgNVBAsMG21hYkBtYXJ2aW4gKE1heCBHaWFsYW5lbGxhKTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAL28FiB4WbacOeMcn4Krgf3pp00uvKegU+zS
VLGTdgxcb+Y/axdSmpPc/xLsTpArnkjJTSO2I6hiJXVuNxO4OtDJleu2343PQDu9
DG1G7wJq1dIQbxVzfLxCtwNPQd9N7Md02S4lcTxydi9dKCtkf5wcX33rK04DSUsl
YEIcIkflYgePknOLDl0dotziaPFKDnXGOOp/MsVZCBms48XqW+IBYEW7HxEhdeDu
cKU28R7KKR2tpm9W5YWC3z0qE3949TVeKT+jr756+FMfEFmoxAedOn/iHlPbmU8Z
yzQI89fRp/A1JR09zzKym5Jg1wuxaLHehE4sxfpwcFoJMGu2UvMCAwEAAaOBizCB
iDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHwYDVR0jBBgw
FoAUzspSlchxoKIVJLKOhPGrcTFjRyowQAYDVR0RBDkwN4IMbWFydmluLmxvY2Fs
gglsb2NhbGhvc3SHBMCoAaSHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZI
hvcNAQELBQADggGBAAaTOkCKiVwsapOAuiEt8kG7HS/r4HG+drLzhb2dUFYfqxpz
mfRlRfFA88JN8nyFtOPcpoeOEaTPMi0hxq0rOw9zHPga5kz6LRAUJeADPgA4pw2S
fYT1CEbPMknmHQyhVODKNZN05l3vWC2CL2SDs9lirGVrzmfg7kZ0im8hc81GQgo+
MsfnC3AT1r1rzMqGLWiBHM8BjeGGwgqjjFZmxoHuGw+0CuV2TZfkZlNoJRtlRtyV
xlkUuRkVDYbLmHLMz7n9+ItOy8epKLToFpIXyhGR+ehAzYyyJeh2SCaboJ71lU+h
+90GQPl20ajWzLtwTsZHEAehHu4l/JLWleNaQh3nVdllHyzvU3IR/C7hhVv6im+q
/KiwDR3W8LqIOGJsemca5iu73EXd1d5UU49alIPm1Ko+Z22X/WMPj74+9CNW65DV
7ebM17NNQgr4tEJdXF3IYwaZ0Epv1/Y7v6bAXT8V2mdjtXfRBwu3HyySl22a9Y4R
h7svqj31cb0ubXEfrA==
-----END CERTIFICATE-----

View File

@ -290,7 +290,7 @@ i.green.icon.icon.icon.icon {
border: none; border: none;
/*height: calc(100% - 69px);*/ /*height: calc(100% - 69px);*/
min-height: 300px; min-height: 500px;
background-color: var(--small_element_bg_color); background-color: var(--small_element_bg_color);
/*margin-bottom: 15px;*/ /*margin-bottom: 15px;*/
@ -309,9 +309,6 @@ i.green.icon.icon.icon.icon {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
max-width: 1100px; max-width: 1100px;
box-shadow: 0 8px 24px rgba(0,0,0,0.1);
} }
.squire-box::selection, .squire-box::selection,
.squire-box::-moz-selection { .squire-box::-moz-selection {
@ -375,37 +372,8 @@ i.green.icon.icon.icon.icon {
.squire-box ol, .squire-box ol,
.note-card-text ul, .note-card-text ul,
.squire-box ul { .squire-box ul {
margin: 3px 0; margin: 8px 0 0 0;
display: block;
} }
/* Add border 1 indent level */
.note-card-text > ol > ol,
.squire-box > ol > ol,
.note-card-text > ul > ul,
.squire-box > ul > ul
{
border-left: 1px solid var(--border_color);
}
.note-card-text ol > ol,
.squire-box ol > ol,
.note-card-text ul > ul,
.squire-box ul > ul {
list-style-type: upper-alpha;
}
ol {
counter-reset: item;
}
ol li {
display: block;
}
ol li:before {
content: counters(item, ".") ".";
counter-increment: item;
padding-right: 10px;
}
.note-card-text ul > li, .note-card-text ul > li,
.squire-box ul > li { .squire-box ul > li {
position: relative; position: relative;
@ -532,6 +500,10 @@ padding-right: 10px;
/* adjust checkboxes for mobile. Make them a little bigger, easier to click */ /* adjust checkboxes for mobile. Make them a little bigger, easier to click */
@media only screen and (max-width: 740px) { @media only screen and (max-width: 740px) {
.squire-box {
min-height: calc(100vh - 122px);
}
.ui.button.shrinking { .ui.button.shrinking {
font-size: 0.85714286rem; font-size: 0.85714286rem;
margin: 0 3px; margin: 0 3px;
@ -958,14 +930,4 @@ padding-right: 10px;
left: 100%; left: 100%;
opacity: 0; opacity: 0;
} }
} }
.shade {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0,0,0,0.7);
z-index: 1000;
}

View File

@ -19,7 +19,7 @@
padding: 1em 5px; padding: 1em 5px;
cursor: pointer; cursor: pointer;
} }
.popup-row > p { .popup-row > span {
/*width: calc(100% - 50px);*/ /*width: calc(100% - 50px);*/
display: inline-block; display: inline-block;
text-align: left; text-align: left;
@ -85,18 +85,6 @@
animation: progressBar 3s linear; animation: progressBar 3s linear;
animation-fill-mode: both; animation-fill-mode: both;
} }
.time-display {
display: inline-block;
width: calc(100% - 25px);
/*text-align: right;*/
color: white;
font-size: 0.7em;
margin: 0 0 0 25px;
}
.text-display {
display: inline-block;
width: 100%;
}
@keyframes progressBar { @keyframes progressBar {
0% { width: 0; } 0% { width: 0; }
@ -113,11 +101,7 @@
<div class="meter"> <div class="meter">
<span><span class="progress"></span></span> <span><span class="progress"></span></span>
</div> </div>
<p class="text-display"> <span><i class="small info circle icon"></i>{{ item }}</span>
<i class="small info circle icon"></i>
{{ item.text }}
<span class="time-display">{{ item.time }}</span>
</p>
</div> </div>
</div> </div>
</template> </template>
@ -135,8 +119,8 @@
} }
}, },
beforeMount(){ beforeMount(){
this.$bus.$on('notification', notificationText => { this.$bus.$on('notification', info => {
this.displayNotification(notificationText) this.displayNotification(info)
}) })
}, },
mounted(){ mounted(){
@ -147,17 +131,8 @@
}, },
methods: { methods: {
displayNotification(notificationText){ displayNotification(newNotification){
this.notifications.push(newNotification)
const date = new Date()
const time = date.toLocaleTimeString()
const notification = {
text: notificationText,
time: time
}
this.notifications.unshift(notification)
clearTimeout(this.totalTimeout) clearTimeout(this.totalTimeout)
this.totalTimeout = setTimeout(() => { this.totalTimeout = setTimeout(() => {
this.dismiss() this.dismiss()

View File

@ -4,7 +4,6 @@
width: 180px; width: 180px;
display: block; display: block;
float: left; float: left;
overflow: hidden;
} }
.global-menu { .global-menu {
width: 180px; width: 180px;
@ -107,7 +106,6 @@
text-align: center; text-align: center;
color: #8c80ae; color: #8c80ae;
cursor: pointer; cursor: pointer;
background-color: var(--menu-background);
} }
.mobile-button { .mobile-button {

View File

@ -1,134 +1,133 @@
<template> <template>
<!-- change class to .master-note-edit to have it popup on the screen. <!-- change class to .master-note-edit to have it popup on the screen.
@keyup.esc="closeButtonAction()" --> @keyup.esc="closeButtonAction()" -->
<div class="master-note-edit"> <div
id="InputNotes"
class="master-note-edit"
>
<!-- Edit Menus --> <!-- Giant Edit Note Menu -->
<div class="edit-menu" :class="{ 'slide-out-top':(sizeDown == true) }">
<div class="menu-top-half" :class="{ 'hide-text':(openNotes > 1) }"> <!-- edit spacer is disabled, it is helpful if menu gets bigger. It adds a left margin, starting the icons at the edge of the note -->
<div class="edit-spacer"></div>
<div class="menu-top-half">
<div class="edit-button" v-on:click="colorpicker = true" data-tooltip="Text Color" data-position="bottom center">
<i class="font icon"></i>
<div class="font-color-bar" :style="{'background':lastUsedColor}"></div>
</div>
<div class="edit-button" v-on:click="toggleBold()" :data-tooltip="`Bold\n(CTRL + b)`" data-position="bottom center" :class="{'edit-active':activeBold}">
<i class="bold icon"></i>
</div>
<div class="edit-button" v-on:click="toggleItalic()" :data-tooltip="`Italic\n(CRTL + i)`" data-position="bottom center" :class="{'edit-active':activeItalics}">
<i class="italic icon"></i>
</div>
<div class="edit-button" v-on:click="toggleUnderline()" :data-tooltip="`Underline\n(CRTL + u)`" data-position="bottom center" :class="{'edit-active':activeUnderline}">
<i class="underline icon"></i>
</div>
<div class="edit-button" v-on:click="modifyCode('1.4em')" data-tooltip="Quote" data-position="bottom center" :class="{'edit-active':activeCode}">
<i class="quote right icon"></i>
</div>
<div class="edit-button" v-on:click="modifyFont('0.9em')" data-tooltip="Sub Title" data-position="bottom center" :class="{'edit-active':activeSubTitle}">
<i class="small text height icon"></i>
</div>
<div class="edit-button" v-on:click="modifyFont('1.4em')" data-tooltip="Title" data-position="bottom center" :class="{'edit-active':activeTitle}">
<i class="text height icon"></i>
</div>
<div class="edit-button" v-on:click="removeFormatting()" data-tooltip="Remove Formatting" data-position="bottom center">
<i class="remove format icon"></i>
</div>
<div class="edit-divide"></div>
<div class="edit-button" v-on:click="editor.increaseQuoteLevel()" :data-tooltip="`Indent\n(TAB)`" data-position="bottom center">
<i class="indent icon"></i>
</div>
<div class="edit-button" v-on:click="editor.decreaseQuoteLevel()" :data-tooltip="`Un-Indent\n(SHIFT + TAB)`" data-position="bottom center">
<i class="outdent icon"></i>
</div>
<div class="edit-button" v-on:click="colorpicker = true" data-tooltip="Text Color" data-position="bottom center">
<i class="font icon"></i>
<div class="font-color-bar" :style="{'background':lastUsedColor}"></div>
<span>Color</span>
</div> </div>
<div class="edit-button" v-on:click="toggleBold()" :data-tooltip="`Bold\n(CTRL + b)`" data-position="bottom center" :class="{'edit-active':activeBold}"> <div class="menu-bottom-half">
<i class="bold icon"></i>
<span>Bold</span>
</div>
<div class="edit-button" v-on:click="toggleItalic()" :data-tooltip="`Italic\n(CRTL + i)`" data-position="bottom center" :class="{'edit-active':activeItalics}"> <!--
<i class="italic icon"></i> <div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/table`)" data-tooltip="Insert Table" data-position="bottom center">
<span>Italic</span> <i class="border all icon"></i>
</div> </div> -->
<div class="edit-button" v-on:click="toggleUnderline()" :data-tooltip="`Underline\n(CRTL + u)`" data-position="bottom center" :class="{'edit-active':activeUnderline}"> <div class="edit-divide"></div>
<i class="underline icon"></i>
<span>Underline</span>
</div>
<div class="edit-button" v-on:click="modifyCode('1.4em')" data-tooltip="Quote" data-position="bottom center" :class="{'edit-active':activeCode}"> <div class="edit-button" v-on:click="toggleList('ul')" :data-tooltip="`Task List\n(CTRL + SHIFT + 8)`" data-position="bottom center" :class="{'edit-active':activeToDo}">
<i class="quote right icon"></i> <i class="tasks icon"></i>
<span>Quote</span> </div>
</div> <div class="edit-button" v-on:click="toggleList('ol')" :data-tooltip="`Ordered List\n(CTRL + SHIFT + 9)`" data-position="bottom center" :class="{'edit-active':activeList}">
<i class="list ol icon"></i>
</div>
<div class="edit-button" v-on:click="modifyFont('0.9em')" data-tooltip="Sub Title" data-position="bottom center" :class="{'edit-active':activeSubTitle}"> <div class="edit-divide"></div>
<i class="small text height icon"></i>
<span>Small Text</span> <div class="edit-button" v-on:click="insertDivide()" data-tooltip="Insert Divide" data-position="bottom center">
</div> <i class="grip lines icon"></i>
</div>
<div class="edit-button" v-on:click="modifyFont('1.4em')" data-tooltip="Title" data-position="bottom center" :class="{'edit-active':activeTitle}">
<i class="text height icon"></i>
<span>Title</span>
</div>
<div class="edit-button" v-on:click="removeFormatting()" data-tooltip="Remove Formatting" data-position="bottom center"> <div class="edit-divide"></div>
<i class="remove format icon"></i>
</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" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
<i class="paint brush icon"></i>
</div> -->
<!-- <div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)" data-tooltip="Tags" data-position="bottom center">
<i class="tags icon"></i>
</div> -->
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/images`)" data-tooltip="Images" data-position="bottom center">
<i class="image icon"></i>
</div>
<div class="edit-button" v-on:click="indentText" :data-tooltip="`Indent\n(TAB)`" data-position="bottom center"> <file-upload-button
<i class="indent icon"></i> data-tooltip="Upload File" data-position="bottom center"
<span>Indent</span> class="edit-button"
</div> :noteId="noteid" />
<div class="edit-button" v-on:click="outdentText" :data-tooltip="`Un-Indent\n(SHIFT + TAB)`" data-position="bottom center">
<i class="outdent icon"></i>
</div>
<div class="edit-divide"></div>
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/options`)" data-tooltip="More Options" data-position="bottom center">
&nbsp;&nbsp;
<i class="ellipsis horizontal icon"></i>
&nbsp;&nbsp;
</div>
<div class="edit-divide"></div>
<div class="edit-button" v-on:click="undoCustom()" :data-tooltip="`Undo\n(CTRL + z)`" data-position="bottom center">
<i class="reply icon"></i>
</div>
<div class="edit-button done-button" v-on:click="closeButtonAction()" :data-tooltip="`Close\n(ESC)`" data-position="bottom center">
<!-- <i class="green close icon"></i> -->
<span class="ui green text">Done</span>
</div>
</div>
</div> </div>
<div class="menu-bottom-half" :class="{ 'hide-text':(openNotes > 1) }"> <!-- invisible menu item, creates BG for bottom menu -->
<div class="bottom-edit-menu"></div>
<!--
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/table`)" data-tooltip="Insert Table" data-position="bottom center">
<i class="border all icon"></i>
</div> -->
<div class="edit-button" v-on:click="toggleList('ul')" :data-tooltip="`Task List\n(CTRL + SHIFT + 8)`" data-position="top center" :class="{'edit-active':activeToDo}">
<i class="tasks icon"></i>
<span>To-Do</span>
</div>
<div class="edit-button" v-on:click="toggleList('ol')" :data-tooltip="`Ordered List\n(CTRL + SHIFT + 9)`" data-position="top center" :class="{'edit-active':activeList}">
<i class="list ol icon"></i>
<span>List</span>
</div>
<div class="edit-divide"></div>
<div class="edit-button" v-on:click="insertDivide()" data-tooltip="Insert Divide" data-position="top center">
<i class="grip lines icon"></i>
<span>Divide</span>
</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="top center" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
<i class="paint brush icon"></i>
</div> -->
<!-- <div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)" data-tooltip="Tags" data-position="top center">
<i class="tags icon"></i>
</div> -->
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/images`)" data-tooltip="Images" data-position="top center">
<i class="image icon"></i>
<span>Images</span>
</div>
<file-upload-button
data-tooltip="Upload File" data-position="top center"
class="edit-button"
:noteId="noteid" />
<div class="edit-divide"></div>
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/options`)" data-tooltip="More Options" data-position="top center">
&nbsp;&nbsp;
<i class="ellipsis horizontal icon"></i>
&nbsp;&nbsp;
</div>
<div class="edit-divide"></div>
<div class="edit-button" v-on:click="undoCustom()" :data-tooltip="`Undo\n(CTRL + z)`" data-position="top center">
<i class="reply icon"></i>
</div>
<div class="edit-button done-button" v-on:click="closeButtonAction()" :data-tooltip="`Close\n(ESC)`" data-position="top center">
<!-- <i class="green close icon"></i> -->
<span class="ui green text">Done</span>
</div>
</div>
<div class="input-container-wrapper" <div class="input-container-wrapper"
:class="{ 'side-menu-open':sideMenuOpen }"> :class="{ 'side-menu-open':sideMenuOpen, 'size-down':(sizeDown == true),}">
<!-- Squire box grows --> <!-- Squire box grows -->
<div class="note-wrapper"> <div id="text-box-container" class="note-wrapper" :style="{ 'background-color':styleObject['noteBackground']}">
<!-- Loading indicator --> <!-- Loading indicator -->
<transition name="fade"> <transition name="fade">
@ -156,9 +155,14 @@
</div> </div>
<!-- tags on the side, only show on desktop --> <!-- tags on the side, only show on desktop -->
<div class="note-mini-tag-area" <div class="note-mini-tag-area" :class="{ 'size-down':sizeDown }"
v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)" v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)"
:style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText'] }"> :style="{ 'background-color':styleObject['noteBackground'] }">
<span>
{{ lastVisibilityState }}
</span>
<span class="add-mini-tag" v-if="allTags.length == 0"> <span class="add-mini-tag" v-if="allTags.length == 0">
<i class="tags icon"></i>Add Tags <i class="tags icon"></i>Add Tags
@ -342,9 +346,9 @@
</side-slide-menu> </side-slide-menu>
<!-- Show side shades if user is on desktop only --> <!-- Show side shades if user is on desktop only -->
<!-- <div class="full-focus-shade shade1" <div class="full-focus-shade shade1"
:class="{ 'fade-me-out':sizeDown }" :class="{ 'fade-me-out':sizeDown }"
v-on:click="closeButtonAction()"></div> --> v-on:click="closeButtonAction()"></div>
</div> </div>
</template> </template>
@ -361,8 +365,8 @@
import SquireButtonFunctions from '@/mixins/SquireButtonFunctions.js' import SquireButtonFunctions from '@/mixins/SquireButtonFunctions.js'
export default { export default {
name: 'NoteInputPanel', name: 'InputNotes',
props: [ 'noteid', 'position', 'openMenu', 'urlData', 'openNotes'], props: [ 'noteid', 'position', 'openMenu', 'urlData' ],
components:{ components:{
'note-tag-edit': () => import('@/components/NoteTagEdit.vue'), 'note-tag-edit': () => import('@/components/NoteTagEdit.vue'),
'color-picker': () => import('@/components/ColorPicker.vue'), 'color-picker': () => import('@/components/ColorPicker.vue'),
@ -452,7 +456,7 @@
this.table = false this.table = false
//If a menu value is set, open it //If a menu value is set, open it
if(newVal.openMenu && newVal.id == this.noteid){ if(newVal.openMenu){
//Only modify menu boolean if its defined //Only modify menu boolean if its defined
if(typeof this[newVal.openMenu] == 'boolean'){ if(typeof this[newVal.openMenu] == 'boolean'){
this.sideMenuOpen = true this.sideMenuOpen = true
@ -470,12 +474,6 @@
this.save() this.save()
} }
}) })
this.$bus.$on('close_note_by_id', (noteId) => {
if(noteId == this.noteid){
this.closeButtonAction()
}
})
}, },
beforeDestroy(){ beforeDestroy(){
@ -490,7 +488,6 @@
//Obliterate squire instance //Obliterate squire instance
this.editor.destroy() this.editor.destroy()
// trigger save actions and reindex
this.close() this.close()
}, },
@ -649,9 +646,9 @@
if(keyCode == 'Tab'){ if(keyCode == 'Tab'){
if(event.shiftKey){ if(event.shiftKey){
this.outdentText() this.editor.decreaseQuoteLevel()
} else { } else {
this.indentText() this.editor.increaseQuoteLevel()
} }
event.preventDefault() event.preventDefault()
@ -687,12 +684,6 @@
this.onKeyup(event) this.onKeyup(event)
}) })
// this.editor.addEventListener("dragstart", e => {
// console.log('Dragging')
// console.log(e)
// if(){}
// });
//Show and hide additional toolbars //Show and hide additional toolbars
// this.editor.addEventListener('focus', e => { // this.editor.addEventListener('focus', e => {
// }) // })
@ -995,14 +986,12 @@
return hash; return hash;
}, },
closeButtonAction(playAnimation = false){ closeButtonAction(){
this.sizeDown = playAnimation this.sizeDown = true
const animationTimeout = (playAnimation ? 300 : 0)
//This timeout allows animation to play before closing //This timeout allows animation to play before closing
setTimeout(() => { setTimeout(() => {
// this.$router.push('/notes') this.$router.push('/notes')
this.close() }, 300)
}, animationTimeout)
}, },
close(){ close(){
@ -1030,9 +1019,9 @@
}) })
}, },
destroyWebSockets(){ destroyWebSockets(){
// this.$io.removeListener('past_diffs') this.$io.removeListener('past_diffs')
// this.$io.removeListener('update_user_count') this.$io.removeListener('update_user_count')
// this.$io.removeListener('incoming_diff') this.$io.removeListener('incoming_diff')
}, },
setupWebSockets(){ setupWebSockets(){
@ -1142,41 +1131,42 @@
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: var(--small_element_bg_color); background-color: var(--menu-accent);
z-index: 999; z-index: 999;
cursor: pointer; cursor: pointer;
opacity: 0.6; opacity: 0.9;
} }
/* squire styles */ /* squire styles */
.input-container-wrapper { .input-container-wrapper {
position: absolute; position: fixed;
top: 0; top: 0;
bottom: 0; bottom: 0;
left: 0; left: 15%;
right: 0; right: 15%;
z-index: 1005;
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;
scrollbar-width: none; scrollbar-width: none;
scrollbar-color: transparent transparent; scrollbar-color: transparent transparent;
overscroll-behavior: contain; overscroll-behavior: contain;
background-color: var(--border_color);
} }
.note-wrapper { .note-wrapper {
background-color: var(--border_color); background-color: var(--small_element_bg_color);
border: 1px solid var(--menu-accent);
margin: 45px 0 45px 0;
position: relative; position: relative;
margin: 50px auto;
max-width: 1100px;
} }
.note-mini-tag-area { .note-mini-tag-area {
width: 100%; width: 100%;
padding: 5px 15px 0 15px; padding: 5px 15px 0 15px;
cursor: pointer; cursor: pointer;
margin-left: auto;
margin-right: auto;
max-width: 1100px;
position: relative; position: relative;
background: var(--small_element_bg_color);
} }
.add-mini-tag { .add-mini-tag {
color: var(--border_color); color: var(--border_color);
@ -1202,29 +1192,22 @@
Edit Menu Styles START Edit Menu Styles START
*/ */
.menu-top-half, .menu-bottom-half { .edit-menu {
display: flex; position: fixed;
justify-content: center; top: 0;
position: absolute;
z-index: 1001;
background-color: green;
border-radius: 3px;
padding: 5px 5px;
background-color: var(--menu-background);
left: 0; left: 0;
right: 0; right: 0;
width: 100%;
display: block;
background-color: var(--small_element_bg_color);
z-index: 1019;
padding: 5px 0;
border: none;
border-bottom: 1px solid var(--menu-accent);
text-align: center;
} }
.menu-top-half{ .menu-top-half, .menu-bottom-half {
top: 0; display: inline-block;
}
.menu-bottom-half {
bottom: 0;
}
.menu-top-half.hide-text .edit-button > span:not(.ui),
.menu-bottom-half.hide-text .edit-button > span:not(.ui)
{
display: none;
} }
.edit-button { .edit-button {
background-color: var(--small_element_bg_color); background-color: var(--small_element_bg_color);
@ -1232,15 +1215,14 @@
display: inline-block; display: inline-block;
border-radius: 3px; border-radius: 3px;
cursor: pointer; cursor: pointer;
font-size: 1em; font-size: 1.4em;
box-shadow: 0 0 1px 0 #c4c4c4; box-shadow: 0 0 1px 0 #c4c4c4;
margin: 0 3px 0; margin: 0 3px 0;
padding: 6px 12px 0; padding: 6px 0 0 0;
text-align: center; text-align: center;
min-width: 25px; min-width: 32px;
min-height: 30px; min-height: 32px;
/*flex-basis: 100%;*/
white-space: nowrap;
} }
.edit-button > i { .edit-button > i {
font-size: 1em; font-size: 1em;
@ -1259,29 +1241,19 @@
} }
.edit-divide { .edit-divide {
display: inline-block; display: inline-block;
background-color: var(--menu-accent);
height: 15px; height: 15px;
width: 7px; width: 1px;
margin: 0 8px;
padding: 0; padding: 0;
} }
@media only screen and (max-width: 740px) { @media only screen and (max-width: 740px) {
.edit-spacer {
display: none;
}
.edit-button { .edit-button {
font-size: 1.2em; font-size: 1.2em;
} }
.menu-top-half, .menu-bottom-half {
padding: 3px 2px;
left: 0;
right: 0;
transform: none;
border-radius: 0;
}
.menu-bottom-half {
position: fixed;
z-index: 100000;
}
.note-wrapper {
margin-bottom: 100px;
margin-top: 38px;
}
} }
/* /*
@ -1356,22 +1328,68 @@
left: calc(50% + 10px) !important; left: calc(50% + 10px) !important;
right: calc(0% + 10px) !important; right: calc(0% + 10px) !important;
} }
/*weird inbetween size for tables*/ @media only screen and (max-width: 740px) {
@media only screen and (max-width: 875px) {
} .master-note-edit {
@media only screen and (max-width: 830px) { left: 0;
right: 0;
}
.input-container-wrapper {
left: 0;
right: 0;
top: 35px;
bottom: 37px;
background-color: var(--small_element_bg_color);
}
.note-wrapper {
margin: 0;
border: none;
}
.shade1, .shade2 { .shade1, .shade2 {
right: 150%; right: 150%;
} }
.edit-menu {
background-color: var(--dark_border_color);
}
/*menu overwrites */
.bottom-edit-menu {
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
display: block;
/*background-color: var(--small_element_bg_color);*/
background-color: var(--dark_border_color);
z-index: 1012;
border: none;
border-top: 1px solid var(--menu-accent);
min-height: 37px;
}
.menu-top-half, .menu-bottom-half {
display: flex;
justify-content: space-around;
}
.edit-divide { .edit-divide {
display: none; display: none;
} }
.edit-button { .menu-bottom-half {
padding: 6px 0px 0; z-index: 1005;
position: fixed;
bottom: 4px;
left: 0;
right: 0;
text-align: center;
} }
.edit-button > span:not(.ui) { .edit-button {
display: none; flex-basis: 100%;
margin: 0 2px;
}
.done-button {
flex-basis: 150%;
font-size: 13px;
} }
} }

View File

@ -9,7 +9,7 @@
<!-- Show title and snippet below it --> <!-- Show title and snippet below it -->
<div class="overflow-hidden note-card-text" @click.stop="cardClicked" v-if="!titleView"> <div class="overflow-hidden note-card-text" @click="cardClicked" v-if="!titleView">
<span v-if="note.title == '' && note.subtext == ''"> <span v-if="note.title == '' && note.subtext == ''">
Empty Note Empty Note
@ -24,7 +24,7 @@
class="big-text"><p>{{ note.title }}</p></span> class="big-text"><p>{{ note.title }}</p></span>
<span class="tags" v-if="note.tags"> <span class="tags" v-if="note.tags">
<span v-for="tag in (note.tags.split(','))" class="little-tag" v-on:click.stop="$emit('tagClick', tag.split(':')[1] )">#{{ tag.split(':')[0] }}</span> <span v-for="tag in (note.tags.split(','))" class="little-tag" v-on:click="$emit('tagClick', tag.split(':')[1] )">#{{ tag.split(':')[0] }}</span>
<br> <br>
</span> </span>
@ -444,10 +444,10 @@
.note-title-display-card { .note-title-display-card {
position: relative; position: relative;
background-color: var(--small_element_bg_color); background-color: var(--small_element_bg_color);
/*The subtle shadow*/ /*The subtle shadow*/
/*box-shadow: 0px 1px 2px 1px rgba(210, 211, 211, 0.46);*/
box-shadow: 2px 2px 6px 0 rgba(0,0,0,.15); box-shadow: 2px 2px 6px 0 rgba(0,0,0,.15);
transition: box-shadow, border-color ease 0.5s, transform linear 0.5s; transition: box-shadow ease 0.5s, transform linear 0.1s;
margin: 5px; margin: 5px;
/*padding: 0.7em 1em;*/ /*padding: 0.7em 1em;*/
border-radius: .28571429rem; border-radius: .28571429rem;
@ -472,8 +472,9 @@
max-height: 450px; max-height: 450px;
} }
.note-title-display-card:hover { .note-title-display-card:hover {
box-shadow: 0 8px 15px rgba(0,0,0,0.3); /*box-shadow: 0px 2px 2px 1px rgba(210, 211, 211, 0.8);*/
border-color: var(--main-accent); /*transform: translateY(-2px);*/
box-shadow: 0 8px 24px rgba(0,0,0,0.1);
} }
.note-title-display-card.title-view { .note-title-display-card.title-view {
width: 100%; width: 100%;

View File

@ -1,116 +0,0 @@
<template>
<div>
<div class="ui right floated basic shrinking icon button" v-on:click="showPasteInputArea">
<i class="paste icon"></i>
Paste
</div>
<div class="shade" v-if="showPasteArea" @click.prevent="close">
<div class="ui stackable grid full-height" @click.prevent="close">
<div class="four wide column"></div>
<div class="eight wide middle aligned center aligned column">
<div class="ui raised segment">
<div class="ui dividing header">
<i class="green paste icon"></i>
Paste & automatically Save
</div>
<div class="ui fluid action input">
<input
id="pastetextarea"
type="text"
ref="pastearea"
@paste.prevent="onPaste"
@keyup.enter.prevent="onEnter"
placeholder="Paste Here">
<button class="ui green labeled icon button" @click.prevent="onEnter">
<i class="save icon"></i>
Save
</button>
</div>
</div>
</div>
<div class="four wide column"></div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'PasteButton',
props: {},
data () {
return {
showPasteArea: false,
}
},
methods: {
close(){
this.showPasteArea = false
},
onEnter(e){
const text = this.$refs.pastearea.value
this.saveText(text)
},
onPaste(e){
// Get pasted data via clipboard API
const clipboardData = e.clipboardData || window.clipboardData
const pastedData = String(clipboardData.getData('Text')).trim()
this.saveText(pastedData)
},
saveText(text){
this.showPasteArea = false
if(!text){
this.$bus.$emit('notification', 'Nothing to save.')
return;
}
axios.post('/api/quick-note/update', { 'pushText':text } )
.then( response => {
this.$bus.$emit('notification', 'Saved To Scratch Pad')
})
.catch(error => {
this.$bus.$emit('notification', 'Failed to Save')
})
},
showPasteInputArea(){
// Show text area and focus its contents
this.showPasteArea = true
this.$nextTick(() => {
const aux = document.getElementById('pastetextarea')
aux.focus();
})
// auto hide after 1 Minute
setTimeout(() => {
this.showPasteArea = false
}, 60*1000)
},
}
}
</script>
<style scoped lang="css">
.paste-text-container {
background-color: green;
position: absolute;
width: 50vw;
height: 80vh;
display: inline-block;
}
.full-height {
height: 100vh;
}
</style>

View File

@ -1,9 +1,9 @@
<style type="text/css" scoped> <style type="text/css" scoped>
.slide-container { .slide-container {
position: absolute; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 50%;
bottom: 0; bottom: 0;
z-index: 1020; z-index: 1020;
overflow: hidden; overflow: hidden;
@ -98,9 +98,11 @@
<slot></slot> <slot></slot>
</div> </div>
</div> </div>
<!-- <div class="slide-shadow" :class="{'full-shadow':fullShadow}" v-on:click="close"></div> --> <div class="slide-shadow" :class="{'full-shadow':fullShadow}" v-on:click="close"></div>
</div> </div>
<!-- </transition> --> <!-- </transition> -->

File diff suppressed because one or more lines are too long

View File

@ -113,7 +113,6 @@
<style type="text/css"> <style type="text/css">
.button-fix { .button-fix {
display: inline-block; display: inline-block;
float: left;
} }
.hover-row:hover { .hover-row:hover {
cursor: pointer; cursor: pointer;

View File

@ -357,21 +357,9 @@ const SquireButtonFunctions = {
}, },
setText(inText){ setText(inText){
this.editor.setHTML(inText) this.editor.setHTML(inText)
// this.noteText = this.editor._getHTML() // this.noteText = this.editor._getHTML()
// this.diffNoteText = this.editor._getHTML() // this.diffNoteText = this.editor._getHTML()
//Make sure all list items have draggable property
let container = document.getElementById('squire-id')
let listItems = container.getElementsByTagName('li')
for(let itemIndex in listItems){
// console.log(listItems[itemIndex])
// listItems[itemIndex].setAttribute('draggable','true')
}
// console.log(listItems)
}, },
getText(){ getText(){
@ -404,26 +392,6 @@ const SquireButtonFunctions = {
this.$router.go(-1) this.$router.go(-1)
}, },
indentText(){
// Lists use increase list level, increase quote breaks numbering
if(this.activeList || this.activeToDo){
this.editor.increaseListLevel()
return
}
this.editor.increaseQuoteLevel()
},
outdentText(){
// Lists use increase list level, increase quote breaks numbering
if(this.activeList || this.activeToDo){
this.editor.decreaseListLevel()
return
}
this.editor.decreaseQuoteLevel()
},
}, },
} }

View File

@ -35,15 +35,6 @@
<i class="copy icon"></i> <i class="copy icon"></i>
Other Files Other Files
</router-link> </router-link>
<router-link
v-if="$store.getters.totals && $store.getters.totals['sharedToNotes']"
exact-active-class="green"
class="ui basic button shrinking"
to="/attachments/type/shared">
<i class="send icon"></i>
Show Shared
</router-link>
</div> </div>
@ -174,12 +165,6 @@
this.searchParams.attachmentType = this.$route.params.type this.searchParams.attachmentType = this.$route.params.type
} }
// include files from shared notes or selected notes
this.searchParams.includeShared = false
if(this.$route.params.type == 'shared'){
this.searchParams.includeShared = true
}
//Set noteId in if in URL //Set noteId in if in URL
if(this.$route.params.id){ if(this.$route.params.id){
this.searchParams.noteId = this.$route.params.id this.searchParams.noteId = this.$route.params.id

View File

@ -149,23 +149,23 @@
<!-- All marketing images if you need to review --> <!-- All marketing images if you need to review -->
<div v-if="false" class="sixteen wide column"> <div v-if="false" class="sixteen wide column">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/add.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/add.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/gardening.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/gardening.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/growth.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/growth.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/icecream.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/icecream.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/investing.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/investing.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/onboarding.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/onboarding.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/robot.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/robot.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/solution.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/solution.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/watching.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/watching.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/cloud.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/cloud.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/grandma.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/grandma.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/hamburger.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/hamburger.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/idea.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/idea.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/notebook.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/notebook.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/plan.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/plan.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/secure.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/secure.svg" alt="">
<img loading="lazy" width="10%" src="/api/static/assets/marketing/void.svg"> <img loading="lazy" width="10%" src="/api/static/assets/marketing/void.svg" alt="">
</div> </div>
<!-- Go to notes button --> <!-- Go to notes button -->
@ -200,7 +200,7 @@
<!-- <h3>Tools to organize and collaborate on thousands of notes while maintaining security and respecting your privacy.</h3> --> <!-- <h3>Tools to organize and collaborate on thousands of notes while maintaining security and respecting your privacy.</h3> -->
</div> </div>
<div class="four wide column"> <div class="four wide column">
<svg-displayer file="idea" alt="Explosion of New Ideas" /> <img loading="lazy" width="100%" src="/api/static/assets/marketing/idea.svg" alt="Explosion of New Ideas">
</div> </div>
</div> </div>
@ -392,7 +392,7 @@
</div> </div>
<div class="six wide column"> <div class="six wide column">
<svg-displayer file="onboarding" alt="Observe this chart" /> <img loading="lazy" width="100%" src="/api/static/assets/marketing/onboarding.svg" alt="">
</div> </div>
</div> </div>
@ -400,7 +400,8 @@
<div class="middle aligned centered row"> <div class="middle aligned centered row">
<div class="four wide right aligned column"> <div class="four wide right aligned column">
<svg-displayer file="secure" alt="So dang secure" /> <img loading="lazy" width="100%" src="/api/static/assets/marketing/secure.svg" alt="marketing mumbo jumbo">
</div> </div>
<div class="six wide column"> <div class="six wide column">
<h2>Only you can read your notes. </h2> <h2>Only you can read your notes. </h2>
@ -414,13 +415,13 @@
<h3>Works on mobile or desktop browsers. <br>Behaves like an installed app on mobile phones.</h3> <h3>Works on mobile or desktop browsers. <br>Behaves like an installed app on mobile phones.</h3>
</div> </div>
<div class="four wide right aligned column"> <div class="four wide right aligned column">
<svg-displayer file="cloud" alt="Girl falling into the spiral of digital chaos" /> <img loading="lazy" width="100%" src="/api/static/assets/marketing/cloud.svg" alt="Girl falling into the spiral of digital chaos">
</div> </div>
</div> </div>
<div class="middle aligned centered row"> <div class="middle aligned centered row">
<div class="four wide right aligned column"> <div class="four wide right aligned column">
<svg-displayer file="robot" alt="Murder Robot in office environment" /> <img loading="lazy" width="100%" src="/api/static/assets/marketing/robot.svg" alt="Shrunken man near giant tablet">
</div> </div>
<div class="six wide column"> <div class="six wide column">
<h2>Secure Data Sharing</h2> <h2>Secure Data Sharing</h2>
@ -439,7 +440,7 @@
<a href="https://pi-hole.net/" target="_blank">Pi-hole</a> on the network.</h3> <a href="https://pi-hole.net/" target="_blank">Pi-hole</a> on the network.</h3>
</div> </div>
<div class="four wide column"> <div class="four wide column">
<svg-displayer file="icecream" alt="Emergence of a 4th dimensional being perceived as a large ice cream" /> <img loading="lazy" width="100%" src="/api/static/assets/marketing/icecream.svg" alt="Emergence of a 4th dimensional being perceived as a large ice cream ">
</div> </div>
</div> </div>
@ -511,7 +512,7 @@
<p>Awesomely Generic Marketing Images - <a target="_blank" href="https://undraw.co/">https://unDraw.co/</a></p> <p>Awesomely Generic Marketing Images - <a target="_blank" href="https://undraw.co/">https://unDraw.co/</a></p>
</div> </div>
<div class="four wide column"> <div class="four wide column">
<svg-displayer file="watching" alt="Drinking the blood of the elderly" /> <img loading="lazy" width="100%" src="/api/static/assets/marketing/watching.svg" alt="Drinking the blood of the elderly">
</div> </div>
</div> </div>
@ -530,7 +531,6 @@ export default {
components: { components: {
'login-form':require('@/components/LoginFormComponent.vue').default, 'login-form':require('@/components/LoginFormComponent.vue').default,
'logo':require('@/components/LogoComponent.vue').default, 'logo':require('@/components/LogoComponent.vue').default,
'svg-displayer':require('@/components/SvgDisplayer.vue').default,
}, },
data(){ data(){
return { return {
@ -543,7 +543,7 @@ export default {
'#00b5ad', //Teal '#00b5ad', //Teal
'#2185d0', //Blue '#2185d0', //Blue
'#7128b9', //Violet '#7128b9', //Violet
'#a333c8', //Purple '#a333c8', // "Purple"
'#e03997', //Pink '#e03997', //Pink
'#db2828', //Red '#db2828', //Red
'#f2711c', //Orange '#f2711c', //Orange

View File

@ -1,10 +1,10 @@
<template> <template>
<div class="page-container"> <div class="page-container" v-on:scroll="onScroll">
<div class="ui grid" ref="content"> <div class="ui grid" ref="content">
<div class="sixteen wide column"> <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"> <div class="ui stackable grid">
@ -27,12 +27,21 @@
v-on:tagClick="tagId => toggleTagFilter(tagId)" v-on:tagClick="tagId => toggleTagFilter(tagId)"
/> />
<paste-button /> <span>
<span class="ui grey text text-fix">
Active Sessions {{ $store.getters.getActiveSessions }} Active Sessions {{ $store.getters.getActiveSessions }}
</span> </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>
<div class="eight wide column" v-if="showClear"> <div class="eight wide column" v-if="showClear">
@ -98,19 +107,7 @@
</h3> </h3>
<!-- Go to one wide column, do not do this on mobile interface --> <!-- Go to one wide column, do not do this on mobile interface -->
<div :class="{'one-column':( showOneColumn), 'floating-list':( isFloatingList ), 'hidden-floating-list':(collapseFloatingList)}" v-on:scroll="onScroll"> <div :class="{'one-column':( showOneColumn() )}">
<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 --> <!-- render each section based on notes in set -->
<div v-for="section,index in noteSections" v-if="section.length > 0" class="note-card-section"> <div v-for="section,index in noteSections" v-if="section.length > 0" class="note-card-section">
@ -123,8 +120,8 @@
:ref="'note-'+note.id" :ref="'note-'+note.id"
:onClick="openNote" :onClick="openNote"
:data="note" :data="note"
:title-view="titleView || isFloatingList" :title-view="titleView"
:currently-open="openNotes.includes(note.id)" :currently-open="activeNoteId1 == note.id"
:key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated" :key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
/> />
</div> </div>
@ -152,21 +149,13 @@
</div> </div>
<div class="show-hidden-note-list-button" v-if="collapseFloatingList" v-on:click="collapseFloatingList = false">
<i class="caret square right outline icon"></i> <note-input-panel
</div> v-if="activeNoteId1 != null"
:key="activeNoteId1"
<!-- flexbox note container evenly spaces open notes --> :noteid="activeNoteId1"
<div class="note-panel-container" :class="{ 'note-panel-fullwidth':collapseFloatingList}" v-if="openNotes.length"> :url-data="$route.params"
<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> </div>
</template> </template>
@ -176,7 +165,7 @@
import axios from 'axios' import axios from 'axios'
export default { export default {
name: 'NotesPage', name: 'SearchBar',
components: { components: {
'note-input-panel': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'), 'note-input-panel': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'),
@ -187,7 +176,6 @@
'attachment-display': require('@/components/AttachmentDisplayCard').default, 'attachment-display': require('@/components/AttachmentDisplayCard').default,
'tag-display':require('@/components/TagDisplayComponent.vue').default, 'tag-display':require('@/components/TagDisplayComponent.vue').default,
'loading-icon':require('@/components/LoadingIconComponent.vue').default, 'loading-icon':require('@/components/LoadingIconComponent.vue').default,
'paste-button':require('@/components/PasteButton.vue').default,
}, },
data () { data () {
return { return {
@ -197,8 +185,6 @@
searchResultsCount: 0, searchResultsCount: 0,
searchTags: [], searchTags: [],
notes: [], notes: [],
openNotes: [],
collapseFloatingList: false,
highlights: [], highlights: [],
searchDebounce: null, searchDebounce: null,
fastFilters: {}, fastFilters: {},
@ -260,34 +246,35 @@
this.$io.on('new_note_created', noteId => { this.$io.on('new_note_created', noteId => {
// Push new note to top of list and animate //Do not update note if its open
this.updateSingleNote(noteId) if(this.activeNoteId1 != noteId){
this.$store.dispatch('fetchAndUpdateUserTotals') this.$store.dispatch('fetchAndUpdateUserTotals')
this.updateSingleNote(noteId, false)
}
}) })
this.$io.on('note_attribute_modified', noteId => { 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 //Do not update note if its open
if(this.openNotes.includes(parseInt(noteId))){ if(this.activeNoteId1 != noteId){
this.$store.dispatch('fetchAndUpdateUserTotals') this.$store.dispatch('fetchAndUpdateUserTotals')
this.updateSingleNote(noteId, false)
} }
}) })
//Update title cards when new note text is saved //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}) => {
const drawFocus = !this.openNotes.includes(parseInt(noteId)) //Do not update note if its open
this.updateSingleNote(noteId, drawFocus) if(this.activeNoteId1 != noteId){
this.updateSingleNote(noteId, true)
}
}) })
this.$bus.$on('update_single_note', (noteId) => { this.$bus.$on('update_single_note', (noteId) => {
//Do not update note if its open
const drawFocus = !this.openNotes.includes(parseInt(noteId)) if(this.activeNoteId1 != noteId){
this.updateSingleNote(noteId, drawFocus) this.updateSingleNote(noteId)
}
}) })
//Update totals for app //Update totals for app
@ -295,7 +282,19 @@
//Close note event //Close note event
this.$bus.$on('close_active_note', ({noteId, modified}) => { this.$bus.$on('close_active_note', ({noteId, modified}) => {
this.closeNote(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.$bus.$on('note_deleted', (noteId) => { this.$bus.$on('note_deleted', (noteId) => {
@ -347,8 +346,6 @@
} }
}) })
// Window scroll needed when scrolling full page.
// second scroll event added on note-list for floating view scroll detection
window.addEventListener('scroll', this.onScroll) window.addEventListener('scroll', this.onScroll)
//Close notes when back button is pressed //Close notes when back button is pressed
@ -357,6 +354,8 @@
//update note on visibility change //update note on visibility change
// document.addEventListener('visibilitychange', this.visibiltyChangeAction); // document.addEventListener('visibilitychange', this.visibiltyChangeAction);
//Find previously stored notes, cache for 20 hours, load them and compare
}, },
beforeDestroy(){ beforeDestroy(){
window.removeEventListener('scroll', this.onScroll) window.removeEventListener('scroll', this.onScroll)
@ -375,9 +374,9 @@
}, },
mounted() { mounted() {
//Open note on PAGE LOAD if ID is set //Open note on load if ID is set
if(this.$route.params.id > 1){ if(this.$route.params.id > 1){
this.openNote(this.$route.params.id) this.activeNoteId1 = this.$route.params.id
} }
//Loads initial batch and tags //Loads initial batch and tags
@ -386,19 +385,16 @@
}, },
watch: { watch: {
'$route.params.id': function(id){ '$route.params.id': function(id){
this.openNote(id) //Open note on ID, null id will close note
this.activeNoteId1 = id
}, },
'$route' (to, from) { '$route' (to, from) {
// Reload the notes if returning to this page // Reload the notes if returning to this page
if(to.fullPath == '/notes' && !from.fullPath.includes('/notes/open/')){ if(to.fullPath == '/notes' && !from.fullPath.includes('/notes/open/')){
this.reset()
}
// Close all notes if returning to /notes page this.reset()
if(to.fullPath == '/notes' && from.fullPath.includes('/notes/open/')){
this.closeAllNotes()
} }
//Lookup tags set in URL //Lookup tags set in URL
@ -413,96 +409,30 @@
} }
} }
}, },
computed: { methods: {
isFloatingList(){ toggleTitleView(){
this.titleView = !this.titleView
//If note 1 or 2 is open, show floating column
return (this.openNotes.length > 0)
}, },
showOneColumn(){ showOneColumn(){
return this.$store.getters.getIsUserOnMobile 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) &&
methods: { !this.$store.getters.getIsUserOnMobile
},
openNote(id, event = null){ 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 //Don't open note if a link is clicked in display card
if(event && event.target && event.target.nodeName){ if(event && event.target && event.target.nodeName){
const nodeClick = event.target.nodeName const nodeClick = event.target.nodeName
if(nodeClick == 'A'){ return } if(nodeClick == 'A'){ return }
} }
// Push note to stack if not open //Open note if a link was not clicked
if(Number.isInteger(intId) && !this.openNotes.includes(intId)){ this.$router.push('/notes/open/'+id)
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 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){ toggleTagFilter(tagId){
this.searchTags = [tagId] this.searchTags = [tagId]
@ -558,6 +488,7 @@
} }
this.lastVisibilityState = document.visibilityState this.lastVisibilityState = document.visibilityState
}, },
// @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, focuseAndAnimate = true){ updateSingleNote(noteId, focuseAndAnimate = true){
@ -593,7 +524,6 @@
return return
} }
// if old note data and new note data exists
if(note && newNote){ if(note && newNote){
//go through each prop and update it with new values //go through each prop and update it with new values
@ -602,7 +532,7 @@
}) })
//Push new note to front if its modified or we want it to //Push new note to front if its modified or we want it to
if( note.updated != newNote.updated ){ if( focuseAndAnimate || note.updated != newNote.updated ){
// Find note, in section, move to front // Find note, in section, move to front
Object.keys(this.noteSections).forEach( key => { Object.keys(this.noteSections).forEach( key => {
@ -616,9 +546,6 @@
}) })
}) })
}
if( focuseAndAnimate ){
this.$nextTick( () => { this.$nextTick( () => {
//Trigger close animation on note //Trigger close animation on note
this.$refs['note-'+noteId][0].justClosed() this.$refs['note-'+noteId][0].justClosed()
@ -882,11 +809,6 @@
</script> </script>
<style type="text/css" scoped> <style type="text/css" scoped>
.text-fix {
padding: 8px 0 0 15px;
display: inline-block;
color: var(--menu-accent);
}
.detail { .detail {
float: right; float: right;
} }
@ -905,133 +827,18 @@
padding: 15px 0 0; padding: 15px 0 0;
} }
.loading-section { .loading-section {
color: var(--main-accent); position: fixed;
box-shadow: 0 1px 3px 0 var(--main-accent); bottom: 40px;
padding: 0 10px;
right: 5px;
box-shadow: 0 1px 3px 0 #656565;
border-radius: 6px; border-radius: 6px;
background-color: var(--small_element_bg_color); background-color: var(--small_element_bg_color);
display: inline-block; opacity: 0.9;
width: 100%; font-size: 0.7em;
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);
}

View File

@ -1,761 +0,0 @@
<template>
<div class="page-container">
<div class="ui grid" ref="content">
<div class="sixteen wide column">
<!-- :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="ui basic button shrinking"
v-on:click="updateFastFilters(3)"
v-if="$store.getters.totals && ($store.getters.totals['youGotMailCount'] > 0)"
style="position: relative;">
<i class="green mail icon"></i>Inbox
<span class="tiny circular floating ui green label">+{{ $store.getters.totals['youGotMailCount'] }}</span>
</div>
<tag-display
:active-tags="searchTags"
v-on:tagClick="tagId => toggleTagFilter(tagId)"
/>
<div class="ui basic shrinking icon button" v-on:click="toggleTitleView()" v-if="$store.getters.totals && $store.getters.totals['totalNotes'] > 0">
<i v-if="titleView" class="th icon"></i>
<i v-if="!titleView" class="bars icon"></i>
</div>
</div>
<div class="eight wide column" v-if="showClear">
<!-- <fast-filters /> -->
<span class="ui fluid green button" @click="reset">
<i class="arrow circle left icon"></i>Show All Notes
</span>
</div>
</div>
</div>
<div class="sixteen wide column" v-if="searchTerm.length > 0 && !loadingInProgress">
<h2 class="ui header">
<div class="content">
{{ 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>
</div>
<div v-if="fastFilters['onlyArchived'] == 1" class="sixteen wide column">
<h2>Archived Notes</h2>
</div>
<div class="sixteen wide column" v-if="fastFilters['onlyShowTrashed'] == 1">
<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>
Empty Trash
</div>
</h2>
</div>
<div class="sixteen wide column" v-if="fastFilters['onlyShowSharedNotes'] == 1">
<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">
<h3 v-if="$store.getters.totals && $store.getters.totals['totalNotes'] == 0 && fastFilters['notesHome'] == 1">
No Notes Yet. <br>Thats ok.<br><br> <br>
<img loading="lazy" width="25%" src="/api/static/assets/marketing/hamburger.svg" alt="Create a new note"><br>
Create one when you feel ready.
</h3>
<!-- Go to one wide column, do not do this on mobile interface -->
<div :class="{'one-column':( showOneColumn() )}">
<!-- render each section based on notes in set -->
<div v-for="section,index in noteSections" v-if="section.length > 0" class="note-card-section">
<h5 class="ui tiny dividing header"><i :class="`green ${sectionData[index][0]} icon`"></i>{{ sectionData[index][1] }}</h5>
<div class="note-card-display-area">
<note-title-display-card
v-on:tagClick="tagId => toggleTagFilter(tagId)"
v-for="note in section"
:ref="'note-'+note.id"
:onClick="openNote"
:data="note"
:title-view="titleView"
:currently-open="activeNoteId1 == note.id"
:key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
/>
</div>
</div>
<loading-icon v-if="loadingInProgress" message="Decrypting Notes" />
</div>
</div>
</div>
<note-input-panel
v-if="activeNoteId1 != null"
:key="activeNoteId1"
:noteid="activeNoteId1"
:url-data="$route.params"
/>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'SearchBar',
components: {
'note-input-panel': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'),
'note-title-display-card': require('@/components/NoteTitleDisplayCard.vue').default,
// 'fast-filters': require('@/components/FastFilters.vue').default,
'search-input': require('@/components/SearchInput.vue').default,
'attachment-display': require('@/components/AttachmentDisplayCard').default,
'counter':require('@/components/AnimatedCounterComponent.vue').default,
'tag-display':require('@/components/TagDisplayComponent.vue').default,
'loading-icon':require('@/components/LoadingIconComponent.vue').default,
},
data () {
return {
initComponent: true,
tagSuggestions:[],
searchTerm: '',
searchResultsCount: 0,
searchTags: [],
notes: [],
highlights: [],
searchDebounce: null,
fastFilters: {},
titleView: false,
//Load up notes in batches
firstLoadBatchSize: 10, //First set of rapidly loaded notes
batchSize: 25, //Size of batch loaded when user scrolls through current batch
batchOffset: 0, //Tracks the current batch that has been loaded
loadingBatchTimeout: null, //Limit how quickly batches can be loaded
loadingInProgress: false,
scrollLoadEnabled: true,
//Clear button is not visible
showClear: false,
initialPostData: null,
//Currently open notes in app
activeNoteId1: null,
activeNoteId2: null,
//Position determines how note is Positioned
activeNote1Position: 0,
activeNote2Position: 0,
lastVisibilityState: null,
foundAttachments: [],
sectionData: {
'pinned': ['thumbtack', 'Pinned'],
'archived': ['archive', 'Archived'],
'shared': ['envelope outline', 'Inbox'],
'sent': ['paper plane outline', 'Sent Notes'],
'notes': ['file','Notes'],
'highlights': ['paragraph', 'Found In Text'],
'trashed': ['poop', 'Trashed Notes'],
'tagged': ['tag', 'Tagged'],
},
noteSections: {
pinned: [],
archived: [],
shared:[],
sent:[],
notes: [],
highlights: [],
trashed: [],
tagged:[],
},
}
},
beforeMount(){
this.$parent.loginGateway()
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)
}
})
this.$io.on('note_attribute_modified', noteId => {
//Do not update note if its open
if(this.activeNoteId1 != 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)
}
})
this.$bus.$on('update_single_note', (noteId) => {
//Do not update note if its open
if(this.activeNoteId1 != noteId){
this.updateSingleNote(noteId)
}
})
//Update totals for app
this.$store.dispatch('fetchAndUpdateUserTotals')
//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.$bus.$on('note_deleted', (noteId) => {
//Remove deleted note from set, its deleted
Object.keys(this.noteSections).forEach( key => {
this.noteSections[key].forEach( (note, index) => {
if(note.id == noteId){
this.noteSections[key].splice(index,1)
this.$store.dispatch('fetchAndUpdateUserTotals')
return
}
})
})
})
this.$bus.$on('update_fast_filters', filterIndex => {
this.updateFastFilters(filterIndex)
})
//Event to update search from other areas
this.$bus.$on('update_search_term', sentInSearchTerm => {
this.searchTerm = sentInSearchTerm
this.search(true, this.batchSize)
.then( () => {
this.searchAttachments()
const postData = {
'tagText':this.searchTerm.trim()
}
this.tagSuggestions = []
axios.post('/api/tag/suggest', postData)
.then( response => {
this.tagSuggestions = response.data
})
// return
})
})
//Reload page content - don't trigger if load is in progress
this.$bus.$on('note_reload', () => {
if(!this.loadingInProgress){
this.reset()
}
})
window.addEventListener('scroll', this.onScroll)
//Close notes when back button is pressed
// window.addEventListener('hashchange', this.hashChangeAction)
//update note on visibility change
// document.addEventListener('visibilitychange', this.visibiltyChangeAction);
},
beforeDestroy(){
window.removeEventListener('scroll', this.onScroll)
// document.removeEventListener('visibilitychange', this.visibiltyChangeAction)
this.$bus.$off('note_reload')
this.$bus.$off('close_active_note')
// this.$bus.$off('update_single_note')
this.$bus.$off('note_deleted')
this.$bus.$off('update_fast_filters')
this.$bus.$off('update_search_term')
//We want to remove event listeners, but something here is messing them up and preventing ALL event listeners from working
// this.$off() // Remove all event listeners
// this.$bus.$off()
},
mounted() {
//Open note on load if ID is set
if(this.$route.params.id > 1){
this.activeNoteId1 = this.$route.params.id
}
//Loads initial batch and tags
this.reset()
},
watch: {
'$route.params.id': function(id){
//Open note on ID, null id will close note
this.activeNoteId1 = id
}
},
methods: {
toggleTitleView(){
this.titleView = !this.titleView
},
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
},
openNote(id, event = null){
//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)
return
},
toggleTagFilter(tagId){
this.searchTags = [tagId]
//Reset note set and load up notes and tags
if(this.searchTags.length > 0){
this.search(true, this.batchSize)
return
}
//If no tags are selected, reset entire page
this.reset()
},
onScroll(e){
clearTimeout(this.loadingBatchTimeout)
this.loadingBatchTimeout = setTimeout(() => {
//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
//Load if less than 500px from the bottom
if(((height - scrolledDown) < 500) && this.scrollLoadEnabled && !this.loadingInProgress){
this.search(false, this.batchSize, true)
}
}, 30)
return
},
visibiltyChangeAction(event){
//Fuck this shit, just use web sockets
return
//@TODO - phase this out, update it via socket.io
//If user leaves page then returns to page, reload the first batch
if(this.lastVisibilityState == 'hidden' && document.visibilityState == 'visible'){
//Load initial batch, then tags, then other batch
this.search(false, this.firstLoadBatchSize)
.then( () => {
// return
})
}
this.lastVisibilityState = document.visibilityState
},
// @TODO Don't even trigger this if the note wasn't changed
updateSingleNote(noteId, focuseAndAnimate = true){
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
//Show that note is working on updating
this.$refs['note-'+noteId][0].showWorking = true
}
//Lookup one note using passed in ID
const postData = {
searchQuery: this.searchTerm,
searchTags: this.searchTags,
fastFilters:{
noteIdSet:[noteId]
}
}
//Note data must be fetched, then sorted into existing note data
axios.post('/api/note/search', postData)
.then(results => {
//Pull note data out of note set
let newNote = results.data.notes[0]
if(newNote === undefined){
return
}
if(note && newNote){
//go through each prop and update it with new values
Object.keys(newNote).forEach(prop => {
note[prop] = newNote[prop]
})
//Push new note to front if its modified or we want it to
if( focuseAndAnimate || note.updated != newNote.updated ){
// 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
}
})
})
this.$nextTick( () => {
//Trigger close animation on note
this.$refs['note-'+noteId][0].justClosed()
this.$refs['note-'+noteId][0].showWorking = false
})
}
}
//New notes don't exist in list, push them to the front
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()
this.$refs['note-'+noteId][0].showWorking = false
}
}
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
this.$refs['note-'+noteId][0].showWorking = false
}
//Trigger section rebuild
this.rebuildNoteCategorise()
})
.catch(error => {
console.log(error)
this.$bus.$emit('notification', 'Failed to Update Note')
})
},
searchAttachments(){
axios.post('/api/attachment/textsearch', {'searchTerm':this.searchTerm})
.then(results => {
this.foundAttachments = results.data
})
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Attachments') })
},
search(showLoading = true, notesInNextLoad = 10, mergeExisting = false){
return new Promise((resolve, reject) => {
//Don't double load note batches
if(this.loadingInProgress){
console.log('Loading already in progress')
return resolve(false)
}
//Reset a lot of stuff if we are not merging batches
if(!mergeExisting){
Object.keys(this.noteSections).forEach( key => {
this.noteSections[key] = []
})
this.batchOffset = 0 // Reset batch offset if we are not merging note batches
}
this.searchResultsCount = 0
//Remove all filter limits from previous queries
delete this.fastFilters.limitSize
delete this.fastFilters.limitOffset
let postData = {
searchQuery: this.searchTerm,
searchTags: this.searchTags,
fastFilters: this.fastFilters,
}
//Save initial post data on first load
if(this.initialPostData == null){
this.initialPostData = JSON.stringify(postData)
}
//If post data is not the same as initial, show clear button
if(JSON.stringify(postData) != this.initialPostData){
this.showClear = true
}
if(notesInNextLoad && notesInNextLoad > 0){
//Create limit based off of the number of notes already loaded
postData.fastFilters.limitSize = notesInNextLoad
postData.fastFilters.limitOffset = this.batchOffset
}
//Perform search - or die
this.loadingInProgress = true
axios.post('/api/note/search', postData)
.then(response => {
// console.timeEnd('Fetch TitleCard Batch '+notesInNextLoad)
//Save the number of notes just loaded
this.batchOffset += response.data.notes.length
//Enable or disable scroll loading
this.scrollLoadEnabled = response.data.notes.length > 0
if(response.data.total > 0){
this.searchResultsCount = response.data.total
}
this.loadingInProgress = false
this.generateNoteCategories(response.data.notes, mergeExisting)
return resolve(true)
})
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Notes') })
})
},
rebuildNoteCategorise(){
let currentNotes = []
Object.keys(this.noteSections).forEach( key => {
this.noteSections[key].forEach( note => {
currentNotes.push(note)
})
})
this.generateNoteCategories(currentNotes, false)
},
generateNoteCategories(notes, mergeExisting){
// Place each note in a category based on certain attributes and fast filters
//Reset all sections if we are not merging existing
if(!mergeExisting){
Object.keys(this.noteSections).forEach( key => {
this.noteSections[key] = []
})
}
//Sort notes into defined sections
notes.forEach(note => {
if(this.searchTerm.length > 0){
if(note.pinned == 1){
this.noteSections.pinned.push(note)
return
}
//Push to default note section
this.noteSections.notes.push(note)
return
}
//Display all tags in tag section
if(this.searchTags.length >= 1){
this.noteSections.tagged.push(note)
return
}
//Only show trashed notes when trashed
if(this.fastFilters.onlyShowTrashed == 1){
if(note.trashed == 1){
this.noteSections.trashed.push(note)
}
return
}
if(note.trashed == 1){
return
}
//Show archived notes
if(this.fastFilters.onlyArchived == 1){
if(note.pinned == 1 && note.archived == 1){
this.noteSections.pinned.push(note)
return
}
if(note.archived == 1){
this.noteSections.archived.push(note)
}
return
}
if(note.archived == 1){ return }
//Only show sent notes section if shared is selected
if(this.fastFilters.onlyShowSharedNotes == 1){
if(note.shared == 2){
this.noteSections.sent.push(note)
}
if(note.shareUsername != null){
this.noteSections.shared.push(note)
}
return
}
//Show shared notes on main list but not notes shared with you
if(note.shareUsername != null){ return }
// Pinned notes are always first, they can appear in the archive
if(note.pinned == 1){
this.noteSections.pinned.push(note)
return
}
//Push to default note section
this.noteSections.notes.push(note)
return
})
},
reset(){
this.showClear = false
this.scrollLoadEnabled = true
this.searchTerm = ''
this.searchTags = []
this.tagSuggestions = []
this.fastFilters = {}
this.foundAttachments = [] //Remove all attachments
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') //Clear out search
const options = [
'withLinks', // 'Only Show Notes with Links'
'withTags', // 'Only Show Notes with Tags'
'onlyArchived', //'Only Show Archived Notes'
'onlyShowSharedNotes', //Only show shared notes
'onlyShowTrashed',
'notesHome',
]
let filter = {}
filter[options[index]] = 1
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))
}
}
}
</script>
<style type="text/css" scoped>
.detail {
float: right;
}
.note-card-display-area {
display: flex;
flex-wrap: wrap;
}
.display-area-title {
width: 100%;
display: inline-block;
}
.note-card-section {
/*padding-bottom: 15px;*/
}
.note-card-section + .note-card-section {
padding: 15px 0 0;
}
</style>

View File

@ -48,7 +48,7 @@ export default new Vuex.Store({
'small_element_bg_color': '#000', 'small_element_bg_color': '#000',
'text_color': '#FFF', 'text_color': '#FFF',
'dark_border_color': '#555',//'#ACACAC', //Lighter color to accent elemnts user can interact with 'dark_border_color': '#555',//'#ACACAC', //Lighter color to accent elemnts user can interact with
'border_color': '#0b0110', 'border_color': '#555',
'menu-accent': '#626262', 'menu-accent': '#626262',
'menu-text': '#d9d9d9', 'menu-text': '#d9d9d9',
}, },

View File

@ -1,5 +1,3 @@
const fs = require('fs')
module.exports = { module.exports = {
pwa: { pwa: {
name: 'SolidScribe', name: 'SolidScribe',
@ -15,10 +13,6 @@ module.exports = {
disableHostCheck: true, disableHostCheck: true,
proxy: 'http://localhost:8081', proxy: 'http://localhost:8081',
public: 'marvin.local', public: 'marvin.local',
https: {
key: fs.readFileSync('./certs/192.168.1.164+4-key.pem'),
cert: fs.readFileSync('./certs/192.168.1.164+4.pem'),
},
}, },
} }

View File

@ -1,158 +0,0 @@
#
# Working dev server config
#
server {
listen 443 ssl;
ssl_certificate /home/mab/ss/client/certs/192.168.1.164+4.pem;
ssl_certificate_key /home/mab/ss/client/certs/192.168.1.164+4-key.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSV1.1 TLSV1.2 TLSV1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/httpslocalhost.access.log;
error_log /var/log/nginx/httpslocalhost.error.log;
client_max_body_size 20M;
location / {
proxy_pass https://127.0.0.1:8081;
proxy_set_header Host localhost;
proxy_set_header X-Forwarded-Host localhost;
proxy_set_header X-Forwarded-Server localhost;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_redirect off;
proxy_connect_timeout 90s;
proxy_read_timeout 90s;
proxy_send_timeout 90s;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
location /sockjs-node {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass https://127.0.0.1:8081;
proxy_redirect off;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
location /api {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
location /socket {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
}
##
## Working Copy below --------------------------------------------
##
server {
listen 443 ssl;
ssl_certificate /home/mab/ss/client/certs/192.168.1.164+4.pem;
ssl_certificate_key /home/mab/ss/client/certs/192.168.1.164+4-key.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSV1.1 TLSV1.2 TLSV1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/httpslocalhost.access.log;
error_log /var/log/nginx/httpslocalhost.error.log;
client_max_body_size 20M;
location / {
proxy_pass https://127.0.0.1:8081;
proxy_set_header Host localhost;
proxy_set_header X-Forwarded-Host localhost;
proxy_set_header X-Forwarded-Server localhost;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_redirect off;
proxy_connect_timeout 90s;
proxy_read_timeout 90s;
proxy_send_timeout 90s;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
location /sockjs-node {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass https://127.0.0.1:8081;
proxy_redirect off;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
location /api {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
location /socket {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3001;
proxy_redirect off;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
}
# Prod settings to serve static index
# location / {
# autoindex on;
# #try_files $uri $uri/ /index.html;
# }
# location / {
# #autoindex on
#
# proxy_pass http://127.0.0.1:8444;
# proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection 'upgrade';
# proxy_set_header Host $host;
# proxy_cache_bypass $http_upgrade;
# }

View File

@ -46,17 +46,14 @@ Attachment.textSearch = (userId, searchTerm) => {
}) })
} }
Attachment.search = (userId, noteId, attachmentType, offset, setSize, includeShared) => { Attachment.search = (userId, noteId, attachmentType, offset, setSize) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let params = [userId] let params = [userId]
let query = ` let query = 'SELECT * FROM attachment WHERE user_id = ? AND visible = 1 '
SELECT attachment.*, note.share_user_id FROM attachment
JOIN note ON (attachment.note_id = note.id)
WHERE attachment.user_id = ? AND visible = 1 `
if(noteId && noteId > 0){ if(noteId && noteId > 0){
query += 'AND attachment.note_id = ? ' query += 'AND note_id = ? '
params.push(noteId) params.push(noteId)
} }
@ -67,16 +64,11 @@ Attachment.search = (userId, noteId, attachmentType, offset, setSize, includeSha
query += 'AND attachment_type > 1 ' query += 'AND attachment_type > 1 '
} }
if(!noteId){
const sharedOrNot = includeShared ? ' NOT ':' '
query += `AND note.share_user_id IS${sharedOrNot}NULL `
}
query += 'ORDER BY last_indexed DESC ' query += 'ORDER BY last_indexed DESC '
const limitOffset = parseInt(offset, 10) || 0 //Either parse int, or use zero const limitOffset = parseInt(offset, 10) || 0 //Either parse int, or use zero
const parsedSetSize = parseInt(setSize, 10) || 20 const parsedSetSize = parseInt(setSize, 10) || 20 //Either parse int, or use zero
query += ` LIMIT ${limitOffset}, ${parsedSetSize}` query += ` LIMIT ${limitOffset}, ${parsedSetSize}`
db.promise() db.promise()

View File

@ -442,10 +442,6 @@ Note.update = (userId, noteId, noteText, noteTitle, color, pinned, archived, has
}) })
.then((rows, fields) => { .then((rows, fields) => {
if(!rows[0] || !rows[0][0] || !rows[0][0]['note_raw_text_id']){
return reject(false)
}
const textId = rows[0][0]['note_raw_text_id'] const textId = rows[0][0]['note_raw_text_id']
let salt = rows[0][0]['salt'] let salt = rows[0][0]['salt']
let snippetSalt = rows[0][0]['snippet_salt'] let snippetSalt = rows[0][0]['snippet_salt']
@ -662,9 +658,6 @@ Note.delete = (userId, noteId, masterKey = null) => {
}) })
} }
//
// Returns noteData
//
Note.get = (userId, noteId, masterKey) => { Note.get = (userId, noteId, masterKey) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View File

@ -13,14 +13,11 @@ QuickNote.get = (userId, masterKey) => {
SELECT note.id FROM note WHERE quick_note = 1 AND user_id = ? LIMIT 1`, [userId]) SELECT note.id FROM note WHERE quick_note = 1 AND user_id = ? LIMIT 1`, [userId])
.then((rows, fields) => { .then((rows, fields) => {
//Quick Note is set, return note object //Quick Note is set, return note text
if(rows[0][0] != undefined){ if(rows[0][0] != undefined){
let noteId = rows[0][0].id let noteId = rows[0][0].id
const note = Note.get(userId, noteId, masterKey) return resolve({'noteId':noteId})
.then(noteData => {
return resolve(noteData)
})
} else { } else {
//Or create a new note and get the id //Or create a new note and get the id
@ -84,7 +81,7 @@ QuickNote.update = (userId, pushText, masterKey) => {
.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 link //Turn links into actual linx
clean = QuickNote.makeUrlLink(clean) clean = QuickNote.makeUrlLink(clean)
if(clean == ''){ clean = '&nbsp;' } if(clean == ''){ clean = '&nbsp;' }
@ -117,7 +114,7 @@ QuickNote.update = (userId, pushText, masterKey) => {
} }
}) })
.then( saveResults => { .then( saveResults => {
return resolve(saveResults) return resolve(true)
}) })
}) })

View File

@ -9,7 +9,7 @@ const speakeasy = require('speakeasy')
let User = module.exports = {} let User = module.exports = {}
const version = '3.5.0' const version = '3.4.2'
//Login a user, if that user does not exist create them //Login a user, if that user does not exist create them
//Issues login token //Issues login token
@ -35,7 +35,7 @@ User.login = (username, password, authToken = null) => {
// //
if(rows[0].length == 1){ if(rows[0].length == 1){
//Pull out user data from database results //Pull out user data from database results
const lookedUpUser = rows[0][0] const lookedUpUser = rows[0][0]
//Verify Token if set //Verify Token if set
@ -255,7 +255,7 @@ User.getCounts = (userId) => {
WHERE user_id = ? WHERE user_id = ?
GROUP BY tag_id GROUP BY tag_id
ORDER BY uses DESC ORDER BY uses DESC
LIMIT 16 LIMIT 5
`, [userId]) `, [userId])
}).then( (rows, fields) => { }).then( (rows, fields) => {

View File

@ -26,7 +26,7 @@ router.use(function setUserId (req, res, next) {
}) })
router.post('/search', function (req, res) { router.post('/search', function (req, res) {
Attachment.search(userId, req.body.noteId, req.body.attachmentType, req.body.offset, req.body.setSize, req.body.includeShared) Attachment.search(userId, req.body.noteId, req.body.attachmentType, req.body.offset, req.body.setSize)
.then( data => res.send(data) ) .then( data => res.send(data) )
}) })

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB