feat: warning for protected note without protection

- Use `.sn-button` everywhere
- Delete permissions modal
- Capitalize "Clear session data"
This commit is contained in:
Baptiste Grob
2021-03-22 16:51:49 +01:00
parent cd7b5cc455
commit cc474da0c3
25 changed files with 418 additions and 476 deletions

View File

@@ -43,7 +43,6 @@ import {
MenuRow,
PanelResizer,
PasswordWizard,
PermissionsModal,
RevisionPreviewModal,
HistoryMenu,
SyncResolutionMenu,
@@ -57,6 +56,7 @@ import { StartApplication } from './startApplication';
import { Bridge } from './services/bridge';
import { SessionsModalDirective } from './components/SessionsModal';
import { NoAccountWarningDirective } from './components/NoAccountWarning';
import { NoProtectionsdNoteWarningDirective } from './components/NoProtectionsNoteWarning';
function reloadHiddenFirefoxTab(): boolean {
@@ -138,12 +138,12 @@ const startApplication: StartApplication = async function startApplication(
.directive('menuRow', () => new MenuRow())
.directive('panelResizer', () => new PanelResizer())
.directive('passwordWizard', () => new PasswordWizard())
.directive('permissionsModal', () => new PermissionsModal())
.directive('revisionPreviewModal', () => new RevisionPreviewModal())
.directive('historyMenu', () => new HistoryMenu())
.directive('syncResolutionMenu', () => new SyncResolutionMenu())
.directive('sessionsModal', SessionsModalDirective)
.directive('noAccountWarning', NoAccountWarningDirective);
.directive('noAccountWarning', NoAccountWarningDirective)
.directive('protectedNotePanel', NoProtectionsdNoteWarningDirective);
// Filters
angular.module('app').filter('trusted', ['$sce', trusted]);

View File

@@ -2,7 +2,9 @@ import { toDirective, useAutorunValue } from './utils';
import Close from '../../icons/ic_close.svg';
import { AppState } from '@/ui_models/app_state';
function NoAccountWarning({ appState }: { appState: AppState }) {
type Props = { appState: AppState };
function NoAccountWarning({ appState }: Props) {
const canShow = useAutorunValue(() => appState.noAccountWarning.show);
if (!canShow) {
return null;
@@ -14,7 +16,7 @@ function NoAccountWarning({ appState }: { appState: AppState }) {
Sign in or register to back up your notes.
</p>
<button
className="sn-btn mt-3 col-start-1 col-end-3 justify-self-start"
className="sn-button info mt-3 col-start-1 col-end-3 justify-self-start"
onClick={(event) => {
event.stopPropagation();
appState.accountMenu.setShow(true);
@@ -28,12 +30,13 @@ function NoAccountWarning({ appState }: { appState: AppState }) {
}}
title="Ignore"
label="Ignore"
style="height: 20px"
className="border-0 m-0 p-0 bg-transparent cursor-pointer rounded-md col-start-2 row-start-1 color-neutral hover:color-info"
>
<Close className="fill-current" />
<Close className="fill-current block" />
</button>
</div>
);
}
export const NoAccountWarningDirective = toDirective(NoAccountWarning);
export const NoAccountWarningDirective = toDirective<Props>(NoAccountWarning);

View File

@@ -0,0 +1,37 @@
import { AppState } from '@/ui_models/app_state';
import { toDirective } from './utils';
type Props = { appState: AppState; onViewNote: () => void };
function NoProtectionsNoteWarning({ appState, onViewNote }: Props) {
console.log("🚀 ~ file: NoProtectionsNoteWarning.tsx ~ line 7 ~ NoProtectionsNoteWarning ~ onViewNote", onViewNote)
return (
<div className="flex flex-col items-center justify-center text-center max-w-md">
<h1 className="text-2xl m-0 w-full">This note is protected</h1>
<p className="text-lg mt-2 w-full">
Add a passcode or create an account to require authentication to view
this note.
</p>
<div className="mt-4 flex gap-3">
<button
className="sn-button info"
onClick={() => {
appState.accountMenu.setShow(true);
}}
>
Open account menu
</button>
<button className="sn-button outlined" onClick={onViewNote}>
View note
</button>
</div>
</div>
);
}
export const NoProtectionsdNoteWarningDirective = toDirective<Props>(
NoProtectionsNoteWarning,
{
onViewNote: '&',
}
);

View File

@@ -171,7 +171,7 @@ const SessionsModal: FunctionComponent<{
{formatter.format(session.updated_at)}
</p>
<button
className="sk-button danger sk-label"
className="sn-button danger sk-label"
disabled={session.revoking}
onClick={() =>
setRevokingSessionUuid(session.uuid)
@@ -210,17 +210,16 @@ const SessionsModal: FunctionComponent<{
<AlertDialogDescription className="sk-panel-row">
<p>{SessionStrings.RevokeText}</p>
</AlertDialogDescription>
<div className="sk-panel-row">
<div className="sk-button-group">
<div className="flex my-1 gap-2">
<button
className="sk-button neutral sk-label"
className="sn-button neutral sk-label"
ref={cancelRevokeRef}
onClick={closeRevokeSessionAlert}
>
<span>{SessionStrings.RevokeCancelButton}</span>
</button>
<button
className="sk-button danger sk-label"
className="sn-button danger sk-label"
onClick={() => {
closeRevokeSessionAlert();
revokeSession(confirmRevokingSessionUuid);
@@ -228,7 +227,6 @@ const SessionsModal: FunctionComponent<{
>
<span>{SessionStrings.RevokeConfirmButton}</span>
</button>
</div>
</div>
</div>
</div>

View File

@@ -20,11 +20,9 @@ export function useAutorun(
useEffect(() => autorun(view, opts), [view, opts]);
}
export function toDirective(
component: FunctionComponent<{
application: WebApplication;
appState: AppState;
}>
export function toDirective<Props>(
component: FunctionComponent<Props>,
scope: Record<string, '=' | '&'> = {}
) {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
return function () {
@@ -37,10 +35,7 @@ export function toDirective(
return {
$onChanges() {
render(
h(component, {
application: $scope.application,
appState: $scope.appState,
}),
h(component, $scope),
$element[0]
);
},
@@ -50,6 +45,7 @@ export function toDirective(
scope: {
application: '=',
appState: '=',
...scope,
},
};
};

View File

@@ -7,7 +7,6 @@ export { InputModal } from './inputModal';
export { MenuRow } from './menuRow';
export { PanelResizer } from './panelResizer';
export { PasswordWizard } from './passwordWizard';
export { PermissionsModal } from './permissionsModal';
export { RevisionPreviewModal } from './revisionPreviewModal';
export { HistoryMenu } from './historyMenu';
export { SyncResolutionMenu } from './syncResolutionMenu';

View File

@@ -1,47 +0,0 @@
import { WebDirective } from './../../types';
import template from '%/directives/permissions-modal.pug';
class PermissionsModalCtrl {
$element: JQLite
callback!: (success: boolean) => void
/* @ngInject */
constructor($element: JQLite) {
this.$element = $element;
}
dismiss() {
const elem = this.$element;
const scope = elem.scope();
scope.$destroy();
elem.remove();
}
accept() {
this.callback(true);
this.dismiss();
}
deny() {
this.callback(false);
this.dismiss();
}
}
export class PermissionsModal extends WebDirective {
constructor() {
super();
this.restrict = 'E';
this.template = template;
this.controller = PermissionsModalCtrl;
this.controllerAs = 'ctrl';
this.bindToController = true;
this.scope = {
show: '=',
component: '=',
permissionsString: '=',
callback: '='
};
}
}

View File

@@ -4,7 +4,6 @@
import '@reach/dialog/styles.css';
import 'sn-stylekit/dist/stylekit.css';
import '../stylesheets/index.css.scss';
// import '../stylesheets/_reach-sub.scss';
// Vendor
import 'angular';

View File

@@ -26,7 +26,6 @@
.sk-sublabel(ng-if='descriptor.identifier == ctrl.activeApplication.identifier')
| Current Application
.sk-menu-panel-column(ng-if='descriptor.identifier == ctrl.activeApplication.identifier')
.sk-button.success(
button.sn-button.success(
ng-click='ctrl.renameDescriptor($event, descriptor)'
)
.sk-label Rename
) Rename

View File

@@ -1,4 +1,4 @@
.main-ui-view(
.main-ui-view.sn-component(
ng-class='self.platformString'
)
#app.app(

View File

@@ -279,18 +279,16 @@ function ChallengeModalView({ ctrl }: { ctrl: ChallengeModalCtrl }) {
</div>
</div>
<div className="sk-panel-footer extra-padding">
<div
<button
className={
'sk-button big block bold ' +
'sn-button w-full py-3 text-base ' +
(ctrl.state.processing ? 'neutral' : 'info')
}
disabled={ctrl.state.processing}
onClick={() => ctrl.submit()}
>
<div className="sk-label">
{ctrl.state.processing ? 'Generating Keys…' : 'Submit'}
</div>
</div>
{ctrl.state.processing ? 'Generating Keys…' : 'Submit'}
</button>
{ctrl.challenge.cancelable && (
<>
<div className="sk-panel-row"></div>

View File

@@ -1,267 +1,275 @@
#editor-column.section.editor.sn-component(aria-label='Note')
.sn-component
.sk-app-bar.no-edges(
ng-if='self.noteLocked',
ng-init="self.lockText = 'Note Locked'",
ng-mouseleave="self.lockText = 'Note Locked'",
ng-mouseover="self.lockText = 'Unlock'"
)
.left
.sk-app-bar-item(ng-click='self.toggleLockNote()')
.sk-label.warning
i.icon.ion-locked
| {{self.lockText}}
#editor-title-bar.section-title-bar(
ng-class="{'locked' : self.noteLocked}",
ng-show='self.note && !self.note.errorDecrypting'
)
.title
input#note-title-editor.input(
ng-blur='self.onTitleBlur()',
ng-change='self.onTitleChange()',
ng-disabled='self.noteLocked',
ng-focus='self.onTitleFocus()',
ng-keyup='$event.keyCode == 13 && self.onTitleEnter($event)',
ng-model='self.editorValues.title',
select-on-focus='true',
spellcheck='false'
)
#save-status
.message(
ng-class="{'warning sk-bold': self.state.syncTakingTooLong, 'danger sk-bold': self.state.saveError}"
) {{self.state.noteStatus.message}}
.desc(ng-show='self.state.noteStatus.desc') {{self.state.noteStatus.desc}}
.editor-tags
#note-tags-component-container(ng-if='self.state.tagsComponent && !self.note.errorDecrypting')
component-view.component-view(
component-uuid='self.state.tagsComponent.uuid',
ng-class="{'locked' : self.noteLocked}",
ng-style="self.noteLocked && {'pointer-events' : 'none'}",
application='self.application'
)
input.tags-input(
ng-blur='self.onTagsInputBlur()',
ng-disabled='self.noteLocked',
ng-if='!self.state.tagsComponent',
ng-keyup='$event.keyCode == 13 && $event.target.blur();',
ng-model='self.editorValues.tagsInputValue',
placeholder='#tags',
spellcheck='false',
type='text'
)
.sn-component(ng-if='self.note')
#editor-menu-bar.sk-app-bar.no-edges
.left
.sk-app-bar-item(
click-outside=`self.setMenuState('showOptionsMenu', false)`,
is-open='self.state.showOptionsMenu',
ng-class="{'selected' : self.state.showOptionsMenu}",
ng-click="self.toggleMenu('showOptionsMenu')"
)
.sk-label Options
.sk-menu-panel.dropdown-menu(ng-if='self.state.showOptionsMenu')
.sk-menu-panel-section
.sk-menu-panel-header
.sk-menu-panel-header-title Note Options
menu-row(
action='self.selectedMenuItem(true); self.togglePin()'
desc="'Pin or unpin a note from the top of your list'",
label="self.note.pinned ? 'Unpin' : 'Pin'"
)
menu-row(
action='self.selectedMenuItem(true); self.toggleArchiveNote()'
desc="'Archive or unarchive a note from your Archived system tag'",
label="self.note.archived ? 'Unarchive' : 'Archive'"
)
menu-row(
action='self.selectedMenuItem(true); self.toggleLockNote()'
desc="'Locking notes prevents unintentional editing'",
label="self.noteLocked ? 'Unlock' : 'Lock'"
)
menu-row(
action='self.selectedMenuItem(true); self.toggleProtectNote()'
desc=`'Protecting a note will require credentials to view it'`,
label="self.note.protected ? 'Unprotect' : 'Protect'"
)
menu-row(
action='self.selectedMenuItem(true); self.toggleNotePreview()'
circle="self.note.hidePreview ? 'danger' : 'success'",
circle-align="'right'",
desc="'Hide or unhide the note preview from the list of notes'",
label="'Preview'"
)
menu-row(
action='self.selectedMenuItem(); self.deleteNote()'
desc="'Send this note to the trash'",
label="'Move to Trash'",
ng-show='!self.state.altKeyDown && !self.note.trashed && !self.note.errorDecrypting',
stylekit-class="'warning'"
)
menu-row(
action='self.selectedMenuItem(); self.deleteNotePermanantely()'
desc="'Delete this note permanently from all your devices'",
label="'Delete Permanently'",
ng-show='!self.note.trashed && self.note.errorDecrypting',
stylekit-class="'danger'"
)
div(ng-if='self.note.trashed || self.state.altKeyDown')
menu-row(
action='self.selectedMenuItem(true); self.restoreTrashedNote()'
desc="'Undelete this note and restore it back into your notes'",
label="'Restore'",
ng-show='self.note.trashed',
stylekit-class="'info'"
)
menu-row(
action='self.selectedMenuItem(true); self.deleteNotePermanantely()'
desc="'Delete this note permanently from all your devices'",
label="'Delete Permanently'",
stylekit-class="'danger'"
)
menu-row(
action='self.selectedMenuItem(true); self.emptyTrash()'
desc="'Permanently delete all notes in the trash'",
label="'Empty Trash'",
ng-show='self.note.trashed || !self.state.altKeyDown',
stylekit-class="'danger'",
subtitle="self.getTrashCount() + ' notes in trash'"
)
.sk-menu-panel-section
.sk-menu-panel-header
.sk-menu-panel-header-title Global Display
menu-row(
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMonospace)"
circle="self.state.monospaceFont ? 'success' : 'neutral'",
desc="'Toggles the font style for the default editor'",
disabled='self.state.editorComponent',
label="'Monospace Font'",
subtitle="self.state.editorComponent ? 'Not available with editor extensions' : null"
)
menu-row(
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeySpellcheck)"
circle="self.state.spellcheck ? 'success' : 'neutral'",
desc="'Toggles spellcheck for the default editor'",
disabled='self.state.editorComponent',
label="'Spellcheck'",
subtitle=`
self.state.editorComponent
? 'Not available with editor extensions'
: (self.state.isDesktop ? 'May degrade editor performance' : null)
`)
menu-row(
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMarginResizers)"
circle="self.state.marginResizersEnabled ? 'success' : 'neutral'",
desc="'Allows for editor left and right margins to be resized'",
faded='!self.state.marginResizersEnabled',
label="'Margin Resizers'"
)
.sk-app-bar-item(
click-outside=`self.setMenuState('showEditorMenu', false)`
is-open='self.state.showEditorMenu',
ng-class="{'selected' : self.state.showEditorMenu}",
ng-click="self.toggleMenu('showEditorMenu')"
)
.sk-label Editor
editor-menu(
callback='self.editorMenuOnSelect',
current-item='self.note',
ng-if='self.state.showEditorMenu',
selected-editor-uuid='self.state.editorComponent && self.state.editorComponent.uuid',
application='self.application'
)
.sk-app-bar-item(
click-outside=`self.setMenuState('showActionsMenu', false)`,
is-open='self.state.showActionsMenu',
ng-class="{'selected' : self.state.showActionsMenu}",
ng-click="self.toggleMenu('showActionsMenu')"
)
.sk-label Actions
actions-menu(
item='self.note',
ng-if='self.state.showActionsMenu',
application='self.application'
)
.sk-app-bar-item(
click-outside=`self.setMenuState('showHistoryMenu', false)`,
is-open='self.state.showHistoryMenu',
ng-class="{'selected' : self.state.showHistoryMenu}",
ng-click="self.toggleMenu('showHistoryMenu')"
)
.sk-label History
history-menu(
item='self.note',
ng-if='self.state.showHistoryMenu',
application='self.application'
)
#editor-content.editor-content(ng-if='!self.note.errorDecrypting')
panel-resizer.left(
control='self.leftPanelPuppet',
hoverable='true',
min-width='300',
ng-if='self.state.marginResizersEnabled',
on-resize-finish='self.onPanelResizeFinish',
panel-id="'editor-content'",
property="'left'"
)
component-view.component-view(
component-uuid='self.state.editorComponent.uuid',
ng-if='self.state.editorComponent && !self.state.editorUnloading',
on-load='self.onEditorLoad',
application='self.application'
)
textarea#note-text-editor.editable.font-editor(
dir='auto',
ng-attr-spellcheck='{{self.state.spellcheck}}',
ng-change='self.contentChanged()',
ng-click='self.clickedTextArea()',
ng-focus='self.onContentFocus()',
ng-if='!self.state.editorComponent && !self.state.textareaUnloading',
ng-model='self.editorValues.text',
ng-model-options='{ debounce: self.state.editorDebounce}',
ng-readonly='self.noteLocked',
ng-trim='false'
autocomplete='off'
)
| {{self.onSystemEditorLoad()}}
panel-resizer(
control='self.rightPanelPuppet',
hoverable='true', min-width='300',
ng-if='self.state.marginResizersEnabled',
on-resize-finish='self.onPanelResizeFinish',
panel-id="'editor-content'",
property="'right'"
)
.section(ng-show='self.note.errorDecrypting')
.sn-component#error-decrypting-container
.sk-panel#error-decrypting-panel
.sk-panel-header
.sk-panel-header-title {{self.note.waitingForKey ? 'Waiting for Key' : 'Unable to Decrypt'}}
.sk-panel-content
.sk-panel-section
p.sk-p(ng-if='self.note.waitingForKey')
| This note is awaiting its encryption key to be ready. Please wait for syncing to complete
| for this note to be decrypted.
p.sk-p(ng-if='!self.note.waitingForKey')
| There was an error decrypting this item. Ensure you are running the
| latest version of this app, then sign out and sign back in to try again.
#editor-pane-component-stack(ng-if='!self.note.errorDecrypting' ng-show='self.note')
#component-stack-menu-bar.sk-app-bar.no-edges(ng-if='self.state.stackComponents.length')
.left
.sk-app-bar-item(
ng-repeat='component in self.state.stackComponents track by component.uuid'
ng-click='self.toggleStackComponentForCurrentItem(component)',
)
.sk-app-bar-item-column
.sk-circle.small(
ng-class="{'info' : !self.stackComponentHidden(component) && component.active, 'neutral' : self.stackComponentHidden(component) || !component.active}"
)
.sk-app-bar-item-column
.sk-label {{component.name}}
protected-note-panel.h-full.flex.justify-center.items-center(
ng-if='self.note.protected && !self.state.showEditor'
app-state='self.appState'
on-view-note='self.dismissProtectedWarning()'
)
div(
ng-if='self.state.showEditor'
)
.sn-component
component-view.component-view.component-stack-item(
ng-repeat='component in self.state.stackComponents track by component.uuid',
component-uuid='component.uuid',
manual-dealloc='true',
ng-show='!self.stackComponentHidden(component)',
application='self.application'
.sk-app-bar.no-edges(
ng-if='self.noteLocked',
ng-init="self.lockText = 'Note Locked'",
ng-mouseleave="self.lockText = 'Note Locked'",
ng-mouseover="self.lockText = 'Unlock'"
)
.left
.sk-app-bar-item(ng-click='self.toggleLockNote()')
.sk-label.warning
i.icon.ion-locked
| {{self.lockText}}
#editor-title-bar.section-title-bar(
ng-class="{'locked' : self.noteLocked}",
ng-show='self.note && !self.note.errorDecrypting'
)
.title
input#note-title-editor.input(
ng-blur='self.onTitleBlur()',
ng-change='self.onTitleChange()',
ng-disabled='self.noteLocked',
ng-focus='self.onTitleFocus()',
ng-keyup='$event.keyCode == 13 && self.onTitleEnter($event)',
ng-model='self.editorValues.title',
select-on-focus='true',
spellcheck='false'
)
#save-status
.message(
ng-class="{'warning sk-bold': self.state.syncTakingTooLong, 'danger sk-bold': self.state.saveError}"
) {{self.state.noteStatus.message}}
.desc(ng-show='self.state.noteStatus.desc') {{self.state.noteStatus.desc}}
.editor-tags
#note-tags-component-container(ng-if='self.state.tagsComponent && !self.note.errorDecrypting')
component-view.component-view(
component-uuid='self.state.tagsComponent.uuid',
ng-class="{'locked' : self.noteLocked}",
ng-style="self.noteLocked && {'pointer-events' : 'none'}",
application='self.application'
)
input.tags-input(
ng-blur='self.onTagsInputBlur()',
ng-disabled='self.noteLocked',
ng-if='!self.state.tagsComponent',
ng-keyup='$event.keyCode == 13 && $event.target.blur();',
ng-model='self.editorValues.tagsInputValue',
placeholder='#tags',
spellcheck='false',
type='text'
)
.sn-component(ng-if='self.note')
#editor-menu-bar.sk-app-bar.no-edges
.left
.sk-app-bar-item(
click-outside=`self.setMenuState('showOptionsMenu', false)`,
is-open='self.state.showOptionsMenu',
ng-class="{'selected' : self.state.showOptionsMenu}",
ng-click="self.toggleMenu('showOptionsMenu')"
)
.sk-label Options
.sk-menu-panel.dropdown-menu(ng-if='self.state.showOptionsMenu')
.sk-menu-panel-section
.sk-menu-panel-header
.sk-menu-panel-header-title Note Options
menu-row(
action='self.selectedMenuItem(true); self.togglePin()'
desc="'Pin or unpin a note from the top of your list'",
label="self.note.pinned ? 'Unpin' : 'Pin'"
)
menu-row(
action='self.selectedMenuItem(true); self.toggleArchiveNote()'
desc="'Archive or unarchive a note from your Archived system tag'",
label="self.note.archived ? 'Unarchive' : 'Archive'"
)
menu-row(
action='self.selectedMenuItem(true); self.toggleLockNote()'
desc="'Locking notes prevents unintentional editing'",
label="self.noteLocked ? 'Unlock' : 'Lock'"
)
menu-row(
action='self.selectedMenuItem(true); self.toggleProtectNote()'
desc=`'Protecting a note will require credentials to view it'`,
label="self.note.protected ? 'Unprotect' : 'Protect'"
)
menu-row(
action='self.selectedMenuItem(true); self.toggleNotePreview()'
circle="self.note.hidePreview ? 'danger' : 'success'",
circle-align="'right'",
desc="'Hide or unhide the note preview from the list of notes'",
label="'Preview'"
)
menu-row(
action='self.selectedMenuItem(); self.deleteNote()'
desc="'Send this note to the trash'",
label="'Move to Trash'",
ng-show='!self.state.altKeyDown && !self.note.trashed && !self.note.errorDecrypting',
stylekit-class="'warning'"
)
menu-row(
action='self.selectedMenuItem(); self.deleteNotePermanantely()'
desc="'Delete this note permanently from all your devices'",
label="'Delete Permanently'",
ng-show='!self.note.trashed && self.note.errorDecrypting',
stylekit-class="'danger'"
)
div(ng-if='self.note.trashed || self.state.altKeyDown')
menu-row(
action='self.selectedMenuItem(true); self.restoreTrashedNote()'
desc="'Undelete this note and restore it back into your notes'",
label="'Restore'",
ng-show='self.note.trashed',
stylekit-class="'info'"
)
menu-row(
action='self.selectedMenuItem(true); self.deleteNotePermanantely()'
desc="'Delete this note permanently from all your devices'",
label="'Delete Permanently'",
stylekit-class="'danger'"
)
menu-row(
action='self.selectedMenuItem(true); self.emptyTrash()'
desc="'Permanently delete all notes in the trash'",
label="'Empty Trash'",
ng-show='self.note.trashed || !self.state.altKeyDown',
stylekit-class="'danger'",
subtitle="self.getTrashCount() + ' notes in trash'"
)
.sk-menu-panel-section
.sk-menu-panel-header
.sk-menu-panel-header-title Global Display
menu-row(
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMonospace)"
circle="self.state.monospaceFont ? 'success' : 'neutral'",
desc="'Toggles the font style for the default editor'",
disabled='self.state.editorComponent',
label="'Monospace Font'",
subtitle="self.state.editorComponent ? 'Not available with editor extensions' : null"
)
menu-row(
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeySpellcheck)"
circle="self.state.spellcheck ? 'success' : 'neutral'",
desc="'Toggles spellcheck for the default editor'",
disabled='self.state.editorComponent',
label="'Spellcheck'",
subtitle=`
self.state.editorComponent
? 'Not available with editor extensions'
: (self.state.isDesktop ? 'May degrade editor performance' : null)
`)
menu-row(
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMarginResizers)"
circle="self.state.marginResizersEnabled ? 'success' : 'neutral'",
desc="'Allows for editor left and right margins to be resized'",
faded='!self.state.marginResizersEnabled',
label="'Margin Resizers'"
)
.sk-app-bar-item(
click-outside=`self.setMenuState('showEditorMenu', false)`
is-open='self.state.showEditorMenu',
ng-class="{'selected' : self.state.showEditorMenu}",
ng-click="self.toggleMenu('showEditorMenu')"
)
.sk-label Editor
editor-menu(
callback='self.editorMenuOnSelect',
current-item='self.note',
ng-if='self.state.showEditorMenu',
selected-editor-uuid='self.state.editorComponent && self.state.editorComponent.uuid',
application='self.application'
)
.sk-app-bar-item(
click-outside=`self.setMenuState('showActionsMenu', false)`,
is-open='self.state.showActionsMenu',
ng-class="{'selected' : self.state.showActionsMenu}",
ng-click="self.toggleMenu('showActionsMenu')"
)
.sk-label Actions
actions-menu(
item='self.note',
ng-if='self.state.showActionsMenu',
application='self.application'
)
.sk-app-bar-item(
click-outside=`self.setMenuState('showHistoryMenu', false)`,
is-open='self.state.showHistoryMenu',
ng-class="{'selected' : self.state.showHistoryMenu}",
ng-click="self.toggleMenu('showHistoryMenu')"
)
.sk-label History
history-menu(
item='self.note',
ng-if='self.state.showHistoryMenu',
application='self.application'
)
#editor-content.editor-content(ng-if='!self.note.errorDecrypting')
panel-resizer.left(
control='self.leftPanelPuppet',
hoverable='true',
min-width='300',
ng-if='self.state.marginResizersEnabled',
on-resize-finish='self.onPanelResizeFinish',
panel-id="'editor-content'",
property="'left'"
)
component-view.component-view(
component-uuid='self.state.editorComponent.uuid',
ng-if='self.state.editorComponent && !self.state.editorUnloading',
on-load='self.onEditorLoad',
application='self.application'
)
textarea#note-text-editor.editable.font-editor(
dir='auto',
ng-attr-spellcheck='{{self.state.spellcheck}}',
ng-change='self.contentChanged()',
ng-click='self.clickedTextArea()',
ng-focus='self.onContentFocus()',
ng-if='!self.state.editorComponent && !self.state.textareaUnloading',
ng-model='self.editorValues.text',
ng-model-options='{ debounce: self.state.editorDebounce}',
ng-readonly='self.noteLocked',
ng-trim='false'
autocomplete='off'
)
| {{self.onSystemEditorLoad()}}
panel-resizer(
control='self.rightPanelPuppet',
hoverable='true', min-width='300',
ng-if='self.state.marginResizersEnabled',
on-resize-finish='self.onPanelResizeFinish',
panel-id="'editor-content'",
property="'right'"
)
.section(ng-show='self.note.errorDecrypting')
.sn-component#error-decrypting-container
.sk-panel#error-decrypting-panel
.sk-panel-header
.sk-panel-header-title {{self.note.waitingForKey ? 'Waiting for Key' : 'Unable to Decrypt'}}
.sk-panel-content
.sk-panel-section
p.sk-p(ng-if='self.note.waitingForKey')
| This note is awaiting its encryption key to be ready. Please wait for syncing to complete
| for this note to be decrypted.
p.sk-p(ng-if='!self.note.waitingForKey')
| There was an error decrypting this item. Ensure you are running the
| latest version of this app, then sign out and sign back in to try again.
#editor-pane-component-stack(ng-if='!self.note.errorDecrypting' ng-show='self.note')
#component-stack-menu-bar.sk-app-bar.no-edges(ng-if='self.state.stackComponents.length')
.left
.sk-app-bar-item(
ng-repeat='component in self.state.stackComponents track by component.uuid'
ng-click='self.toggleStackComponentForCurrentItem(component)',
)
.sk-app-bar-item-column
.sk-circle.small(
ng-class="{'info' : !self.stackComponentHidden(component) && component.active, 'neutral' : self.stackComponentHidden(component) || !component.active}"
)
.sk-app-bar-item-column
.sk-label {{component.name}}
.sn-component
component-view.component-view.component-stack-item(
ng-repeat='component in self.state.stackComponents track by component.uuid',
component-uuid='component.uuid',
manual-dealloc='true',
ng-show='!self.stackComponentHidden(component)',
application='self.application'
)

View File

@@ -80,6 +80,7 @@ type EditorState = {
textareaUnloading: boolean
/** Fields that can be directly mutated by the template */
mutable: any
showEditor: boolean
}
type EditorValues = {
@@ -223,7 +224,8 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
textareaUnloading: false,
mutable: {
tagsString: ''
}
},
showEditor: false,
} as EditorState;
}
@@ -272,15 +274,17 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
async handleEditorNoteChange() {
this.cancelPendingSetStatus();
const note = this.editor.note;
const showEditor = !note.protected;
await this.setState({
showActionsMenu: false,
showOptionsMenu: false,
showEditorMenu: false,
showHistoryMenu: false,
altKeyDown: false,
noteStatus: undefined
noteStatus: undefined,
showEditor,
});
const note = this.editor.note;
this.editorValues.title = note.title;
this.editorValues.text = note.text;
this.reloadEditor();
@@ -288,11 +292,18 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
this.reloadPreferences();
this.reloadStackComponents();
this.reloadNoteTagsComponent();
if (note.safeText().length === 0) {
if (note.safeText().length === 0 && showEditor) {
this.focusTitle();
}
}
async dismissProtectedWarning() {
await this.setState({
showEditor: true
});
this.focusTitle();
}
/**
* Because note.locked accesses note.content.appData,
* we do not want to expose the template to direct access to note.locked,

View File

@@ -1,5 +1,7 @@
editor-view(
.flex-grow(
ng-repeat='editor in self.editors'
application='self.application'
editor='editor'
)
editor-view(
application='self.application'
editor='editor'
)