Added rate limiting and server security
Ton of little visual style tweaks and little up improvements for mobile
This commit is contained in:
parent
749d2cea94
commit
ecbf6a9cde
@ -6,7 +6,7 @@ mkdir -p $BACKUPDIR
|
||||
cd $BACKUPDIR
|
||||
|
||||
NOW=$(date +"%Y-%m-%d_%H-%M")
|
||||
ssh mab@avidhabit.com -p 13328 "mysqldump --all-databases --user root -p***REMOVED***" > "backup-$NOW.sql"
|
||||
ssh mab@solidscribe.com -p 13328 "mysqldump --all-databases --user root -p***REMOVED***" > "backup-$NOW.sql"
|
||||
|
||||
cp "backup-$NOW.sql" "/mnt/Windows Data/DatabaseBackups/backup-$NOW.sql"
|
||||
|
||||
|
@ -18,14 +18,14 @@ tar -czf release.tar.gz server node_modules client/dist staticFiles/assets
|
||||
|
||||
#send compressed release to remote machine
|
||||
echo -e "\e[32m\nMoving compressed release to production... \n\e[0m"
|
||||
rsync -e 'ssh -p 13328' -havzC --update release.tar.gz mab@avidhabit.com:/home/mab/pi/
|
||||
rsync -e 'ssh -p 13328' -havzC --update release.tar.gz mab@solidscribe.com:/home/mab/pi/
|
||||
|
||||
# Remove Release from local after its been uploaded
|
||||
rm release.tar.gz
|
||||
|
||||
#uncompress release on server
|
||||
echo -e "\e[32m\nExtracting release on production... \n\e[0m"
|
||||
ssh mab@avidhabit.com -p 13328 "cd /home/mab/pi/; rm -r server node_modules client; tar -xzf *.tar.gz --overwrite; rm *.tar.gz; pm2 reload all"
|
||||
ssh mab@solidscribe.com -p 13328 "cd /home/mab/pi/; rm -r server node_modules client; tar -xzf *.tar.gz --overwrite; rm *.tar.gz; pm2 reload all"
|
||||
|
||||
#Congratulate how awesome you are
|
||||
echo -e "\e[32m\nRelease Complete! Nice Work! \n\e[0m"
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div id="app" :class="{ 'night-mode':($store.getters.getIsNightMode) }">
|
||||
|
||||
<global-site-menu />
|
||||
|
||||
|
@ -35,6 +35,14 @@ div.ui.basic.segment.no-fluf-segment {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
/* Night mode modifiers */
|
||||
|
||||
/*Make images sepia in night mode */
|
||||
.night-mode img {
|
||||
filter: grayscale(50%) brightness(80%) sepia(80%);
|
||||
|
||||
}
|
||||
|
||||
/* OVERWRITE DEFAULT SEMANTIC STYLES FOR CUSTOM/NIGHT MODES*/
|
||||
body {
|
||||
color: var(--text_color);
|
||||
@ -231,22 +239,27 @@ a:hover {
|
||||
.squire-box a {
|
||||
cursor: pointer;
|
||||
}
|
||||
/* .note-card-text i,
|
||||
.note-card-text i:not(.icon),
|
||||
.squire-box i {
|
||||
padding: 0.5em 0.99em;
|
||||
border: 1px solid #CCC;
|
||||
margin: 1px;
|
||||
border-radius: 9px;
|
||||
border-radius: 1px;
|
||||
display: inline-block;
|
||||
}*/
|
||||
font-style: normal;
|
||||
background-color: rgba(113, 113, 113, 0.1);
|
||||
}
|
||||
.night-mode .note-card-text i:not(.icon),
|
||||
.night-mode .squire-box i {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.note-card-text p,
|
||||
.squire-box p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.note-card-text blockquote,
|
||||
.squire-box blockquote {
|
||||
margin: 0;
|
||||
padding: 0.8em;
|
||||
border-left: 2px solid blue;
|
||||
padding: 0 0 0 2.5em;
|
||||
}
|
||||
.note-card-text img {
|
||||
max-width:100%;
|
||||
@ -305,6 +318,10 @@ a:hover {
|
||||
/* adjust checkboxes for mobile. Make them a little bigger, easier to click */
|
||||
@media only screen and (max-width: 740px) {
|
||||
|
||||
.ui.button.shrinking {
|
||||
font-size: 0.85714286rem;
|
||||
}
|
||||
|
||||
.note-card-text ul > li,
|
||||
.squire-box ul > li {
|
||||
min-height: 30px;
|
||||
@ -346,6 +363,12 @@ a:hover {
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
.ui.grid.reduced-padding > .column {
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.textarea-height {
|
||||
height: calc(100% - 90px);
|
||||
|
@ -18,6 +18,11 @@
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.menu-logo-display {
|
||||
width: 25px;
|
||||
margin: 5px 0 0 34px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
color: #fff;
|
||||
@ -101,31 +106,39 @@
|
||||
<i class="green bars icon"></i>
|
||||
</div>
|
||||
|
||||
<router-link class="ui large basic compact icon button" to="/notes" v-on:click.native="emitReloadEvent()">
|
||||
<router-link v-if="loggedIn" class="ui large basic compact icon button" to="/notes" v-on:click.native="emitReloadEvent()">
|
||||
<i class="green home icon"></i>
|
||||
</router-link>
|
||||
|
||||
<router-link v-if="loggedIn" class="ui basic icon button" exact-active-class="active" to="/attachments">
|
||||
<i class="open folder outline icon"></i>
|
||||
</router-link>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="two wide center aligned bottom aligned column">
|
||||
<img loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
|
||||
</div>
|
||||
|
||||
<div class="seven wide right aligned column">
|
||||
|
||||
<div v-on:click="toggleNightMode" class="ui large basic compact icon button">
|
||||
<i class="green moon outline icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="six wide center aligned column">
|
||||
<img v-if="!loggedIn" src="/api/static/assets/favicon.ico" alt="logo" />
|
||||
|
||||
<search-input v-if="loggedIn && mobile"></search-input>
|
||||
</div>
|
||||
<div class="three wide right aligned column">
|
||||
|
||||
<!-- mobile create note button -->
|
||||
<div v-if="loggedIn">
|
||||
<div v-if="!disableNewNote" @click="createNote" class="ui large basic compact icon button">
|
||||
<span v-if="loggedIn">
|
||||
<span v-if="!disableNewNote" @click="createNote" class="ui large basic compact icon button">
|
||||
<i class="green plus icon"></i>
|
||||
</div>
|
||||
<div v-if="disableNewNote" class="ui large basic compact icon button">
|
||||
</span>
|
||||
<span v-if="disableNewNote" class="ui large basic compact icon button">
|
||||
<i class="grey plus icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -136,10 +149,11 @@
|
||||
|
||||
<div class="global-menu" v-if="!collapsed" v-on:click="menuClicked">
|
||||
|
||||
<div class="menu-section">
|
||||
<div class="menu-item menu-button" v-on:click="collapseMenu">
|
||||
<i class="angle left icon"></i>
|
||||
</div>
|
||||
<div class="menu-section" v-on:click="collapseMenu">
|
||||
<!-- <div class="menu-item menu-button" > -->
|
||||
<i class="white angle left icon"></i>
|
||||
<img class="menu-logo-display" loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
|
||||
<div class="menu-section" v-if="loggedIn">
|
||||
|
@ -19,23 +19,24 @@
|
||||
|
||||
<div class="note-menu">
|
||||
|
||||
<nm-button v-on:click.native="close" icon="close" />
|
||||
<nm-button tip="Close" bottom-tip="true" v-on:click.native="close" icon="close" />
|
||||
|
||||
<nm-button v-on:click.native="toggleList('ol')" icon="list ol" />
|
||||
<nm-button tip="Numbered List" bottom-tip="true" v-on:click.native="toggleList('ol')" icon="list ol" />
|
||||
|
||||
<nm-button v-on:click.native="toggleList('ul')" icon="tasks" />
|
||||
<nm-button tip="Task List" bottom-tip="true" v-on:click.native="toggleList('ul')" icon="tasks" />
|
||||
|
||||
<nm-button v-on:click.native="toggleBold()" icon="bold" />
|
||||
<nm-button tip="Bold" bottom-tip="true" v-on:click.native="toggleBold()" icon="bold" />
|
||||
|
||||
<nm-button v-on:click.native="toggleItalic()" icon="quote left" />
|
||||
<nm-button tip="Quote" bottom-tip="true" v-on:click.native="toggleItalic()" icon="quote left" />
|
||||
|
||||
<nm-button v-on:click.native="modifyFont('1.4em')" icon="text height" />
|
||||
<nm-button tip="Title" bottom-tip="true" v-on:click.native="modifyFont('1.4em')" icon="text height" />
|
||||
|
||||
<nm-button v-on:click.native="undoCustom()" icon="undo" />
|
||||
<nm-button tip="Indent" bottom-tip="true" v-on:click.native="editor.increaseQuoteLevel()" icon="indent" />
|
||||
|
||||
<nm-button v-if="usersOnNote > 1" icon="green user circle" />
|
||||
<nm-button tip="Outdent" bottom-tip="true" v-on:click.native="editor.decreaseQuoteLevel()" icon="outdent" />
|
||||
|
||||
<nm-button tip="Users on Note" bottom-tip="true" v-if="usersOnNote > 1" icon="green user circle" />
|
||||
|
||||
<nm-button icon="ellipsis horizontal" v-on:click.native="showNoteOptions = !showNoteOptions" />
|
||||
</div>
|
||||
|
||||
<!-- Squire box grows -->
|
||||
@ -92,25 +93,52 @@
|
||||
|
||||
<!-- bottom stats -->
|
||||
<div class="ui basic segment">
|
||||
<div class="ui grid">
|
||||
<div class="sixteen wide column">
|
||||
<div class="ui grid reduced-padding">
|
||||
|
||||
<div class="four wide column">
|
||||
<!-- Tags -->
|
||||
<button class="ui compact basic fluid button shrinking" v-on:click="showTagSlideMenu = !showTagSlideMenu; modified = true">
|
||||
<i class="tags icon"></i> Tags
|
||||
</button>
|
||||
</div>
|
||||
<div class="four wide column">
|
||||
<!-- Archive Button -->
|
||||
<button class="ui compact basic fluid button shrinking" v-on:click="onToggleArchived">
|
||||
<span v-if="archived == 1"><i class="green archive icon"></i> Archived</span>
|
||||
<span v-if="archived != 1"><i class="archive icon"></i> Archive</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="four wide column"><!-- Pin button -->
|
||||
<button class="ui compact basic fluid button shrinking" v-on:click="onTogglePinned">
|
||||
<span v-if="pinned == 1"><i class="green pin icon"></i> Pinned</span>
|
||||
<span v-if="pinned != 1"><i class="pin icon"></i> Pin</span>
|
||||
</button></div>
|
||||
<div class="four wide column">
|
||||
<!-- files button -->
|
||||
<button class="ui compact basic fluid button shrinking" v-on:click="openEditAttachment">
|
||||
<i class="folder icon"></i> Files
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- <div class="sixteen wide column"></div> -->
|
||||
|
||||
<div class="eight wide column">
|
||||
|
||||
<div class="ui basic button"v-if="!isEncrypted" v-on:click="passwordEnterVisible = true">
|
||||
<button class="ui basic compact button shrinking" v-if="!isEncrypted" v-on:click="passwordEnterVisible = true">
|
||||
<i class="shield alternate icon"></i>
|
||||
Password Protect
|
||||
</div>
|
||||
<div class="ui icon basic button" v-if="isEncrypted && isDecrypted" v-on:click="disableEncryption">
|
||||
</button>
|
||||
<button class="ui icon basic compact button shrinking" v-if="isEncrypted && isDecrypted" v-on:click="disableEncryption">
|
||||
<i class="unlock icon"></i>
|
||||
Remove Password
|
||||
</div>
|
||||
|
||||
<div class="ui basic compact button">
|
||||
Status: {{ statusText }}
|
||||
</div>
|
||||
<div class="ui basic compact button" :data-tooltip="`Created: ${$helpers.timeAgo(created)}`">
|
||||
Last Change: {{ $helpers.timeAgo(updated) }}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="seven wide right aligned middle aligned column">
|
||||
<span :data-tooltip="`Created: ${$helpers.timeAgo(created)}`">
|
||||
Edited: {{ $helpers.timeAgo(updated) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="one wide column"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -126,31 +154,13 @@
|
||||
<div class="all-settings" :class="{ 'low-settings':!extraToolbarsVisible }">
|
||||
|
||||
<div class="note-menu shrink-icons-on-mobile">
|
||||
|
||||
<!-- Pin Button -->
|
||||
<nm-button
|
||||
v-on:click.native="onToggleArchived"
|
||||
:icon="(archived == 1)?'green archive':'archive'"
|
||||
:text="(archived == 1)?'Archived':'Archive'"
|
||||
tip="Show in archive"
|
||||
:showText="true"
|
||||
></nm-button>
|
||||
|
||||
<!-- archive button -->
|
||||
<nm-button
|
||||
v-on:click.native="onTogglePinned"
|
||||
:icon="(pinned == 1)?'green pin':'pin'"
|
||||
:text="(pinned == 1)?'Pinned':'Pin'"
|
||||
tip="Pin to top of list"
|
||||
:showText="true"
|
||||
></nm-button>
|
||||
|
||||
<!-- colors button -->
|
||||
<nm-button
|
||||
v-on:click.native="showColorPicker"
|
||||
icon="paint brush"
|
||||
text="Colors"
|
||||
tip="Colors"
|
||||
text="Color"
|
||||
tip="Note Color"
|
||||
></nm-button>
|
||||
|
||||
<!-- add images panel -->
|
||||
@ -161,27 +171,18 @@
|
||||
tip="Images"
|
||||
></nm-button>
|
||||
|
||||
<!-- Tags -->
|
||||
<nm-button
|
||||
v-on:click.native="showTagSlideMenu = !showTagSlideMenu; modified = true"
|
||||
icon="tags"
|
||||
text="Tags"
|
||||
tip="Tags"
|
||||
></nm-button>
|
||||
|
||||
<!-- file upload button -->
|
||||
<file-upload-button
|
||||
class="nm-button"
|
||||
:noteId="noteid" />
|
||||
|
||||
<!-- files button -->
|
||||
<nm-button
|
||||
v-on:click.native="openEditAttachment"
|
||||
icon="folder"
|
||||
text="Files"
|
||||
tip="Files on Note"
|
||||
:showText="true"
|
||||
></nm-button>
|
||||
<nm-button v-on:click.native="undoCustom()" icon="undo" tip="Undo" text="Undo" />
|
||||
|
||||
<nm-button
|
||||
icon="ellipsis horizontal"
|
||||
text="Options"
|
||||
tip="More Options"
|
||||
v-on:click.native="showNoteOptions = !showNoteOptions" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -238,12 +239,6 @@
|
||||
Uncheck all Checked items
|
||||
</div>
|
||||
</div>
|
||||
<div class="eight wide column">
|
||||
<div class="ui labeled icon fluid basic button" v-on:click="undoCustom">
|
||||
<i class="undo icon"></i>
|
||||
Undo last change
|
||||
</div>
|
||||
</div>
|
||||
<div class="eight wide column">
|
||||
<div class="ui labeled icon fluid basic button" v-on:click="calculateMath" data-tooltip="Calculates algebra before '='">
|
||||
<i class="calculator icon"></i>
|
||||
@ -251,6 +246,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="sixteen wide column" v-if="rawTextId > 0">
|
||||
<h2>Share Note</h2>
|
||||
<share-note-component
|
||||
:note-id="noteid"
|
||||
:raw-text-id="rawTextId"
|
||||
@ -274,7 +270,7 @@
|
||||
<h2><i class="green lock alternate icon"></i>Password protect this Note</h2>
|
||||
<p>Password protection will prevent anyone from reading the text of this note, unless they enter the correct password.</p>
|
||||
<p><b>Only the note text is protected. Title, tags, and files are not encrypted and remain visible without a password.</b></p>
|
||||
<p>The password you select will only be used for this note. You can use the same password on multiple notes. The note will be encrypted using the password entered. A longer password is will be more secure.</p>
|
||||
<p>The password you select will only be used for this note. You can use the same password on multiple notes. The note will be encrypted using the password entered. A longer password will be more secure.</p>
|
||||
<h4><i class="red icon exclamation triangle"></i> Warning. There is no way to recover a lost password.</h4>
|
||||
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="nm-button" :class="moreClass" :data-tooltip="tip" data-inverted>
|
||||
<div class="nm-button" :class="moreClass" :data-tooltip="tip" data-inverted :data-position=" bottomTip?'bottom center':'top center'">
|
||||
<!-- Display Icon and text -->
|
||||
<i v-if="icon" :class="`${icon} icon`"></i>
|
||||
<span v-if="(text && mobile) || (text && showText)">{{text}}</span>
|
||||
@ -21,12 +21,11 @@
|
||||
|
||||
export default {
|
||||
name: 'NoteMenuButtonComponent',
|
||||
props: [ 'icon', 'text', 'tooltip', 'moreClass', 'showText', 'tip'],
|
||||
props: [ 'icon', 'text', 'tooltip', 'moreClass', 'showText', 'tip', 'bottomTip'],
|
||||
data () {
|
||||
return {
|
||||
files: [],
|
||||
mobile: false,
|
||||
showTooltip: false,
|
||||
}
|
||||
},
|
||||
beforeMount(){
|
||||
|
@ -1,10 +1,46 @@
|
||||
<style type="text/css" scoped>
|
||||
.fixed-search {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="ui form">
|
||||
<div class="ui left icon fluid input">
|
||||
<input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes and Files" />
|
||||
<i class="search icon"></i>
|
||||
<span>
|
||||
|
||||
<div class="ui form" v-if="!$store.getters.getIsUserOnMobile">
|
||||
<!-- normal search menu -->
|
||||
<div class="ui left icon fluid input">
|
||||
<input v-model="searchTerm" @keyup="searchKeyUp" @keyup.enter="search" placeholder="Search Notes and Files" ref="searchInput"/>
|
||||
<i class="search icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<span class="ui basic icon button" v-on:click="openFloatingSearch">
|
||||
<i class="green search icon"></i>
|
||||
</span>
|
||||
|
||||
<div class="fixed-search" v-if="showFixedSearch">
|
||||
<div class="ui raised segment">
|
||||
<h2 class="ui center aligned header">Search!</h2>
|
||||
<div class="ui form">
|
||||
<div class="ui left icon fluid input">
|
||||
<input
|
||||
ref="fixedSearch"
|
||||
v-model="searchTerm"
|
||||
@keyup.enter="search"
|
||||
v-on:blur="showFixedSearch = false"
|
||||
placeholder="Press Enter to Search" />
|
||||
<i class="search icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -16,6 +52,7 @@
|
||||
searchTerm: '',
|
||||
searchTimeout: null,
|
||||
searchDebounceDuration: 300,
|
||||
showFixedSearch: false,
|
||||
}
|
||||
},
|
||||
beforeCreate: function(){
|
||||
@ -29,13 +66,27 @@
|
||||
|
||||
},
|
||||
methods: {
|
||||
openFloatingSearch(){
|
||||
this.showFixedSearch = !this.showFixedSearch
|
||||
|
||||
if(this.showFixedSearch){
|
||||
this.$nextTick( () => {
|
||||
this.searchTerm = ''
|
||||
this.$refs.fixedSearch.focus()
|
||||
})
|
||||
}
|
||||
},
|
||||
searchKeyUp(){
|
||||
//This event is not triggered on mobile
|
||||
clearTimeout(this.searchTimeout)
|
||||
this.searchTimeout = setTimeout(() => {
|
||||
this.search()
|
||||
}, this.searchDebounceDuration)
|
||||
},
|
||||
search(){
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.$refs.fixedSearch.blur()
|
||||
}
|
||||
this.$bus.$emit('update_search_term', this.searchTerm)
|
||||
},
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="ui basic segment no-fluf-segment" ref="content">
|
||||
<div class="ui grid">
|
||||
<div class="ui stacking grid">
|
||||
|
||||
<div class="ui twelve wide column">
|
||||
<div class="sixteen wide column">
|
||||
<h2 class="ui header">
|
||||
<i class="folder open outline icon"></i>
|
||||
<div class="content">
|
||||
@ -14,7 +14,7 @@
|
||||
<!-- subnav -->
|
||||
<router-link
|
||||
exact-active-class="green"
|
||||
class="ui basic button"
|
||||
class="ui basic button shrinking"
|
||||
to="/attachments">
|
||||
<i class="open folder outline icon"></i>
|
||||
All
|
||||
@ -22,7 +22,7 @@
|
||||
<router-link
|
||||
v-if="$store.getters.totals && $store.getters.totals['linkFiles']"
|
||||
exact-active-class="green"
|
||||
class="ui basic button"
|
||||
class="ui basic button shrinking"
|
||||
to="/attachments/type/links">
|
||||
<i class="linkify icon"></i>
|
||||
Links
|
||||
@ -30,16 +30,13 @@
|
||||
<router-link
|
||||
v-if="$store.getters.totals && $store.getters.totals['otherFiles']"
|
||||
exact-active-class="green"
|
||||
class="ui basic button"
|
||||
class="ui basic button shrinking"
|
||||
to="/attachments/type/files">
|
||||
<i class="copy icon"></i>
|
||||
Other Files
|
||||
</router-link>
|
||||
|
||||
</div>
|
||||
<div class="four wide bottom aligned column">
|
||||
<i v-if="loading" class="green sync alternate loading icon"></i>
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide column" v-if="searchParams.noteId">
|
||||
<router-link class="ui green button" to="/attachments">
|
||||
@ -50,6 +47,8 @@
|
||||
<i class="file outline icon"></i>
|
||||
Open Note
|
||||
</div>
|
||||
|
||||
<i v-if="loading" class="green sync alternate loading icon"></i>
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide column" v-if="searchParams['noteId'] && attachments.length == 0">
|
||||
|
@ -11,12 +11,16 @@
|
||||
-moz-animation: fadeorama 16s ease infinite;
|
||||
animation: fadeorama 16s ease infinite;
|
||||
}
|
||||
.logo-display {
|
||||
width: 50%;
|
||||
}
|
||||
.lightly-padded {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.massive-text {
|
||||
color: white;
|
||||
font-size: 4rem;
|
||||
text-align: center;
|
||||
}
|
||||
.blinking {
|
||||
animation:blinkingText 1.5s linear infinite;
|
||||
@ -63,6 +67,9 @@
|
||||
}
|
||||
|
||||
/*safari fix - prevents page from being below the menu */
|
||||
.green-text {
|
||||
color: #3710a4;
|
||||
}
|
||||
.dont-pad-me {
|
||||
margin-right: 0 !important;
|
||||
margin-left: 0 !important;
|
||||
@ -101,13 +108,18 @@
|
||||
|
||||
<!-- desktop column - large screen only -->
|
||||
<div class="seven wide middle aligned left aligned column">
|
||||
<h2 class="massive-text">Take Notes, <br>Like Never Before</h2>
|
||||
|
||||
<h2 class="massive-text">
|
||||
<img class="logo-display" loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
|
||||
<br>
|
||||
Solid Scribe
|
||||
</h2>
|
||||
|
||||
<h3 class="subtext">
|
||||
Using an online note application <i class="i cursor icon blinking"></i>
|
||||
Take Notes Like Never Before<i class="i cursor icon blinking"></i>
|
||||
</h3>
|
||||
<p>Assuming you have never used a note application previously in your life.</p>
|
||||
<br>
|
||||
<i class="huge inverted chevron circle down icon"></i>
|
||||
<p class="green-text">Assuming you have never used a note application previously in your life.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="eight wide middle aligned left aligned column">
|
||||
@ -269,7 +281,6 @@
|
||||
<p>
|
||||
If you see anything broken or want to see a feature implemented, I'm open to suggestions. <i class="thumbs up icon"></i>
|
||||
</p>
|
||||
<p>Hero Slide Photo Credit - <a target="_blank" href="https://unsplash.com/@tkaslik14">https://unsplash.com/@tkaslik14</a></p>
|
||||
<p>Generic Marketing Images - <a target="_blank" href="https://undraw.co/">https://unDraw.co/</a></p>
|
||||
</div>
|
||||
<div class="four wide column">
|
||||
@ -291,15 +302,14 @@ export default {
|
||||
realInformation: false,
|
||||
}
|
||||
},
|
||||
beforeMount(){
|
||||
|
||||
|
||||
|
||||
beforeCreate(){
|
||||
//Force HTTPS on prod, always. Dev doesn't have certs
|
||||
const isDev = process.env['NODE_ENV'] == 'development'
|
||||
if (!isDev && location.protocol != 'https:'){
|
||||
window.location.replace('https://www.avidhabit.com')
|
||||
window.location.replace('https://www.solidscribe.com')
|
||||
}
|
||||
},
|
||||
beforeMount(){
|
||||
|
||||
//Don't change hero banner on mobile
|
||||
if(!this.$store.getters.getIsUserOnMobile){
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
<div class="ten wide column" :class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">
|
||||
|
||||
<div class="ui basic button"
|
||||
<div class="ui basic button shrinking"
|
||||
v-on:click="updateFastFilters(3)"
|
||||
v-if="$store.getters.totals && ($store.getters.totals['sharedToNotes'] > 0 || $store.getters.totals['sharedFromNotes'] > 0)"
|
||||
style="position: relative;">
|
||||
@ -24,12 +24,12 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="ui basic button" v-on:click="updateFastFilters(2)" v-if="$store.getters.totals && $store.getters.totals['archivedNotes'] > 0">
|
||||
<div class="ui basic button shrinking" v-on:click="updateFastFilters(2)" v-if="$store.getters.totals && $store.getters.totals['archivedNotes'] > 0">
|
||||
<i class="green archive icon"></i>Archived
|
||||
<!-- <span>{{ $store.getters.totals['archivedNotes'] }}</span> -->
|
||||
</div>
|
||||
|
||||
<div class="ui basic button" v-on:click="updateFastFilters(4)" v-if="$store.getters.totals && $store.getters.totals['encryptedNotes'] > 0">
|
||||
<div class="ui basic button shrinking" v-on:click="updateFastFilters(4)" v-if="$store.getters.totals && $store.getters.totals['encryptedNotes'] > 0">
|
||||
<i class="green lock alternate icon"></i>Locked
|
||||
<!-- <span>{{ $store.getters.totals['encryptedNotes'] }}</span> -->
|
||||
</div>
|
||||
|
@ -12,8 +12,11 @@
|
||||
"body-parser": "^1.18.3",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"express": "^4.16.4",
|
||||
"express-rate-limit": "^5.1.1",
|
||||
"gm": "^1.23.1",
|
||||
"helmet": "^3.21.3",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"module-alias": "^2.2.2",
|
||||
"multer": "^1.4.2",
|
||||
"mysql2": "^1.6.5",
|
||||
"node-tesseract-ocr": "^1.0.0",
|
||||
|
@ -26,6 +26,17 @@ ProcessText.stripBlankHtmlLines = (string) => {
|
||||
return string.replace(/\<p\>\<br\>\<\/p\>/g,'')
|
||||
}
|
||||
|
||||
//Remove Double Empty HTML lines from a string
|
||||
ProcessText.stripDoubleBlankLines = (string) => {
|
||||
|
||||
if(string == undefined || string == null || string.length == 0){
|
||||
return ''
|
||||
}
|
||||
|
||||
//Blank lines look like this -> <p><br></p>
|
||||
return string.replace(/\<p\>\<br\>\<\/p\>\<p\>\<br\>\<\/p\>/g,'')
|
||||
}
|
||||
|
||||
ProcessText.getUrlsFromString = (string) => {
|
||||
const urlPattern = /(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[A-Z0-9+&@#/%=~_|$])/igm
|
||||
return string.match(urlPattern)
|
||||
@ -41,11 +52,16 @@ ProcessText.getUrlsFromString = (string) => {
|
||||
+ If note starts as a list, skip the title
|
||||
*/
|
||||
|
||||
ProcessText.deduceNoteTitle = (inString) => {
|
||||
ProcessText.deduceNoteTitle = (inTitle, inString) => {
|
||||
|
||||
let title = '' //Title of note
|
||||
let title = inTitle //Title of note
|
||||
let sub = '' //sub text below note
|
||||
|
||||
//Always return a title as a String
|
||||
if(title == null){
|
||||
title = ''
|
||||
}
|
||||
|
||||
if(!inString || inString == null || inString.length == 0){
|
||||
return {title, sub}
|
||||
}
|
||||
@ -55,16 +71,17 @@ ProcessText.deduceNoteTitle = (inString) => {
|
||||
|
||||
const tagFreeLength = ProcessText.removeHtml(inString).length
|
||||
|
||||
if(tagFreeLength < 100){
|
||||
sub = ProcessText.stripBlankHtmlLines(inString)
|
||||
return {title, sub}
|
||||
//
|
||||
// Simplified attempt!
|
||||
// Remove tags, push caret if greater than 200 chars...thats it
|
||||
// Still needs, links to open in a new window.
|
||||
|
||||
sub = ProcessText.stripDoubleBlankLines(inString)
|
||||
if(tagFreeLength > 200){
|
||||
sub += '... <i class="green caret down icon"></i>'
|
||||
}
|
||||
|
||||
//Primare Case - Short notes
|
||||
if(tagFreeLength < 300){
|
||||
sub = ProcessText.stripBlankHtmlLines(inString)
|
||||
return {title, sub}
|
||||
}
|
||||
return {title, sub}
|
||||
|
||||
//Emergency ending tag if truncated. This will help regex find all the lines
|
||||
inString += '</end>'
|
||||
@ -87,6 +104,7 @@ ProcessText.deduceNoteTitle = (inString) => {
|
||||
let charLimit = 400
|
||||
let listStart = false
|
||||
let noTitleJustList = false
|
||||
let appendCaret = false
|
||||
|
||||
for(let i=0; i < totalLines; i++){
|
||||
|
||||
@ -167,8 +185,8 @@ ProcessText.deduceNoteTitle = (inString) => {
|
||||
if(cleanCutString.length == 0){
|
||||
cleanCutString = cutString
|
||||
}
|
||||
|
||||
finalLines.push(cleanCutString + '... <i class="green caret down icon"></i>')
|
||||
appendCaret = true
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -176,9 +194,13 @@ ProcessText.deduceNoteTitle = (inString) => {
|
||||
|
||||
}
|
||||
|
||||
if(tagFreeLength.length >= 300 || appendCaret){
|
||||
finalLines.push('... <i class="green caret down icon"></i>')
|
||||
}
|
||||
|
||||
//Pull out title if its not an empty string
|
||||
if(ProcessText.removeHtml(finalLines[0]).trim().replace(' ','').length > 0 && !noTitleJustList){
|
||||
// title = finalLines.shift()
|
||||
if(!noTitleJustList && title == ''){
|
||||
title = ProcessText.removeHtml( finalLines.shift() ).replace(' ','')
|
||||
}
|
||||
|
||||
sub = finalLines.join('')
|
||||
|
@ -3,10 +3,29 @@ require('module-alias/register')
|
||||
|
||||
let Auth = require('@helpers/Auth')
|
||||
|
||||
const helmet = require('helmet')
|
||||
|
||||
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
app.use( helmet() )
|
||||
const port = 3000
|
||||
|
||||
|
||||
//
|
||||
// Request Rate Limiter
|
||||
//
|
||||
const rateLimit = require('express-rate-limit');
|
||||
const limiter = rateLimit({
|
||||
windowMs: 10 * 60 * 1000, // minutes
|
||||
max: 1000 // limit each IP to 100 requests per windowMs
|
||||
});
|
||||
|
||||
// apply to all requests
|
||||
app.use(limiter);
|
||||
|
||||
|
||||
|
||||
var http = require('http').createServer(app);
|
||||
var io = require('socket.io')(http, {
|
||||
path:'/socket'
|
||||
|
@ -512,7 +512,7 @@ Note.solrQuery = (userId, searchQuery, searchTags) => {
|
||||
} else {
|
||||
|
||||
//Number of characters before and after search word
|
||||
const front = 5
|
||||
const front = 20
|
||||
const tail = 150
|
||||
|
||||
db.promise()
|
||||
@ -584,7 +584,7 @@ Note.search = (userId, searchQuery, searchTags, fastFilters) => {
|
||||
let searchParams = [userId]
|
||||
let noteSearchQuery = `
|
||||
SELECT note.id,
|
||||
SUBSTRING(note_raw_text.text, 1, 1500) as text,
|
||||
SUBSTRING(note_raw_text.text, 1, 500) as text,
|
||||
note_raw_text.title as title,
|
||||
note_raw_text.updated as updated,
|
||||
opened,
|
||||
@ -722,15 +722,10 @@ Note.search = (userId, searchQuery, searchTags, fastFilters) => {
|
||||
if(note.encrypted == 1){ note.text = '' }
|
||||
|
||||
//Deduce note title
|
||||
const textData = ProcessText.deduceNoteTitle(note.text)
|
||||
const textData = ProcessText.deduceNoteTitle(note.title, note.text)
|
||||
// console.log(textData)
|
||||
|
||||
// console.log(textData)
|
||||
|
||||
if(note.title == null){
|
||||
note.title = ''
|
||||
}
|
||||
|
||||
note.title = textData.title
|
||||
note.subtext = textData.sub
|
||||
note.titleLength = textData.titleLength
|
||||
note.subtextLength = textData.subtextLength
|
||||
|
@ -5,6 +5,10 @@ let Tag = module.exports = {}
|
||||
Tag.userTags = (userId, searchQuery, searchTags, fastFilters) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if(searchQuery && searchQuery.length > 0){
|
||||
return resolve([])
|
||||
}
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
tag.id,
|
||||
@ -12,7 +16,7 @@ Tag.userTags = (userId, searchQuery, searchTags, fastFilters) => {
|
||||
COUNT(note_tag.note_id) as usages
|
||||
FROM tag
|
||||
JOIN note_tag ON tag.id = note_tag.tag_id
|
||||
JOIN note On note.id = note_tag.note_id
|
||||
JOIN note ON note.id = note_tag.note_id
|
||||
WHERE note_tag.user_id = ?
|
||||
`
|
||||
|
||||
|
BIN
staticFiles/assets/favicon.ico
Normal file → Executable file
BIN
staticFiles/assets/favicon.ico
Normal file → Executable file
Binary file not shown.
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 41 KiB |
Loading…
Reference in New Issue
Block a user