Added privacy policy
Updated marketing Added some keyboard shortcuts Added settings page Added accent theming Added beta 2FA
This commit is contained in:
@@ -97,6 +97,12 @@ export default {
|
||||
//Detect if user is on a mobile browser and set a flag in store
|
||||
this.$store.commit('detectIsUserOnMobile')
|
||||
|
||||
//Set Main theme color
|
||||
const accentColor = localStorage.getItem('main-accent')
|
||||
if(accentColor){
|
||||
document.documentElement.style.setProperty('--main-accent', accentColor)
|
||||
}
|
||||
|
||||
//Set color theme based on local storage
|
||||
const themeNumber = localStorage.getItem('nightMode')
|
||||
if(themeNumber != null){
|
||||
|
@@ -4,6 +4,10 @@ const helpers = {}
|
||||
|
||||
helpers.timeAgo = (time) => {
|
||||
|
||||
if(time == null){
|
||||
time = Math.round(time/1000)
|
||||
}
|
||||
|
||||
if(time.toString().length >= 13){
|
||||
time = Math.round(time/1000)
|
||||
}
|
||||
|
@@ -18,7 +18,8 @@
|
||||
|
||||
:root {
|
||||
|
||||
--main-accent: #16ab39;
|
||||
/*main accent for all buttons, icons and logos*/
|
||||
--main-accent: #21BA45;
|
||||
|
||||
/*theme colors */
|
||||
--body_bg_color: #f5f6f7;
|
||||
@@ -105,7 +106,7 @@ div.ui.basic.green.label {
|
||||
background-color: var(--small_element_bg_color) !important;
|
||||
}
|
||||
.ui.basic.button, .ui.basic.buttons .button {
|
||||
background-color: var(--small_element_bg_color) !important;
|
||||
background-color: var(--small_element_bg_color);
|
||||
color: var(--text_color) !important;
|
||||
border: 1px solid;
|
||||
border-color: var(--dark_border_color) !important;
|
||||
@@ -125,6 +126,24 @@ div.ui.basic.green.label {
|
||||
color: var(--text_color) !important;
|
||||
border-color: var(--dark_border_color) !important;
|
||||
}
|
||||
/*Overwrites for modifiable theme color */
|
||||
i.green.icon.icon.icon.icon {
|
||||
color: var(--main-accent);
|
||||
}
|
||||
.ui.green.buttons, .ui.green.button, .ui.green.button:hover {
|
||||
background-color: var(--main-accent);
|
||||
}
|
||||
.ui.basic.green.button, .ui.basic.green.buttons .button:hover, .ui.basic.green.button:hover, .ui.basic.green.button:focus {
|
||||
box-shadow: var(--main-accent) 0px 0px 0px 1px inset;
|
||||
}
|
||||
.ui.green.labels .label, .ui.ui.ui.green.label {
|
||||
background-color: var(--main-accent);
|
||||
border-color: var(--main-accent);
|
||||
}
|
||||
.ui.grid > .green.row, .ui.grid > .green.column, .ui.grid > .row > .green.column {
|
||||
background-color: var(--main-accent);
|
||||
}
|
||||
|
||||
/* OVERWRITE DEFAULT SEMANTIC STYLES FOR CUSTOM/NIGHT MODES*/
|
||||
|
||||
/*//
|
||||
@@ -235,7 +254,7 @@ div.ui.basic.green.label {
|
||||
/*border-bottom: 1px solid #ccc;*/
|
||||
scrollbar-width: none;
|
||||
scrollbar-color: transparent transparent;
|
||||
caret-color: #21BA45;
|
||||
caret-color: var(--main-accent);
|
||||
}
|
||||
.squire-box::selection,
|
||||
.squire-box::-moz-selection {
|
||||
@@ -253,7 +272,7 @@ div.ui.basic.green.label {
|
||||
cursor: pointer;
|
||||
}
|
||||
.night-mode .note-card-text i:not(.icon),
|
||||
.night-mode .squire-box i {
|
||||
.night-mode .squire-box i:not(.icon) {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
@@ -322,9 +341,55 @@ div.ui.basic.green.label {
|
||||
|
||||
font-family: 'Icons';
|
||||
content: "\f058";
|
||||
color: #21BA45;
|
||||
color: var(--main-accent);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.note-title-display-card .divide,
|
||||
.squire-box .divide {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
height: 2px;
|
||||
background-color: var(--main-accent);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
font-weight: normal;
|
||||
}
|
||||
/* table:hover th, table:hover td {
|
||||
border: 1px solid black;
|
||||
}*/
|
||||
|
||||
th, td {
|
||||
padding: 3px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.t-table {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.t-table > span,
|
||||
.t-table > div {
|
||||
display: flex; /* aligns all child elements (flex items) in a row */
|
||||
}
|
||||
|
||||
.t-table > span > span,
|
||||
.t-table > div > div {
|
||||
flex: 1; /* distributes space on the line equally among items */
|
||||
border: 1px solid #DDD;
|
||||
}
|
||||
|
||||
|
||||
/* adjust checkboxes for mobile. Make them a little bigger, easier to click */
|
||||
@media only screen and (max-width: 740px) {
|
||||
|
||||
|
@@ -1096,6 +1096,9 @@ var moveRangeBoundariesUpTree = function ( range, startMax, endMax, root ) {
|
||||
}
|
||||
|
||||
while ( true ) {
|
||||
if ( endContainer === endMax || endContainer === root ) {
|
||||
break;
|
||||
}
|
||||
if ( maySkipBR &&
|
||||
endContainer.nodeType !== TEXT_NODE &&
|
||||
endContainer.childNodes[ endOffset ] &&
|
||||
@@ -1103,9 +1106,7 @@ var moveRangeBoundariesUpTree = function ( range, startMax, endMax, root ) {
|
||||
endOffset += 1;
|
||||
maySkipBR = false;
|
||||
}
|
||||
if ( endContainer === endMax ||
|
||||
endContainer === root ||
|
||||
endOffset !== getLength( endContainer ) ) {
|
||||
if ( endOffset !== getLength( endContainer ) ) {
|
||||
break;
|
||||
}
|
||||
parent = endContainer.parentNode;
|
||||
@@ -1117,6 +1118,20 @@ var moveRangeBoundariesUpTree = function ( range, startMax, endMax, root ) {
|
||||
range.setEnd( endContainer, endOffset );
|
||||
};
|
||||
|
||||
var moveRangeBoundaryOutOf = function ( range, nodeName, root ) {
|
||||
var parent = getNearest( range.endContainer, root, 'A' );
|
||||
if ( parent ) {
|
||||
var clone = range.cloneRange();
|
||||
parent = parent.parentNode;
|
||||
moveRangeBoundariesUpTree( clone, parent, parent, root );
|
||||
if ( clone.endContainer === parent ) {
|
||||
range.setStart( clone.endContainer, clone.endOffset );
|
||||
range.setEnd( clone.endContainer, clone.endOffset );
|
||||
}
|
||||
}
|
||||
return range;
|
||||
};
|
||||
|
||||
// Returns the first block at least partially contained by the range,
|
||||
// or null if no block is contained by the range.
|
||||
var getStartBlockOfRange = function ( range, root ) {
|
||||
@@ -1285,10 +1300,13 @@ var onKey = function ( event ) {
|
||||
if ( event.altKey ) { modifiers += 'alt-'; }
|
||||
if ( event.ctrlKey ) { modifiers += 'ctrl-'; }
|
||||
if ( event.metaKey ) { modifiers += 'meta-'; }
|
||||
if ( event.shiftKey ) { modifiers += 'shift-'; }
|
||||
}
|
||||
// However, on Windows, shift-delete is apparently "cut" (WTF right?), so
|
||||
// we want to let the browser handle shift-delete.
|
||||
if ( event.shiftKey ) { modifiers += 'shift-'; }
|
||||
// we want to let the browser handle shift-delete in this situation.
|
||||
if ( isWin && event.shiftKey && key === 'delete' ) {
|
||||
modifiers += 'shift-';
|
||||
}
|
||||
|
||||
key = modifiers + key;
|
||||
|
||||
@@ -1465,12 +1483,7 @@ var handleEnter = function ( self, shiftKey, range ) {
|
||||
// just play it safe and insert a <br>.
|
||||
if ( !block || shiftKey || /^T[HD]$/.test( block.nodeName ) ) {
|
||||
// If inside an <a>, move focus out
|
||||
parent = getNearest( range.endContainer, root, 'A' );
|
||||
if ( parent ) {
|
||||
parent = parent.parentNode;
|
||||
moveRangeBoundariesUpTree( range, parent, parent, root );
|
||||
range.collapse( false );
|
||||
}
|
||||
moveRangeBoundaryOutOf( range, 'A', root );
|
||||
insertNodeInRange( range, self.createElement( 'BR' ) );
|
||||
range.collapse( false );
|
||||
self.setSelection( range );
|
||||
@@ -1821,16 +1834,45 @@ if ( !isMac ) {
|
||||
};
|
||||
}
|
||||
|
||||
const changeIndentationLevel = function ( methodIfInQuote, methodIfInList ) {
|
||||
return function ( self, event ) {
|
||||
event.preventDefault();
|
||||
var path = self.getPath();
|
||||
if ( /(?:^|>)BLOCKQUOTE/.test( path ) ||
|
||||
!/(?:^|>)[OU]L/.test( path ) ) {
|
||||
self[ methodIfInQuote ]();
|
||||
} else {
|
||||
self[ methodIfInList ]();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const toggleList = function ( listRegex, methodIfNotInList ) {
|
||||
return function ( self, event ) {
|
||||
event.preventDefault();
|
||||
var path = self.getPath();
|
||||
if ( !listRegex.test( path ) ) {
|
||||
self[ methodIfNotInList ]();
|
||||
} else {
|
||||
self.removeList();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
keyHandlers[ ctrlKey + 'b' ] = mapKeyToFormat( 'B' );
|
||||
keyHandlers[ ctrlKey + 'i' ] = mapKeyToFormat( 'I' );
|
||||
keyHandlers[ ctrlKey + 'u' ] = mapKeyToFormat( 'U' );
|
||||
keyHandlers[ ctrlKey + 'shift-7' ] = mapKeyToFormat( 'S' );
|
||||
keyHandlers[ ctrlKey + 'shift-5' ] = mapKeyToFormat( 'SUB', { tag: 'SUP' } );
|
||||
keyHandlers[ ctrlKey + 'shift-6' ] = mapKeyToFormat( 'SUP', { tag: 'SUB' } );
|
||||
keyHandlers[ ctrlKey + 'shift-8' ] = mapKeyTo( 'makeUnorderedList' );
|
||||
keyHandlers[ ctrlKey + 'shift-9' ] = mapKeyTo( 'makeOrderedList' );
|
||||
keyHandlers[ ctrlKey + '[' ] = mapKeyTo( 'decreaseQuoteLevel' );
|
||||
keyHandlers[ ctrlKey + ']' ] = mapKeyTo( 'increaseQuoteLevel' );
|
||||
keyHandlers[ ctrlKey + 'shift-8' ] =
|
||||
toggleList( /(?:^|>)UL/, 'makeUnorderedList' );
|
||||
keyHandlers[ ctrlKey + 'shift-9' ] =
|
||||
toggleList( /(?:^|>)OL/, 'makeOrderedList' );
|
||||
keyHandlers[ ctrlKey + '[' ] =
|
||||
changeIndentationLevel( 'decreaseQuoteLevel', 'decreaseListLevel' );
|
||||
keyHandlers[ ctrlKey + ']' ] =
|
||||
changeIndentationLevel( 'increaseQuoteLevel', 'increaseListLevel' );
|
||||
keyHandlers[ ctrlKey + 'd' ] = mapKeyTo( 'toggleCode' );
|
||||
keyHandlers[ ctrlKey + 'y' ] = mapKeyTo( 'redo' );
|
||||
keyHandlers[ ctrlKey + 'z' ] = mapKeyTo( 'undo' );
|
||||
@@ -4417,6 +4459,12 @@ proto.insertHTML = function ( html, isPaste ) {
|
||||
this._docWasChanged();
|
||||
}
|
||||
range.collapse( false );
|
||||
|
||||
// After inserting the fragment, check whether the cursor is inside
|
||||
// an <a> element and if so if there is an equivalent cursor
|
||||
// position after the <a> element. If there is, move it there.
|
||||
moveRangeBoundaryOutOf( range, 'A', root );
|
||||
|
||||
this._ensureBottomLine();
|
||||
}
|
||||
|
||||
@@ -4947,4 +4995,4 @@ if ( typeof exports === 'object' ) {
|
||||
}
|
||||
}
|
||||
|
||||
}( document ) );
|
||||
}( document ) );
|
||||
|
@@ -182,7 +182,6 @@
|
||||
openNote(){
|
||||
const noteId = this.item.note_id
|
||||
this.$router.push('/notes/open/'+noteId)
|
||||
this.$bus.$emit('open_note', noteId)
|
||||
},
|
||||
openEditAttachments(){
|
||||
const noteId = this.item.note_id
|
||||
|
@@ -24,9 +24,9 @@
|
||||
}
|
||||
},
|
||||
beforeMount(){
|
||||
this.$bus.$on('reset_fast_filters', () => {
|
||||
this.orderString = 'Order by Last Edited'
|
||||
})
|
||||
// this.$bus.$on('reset_fast_filters', () => {
|
||||
// this.orderString = 'Order by Last Edited'
|
||||
// })
|
||||
},
|
||||
methods:{
|
||||
displayString(){
|
||||
|
@@ -19,9 +19,10 @@
|
||||
bottom: 0;
|
||||
}
|
||||
.menu-logo-display {
|
||||
width: 25px;
|
||||
margin: 5px 0 0 42px;
|
||||
width: 27px;
|
||||
margin: 5px 0 0 41px;
|
||||
display: inline-block;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
@@ -79,15 +80,17 @@
|
||||
background-color: var(--small_element_bg_color);
|
||||
border-bottom: 1px solid;
|
||||
border-color: var(--border_color);
|
||||
padding: 5px 1rem 5px;
|
||||
/*padding: 5px 1rem 5px;*/
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.place-holder {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
.top-menu-bar img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
.logo-display {
|
||||
width: 27px;
|
||||
height: auto;
|
||||
}
|
||||
.version-display {
|
||||
position: absolute;
|
||||
@@ -101,6 +104,19 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mobile-button {
|
||||
display: inline-block;
|
||||
font-size: 2em;
|
||||
padding: 6px 3px 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.mobile-button.active {
|
||||
background-color: transparent;
|
||||
}
|
||||
.mobile-button i {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<template>
|
||||
@@ -110,45 +126,37 @@
|
||||
|
||||
<!-- collapsed menu, appears as a bar -->
|
||||
<div class="top-menu-bar" v-if="(collapsed || mobile) && !menuOpen">
|
||||
<div class="ui grid">
|
||||
|
||||
<div class="seven wide column">
|
||||
<div class="ui large basic compact icon button" v-on:click="collapseMenu">
|
||||
<i class="green bars icon"></i>
|
||||
</div>
|
||||
|
||||
<!-- <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>
|
||||
|
||||
<!-- mobile create note button -->
|
||||
<span v-if="loggedIn">
|
||||
<span v-if="!disableNewNote" @click="createNote" class="ui large green compact icon button">
|
||||
<i class="plus icon"></i>
|
||||
</span>
|
||||
<span v-if="disableNewNote" class="ui large basic compact icon button">
|
||||
<i class="grey plus icon"></i>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mobile-button">
|
||||
<i class="green link bars icon" v-on:click="collapseMenu"></i>
|
||||
</div>
|
||||
|
||||
<div class="mobile-button"></div>
|
||||
|
||||
<router-link v-if="loggedIn" to="/quick" class="mobile-button" exact-active-class="active">
|
||||
<i class="green sticky note outline icon"></i>
|
||||
</router-link>
|
||||
|
||||
<router-link v-if="loggedIn" class="mobile-button" exact-active-class="active" to="/notes" v-on:click.native="emitReloadEvent()">
|
||||
<logo class="logo-display" color="var(--main-accent)" />
|
||||
</router-link>
|
||||
|
||||
<router-link v-if="loggedIn" class="mobile-button" exact-active-class="active" to="/attachments">
|
||||
<i class="green open folder outline icon"></i>
|
||||
</router-link>
|
||||
|
||||
<div class="mobile-button"></div>
|
||||
|
||||
<!-- mobile create note button -->
|
||||
<span v-if="loggedIn">
|
||||
<span v-if="!disableNewNote" @click="createNote" class="mobile-button">
|
||||
<i class="green plus icon"></i>
|
||||
</span>
|
||||
<span v-if="disableNewNote" class="mobile-button">
|
||||
<i class="grey plus icon"></i>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="shade" v-if="mobile && !collapsed" v-on:click="collapseMenu"></div>
|
||||
@@ -161,7 +169,7 @@
|
||||
<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">
|
||||
<logo class="menu-logo-display" color="var(--main-accent)" />
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
|
||||
@@ -236,14 +244,14 @@
|
||||
|
||||
<div class="menu-section">
|
||||
<router-link class="menu-item menu-button" exact-active-class="active" to="/help">
|
||||
<i class="question circle outline icon"></i>Help
|
||||
<i class="question circle outline icon"></i>Help / Terms
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div class="menu-section" v-if="loggedIn" :data-tooltip="`Logout ${this.$store.getters.getUsername}`" data-inverted="" data-position="right center">
|
||||
<div v-on:click="destroyLoginToken" class="menu-item menu-button">
|
||||
<i v-if="userIcon" class="user outline icon"></i>{{ usernameDisplay }}
|
||||
</div>
|
||||
<div class="menu-section" v-if="loggedIn" :data-tooltip="`Settings for ${this.$store.getters.getUsername}`" data-inverted="" data-position="right center">
|
||||
<router-link class="menu-item menu-button" exact-active-class="active" to="/settings">
|
||||
<i v-if="userIcon" class="cog icon"></i>{{ usernameDisplay }}
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -264,6 +272,7 @@
|
||||
components: {
|
||||
'search-input': require('@/components/SearchInput.vue').default,
|
||||
'counter':require('@/components/AnimatedCounterComponent.vue').default,
|
||||
'logo':require('@/components/LogoComponent.vue').default,
|
||||
},
|
||||
data: function(){
|
||||
return {
|
||||
@@ -274,10 +283,14 @@
|
||||
disableNewNote: false,
|
||||
menuOpen: true,
|
||||
userIcon: true,
|
||||
resizeDebounce: null,
|
||||
}
|
||||
},
|
||||
beforeCreate: function(){
|
||||
|
||||
beforeMount(){
|
||||
window.addEventListener('resize', this.resizeEventHandler)
|
||||
},
|
||||
beforeDestroy(){
|
||||
window.removeEventListener('resize', this.resizeEventHandler)
|
||||
},
|
||||
mounted: function(){
|
||||
this.mobile = this.$store.getters.getIsUserOnMobile
|
||||
@@ -316,6 +329,19 @@
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
resizeEventHandler(e) {
|
||||
clearTimeout(this.resizeDebounce)
|
||||
this.resizeDebounce = setTimeout(() => {
|
||||
|
||||
this.menuOpen = false
|
||||
this.collapsed = false
|
||||
|
||||
if(window.innerWidth < 700){
|
||||
|
||||
this.collapsed = true
|
||||
}
|
||||
}, 100)
|
||||
},
|
||||
menuClicked(){
|
||||
//Collapse menu when item is clicked in mobile
|
||||
if(this.mobile && !this.collapsed){
|
||||
@@ -334,28 +360,22 @@
|
||||
|
||||
},
|
||||
createNote(event){
|
||||
const title = ''
|
||||
|
||||
this.disableNewNote = true
|
||||
|
||||
axios.post('/api/note/create', {title})
|
||||
axios.post('/api/note/create', {title:''})
|
||||
.then(response => {
|
||||
|
||||
if(response.data && response.data.id){
|
||||
//Redirect to note page if user is not on it
|
||||
this.$bus.$emit('open_note', response.data.id)
|
||||
|
||||
//Push new note to url and it will open
|
||||
this.$router.push('/notes/open/'+response.data.id)
|
||||
|
||||
this.disableNewNote = false
|
||||
}
|
||||
})
|
||||
.catch(error => { this.$bus.$emit('notification', 'Failed to create note') })
|
||||
},
|
||||
destroyLoginToken() {
|
||||
axios.post('/api/user/logout')
|
||||
setTimeout(() => {
|
||||
this.$bus.$emit('notification', 'Logged Out')
|
||||
this.$store.commit('destroyLoginToken')
|
||||
this.$router.push('/')
|
||||
}, 200)
|
||||
},
|
||||
toggleNightMode(){
|
||||
this.$store.commit('toggleNightMode')
|
||||
},
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="loading-container">
|
||||
<svg version="1.1" id="L6" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||
<rect fill="none" :stroke="$store.getters.getIsNightMode > 0 ? '#FFF':'#16ab39'" stroke-width="4" x="25" y="25" width="50" height="50" rx="5">
|
||||
<rect fill="none" :stroke="$store.getters.getIsNightMode > 0 ? '#FFF':'var(--main-accent)'" stroke-width="4" x="25" y="25" width="50" height="50" rx="5">
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
dur="0.5s"
|
||||
@@ -12,7 +12,7 @@
|
||||
attributeType="XML"
|
||||
begin="rectBox.end"/>
|
||||
</rect>
|
||||
<rect x="25" y="25" :fill="$store.getters.getIsNightMode > 0 ? '#FFF':'#16ab39'" width="50" height="50">
|
||||
<rect x="25" y="25" :fill="$store.getters.getIsNightMode > 0 ? '#FFF':'var(--main-accent)'" width="50" height="50">
|
||||
<animate
|
||||
attributeName="height"
|
||||
dur="1.3s"
|
||||
|
@@ -1,3 +1,4 @@
|
||||
|
||||
<template>
|
||||
|
||||
<div v-on:keyup.enter="login()">
|
||||
@@ -14,6 +15,11 @@
|
||||
<input v-model="password" type="password" name="password" placeholder="Password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field" v-if="require2FA">
|
||||
<div class="ui input">
|
||||
<input v-model="authToken" ref="authForm" type="text" name="authToken" placeholder="Authorization Token">
|
||||
</div>
|
||||
</div>
|
||||
<div class="sixteen wide field">
|
||||
<div class="ui fluid buttons">
|
||||
<div :class="{ 'disabled':(username.length == 0 || password.length == 0)}" v-on:click="login()" class="ui green button">
|
||||
@@ -27,34 +33,54 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sixteen wide column">
|
||||
<span class="small-terms">
|
||||
By signing up you agree to Solid Scribe's
|
||||
<router-link to="/help">
|
||||
Terms of Use
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Thin form display -->
|
||||
<div v-if="thin" class="ui small form">
|
||||
<div class="fields">
|
||||
<div class="four wide field">
|
||||
<div class="equal width fields">
|
||||
<div class="field">
|
||||
<div class="ui input">
|
||||
<input ref="nameForm" v-model="username" type="text" name="email" placeholder="Username or E-mail">
|
||||
</div>
|
||||
</div>
|
||||
<div class="four wide field">
|
||||
<div class="field">
|
||||
<div class="ui input">
|
||||
<input v-model="password" type="password" name="password" placeholder="Password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="four wide field">
|
||||
<div class="field" v-if="require2FA">
|
||||
<div class="ui input">
|
||||
<input v-model="authToken" ref="authForm" type="text" name="authToken" placeholder="Authorization Token">
|
||||
</div>
|
||||
</div>
|
||||
<!-- hide this field if someone is logging in with 2FA -->
|
||||
<div class="field" v-if="!require2FA">
|
||||
<div v-on:click="register()" class="ui fluid green button">
|
||||
<i class="plug icon"></i>
|
||||
Sign Up
|
||||
</div>
|
||||
</div>
|
||||
<div class="four wide field">
|
||||
<div class="field">
|
||||
<div v-on:click="login()" class="ui fluid button">
|
||||
<i class="power icon"></i>
|
||||
Login
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="small-terms">
|
||||
By signing up you agree to Solid Scribe's
|
||||
<router-link to="/help">
|
||||
Terms of Use
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -83,7 +109,9 @@
|
||||
return {
|
||||
enabled: false,
|
||||
username: '',
|
||||
password: ''
|
||||
password: '',
|
||||
authToken: '',
|
||||
require2FA: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -139,14 +167,30 @@
|
||||
return
|
||||
}
|
||||
|
||||
axios.post('/api/user/login', {'username': this.username, 'password': this.password})
|
||||
axios.post('/api/user/login', {'username': this.username, 'password': this.password, 'authToken':this.authToken })
|
||||
.then(({data}) => {
|
||||
|
||||
if(data == false){
|
||||
this.$bus.$emit('notification', 'Unable to Login - Incorrect Username or Password')
|
||||
//Enable 2FA on form
|
||||
if(data.success == false && data.verificationRequired == true && this.require2FA == false){
|
||||
this.$bus.$emit('notification', data.message)
|
||||
this.require2FA = true
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.authForm.focus()
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.finalizeLogin(data)
|
||||
if(data.success == false){
|
||||
this.$bus.$emit('notification', data.message)
|
||||
return
|
||||
}
|
||||
|
||||
if(data.success){
|
||||
this.finalizeLogin(data)
|
||||
return
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.$bus.$emit('notification', 'Unable to Login - Incorrect Username or Password')
|
||||
@@ -154,4 +198,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<style type="text/css" scoped="true">
|
||||
.small-terms {
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
</style>
|
80
client/src/components/LogoComponent.vue
Normal file
80
client/src/components/LogoComponent.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 132.29166 132.29167"
|
||||
height="500"
|
||||
width="500">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
style="display:inline"
|
||||
transform="translate(0,-164.70832)"
|
||||
id="layer1">
|
||||
<path
|
||||
class="darken-accent"
|
||||
id="path3813-4"
|
||||
d="m 56.22733,165.36641 -55.56249926,15.875 8e-7,63.5 47.62499846,11.90625 v 27.78125 l -47.76066333,-13.9757 0.13566407,10.00695 55.56249926,15.875 v -47.625 l -47.6249985,-11.90625 -8e-7,-47.625 47.7606633,-13.94121 c 0.135664,-2.30629 -0.135664,-9.87129 -0.135664,-9.87129 z"
|
||||
:style="`fill:${displayColor};fill-opacity:1;stroke:none;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1`" />
|
||||
<path
|
||||
class="brighten-accent"
|
||||
id="path4563"
|
||||
d="m 20.508581,220.92891 c 15.265814,-14.23899 27.809717,-7.68002 39.687499,3.96875 v -7.9375 C 51.75093,200.8366 37.512584,206.01499 20.508581,205.05391 Z"
|
||||
:style="`fill:${displayColor};fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`" />
|
||||
<path
|
||||
class="brighten-accent"
|
||||
id="path4563-6"
|
||||
d="m 111.78985,220.92891 c -15.265834,-14.23899 -27.809737,-7.68002 -39.68752,3.96875 v -7.9375 c 8.445151,-16.12356 22.683497,-10.94517 39.68752,-11.90625 z"
|
||||
:style="`display:inline;fill:${displayColor};fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`" />
|
||||
<path
|
||||
class="brighten-accent"
|
||||
id="path3813-4-2"
|
||||
d="m 76.07108,165.36641 55.5625,15.875 v 63.5 l -47.625,11.90625 v 27.78125 l 47.76067,-13.9757 -0.13567,10.00695 -55.5625,15.875 v -47.625 l 47.625,-11.90626 V 189.17891 L 75.93542,175.2377 c -0.13567,-2.30629 0.13566,-9.87129 0.13566,-9.87129 z"
|
||||
:style="`display:inline;fill:${displayColor};fill-opacity:1;stroke:none;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1`" />
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'LoadingIcon',
|
||||
props:[ 'color' ],
|
||||
data(){
|
||||
return {
|
||||
displayColor: '#21BA45', //Default green color
|
||||
}
|
||||
},
|
||||
created(){
|
||||
//Set color if passed
|
||||
if(this.color){
|
||||
this.displayColor = this.color
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style type="text/css" scoped>
|
||||
.darken-accent {
|
||||
filter: brightness(62%);
|
||||
}
|
||||
.brighten-accent {
|
||||
filter: saturate(145%);
|
||||
}
|
||||
</style>
|
@@ -2,9 +2,8 @@
|
||||
<!-- change class to .master-note-edit to have it popup on the screen -->
|
||||
<div
|
||||
id="InputNotes"
|
||||
class="master-note-edit full-focus"
|
||||
@keyup.esc="close()"
|
||||
:class="[ 'position-'+position ]"
|
||||
class="master-note-edit full-focus position-0"
|
||||
@keyup.esc="closeButtonAction()"
|
||||
>
|
||||
|
||||
<!-- Giant Edit Note Menu -->
|
||||
@@ -14,7 +13,7 @@
|
||||
<div class="edit-spacer"></div>
|
||||
|
||||
<div class="menu-top-half">
|
||||
<div class="edit-button" v-on:click="close()" data-tooltip="Close" data-position="bottom center" data-inverted>
|
||||
<div class="edit-button" v-on:click="closeButtonAction()" data-tooltip="Close" data-position="bottom center" data-inverted>
|
||||
<i class="close icon"></i>
|
||||
</div>
|
||||
|
||||
@@ -61,7 +60,19 @@
|
||||
</div>
|
||||
|
||||
<div class="menu-bottom-half">
|
||||
|
||||
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/table`)" data-tooltip="Insert Table" data-position="bottom center" data-inverted>
|
||||
<i class="border all icon"></i>
|
||||
</div>
|
||||
|
||||
<div class="edit-button" v-on:click="insertDivide()" data-tooltip="Insert Divide" data-position="bottom center" data-inverted>
|
||||
<i class="grip lines icon"></i>
|
||||
</div>
|
||||
|
||||
<div class="edit-button" v-on:click="insertTable(4,4)" data-tooltip="Insert Table" data-position="bottom center" data-inverted>
|
||||
<i class="book dead icon"></i>
|
||||
</div>
|
||||
|
||||
<div class="edit-button" v-on:click="removeFormatting()" data-tooltip="Remove Formatting" data-position="bottom center" data-inverted>
|
||||
<i class="remove format icon"></i>
|
||||
</div>
|
||||
@@ -95,7 +106,8 @@
|
||||
|
||||
<div class="edit-divide"></div>
|
||||
|
||||
<!-- <div class="edit-button" v-on:click="onToggleArchived()" :data-tooltip="archived == 1?'Move to main list':'Move to Archive'" data-position="bottom center" data-inverted>
|
||||
<!--
|
||||
<div class="edit-button" v-on:click="onToggleArchived()" :data-tooltip="archived == 1?'Move to main list':'Move to Archive'" data-position="bottom center" data-inverted>
|
||||
<span v-if="archived == 1"><i class="green archive icon"></i></span>
|
||||
<span v-if="archived != 1"><i class="archive icon"></i></span>
|
||||
</div>
|
||||
@@ -105,17 +117,13 @@
|
||||
<span v-if="pinned != 1"><i class="pin icon"></i></span>
|
||||
</div> -->
|
||||
|
||||
<!-- data-tooltip="Files on note" -->
|
||||
<!-- <div v-if="attachmentCount > 0" class="edit-button" v-on:click="openEditAttachment" data-tooltip="Files" data-position="bottom center" data-inverted>
|
||||
<i class="folder icon"></i>
|
||||
{{ attachmentCount }}
|
||||
</div> -->
|
||||
|
||||
<div class="edit-button" v-if="usersOnNote > 1">
|
||||
<i class="green eye icon"></i> {{ usersOnNote }}
|
||||
</div>
|
||||
|
||||
<!-- <div class="edit-button" v-on:click="simulateTyping()">
|
||||
<!--
|
||||
<div class="edit-button" v-on:click="simulateTyping()">
|
||||
<i class="purple bolt icon"></i>
|
||||
</div> -->
|
||||
|
||||
@@ -132,7 +140,6 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="bottom-edit-menu"></div>
|
||||
@@ -163,7 +170,7 @@
|
||||
</textarea>
|
||||
|
||||
<!-- Squire Box -->
|
||||
<div id="squire-id" class="squire-box" ref="squirebox" placeholder="Note Text"></div>
|
||||
<div id="squire-id" class="squire-box" ref="squirebox" placeholder="Type Note Here"></div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -224,19 +231,19 @@
|
||||
<div class="sixteen wide column">
|
||||
<div class="ui labeled icon fluid basic button" v-on:click="sortList">
|
||||
<i class="sort amount up icon"></i>
|
||||
Sort List items (Move checked to bottom)
|
||||
Sort List
|
||||
</div>
|
||||
</div>
|
||||
<div class="eight wide column">
|
||||
<div class="ui labeled icon fluid basic button" v-on:click="deleteCompletedListItems">
|
||||
<i class="trash icon"></i>
|
||||
Delete Checked Items
|
||||
Delete Checked
|
||||
</div>
|
||||
</div>
|
||||
<div class="eight wide column">
|
||||
<div class="ui labeled icon fluid basic button" v-on:click="uncheckAllListItems">
|
||||
<i class="list ul icon"></i>
|
||||
Uncheck all Checked items
|
||||
Uncheck All
|
||||
</div>
|
||||
</div>
|
||||
<div class="eight wide column">
|
||||
@@ -245,6 +252,15 @@
|
||||
Simple Math
|
||||
</div>
|
||||
</div>
|
||||
<div class="eight wide column">
|
||||
<!-- data-tooltip="Files on note" -->
|
||||
<div v-on:click="openEditAttachment" class="ui labeled icon fluid basic button">
|
||||
<i class="folder icon"></i>
|
||||
Note Files
|
||||
{{ attachmentCount }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide column" v-if="rawTextId > 0">
|
||||
<h2>Share Note</h2>
|
||||
<share-note-component
|
||||
@@ -257,13 +273,20 @@
|
||||
</div>
|
||||
</side-slide-menu>
|
||||
|
||||
<!-- create table option -->
|
||||
<side-slide-menu v-if="table" v-on:close="table = false; fetchNoteTags()" name="table" :style-object="styleObject">
|
||||
<div class="ui basic segment">
|
||||
Create a table
|
||||
</div>
|
||||
</side-slide-menu>
|
||||
|
||||
<!-- Show side shades if user is on desktop only -->
|
||||
<div class="full-focus-shade shade1"
|
||||
:class="{ 'slide-out-left':sizeDown }"
|
||||
v-on:click="close()"></div>
|
||||
v-on:click="closeButtonAction()"></div>
|
||||
<div class="full-focus-shade shade2"
|
||||
:class="{ 'slide-out-right':sizeDown }"
|
||||
v-on:click="close()"></div>
|
||||
v-on:click="closeButtonAction()"></div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -335,6 +358,7 @@
|
||||
images: false,
|
||||
options: false,
|
||||
colorpicker: false,
|
||||
table: false,
|
||||
|
||||
//Diff text/sync text variables
|
||||
diffTextTimeout: null,
|
||||
@@ -355,7 +379,7 @@
|
||||
//Handle changes in URL to
|
||||
|
||||
if(newVal.id == undefined || newVal.id != this.noteid){
|
||||
this.close()
|
||||
// this.closeButtonAction()
|
||||
}
|
||||
|
||||
//Reset all note menus on URL change
|
||||
@@ -364,6 +388,7 @@
|
||||
this.tags = false
|
||||
this.options = false
|
||||
this.images = false
|
||||
this.table = false
|
||||
|
||||
//If a menu value is set, open it
|
||||
if(newVal.openMenu){
|
||||
@@ -394,18 +419,20 @@
|
||||
|
||||
document.removeEventListener('visibilitychange', this.checkForUpdatedNote)
|
||||
|
||||
// if(this.editor){
|
||||
this.editor.destroy()
|
||||
// }
|
||||
//Obliterate squire instance
|
||||
this.editor.destroy()
|
||||
|
||||
this.close()
|
||||
|
||||
},
|
||||
mounted: function() {
|
||||
|
||||
//Show loading for a minimum time
|
||||
setTimeout(()=>{
|
||||
this.forceShowLoading = false
|
||||
}, 500)
|
||||
|
||||
document.addEventListener('visibilitychange', this.checkForUpdatedNote)
|
||||
// document.addEventListener('visibilitychange', this.checkForUpdatedNote)
|
||||
|
||||
//Init squire as early as possible
|
||||
this.editor = new Squire( this.$refs.squirebox, {blockTag: 'p' })
|
||||
@@ -599,6 +626,30 @@
|
||||
|
||||
this.editor.addEventListener('keydown', event => {
|
||||
|
||||
//Tab to increase quote level, tab + shigt to decrease quote level
|
||||
const keyCode = event.key
|
||||
if(keyCode == 'Tab'){
|
||||
|
||||
if(event.shiftKey){
|
||||
this.editor.decreaseQuoteLevel()
|
||||
} else {
|
||||
this.editor.increaseQuoteLevel()
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
return false
|
||||
}
|
||||
|
||||
//Save on pressing CTRL/CMD + S
|
||||
if(keyCode == 's' && (event.ctrlKey || event.metaKey) ){
|
||||
|
||||
this.$bus.$emit('notification', 'Note Saved')
|
||||
this.save()
|
||||
|
||||
event.preventDefault()
|
||||
return false
|
||||
}
|
||||
|
||||
//Prevent new list items from having
|
||||
this.$nextTick( () => {
|
||||
//Wait a moment to get item under cursor
|
||||
@@ -612,10 +663,6 @@
|
||||
})
|
||||
})
|
||||
|
||||
this.editor.addEventListener('keydown', event => {
|
||||
|
||||
})
|
||||
|
||||
//Bind event handlers
|
||||
this.editor.addEventListener('keyup', event => {
|
||||
|
||||
@@ -682,7 +729,7 @@
|
||||
//Block notes you don't have access to from opening
|
||||
if(response.data === false){
|
||||
this.$bus.$emit('notification', 'Error opening Note')
|
||||
this.close(true)
|
||||
this.close()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -915,18 +962,21 @@
|
||||
|
||||
return hash;
|
||||
},
|
||||
close(force = false){
|
||||
closeButtonAction(){
|
||||
this.sizeDown = true
|
||||
//This timeout allows animation to play before closing
|
||||
setTimeout(() => {
|
||||
this.$router.push('/notes')
|
||||
}, 300)
|
||||
},
|
||||
close(){
|
||||
|
||||
// force = true
|
||||
|
||||
// console.log(`Close Note ${this.noteid} -> force: ${force}, modified: ${this.modified}`)
|
||||
|
||||
if(force){
|
||||
this.$bus.$emit('close_active_note', {
|
||||
noteId: this.noteid, modified: this.modified
|
||||
})
|
||||
return
|
||||
}
|
||||
//Skip everything if foce close is true. Note will just die.
|
||||
if(this.currentNoteId == 0){ return }
|
||||
|
||||
this.loadingMessage = 'Saving...'
|
||||
this.loading = true
|
||||
@@ -938,14 +988,10 @@
|
||||
axios.post('/api/note/reindex')
|
||||
}
|
||||
|
||||
this.sizeDown = true
|
||||
//This timeout allows animation to play before closing
|
||||
setTimeout(() => {
|
||||
this.$bus.$emit('close_active_note', {
|
||||
noteId: this.noteid, modified: this.modified
|
||||
})
|
||||
return
|
||||
}, 300)
|
||||
this.$bus.$emit('close_active_note', {
|
||||
noteId: this.noteid, modified: this.modified
|
||||
})
|
||||
return
|
||||
})
|
||||
},
|
||||
destroyWebSockets(){
|
||||
@@ -1005,8 +1051,8 @@
|
||||
let element = this.$refs.titleTextarea
|
||||
let padding = 0
|
||||
|
||||
element.style.height = 'auto';
|
||||
element.style.height = (element.scrollHeight + padding) +'px';
|
||||
element.style.height = 'auto'
|
||||
element.style.height = (element.scrollHeight + padding) +'px'
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1152,7 +1198,7 @@
|
||||
background-color: var(--menu-accent);
|
||||
}
|
||||
.edit-active {
|
||||
background-color: #21BA45;
|
||||
background-color: var(--main-accent);
|
||||
color: white;
|
||||
}
|
||||
.edit-divide {
|
||||
|
@@ -67,7 +67,7 @@
|
||||
</span>
|
||||
|
||||
<span class="time-ago-display" :class="{ 'hover-hide':(!$store.getters.getIsUserOnMobile) }">
|
||||
{{$helpers.timeAgo(note.updated)}}
|
||||
{{$helpers.timeAgo( note.updated )}}
|
||||
</span>
|
||||
|
||||
<span class="teeny-buttons" :class="{ 'hover-hide':(!$store.getters.getIsUserOnMobile) }">
|
||||
@@ -234,12 +234,12 @@
|
||||
},
|
||||
justClosed(){
|
||||
|
||||
//Scroll note into view
|
||||
// this.$el.scrollIntoView({
|
||||
// behavior: 'smooth',
|
||||
// block: 'center',
|
||||
// inline: 'center'
|
||||
// })
|
||||
// Scroll note into view
|
||||
this.$el.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
inline: 'center'
|
||||
})
|
||||
|
||||
//After scroll, trigger green outline animation
|
||||
setTimeout(() => {
|
||||
@@ -356,13 +356,14 @@
|
||||
|
||||
/*Strict font sizes for card display*/
|
||||
.small-text {
|
||||
max-height: 261px;
|
||||
max-height: 267px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
}
|
||||
.small-text, .small-text > p, .small-text > h1, .small-text > h2 {
|
||||
/*font-size: 1.0em !important;*/
|
||||
font-size: 16px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
.small-text > p, , .small-text > h1, .small-text > h2 {
|
||||
margin-bottom: 0.5em;
|
||||
@@ -370,7 +371,7 @@
|
||||
.big-text > p:first-child,
|
||||
.big-text > h1, .big-text > h2 {
|
||||
/*font-size: 1.3em !important;*/
|
||||
font-size: 17px !important;
|
||||
font-size: 20px !important;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
@@ -415,14 +416,14 @@
|
||||
border-color: var(--border_color);
|
||||
/*width: calc(33.333% - 10px);*/
|
||||
width: calc(25% - 10px);
|
||||
min-width: 190px;
|
||||
/*min-width: 190px;*/
|
||||
min-height: 130px;
|
||||
/*transition: box-shadow 0.3s;*/
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
|
||||
line-height: 1.8rem;
|
||||
letter-spacing: 0.02rem;
|
||||
letter-spacing: 0.05rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
@@ -555,27 +556,50 @@
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* Tweak mobile display to show only one column */
|
||||
@media only screen and (min-width: 1500px) {
|
||||
.note-title-display-card {
|
||||
width: calc(20% - 10px);
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 740px) {
|
||||
/* Break points determine when display cards shrink */
|
||||
@media only screen and (max-width: 700px) {
|
||||
.note-title-display-card {
|
||||
width: calc(100% + 10px);
|
||||
margin: 0px -5px 10px -5px;
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width: 700px) and (max-width: 900px) {
|
||||
.note-title-display-card {
|
||||
width: calc(50% - 10px);
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width: 900px) and (max-width: 1100px) {
|
||||
.note-title-display-card {
|
||||
width: calc(33.33333% - 10px);
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width: 1100px) and (max-width: 1300px) {
|
||||
.note-title-display-card {
|
||||
width: calc(25% - 10px);
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width: 1300px) and (max-width: 1800px) {
|
||||
.note-title-display-card {
|
||||
width: calc(20% - 10px);
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width: 1800px) {
|
||||
.note-title-display-card {
|
||||
width: calc(16.66666% - 10px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*Animations for cool border effects*/
|
||||
@keyframes bgin {
|
||||
0% {
|
||||
background-image:
|
||||
linear-gradient(to right, #21BA45 50%, #21BA45 100%), /* TopLeft to Right */
|
||||
linear-gradient(to bottom, #21BA45 50%, #21BA45 100%), /* TopRight to Bottom */
|
||||
linear-gradient(to right, #21BA45 50%, #21BA45 100%), /* BottomLeft to Right*/
|
||||
linear-gradient(to bottom, #21BA45 50%, #21BA45 100%); /* TopLeft to Bottom */
|
||||
linear-gradient(to right, var(--main-accent) 50%, var(--main-accent) 100%), /* TopLeft to Right */
|
||||
linear-gradient(to bottom, var(--main-accent) 50%, var(--main-accent) 100%), /* TopRight to Bottom */
|
||||
linear-gradient(to right, var(--main-accent) 50%, var(--main-accent) 100%), /* BottomLeft to Right*/
|
||||
linear-gradient(to bottom, var(--main-accent) 50%, var(--main-accent) 100%); /* TopLeft to Bottom */
|
||||
/*Initial state, no BG*/
|
||||
background-size: 0 4px, 4px 0, 0 4px, 4px 0;
|
||||
}
|
||||
@@ -590,10 +614,10 @@
|
||||
30% {
|
||||
background-size: 100% 4px, 4px 100%, 100% 4px, 4px 100%;
|
||||
background-image:
|
||||
linear-gradient(to right, #21BA45 50%, #21BA45 100%), /* TopLeft to Right */
|
||||
linear-gradient(to bottom, #21BA45 50%, #21BA45 100%), /* TopRight to Bottom */
|
||||
linear-gradient(to right, #21BA45 50%, #21BA45 100%), /* BottomLeft to Right*/
|
||||
linear-gradient(to bottom, #21BA45 50%, #21BA45 100%); /* TopLeft to Bottom */
|
||||
linear-gradient(to right, var(--main-accent) 50%, var(--main-accent) 100%), /* TopLeft to Right */
|
||||
linear-gradient(to bottom, var(--main-accent) 50%, var(--main-accent) 100%), /* TopRight to Bottom */
|
||||
linear-gradient(to right, var(--main-accent) 50%, var(--main-accent) 100%), /* BottomLeft to Right*/
|
||||
linear-gradient(to bottom, var(--main-accent) 50%, var(--main-accent) 100%); /* TopLeft to Bottom */
|
||||
}
|
||||
100% {
|
||||
background-image:
|
||||
|
@@ -98,13 +98,17 @@
|
||||
},
|
||||
beforeCreate: function(){
|
||||
},
|
||||
mounted: function(){
|
||||
|
||||
beforeMount(){
|
||||
//search clear
|
||||
this.$bus.$on('reset_fast_filters', () => {
|
||||
this.searchTerm = ''
|
||||
this.tagSuggestions = []
|
||||
})
|
||||
},
|
||||
beforeDestroy(){
|
||||
this.$bus.$off('reset_fast_filters')
|
||||
},
|
||||
mounted: function(){
|
||||
|
||||
},
|
||||
methods: {
|
||||
@@ -148,7 +152,6 @@
|
||||
|
||||
if(response.data && response.data.id){
|
||||
this.$router.push('/notes/open/'+response.data.id)
|
||||
this.$bus.$emit('open_note', response.data.id)
|
||||
}
|
||||
})
|
||||
.catch(error => { this.$bus.$emit('notification', 'Failed to create note') })
|
||||
|
@@ -17,6 +17,7 @@ const SquireButtonFunctions = {
|
||||
//
|
||||
|
||||
pathChangeEvent(e){
|
||||
|
||||
//Reset all button states
|
||||
this.activeBold = false
|
||||
this.activeTitle = false
|
||||
@@ -143,28 +144,23 @@ const SquireButtonFunctions = {
|
||||
// Uncheck All List Items
|
||||
//
|
||||
|
||||
//Close menu if user is on mobile, then sort list
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.options = false
|
||||
}
|
||||
|
||||
//Fetch the container
|
||||
let container = document.getElementById('squire-id')
|
||||
|
||||
Array.from( container.getElementsByClassName('active') ).forEach(item => {
|
||||
item.classList.remove('active');
|
||||
})
|
||||
|
||||
//Close menu if user is on mobile, then sort list
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.$router.go(-1)
|
||||
}
|
||||
},
|
||||
deleteCompletedListItems(){
|
||||
//
|
||||
// Delete Completed List Items
|
||||
//
|
||||
|
||||
//Close menu if user is on mobile, then sort list
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.options = false
|
||||
}
|
||||
|
||||
//Fetch the container
|
||||
let container = document.getElementById('squire-id')
|
||||
|
||||
@@ -210,17 +206,17 @@ const SquireButtonFunctions = {
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
//Close menu if user is on mobile, then sort list
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.$router.go(-1)
|
||||
}
|
||||
},
|
||||
sortList(){
|
||||
//
|
||||
// Sort list, checked at the bottom, unchecked at the top
|
||||
//
|
||||
|
||||
//Close menu if user is on mobile, then sort list
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.options = false
|
||||
}
|
||||
|
||||
//Fetch the container
|
||||
let container = document.getElementById('squire-id')
|
||||
|
||||
@@ -274,17 +270,17 @@ const SquireButtonFunctions = {
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
//Close menu if user is on mobile
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.$router.go(-1)
|
||||
}
|
||||
},
|
||||
calculateMath(){
|
||||
//
|
||||
// Find math in note and calculate the outcome
|
||||
//
|
||||
|
||||
//Close menu if user is on mobile, then sort list
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.options = false
|
||||
}
|
||||
|
||||
//Fetch the container
|
||||
let container = document.getElementById('squire-id')
|
||||
|
||||
@@ -327,6 +323,11 @@ const SquireButtonFunctions = {
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
//Close menu if user is on mobile, then sort list
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.$router.go(-1)
|
||||
}
|
||||
},
|
||||
setText(inText){
|
||||
|
||||
@@ -338,6 +339,69 @@ const SquireButtonFunctions = {
|
||||
|
||||
return this.editor.getHTML()
|
||||
},
|
||||
insertDivide(){
|
||||
|
||||
this.editor.insertHTML(`<p><div class='divide'></div><br></p>`)
|
||||
this.editor.focus()
|
||||
this.editor.moveCursorToEnd()
|
||||
},
|
||||
insertTable(wide, tall){
|
||||
console.log('Insert a table')
|
||||
|
||||
let tableSyntax = `
|
||||
<div>
|
||||
<table>
|
||||
<tr>
|
||||
<th><p><br></p></th>
|
||||
<th><p><br></p></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
`
|
||||
|
||||
tableSyntax = `
|
||||
<span class="t-table">
|
||||
<span>
|
||||
<span>
|
||||
<p><br></p>
|
||||
</span>
|
||||
<span>
|
||||
<p><br></p>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
<span>
|
||||
<p><br></p>
|
||||
</span>
|
||||
<span>
|
||||
<p><br></p>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<p><br></p>
|
||||
`
|
||||
tableSyntax = ''
|
||||
tableSyntax += '<span class="t-table">'
|
||||
for (let i = 0; i < tall; i++) {
|
||||
|
||||
for (let j = 0; j < wide; j++) {
|
||||
|
||||
}
|
||||
}
|
||||
tableSyntax += '</span><p><br></p>'
|
||||
|
||||
this.editor.insertHTML(tableSyntax)
|
||||
this.editor.focus()
|
||||
this.editor.moveCursorToEnd()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@@ -110,7 +110,7 @@
|
||||
</h2>
|
||||
|
||||
<h3 class="subtext">
|
||||
A free, secure Note App<i class="i cursor icon blinking"></i>
|
||||
A free, secure, online note taking application<i class="i cursor icon blinking"></i>
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
@@ -210,18 +210,7 @@
|
||||
<i class="bottom left corner blue pen icon"></i>
|
||||
</i>
|
||||
Document Editing Tools
|
||||
<div class="sub header">Bold, Underline, Title, Add Links, Add Tables Color Text, Color Background and more.</div>
|
||||
</div>
|
||||
</h2>
|
||||
|
||||
<h2 class="ui dividing header">
|
||||
<div class="content">
|
||||
<i class="icons">
|
||||
<i class="grey tags icon"></i>
|
||||
<i class="bottom left corner purple plus icon"></i>
|
||||
</i>
|
||||
Tag Notes
|
||||
<div class="sub header">Easily add and edit tags on notes then sort notes by tag.</div>
|
||||
<div class="sub header">Bold, Underline, Title, Add Links, Add Tables, Color Text, Color Background and more.</div>
|
||||
</div>
|
||||
</h2>
|
||||
|
||||
@@ -236,6 +225,17 @@
|
||||
</div>
|
||||
</h2>
|
||||
|
||||
<h2 class="ui dividing header">
|
||||
<div class="content">
|
||||
<i class="icons">
|
||||
<i class="grey tags icon"></i>
|
||||
<i class="bottom left corner purple plus icon"></i>
|
||||
</i>
|
||||
Tag Notes
|
||||
<div class="sub header">Easily add and edit tags on notes then sort notes by tag.</div>
|
||||
</div>
|
||||
</h2>
|
||||
|
||||
<h2 class="ui dividing header">
|
||||
<div class="content">
|
||||
<i class="icons">
|
||||
@@ -254,7 +254,7 @@
|
||||
<i class="bottom left corner share icon"></i>
|
||||
</i>
|
||||
Share Encrypted Notes
|
||||
<div class="sub header">Share notes with friends without compromising security. And its easy to disable sharing.</div>
|
||||
<div class="sub header">Share encrypted notes with friends without compromising security.</div>
|
||||
</div>
|
||||
</h2>
|
||||
|
||||
@@ -290,6 +290,17 @@
|
||||
<div class="sub header">Add text to Images and links than can be searched.</div>
|
||||
</div>
|
||||
</h2>
|
||||
|
||||
<h2 class="ui dividing header">
|
||||
<div class="content">
|
||||
<i class="icons">
|
||||
<i class="grey tv icon"></i>
|
||||
<i class="bottom left corner blue mobile icon"></i>
|
||||
</i>
|
||||
Two Factor Authentication
|
||||
<div class="sub header">Enable two factor authentication for added peace of mind.</div>
|
||||
</div>
|
||||
</h2>
|
||||
|
||||
</div>
|
||||
<div class="four wide column">
|
||||
|
@@ -25,7 +25,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<p>You will remain logged in on this browser, for 30 days or until you log out.</p>
|
||||
<p>You will remain logged in on this browser, for 20 days or until you log out.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -31,7 +31,7 @@
|
||||
<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">
|
||||
@@ -117,7 +117,7 @@
|
||||
:onClick="openNote"
|
||||
:data="note"
|
||||
:title-view="titleView"
|
||||
:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
|
||||
:currently-open="activeNoteId1 == note.id"
|
||||
:key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
||||
/>
|
||||
</div>
|
||||
@@ -132,13 +132,12 @@
|
||||
</div>
|
||||
|
||||
|
||||
<input-notes
|
||||
<note-input-panel
|
||||
v-if="activeNoteId1 != null"
|
||||
:key="'active_note_'+activeNoteId1"
|
||||
:key="activeNoteId1"
|
||||
:noteid="activeNoteId1"
|
||||
:position="activeNote1Position"
|
||||
:url-data="$route.params"
|
||||
ref="note1" />
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -151,7 +150,7 @@
|
||||
name: 'SearchBar',
|
||||
components: {
|
||||
|
||||
'input-notes': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'),
|
||||
'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,
|
||||
@@ -247,7 +246,7 @@
|
||||
|
||||
//Do not update note if its open
|
||||
if(this.activeNoteId1 != noteId){
|
||||
this.updateSingleNote(noteId, false)
|
||||
this.updateSingleNote(noteId, true)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -264,10 +263,18 @@
|
||||
//Close note event
|
||||
this.$bus.$on('close_active_note', ({noteId, modified}) => {
|
||||
|
||||
this.closeNote()
|
||||
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(parseInt(noteId), modified)
|
||||
this.updateSingleNote(noteId, modified)
|
||||
})
|
||||
|
||||
this.$bus.$on('note_deleted', (noteId) => {
|
||||
@@ -312,35 +319,25 @@
|
||||
})
|
||||
})
|
||||
|
||||
//New note button pushes open note event
|
||||
this.$bus.$on('open_note', noteId => {
|
||||
this.openNote(noteId)
|
||||
})
|
||||
|
||||
//Reload page content
|
||||
//Reload page content - don't trigger if load is in progress
|
||||
this.$bus.$on('note_reload', () => {
|
||||
this.reset()
|
||||
if(!this.loadingInProgress){
|
||||
this.reset()
|
||||
}
|
||||
})
|
||||
|
||||
//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)
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', this.onScroll)
|
||||
|
||||
//Close notes when back button is pressed
|
||||
window.addEventListener('hashchange', this.hashChangeAction)
|
||||
// window.addEventListener('hashchange', this.hashChangeAction)
|
||||
|
||||
//update note on visibility change
|
||||
document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
||||
// document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
||||
|
||||
},
|
||||
beforeDestroy(){
|
||||
window.removeEventListener('scroll', this.onScroll)
|
||||
window.removeEventListener('hashchange', this.hashChangeAction)
|
||||
document.removeEventListener('visibilitychange', this.visibiltyChangeAction)
|
||||
// document.removeEventListener('visibilitychange', this.visibiltyChangeAction)
|
||||
|
||||
this.$bus.$off('note_reload')
|
||||
this.$bus.$off('close_active_note')
|
||||
@@ -348,7 +345,6 @@
|
||||
this.$bus.$off('note_deleted')
|
||||
this.$bus.$off('update_fast_filters')
|
||||
this.$bus.$off('update_search_term')
|
||||
this.$bus.$off('open_note')
|
||||
|
||||
//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
|
||||
@@ -356,11 +352,20 @@
|
||||
},
|
||||
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()
|
||||
|
||||
// this.search(true, this.firstLoadBatchSize, false)
|
||||
// .then( r => this.search(false, this.batchSize, true))
|
||||
},
|
||||
watch: {
|
||||
'$route.params.id': function(id){
|
||||
//Open note on ID, null id will close note
|
||||
this.activeNoteId1 = id
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleTitleView(){
|
||||
@@ -382,17 +387,9 @@
|
||||
if(nodeClick == 'A'){ return }
|
||||
}
|
||||
|
||||
//1 note open
|
||||
if(this.activeNoteId1 == null){
|
||||
this.activeNoteId1 = id
|
||||
this.activeNote1Position = 0 //Middel of page
|
||||
this.$router.push('/notes/open/'+this.activeNoteId1).catch(e => { console.log(e) })
|
||||
return
|
||||
}
|
||||
},
|
||||
closeNote(position){
|
||||
this.activeNoteId1 = null
|
||||
this.$router.push('/notes')
|
||||
//Open note if a link was not clicked
|
||||
this.$router.push('/notes/open/'+id)
|
||||
return
|
||||
},
|
||||
toggleTagFilter(tagId){
|
||||
|
||||
@@ -429,34 +426,6 @@
|
||||
|
||||
return
|
||||
},
|
||||
//Try to close notes on URL hash change /notes/open/123 to /notes - parse 123, close note id 123
|
||||
hashChangeAction(event){
|
||||
|
||||
//Clean up path of hash change
|
||||
let path = window.location.protocol + '//' + window.location.hostname + window.location.pathname + window.location.hash
|
||||
let newPath = event.newURL.replace(path,'')
|
||||
let oldPath = event.oldURL.replace(path,'')
|
||||
|
||||
// console.log(this.$route.params)
|
||||
// console.log(this.$router)
|
||||
|
||||
//Open note if user goes forward to a note id
|
||||
if(this.$route.params && this.$route.params.id){
|
||||
this.openNote(this.$route.params.id)
|
||||
}
|
||||
|
||||
//If we go from open note ID to no note ID, close the note
|
||||
if(newPath == '' && oldPath.indexOf('/open/') != -1){
|
||||
//Pull note ID out of URL
|
||||
const noteIdToClose = oldPath.split('/').pop()
|
||||
|
||||
// console.log(noteIdToClose)
|
||||
|
||||
if(this.$refs.note1 && this.$refs.note1.currentNoteId == noteIdToClose){
|
||||
// this.$refs.note1.close()
|
||||
}
|
||||
}
|
||||
},
|
||||
visibiltyChangeAction(event){
|
||||
|
||||
//Fuck this shit, just use web sockets
|
||||
@@ -484,8 +453,11 @@
|
||||
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,
|
||||
@@ -508,18 +480,13 @@
|
||||
|
||||
if(note && newNote){
|
||||
|
||||
//Don't move notes that were not changed
|
||||
if(note.updated == newNote.updated){
|
||||
// return
|
||||
}
|
||||
|
||||
//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
|
||||
if(focuseAndAnimate){
|
||||
//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 => {
|
||||
@@ -536,6 +503,7 @@
|
||||
this.$nextTick( () => {
|
||||
//Trigger close animation on note
|
||||
this.$refs['note-'+noteId][0].justClosed()
|
||||
this.$refs['note-'+noteId][0].showWorking = false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -547,9 +515,14 @@
|
||||
//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()
|
||||
})
|
||||
@@ -610,7 +583,6 @@
|
||||
|
||||
//Perform search - or die
|
||||
this.loadingInProgress = true
|
||||
// console.time('Fetch TitleCard Batch '+notesInNextLoad)
|
||||
axios.post('/api/note/search', postData)
|
||||
.then(response => {
|
||||
|
||||
@@ -735,7 +707,6 @@
|
||||
this.fastFilters = {}
|
||||
this.foundAttachments = [] //Remove all attachments
|
||||
|
||||
this.$bus.$emit('reset_fast_filters')
|
||||
this.updateFastFilters(5) //This loads notes
|
||||
|
||||
},
|
||||
|
@@ -14,6 +14,11 @@
|
||||
|
||||
<div class="sixteen wide middle aligned column" v-if="quickNoteId > 0">
|
||||
|
||||
<div v-if="quickNoteId" v-on:click="openNoteEdit" class="ui compact basic button">
|
||||
<i class="file outline icon"></i>
|
||||
Open Note
|
||||
</div>
|
||||
|
||||
<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 Scratch Pad
|
||||
@@ -46,10 +51,6 @@
|
||||
<i class="folder open outline icon"></i>
|
||||
Files
|
||||
</div>
|
||||
<div v-if="quickNoteId" v-on:click="openNoteEdit" class="ui right floated basic button">
|
||||
<i class="file outline icon"></i>
|
||||
Open Note
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
182
client/src/pages/SettingsPage.vue
Normal file
182
client/src/pages/SettingsPage.vue
Normal file
@@ -0,0 +1,182 @@
|
||||
<template>
|
||||
<div class="ui grid">
|
||||
<div class="row"></div>
|
||||
<!-- spacer column -->
|
||||
<div class="sixteen wide column">
|
||||
<h2 class="ui dividing header">
|
||||
<i class="cog icon"></i>
|
||||
Settings
|
||||
</h2>
|
||||
|
||||
<!-- Accent Color -->
|
||||
<div class="ui segment">
|
||||
<div class="ui grid">
|
||||
<div class="sixteen wide column">
|
||||
<h3 class="ui header">
|
||||
Accent Color
|
||||
</h3>
|
||||
<div
|
||||
v-for="color in themeColors"
|
||||
class="ui compact basic button"
|
||||
:style="`background: linear-gradient(0deg, ${color} 4%, rgba(0,0,0,0) 5%);`"
|
||||
v-on:click="setAccentColor(color)">
|
||||
<logo style="width: 33px; height: auto;" :color="color" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Enable Two Factor -->
|
||||
<div class="ui segment">
|
||||
<h3>Two Factor Authentication</h3>
|
||||
<div class="ui stackable grid">
|
||||
<div class="four wide column">
|
||||
<p>1. Enter Password and get QR</p>
|
||||
<div class="ui fluid action input">
|
||||
<input type="password" placeholder="Current Password" v-model="password">
|
||||
|
||||
<div v-if="password.length == 0" class="ui disabled button">
|
||||
Get QR code
|
||||
</div>
|
||||
<div v-if="password.length > 0" class="ui green button" v-on:click="getQrCode()">
|
||||
Get QR code
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="five wide column">
|
||||
<p>2. Scan QR Code</p>
|
||||
<p v-if="qrCode == ''">QR Code Will appear here.</p>
|
||||
<img v-if="qrCode != ''" :src="qrCode" alt="QR Code">
|
||||
</div>
|
||||
<div class="four wide column">
|
||||
<p>3. Verify with code</p>
|
||||
<div class="ui input" v-if="qrCode != ''">
|
||||
<input type="text" placeholder="Verification Code" v-model="verificationToken" v-on:keyup.enter="verifyQrCode()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- change password -->
|
||||
<div class="ui segment">
|
||||
<h3>Change Password</h3>
|
||||
<div class="ui grid">
|
||||
<div class="five wide column">
|
||||
<label>Current Password</label>
|
||||
<div class="ui fluid input">
|
||||
<input type="text" placeholder="Current Password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="five wide column">
|
||||
<label>New Password</label>
|
||||
<div class="ui fluid input">
|
||||
<input type="text" placeholder="New Password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
<label>Rereat New Password</label>
|
||||
<div class="ui fluid action input">
|
||||
<input type="text" placeholder="Repeat Password">
|
||||
<div class="ui green button">
|
||||
Change it!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- log out -->
|
||||
<div class="ui segment">
|
||||
<div class="ui grid">
|
||||
<div class="sixteen wide column">
|
||||
<h3>Log Out</h3>
|
||||
</div>
|
||||
<div class="eight wide column">
|
||||
<div class="ui button" v-on:click="logout()">
|
||||
Log Out this browser
|
||||
</div>
|
||||
</div>
|
||||
<div class="eight wide column">
|
||||
<div class="ui button">
|
||||
Log Out all other browsers
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'SettingsPage',
|
||||
components: {
|
||||
'logo':require('@/components/LogoComponent.vue').default,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
password: '',
|
||||
qrCode: '',
|
||||
verificationToken: '',
|
||||
|
||||
themeColors: [
|
||||
'#21BA45', //Green
|
||||
'#b5cc18', //Lime
|
||||
'#00b5ad', //Teal
|
||||
'#2185d0', //Blue
|
||||
'#7128b9', //Violet
|
||||
'#a333c8', // "Purple"
|
||||
'#e03997', //Pink
|
||||
'#db2828', //Red
|
||||
'#f2711c', //Orange
|
||||
'#fbbd08', //Yellow
|
||||
'#767676', //Grey
|
||||
'#303030', //Black-almost
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
logout() {
|
||||
this.$store.commit('destroyLoginToken')
|
||||
this.$router.push('/')
|
||||
axios.post('/api/user/logout')
|
||||
setTimeout(() => {
|
||||
this.$bus.$emit('notification', 'Logged Out')
|
||||
}, 200)
|
||||
},
|
||||
setAccentColor(color){
|
||||
|
||||
let root = document.documentElement
|
||||
root.style.setProperty('--main-accent', color)
|
||||
localStorage.setItem('main-accent', color)
|
||||
|
||||
if(!color || color == '#21BA45'){
|
||||
localStorage.removeItem('main-accent')
|
||||
}
|
||||
},
|
||||
getQrCode(){
|
||||
|
||||
axios.post('/api/user/twofactorsetup', { password:this.password })
|
||||
.then(({data}) => {
|
||||
this.qrCode = data
|
||||
})
|
||||
},
|
||||
verifyQrCode(){
|
||||
|
||||
axios.post('/api/user/verifytwofactorsetuptoken', { password:this.password, token: this.verificationToken })
|
||||
.then(({data}) => {
|
||||
if(data == true){
|
||||
//Two FA is set up
|
||||
} else {
|
||||
//It failed
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@@ -6,6 +6,7 @@ import Router from 'vue-router'
|
||||
const HomePage = () => import(/* webpackChunkName: "HomePage" */ '@/pages/HomePage')
|
||||
const LoginPage = () => import(/* webpackChunkName: "LoginPage" */ '@/pages/LoginPage')
|
||||
const HelpPage = () => import(/* webpackChunkName: "HelpPage" */ '@/pages/HelpPage')
|
||||
const SettingsPage = () => import(/* webpackChunkName: "SettingsPage" */ '@/pages/SettingsPage')
|
||||
const SharePage = () => import(/* webpackChunkName: "SharePage" */ '@/pages/SharePage')
|
||||
const NotesPage = () => import(/* webpackChunkName: "NotesPage" */ '@/pages/NotesPage')
|
||||
const QuickPage = () => import(/* webpackChunkName: "QuickPage" */ '@/pages/QuickPage')
|
||||
@@ -51,6 +52,12 @@ export default new Router({
|
||||
name: 'Help',
|
||||
meta: {title:'Help'},
|
||||
component: HelpPage
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'Settings',
|
||||
meta: {title:'Settings'},
|
||||
component: SettingsPage
|
||||
},
|
||||
{
|
||||
path: '/public/note/:id/:token',
|
||||
|
@@ -85,6 +85,7 @@ export default new Vuex.Store({
|
||||
Object.keys( themes[currentTheme] ).forEach( attribute => {
|
||||
root.style.setProperty('--'+attribute, themes[currentTheme][attribute])
|
||||
})
|
||||
|
||||
},
|
||||
detectIsUserOnMobile(state){
|
||||
|
||||
|
Reference in New Issue
Block a user