* Adjusted theme colors to add more contrast on white theme while making black more OLED friendly
* Links now get an underline on hover * Cleaned up CSS variable names, added another theme color for more control * Cleaned up unused CSS, removed scrollbars popping up, tons of other little UI tweaks * Renamed shared notes to inbox * Tweaked form display, seperated login and create accouts * Put login/sign up form on home page * Created more legitimate marketing for home page * Tons up updates to note page and note input panel * Better support for two users editing a note * MUCH better diff handling, web sockets restore notes with unsaved diffs * Moved all squire text modifier functions into a mixin class * It now says saving when closing a note * Lots of cleanup and better handiling of events on mount and destroy * Scroll behavior modified to load notes when closer to bottom of page * Pretty decent shared notes and sharable link support * Updated help text * Search now includes tag suggestions and attachment suggestions * Cleaned up scratch pad a ton, allow for users to create new scratch pads * Created a 404 Page and a Shared note page * So many other small improvements. Oh my god, what is wrong with me, not doing commits!?
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
<!-- Content copied from note -->
|
||||
<!-- https://www.solidscribe.com/#/notes/open/552 -->
|
||||
|
||||
<p><b>Every Note is Encrypted</b><br></p><p>Only you can read your notes. Even if every note in the database was leaked, nothing would be readable. If the government asked for your notes, it would all be gibberish. <br></p><p><br></p><p><b>Some Data is not encrypted</b><br></p><p>Everything isn't encrypted, to keep up ease of use. Files, Tags and Attachments are not encrypted.<br></p><p><br></p><p><b>Searching is somewhat limited</b><br></p><p>Since every note is encrypted, searching is limited. To maintain security, only single words can be searched. Your search index is private and Encrypted.<br></p><p><br></p><p><b>Quick Note</b><br></p><p>The Quick note feature was designed to allow rapid input to a single note. Rather than junking up all your notes with random links, numbers or haikus, you can put them all in one place. <br></p><p>All data pushed to the quick note can still be edited like a normal note.<br></p><p><br></p><p><b>Dark Theme</b><br></p><p>Dark theme was designed to minimize the amount of blue. Less blue entering your eyes is supposed to help you fall asleep.<br></p><p>Most things turn sepia and a filter is applied to images to make them more sepia.<br></p><p>Here is some good research on the topic: <a href="https://justgetflux.com/research.html">https://justgetflux.com/research.html</a><br></p><p><br></p><p><b>Password Protected Notes</b><br></p><p>Note protected with a password are encrypted. This means the data is scrambled and unreadable unless the correct password is used to decrypt them.<br></p><p>If a password is forgotten, it can never be recovered. Passwords are not saved for encrypted notes. If you lose the password to a protected note, that note text is lost. <br></p><p>Only the text of the note is protected. Tags, Files attached to the note, and the title of the note are still visible without a password. You can not search text in a password protected note. But you can search by the title.<br></p><p><br></p><p><b>Links in notes</b><br></p><p>Links put into notes are automatically scraped. This means the data from the link will be scanned to get an image and some text from the website to help make that link more accessible in the future. <br></p><p><br></p><p><b>Files in notes</b><br></p><p>Files can be uploaded to notes. If its an image, the picture will be put into the note.<br></p><p>Images added to notes will have the text pulled out so it can be searched (This isn't super accurate so don't rely to heavily on it.) The text can be updated at any time.<br></p><p><br></p><p><b>Deleting notes</b><br></p><p>When<b> </b>notes are deleted, none of the files related to the note are deleted. <br></p><p><br></p><p><b>Daily Backups</b><br></p><p>All notes are backed up, every night, at midnight. If there is data loss, it can be restored from a backup. If you experience some sort of cataclysmic data loss please contact the system administrator for a copy of your data or a restoration procedure. <br></p>
|
||||
<p><b>Only Note Text is Encrypted</b><br></p><p>Only you can read your notes. Encryption is the transformation of data into a form unreadable by anyone without the password. Its purpose is to ensure privacy by keeping the information hidden from anyone for whom it is not intended, even those who can see the encrypted data. Even if every note in the database was leaked, nothing would be readable. If the government asked for your notes, it would all be gibberish. <br></p><p><br></p><p><b>Some Data is not encrypted</b><br></p><p>Everything isn't encrypted, to keep up ease of use. Files, Tags and Attachments are not encrypted.<br></p><p><br></p><p><b>Searching is somewhat limited</b><br></p><p>Since every note is encrypted, searching is limited. To maintain security, only single words can be searched. Your search index is private and Encrypted.<br></p><p><br></p><p><b>The Scrat</b><b></b><b>ch Pad</b><b></b><br></p><p>The Scratch Pad was designed to allow rapid input to a single note. Rather than junking up all your notes with random links, numbers or haikus, you can put them all in one place. <br></p><ul><li>All data pushed to the quick note can still be edited like a normal note.<br></li><li>Creating a new quick note will not erase your old <br></li></ul><p><br></p><p><b>Flux Theme</b><br></p><p>Flux theme limits the amount of blue emitted by your screen. Most things turn sepia and a filter is applied to images to make them more sepia. Less blue light at night is supposed to be helpful for falling asleep.<br></p><p>Here is some good research on the topic: <a href="https://justgetflux.com/research.html">https://justgetflux.com/research.html</a><br></p><p><br></p><p><b>Keyboard Shor</b><b></b><b>tcuts</b><br></p><p>Number List - CTRL + SHIFT + 9<br></p><p>Todo List - CTRL + SHIFT + 8<br></p><p>Underline CTRL + u<br></p><p>Bold - CTRL + b<br></p><p>Quote - CRTL + i<br></p><p>Indent - CTL + ]<br></p><p>Outdent - CRTL + [<br></p><p>Undo - CTRL + z<br></p><p>Redo - CTRL + y<br></p><p><br></p><p><b>Links in notes</b><br></p><p>Links put into notes are automatically scraped. This means the data from the link will be scanned to get an image and some text from the website to help make that link more accessible in the future. You can edit the text of scarped links and any time and search for it later. <br></p><p><br></p><p><b>Files in notes</b><br></p><p>Files can be uploaded to notes. If its an image, the picture will be put into the note.<br></p><p>Images added to notes will have text scanned, so it can be searched (This isn't super accurate so don't rely to heavily on it.) The text can be updated at any time.<br></p><p><br></p><p><b>Deleting notes</b><br></p><p>When<b> </b>notes are deleted, none of the files related to the note are deleted. <br></p><p><br></p><p><b>Daily Backups</b><br></p><p>All notes are backed up, every night, at midnight. If there is data loss, it can be restored from a backup. If you experience some sort of cataclysmic data loss please contact the system administrator for a copy of your data or a restoration procedure. <br></p>
|
||||
|
||||
<!-- content copied from note -->
|
||||
</div>
|
||||
|
@@ -78,6 +78,10 @@
|
||||
.home-main img {
|
||||
max-height: 400px !important;
|
||||
}
|
||||
.white-link {
|
||||
text-decoration: underline;
|
||||
color: white;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -120,7 +124,7 @@
|
||||
</h2>
|
||||
|
||||
<h3 class="subtext">
|
||||
An easy, free, secure Note App<i class="i cursor icon blinking"></i>
|
||||
A free, secure Note App<i class="i cursor icon blinking"></i>
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
@@ -146,7 +150,7 @@
|
||||
<div class="ui text container">
|
||||
<h2>
|
||||
<i class="plug icon"></i>
|
||||
Sign Up Now - Only a Username and Password are required.</h2>
|
||||
Sign Up Now - Only a Username and Password required</h2>
|
||||
<login-form :thin="true" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -155,7 +159,7 @@
|
||||
<!-- set -->
|
||||
<div class="middle aligned centered row">
|
||||
<div class="six wide right aligned column">
|
||||
<h2>Solid Scribe is an online note application that focuses on ease of use and security</h2>
|
||||
<h2>Solid Scribe is a browser based note application that focuses on ease of use while keeping your data private</h2>
|
||||
<h3>Tools to organize and collaborate on notes while maintaining security and respecting your privacy.</h3>
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
@@ -163,24 +167,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="middle aligned centered row">
|
||||
<div class="middle aligned centered green row">
|
||||
<div class="six wide right aligned column">
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/gardening.svg" alt="Pruning the mind garden">
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/secure.svg" alt="marketing mumbo jumbo">
|
||||
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
<h2>Tools to organize thousands of notes</h2>
|
||||
<h3>Tag, Pin, Color, Archive, Attach Images and Search notes or links in notes</h3>
|
||||
<h2>All Note text is encrypted</h2>
|
||||
<h3>Only you can read your notes. <a class="white-link" target="_blank" href="https://www.forbes.com/sites/zakdoffman/2019/01/30/facebook-has-just-been-caught-spying-on-users-private-messages-and-data-again/#1e27e00a31ce"> Employees can not snoop your account</a>. <a class="white-link" target="_blank" href="https://mashable.com/article/google-reading-your-emails-response/">No one can read your data for advertising</a>. Note text is completely unreadable without your password.</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- set -->
|
||||
<div class="middle aligned centered green row">
|
||||
<div class="middle aligned centered row">
|
||||
<div class="six wide column">
|
||||
<h2>Privacy through Encryption</h2>
|
||||
<h3>All notes are encrypted. No one can read your notes, even if they steal the data from the database.</h3>
|
||||
<h2>Organize your notes</h2>
|
||||
<h3>Tag, Pin, Color, Archive, Attach Images, Share Encrypted Notes and Search</h3>
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/secure.svg" alt="marketing mumbo jumbo">
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/gardening.svg" alt="Pruning the mind garden">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -189,7 +194,7 @@
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/cloud.svg" alt="Girl falling into the spiral of digital chaos">
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
<h2>Extremely accessible</h2>
|
||||
<h2>Extremely accessible - Nothing to install</h2>
|
||||
<h3>Works on mobile or desktop browsers. <br>Behaves like an installed app on mobile phones.</h3>
|
||||
</div>
|
||||
</div>
|
||||
@@ -198,7 +203,7 @@
|
||||
<div class="middle aligned centered row">
|
||||
<div class="six wide right aligned column">
|
||||
<h2>Secure Search</h2>
|
||||
<h3>Keyword search using an encrypted search index helps you find what you need without compromising security</h3>
|
||||
<h3>Keyword search using an encrypted search index helps you find what you need without compromising security.</h3>
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/solution.svg" alt="Hypercube of Solutions">
|
||||
@@ -210,16 +215,16 @@
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/plan.svg" alt="Scheme for planetary destruction">
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
<h2>Embrace the Void</h2>
|
||||
<h3>Remove unnecessary clutter for your brain and save it to the cloud, allowing you to easily embrace the gaping abyss</h3>
|
||||
<h2>Create Lists with Check Boxes</h2>
|
||||
<h3>Todo lists are supported. With options to removed checked items, sort by completed and un-check all.</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- set -->
|
||||
<div class="middle aligned centered row">
|
||||
<div class="six wide right aligned column">
|
||||
<h2>Space for Growth</h2>
|
||||
<h3>Groom a clear path for new expressions and innovations. Elevate your being and lower your cholesterol</h3>
|
||||
<h2>Powerful Text Editing</h2>
|
||||
<h3>A plethora of editing tools are provided for coloring, underlining, bolding, attaching images and more.</h3>
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/growth.svg" alt="Endless progress at the cost of sanity and health">
|
||||
@@ -231,13 +236,13 @@
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/onboarding.svg" alt="Shrunken man near giant tablet">
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
<h2>Become your Data</h2>
|
||||
<h3>We exist as electrical impulses, no different from data on a computer</h3>
|
||||
<h2>Secure Data Sharing</h2>
|
||||
<h3>Share notes with friends without compromising privacy. The data remains encrypted with a shared password for you and people you invite to view it.</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- set -->
|
||||
<div class="middle aligned centered row">
|
||||
<!-- <div class="middle aligned centered row">
|
||||
<div class="six wide right aligned column">
|
||||
<h2>Ice Cream</h2>
|
||||
<h3>Get excited without all the screaming</h3>
|
||||
@@ -265,7 +270,7 @@
|
||||
<div class="six wide column">
|
||||
<img loading="lazy" width="100%" src="/api/static/assets/marketing/grandma.svg" alt="Drinking the blood of the elderly">
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- final slide -->
|
||||
<div class="middle aligned centered green row">
|
||||
@@ -282,20 +287,18 @@
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
OR
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<span class="ui button" v-on:click="showRealInformation">View real information about this site</span>
|
||||
<span class="ui button" v-on:click="showRealInformation">About</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="realInformation" class="middle aligned centered row" ref="real">
|
||||
<div class="six wide column">
|
||||
<h2 class="ui center aligned">
|
||||
What is this really?
|
||||
Why Does this App exist?
|
||||
</h2>
|
||||
<h3>Its just a little web app for taking notes. This page is mocking the "over the top" marketing sites use to sell their products.</h3>
|
||||
<p>
|
||||
This App exists because I was tired of all my data being owned by big companies, having it farmed out for marketing, and leaving the contents of my life exposed to corporations.
|
||||
</p>
|
||||
|
@@ -10,7 +10,7 @@
|
||||
<div class="ui text container">
|
||||
|
||||
|
||||
<div class="ui segment" v-on:keyup.enter="submit">
|
||||
<div class="ui segment">
|
||||
|
||||
<h4 class="ui header">
|
||||
<i class="plug icon"></i>
|
||||
@@ -44,53 +44,10 @@
|
||||
data () {
|
||||
return {
|
||||
enabled: false,
|
||||
username: '',
|
||||
password: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit(){
|
||||
|
||||
//Both fields are required
|
||||
if(this.username <= 0){
|
||||
return false
|
||||
}
|
||||
if(this.password <= 0){
|
||||
return false
|
||||
}
|
||||
|
||||
let vm = this
|
||||
|
||||
let data = {
|
||||
username: this.username,
|
||||
password: this.password
|
||||
}
|
||||
|
||||
axios.post('/api/user/login', data)
|
||||
.then(response => {
|
||||
if(response.data.success){
|
||||
|
||||
const token = response.data.token
|
||||
const username = response.data.username
|
||||
const masterKey = response.data.masterKey
|
||||
|
||||
this.$store.commit('setLoginToken', {token, username, masterKey})
|
||||
|
||||
//Setup socket io after user logs in
|
||||
this.$io.emit('user_connect', token)
|
||||
|
||||
//Redirect user to notes section after login
|
||||
this.$router.push('/notes')
|
||||
} else {
|
||||
// this.password = ''
|
||||
this.$bus.$emit('notification', 'Incorrect Username or Password')
|
||||
vm.$store.commit('destroyLoginToken')
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.$bus.$emit('notification', 'Incorrect Username or Password')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
30
client/src/pages/NotFoundPage.vue
Normal file
30
client/src/pages/NotFoundPage.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div class="ui basic segment">
|
||||
<div class="ui grid">
|
||||
<div class="sixteen wide column">
|
||||
<div class="ui text container">
|
||||
|
||||
<h2 class="ui dividing header">
|
||||
Page Not Found
|
||||
</h2>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NotFoundPage',
|
||||
props:[ 'message' ],
|
||||
data () {
|
||||
return {
|
||||
items: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
@@ -7,27 +7,19 @@
|
||||
<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
|
||||
|
||||
<div class="ui stackable grid">
|
||||
|
||||
<div class="six wide column" v-if="$store.getters.totals && $store.getters.totals['totalNotes']">
|
||||
<search-input />
|
||||
</div>
|
||||
|
||||
<div class="ten wide column"
|
||||
:class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">
|
||||
<div class="ten wide column" :class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">
|
||||
|
||||
<div class="ui basic button shrinking"
|
||||
v-on:click="updateFastFilters(3)"
|
||||
v-if="$store.getters.totals && ($store.getters.totals['sharedToNotes'] > 0 || $store.getters.totals['sharedFromNotes'] > 0)"
|
||||
v-if="$store.getters.totals && ($store.getters.totals['youGotMailCount'] > 0)"
|
||||
style="position: relative;">
|
||||
<i class="green mail icon"></i>Shared Notes
|
||||
<span class="floating ui green label" v-if="$store.getters.totals['unreadNotes'] > 0">
|
||||
{{ $store.getters.totals['unreadNotes'] }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="ui basic button shrinking" v-on:click="updateFastFilters(2)" v-if="$store.getters.totals && $store.getters.totals['archivedNotes'] > 0">
|
||||
<i class="green archive icon"></i>Archived
|
||||
<!-- <span>{{ $store.getters.totals['archivedNotes'] }}</span> -->
|
||||
</div>
|
||||
|
||||
<div class="ui basic icon button shrinking" v-on:click="updateFastFilters(4)" v-if="$store.getters.totals && $store.getters.totals['trashedNotes'] > 0">
|
||||
<i class="trash alternate outline icon"></i>
|
||||
<i class="green mail icon"></i>Inbox
|
||||
+{{ $store.getters.totals['youGotMailCount'] }}
|
||||
</div>
|
||||
|
||||
<tag-display
|
||||
@@ -42,12 +34,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="six wide column">
|
||||
<search-input
|
||||
v-on:tagClick="tagId => toggleTagFilter(tagId)"
|
||||
v-if="$store.getters.totals && $store.getters.totals['totalNotes']" />
|
||||
</div>
|
||||
|
||||
<div class="eight wide column" v-if="showClear">
|
||||
<!-- <fast-filters /> -->
|
||||
<span class="ui fluid green button" @click="reset">
|
||||
@@ -75,7 +61,7 @@
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide column" v-if="fastFilters['onlyShowTrashed'] == 1">
|
||||
<h2 >Trash
|
||||
<h2>Trash
|
||||
<span>({{ $store.getters.totals['trashedNotes'] }})</span>
|
||||
<div class="ui right floated basic button" data-tooltip="This doesn't work yet">
|
||||
<i class="poo storm icon"></i>
|
||||
@@ -88,6 +74,25 @@
|
||||
<h2>Shared Notes</h2>
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide column" v-if="tagSuggestions.length > 0">
|
||||
<h5 class="ui tiny dividing header"><i class="green tags icon"></i> Tags ({{ tagSuggestions.length }})</h5>
|
||||
<div class="ui clickable green label" v-for="tag in tagSuggestions" v-on:click="tagId => toggleTagFilter(tag.id)">
|
||||
<i class="tag icon"></i>
|
||||
{{ tag.text }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- found attachments -->
|
||||
<div class="sixteen wide column" v-if="foundAttachments.length > 0">
|
||||
<h5 class="ui tiny dividing header"><i class="green folder open outline icon"></i> Files ({{ foundAttachments.length }})</h5>
|
||||
<attachment-display
|
||||
v-for="item in foundAttachments"
|
||||
:item="item"
|
||||
:key="item.id"
|
||||
:search-params="{}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Note title card display -->
|
||||
<div class="sixteen wide column">
|
||||
|
||||
@@ -123,18 +128,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- found attachments -->
|
||||
<div class="sixteen wide column" v-if="foundAttachments.length > 0">
|
||||
<h4><i class="folder open outline icon"></i> Found in Files ({{ foundAttachments.length }})</h4>
|
||||
<attachment-display
|
||||
v-for="item in foundAttachments"
|
||||
:item="item"
|
||||
:key="item.id"
|
||||
:search-params="{}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -170,7 +163,7 @@
|
||||
data () {
|
||||
return {
|
||||
initComponent: true,
|
||||
commonTags: [],
|
||||
tagSuggestions:[],
|
||||
searchTerm: '',
|
||||
searchResultsCount: 0,
|
||||
searchTags: [],
|
||||
@@ -191,13 +184,6 @@
|
||||
//Clear button is not visible
|
||||
showClear: false,
|
||||
initialPostData: null,
|
||||
currentPostData: null,
|
||||
|
||||
containsNormalNotes: 0,
|
||||
containsPinnednotes: 0,
|
||||
containsTextResults: 0,
|
||||
// containsTagResults: 0,
|
||||
// containsAttachmentResults: 0,
|
||||
|
||||
//Currently open notes in app
|
||||
activeNoteId1: null,
|
||||
@@ -214,8 +200,8 @@
|
||||
sectionData: {
|
||||
'pinned': ['thumbtack', 'Pinned'],
|
||||
'archived': ['archive', 'Archived'],
|
||||
'shared': ['envelope outline', 'Received Notes'],
|
||||
'sent': ['paper plane outline', 'Shared Notes'],
|
||||
'shared': ['envelope outline', 'Inbox'],
|
||||
'sent': ['paper plane outline', 'Sent Notes'],
|
||||
'notes': ['file','Notes'],
|
||||
'highlights': ['paragraph', 'Found In Text'],
|
||||
'trashed': ['poop', 'Trashed Notes'],
|
||||
@@ -275,13 +261,12 @@
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
|
||||
//Close note event
|
||||
this.$bus.$on('close_active_note', ({position, noteId, modified}) => {
|
||||
this.$bus.$on('close_active_note', ({noteId, modified}) => {
|
||||
|
||||
this.closeNote()
|
||||
if(modified){
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
this.updateSingleNote(parseInt(noteId))
|
||||
}
|
||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||
//Focus and animate if modified
|
||||
this.updateSingleNote(parseInt(noteId), modified)
|
||||
})
|
||||
|
||||
this.$bus.$on('note_deleted', (noteId) => {
|
||||
@@ -295,15 +280,12 @@
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
this.$bus.$on('update_fast_filters', newFilter => {
|
||||
this.fastFilters = newFilter
|
||||
//Fast filters always return all the results and tags
|
||||
this.search(true, this.batchSize, false).then( () => {
|
||||
// return
|
||||
})
|
||||
this.$bus.$on('update_fast_filters', filterIndex => {
|
||||
|
||||
this.updateFastFilters(filterIndex)
|
||||
})
|
||||
|
||||
//Event to update search from other areas
|
||||
@@ -312,8 +294,18 @@
|
||||
this.search(true, this.batchSize)
|
||||
.then( () => {
|
||||
|
||||
console.log('Search attachments disabled for now')
|
||||
// this.searchAttachments()
|
||||
this.searchAttachments()
|
||||
|
||||
const postData = {
|
||||
'tagText':this.searchTerm.trim()
|
||||
}
|
||||
|
||||
this.tagSuggestions = []
|
||||
axios.post('/api/tag/suggest', postData)
|
||||
.then( response => {
|
||||
|
||||
this.tagSuggestions = response.data
|
||||
})
|
||||
|
||||
// return
|
||||
})
|
||||
@@ -365,6 +357,9 @@
|
||||
|
||||
//Loads initial batch and tags
|
||||
this.reset()
|
||||
|
||||
// this.search(true, this.firstLoadBatchSize, false)
|
||||
// .then( r => this.search(false, this.batchSize, true))
|
||||
},
|
||||
methods: {
|
||||
toggleTitleView(){
|
||||
@@ -390,7 +385,7 @@
|
||||
if(this.activeNoteId1 == null){
|
||||
this.activeNoteId1 = id
|
||||
this.activeNote1Position = 0 //Middel of page
|
||||
this.$router.push('/notes/open/'+this.activeNoteId1)
|
||||
this.$router.push('/notes/open/'+this.activeNoteId1).catch(e => { console.log(e) })
|
||||
return
|
||||
}
|
||||
},
|
||||
@@ -417,24 +412,18 @@
|
||||
clearTimeout(this.loadingBatchTimeout)
|
||||
this.loadingBatchTimeout = setTimeout(() => {
|
||||
|
||||
//Distance to bottom of page
|
||||
const bottomOfWindow =
|
||||
Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop)
|
||||
+ window.innerHeight
|
||||
//Detect distance scrolled down the page
|
||||
const scrolledDown = window.pageYOffset + window.innerHeight
|
||||
//Get height of div to properly detect scroll distance down
|
||||
const height = document.getElementById('app').scrollHeight
|
||||
|
||||
//height of page
|
||||
const offsetHeight = this.$refs.content.clientHeight
|
||||
|
||||
//Determine percentage down the page
|
||||
const percentageDown = Math.round( (bottomOfWindow/offsetHeight)*100 )
|
||||
|
||||
//If greater than 80 of the way down the page, load the next batch
|
||||
if(percentageDown >= 65 && this.scrollLoadEnabled){
|
||||
//Load if less than 500px from the bottom
|
||||
if(((height - scrolledDown) < 500) && this.scrollLoadEnabled && !this.loadingInProgress){
|
||||
|
||||
this.search(false, this.batchSize, true)
|
||||
}
|
||||
|
||||
}, 50)
|
||||
}, 30)
|
||||
|
||||
|
||||
return
|
||||
@@ -491,7 +480,10 @@
|
||||
noteId = parseInt(noteId)
|
||||
|
||||
//Find local note, if it exists; continue
|
||||
|
||||
let note = null
|
||||
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0] && this.$refs['note-'+noteId][0].note){
|
||||
note = this.$refs['note-'+noteId][0].note
|
||||
}
|
||||
|
||||
//Lookup one note using passed in ID
|
||||
const postData = {
|
||||
@@ -508,60 +500,62 @@
|
||||
|
||||
//Pull note data out of note set
|
||||
let newNote = results.data.notes[0]
|
||||
let foundNote = false
|
||||
|
||||
if(newNote === undefined){
|
||||
return
|
||||
}
|
||||
|
||||
//Find Just updated note and modify all its attributes
|
||||
Object.keys(this.noteSections).forEach(key => {
|
||||
if(note && newNote){
|
||||
|
||||
this.noteSections[key].forEach( (note,index) => {
|
||||
//Don't move notes that were not changed
|
||||
if(note.updated == newNote.updated){
|
||||
return
|
||||
}
|
||||
|
||||
if(note.id == noteId){
|
||||
foundNote = true
|
||||
//go through each prop and update it with new values
|
||||
Object.keys(newNote).forEach(prop => {
|
||||
note[prop] = newNote[prop]
|
||||
})
|
||||
|
||||
//Don't move notes that were not changed
|
||||
if(note.updated == newNote.updated){
|
||||
// return
|
||||
}
|
||||
//Push new note to front if its modified
|
||||
if(focuseAndAnimate){
|
||||
|
||||
//Compare note tags, if they changed, reload tags
|
||||
if(newNote.tag_count != note.tag_count){
|
||||
|
||||
}
|
||||
|
||||
//go through each prop and update it with new values
|
||||
Object.keys(newNote).forEach(prop => {
|
||||
note[prop] = newNote[prop]
|
||||
})
|
||||
|
||||
//Remove note from location and push to front
|
||||
this.noteSections[key].splice(index, 1)
|
||||
this.noteSections[key].unshift(note)
|
||||
|
||||
this.$nextTick( () => {
|
||||
|
||||
//Trigger close animation on note
|
||||
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0] && focuseAndAnimate){
|
||||
this.$refs['note-'+noteId][0].justClosed()
|
||||
// Find note, in section, move to front
|
||||
Object.keys(this.noteSections).forEach( key => {
|
||||
this.noteSections[key].forEach( (searchNote, index) => {
|
||||
if(searchNote.id == noteId){
|
||||
//Remove note from location and push to front
|
||||
this.noteSections[key].splice(index, 1)
|
||||
this.noteSections[key].unshift(note)
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
this.$nextTick( () => {
|
||||
//Trigger close animation on note
|
||||
this.$refs['note-'+noteId][0].justClosed()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//New notes don't exist in list, push them to the front
|
||||
if(!foundNote){
|
||||
if(note == null){
|
||||
this.noteSections.notes.unshift(newNote)
|
||||
//Trigger close animation on note
|
||||
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
||||
this.$refs['note-'+noteId][0].justClosed()
|
||||
}
|
||||
}
|
||||
|
||||
//Trigger section rebuild
|
||||
this.rebuildNoteCategorise()
|
||||
})
|
||||
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Notes') })
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
this.$bus.$emit('notification', 'Failed to Update Note')
|
||||
})
|
||||
},
|
||||
searchAttachments(){
|
||||
axios.post('/api/attachment/textsearch', {'searchTerm':this.searchTerm})
|
||||
@@ -570,13 +564,13 @@
|
||||
})
|
||||
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Attachments') })
|
||||
},
|
||||
search(showLoading = true, notesInNextLoad = null, mergeExisting = false){
|
||||
search(showLoading = true, notesInNextLoad = 10, mergeExisting = false){
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
//Don't double load note batches
|
||||
if(this.loadingInProgress){
|
||||
console.log('Loading in progress, cancel operation')
|
||||
return resolve()
|
||||
console.log('Loading already in progress')
|
||||
return resolve(false)
|
||||
}
|
||||
|
||||
//Reset a lot of stuff if we are not merging batches
|
||||
@@ -585,7 +579,6 @@
|
||||
this.noteSections[key] = []
|
||||
})
|
||||
this.batchOffset = 0 // Reset batch offset if we are not merging note batches
|
||||
// this.commonTags = [] //Don't reset tags, if search returns tags, they will be set
|
||||
}
|
||||
this.searchResultsCount = 0
|
||||
|
||||
@@ -628,11 +621,6 @@
|
||||
//Enable or disable scroll loading
|
||||
this.scrollLoadEnabled = response.data.notes.length > 0
|
||||
|
||||
//Mush the two new sets of data together (set will be empty is reset is on)
|
||||
// if(response.data.tags.length > 0){
|
||||
// this.commonTags = response.data.tags
|
||||
// }
|
||||
|
||||
if(response.data.total > 0){
|
||||
this.searchResultsCount = response.data.total
|
||||
}
|
||||
@@ -742,33 +730,22 @@
|
||||
this.scrollLoadEnabled = true
|
||||
this.searchTerm = ''
|
||||
this.searchTags = []
|
||||
this.tagSuggestions = []
|
||||
this.fastFilters = {}
|
||||
this.updateFastFilters(5)
|
||||
this.foundAttachments = [] //Remove all attachments
|
||||
this.$bus.$emit('reset_fast_filters')
|
||||
|
||||
//Load initial batch, then tags, then other batch
|
||||
this.search(true, this.firstLoadBatchSize)
|
||||
.then( () => {
|
||||
//Load a larger batch once first batch has loaded
|
||||
return this.search(false, this.batchSize, true)
|
||||
})
|
||||
this.$bus.$emit('reset_fast_filters')
|
||||
this.updateFastFilters(5) //This loads notes
|
||||
|
||||
},
|
||||
updateFastFilters(index){
|
||||
|
||||
//clear out tags
|
||||
this.searchTags = []
|
||||
this.tagSuggestions = []
|
||||
this.loadingInProgress = false
|
||||
this.searchTerm = ''
|
||||
this.$bus.$emit('reset_fast_filters')
|
||||
|
||||
//A little hacky, brings user to notes page then filters on click
|
||||
if(this.$route.name != 'Note Page'){
|
||||
this.$router.push('/notes')
|
||||
setTimeout( () => {
|
||||
this.updateFastFilters(index)
|
||||
}, 500 )
|
||||
}
|
||||
this.$bus.$emit('reset_fast_filters') //Clear out search
|
||||
|
||||
const options = [
|
||||
'withLinks', // 'Only Show Notes with Links'
|
||||
@@ -782,7 +759,10 @@
|
||||
let filter = {}
|
||||
filter[options[index]] = 1
|
||||
|
||||
this.$bus.$emit('update_fast_filters', filter)
|
||||
this.fastFilters = filter
|
||||
//Fetch First batch of notes with new filter
|
||||
this.search(true, this.firstLoadBatchSize, false)
|
||||
.then( r => this.search(false, this.batchSize, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -12,11 +12,11 @@
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide middle aligned column">
|
||||
<div class="sixteen wide middle aligned column" v-if="quickNoteId > 0">
|
||||
|
||||
<div class="ui compact basic right floated button shrinking" v-if="!showNewNoteConfirm" v-on:click="showNewNoteConfirm = true">
|
||||
<i class="sync alternate reload icon"></i>
|
||||
New Quick Note
|
||||
New Scratch Pad
|
||||
</div>
|
||||
<div v-if="showNewNoteConfirm" class="ui compact basic right floated button shrinking" v-on:click="showNewNoteConfirm = false">
|
||||
<i class="close icon"></i>
|
||||
|
@@ -1,9 +1,49 @@
|
||||
<template>
|
||||
<div class="ui basic segment">
|
||||
<div class="ui container">
|
||||
<div class="fun" :style="{'color':color}" v-if="noteText" v-html="noteText"></div>
|
||||
<div class="ui grid">
|
||||
|
||||
<div class="sixteen wide column"></div>
|
||||
|
||||
<div class="sixteen wide column" v-if="text.length > 0 || title.length > 0">
|
||||
<div class="ui text container squire-box" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
|
||||
|
||||
<h1 v-if="title">{{title}}</h1>
|
||||
|
||||
<div v-if="text" v-html="text"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui basic segment"></div>
|
||||
|
||||
<div class="sixteen wide column" v-if="!$store.getters.getLoggedIn">
|
||||
<div class="ui text container">
|
||||
<h2 class="ui header">
|
||||
<img class="small-logo" loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
|
||||
<div class="content">
|
||||
Solid Scribe is an easy, free, secure Note App
|
||||
<div class="sub header">
|
||||
Encrypted notes, only readable by you. Unless you share them.
|
||||
</div>
|
||||
</div>
|
||||
</h2>
|
||||
<div class="ui grid">
|
||||
<div class="eight wide center aligned column">
|
||||
<router-link class="ui compact green button" to="/login">
|
||||
<i class="plug icon"></i>Sign Up
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="eight wide center aligned column">
|
||||
<router-link class="ui compact green button" to="/">
|
||||
<i class="comment outline icon"></i>
|
||||
Learn More
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui sixteen wide center aligned column">
|
||||
<h4>{{ failText }}</h4>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -15,36 +55,51 @@
|
||||
name: 'SharePage',
|
||||
data(){
|
||||
return {
|
||||
noteText: null,
|
||||
color: '#000'
|
||||
title: '',
|
||||
text: '',
|
||||
failText: '',
|
||||
styleObject:{},
|
||||
}
|
||||
},
|
||||
beforeMount(){
|
||||
//Mount notes on load if note ID is set
|
||||
if(this.$route.params && this.$route.params.id){
|
||||
const id = this.$route.params.id
|
||||
this.openNote(id)
|
||||
}
|
||||
|
||||
//You can put something here for live updates
|
||||
// this.$io.on
|
||||
|
||||
this.openNote()
|
||||
|
||||
},
|
||||
methods:{
|
||||
openNote(noteId){
|
||||
axios.post('/api/public/note', {'noteId': noteId})
|
||||
.then( response => {
|
||||
fail(){
|
||||
this.failText = 'Failed to open Shared Note'
|
||||
this.$bus.$emit('notification', 'Failed to Open Shared Note')
|
||||
},
|
||||
openNote(){
|
||||
|
||||
let colors = JSON.parse(response.data.color)
|
||||
const noteId = this.$route.params.id
|
||||
const sharedKey = this.$route.params.token
|
||||
|
||||
if(colors && colors.noteBackground){
|
||||
document.body.style.background = colors.noteBackground
|
||||
axios.post('/api/public/opensharednote', {noteId, sharedKey})
|
||||
.then( ({data}) => {
|
||||
|
||||
if(data.success){
|
||||
this.title = data.title
|
||||
this.text = data.text
|
||||
this.styleObject = data.styleObject
|
||||
} else {
|
||||
this.fail()
|
||||
}
|
||||
if(colors && colors.noteText){
|
||||
this.color = colors.noteText
|
||||
}
|
||||
|
||||
this.noteText = response.data.text
|
||||
})
|
||||
.catch(error => { this.$bus.$emit('notification', 'Failed to Open Public Note') })
|
||||
.catch(error => { this.fail() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<style type="text/css" scoped>
|
||||
.small-logo {
|
||||
width: 30px;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user