diff --git a/app/assets/javascripts/app.ts b/app/assets/javascripts/app.ts index 8f1aab4d7..396efb323 100644 --- a/app/assets/javascripts/app.ts +++ b/app/assets/javascripts/app.ts @@ -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]); diff --git a/app/assets/javascripts/components/NoAccountWarning.tsx b/app/assets/javascripts/components/NoAccountWarning.tsx index 83b7dc9c4..f9f8ea719 100644 --- a/app/assets/javascripts/components/NoAccountWarning.tsx +++ b/app/assets/javascripts/components/NoAccountWarning.tsx @@ -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.

); } -export const NoAccountWarningDirective = toDirective(NoAccountWarning); +export const NoAccountWarningDirective = toDirective(NoAccountWarning); diff --git a/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx b/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx new file mode 100644 index 000000000..ab84eaff2 --- /dev/null +++ b/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx @@ -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 ( +
+

This note is protected

+

+ Add a passcode or create an account to require authentication to view + this note. +

+
+ + +
+
+ ); +} + +export const NoProtectionsdNoteWarningDirective = toDirective( + NoProtectionsNoteWarning, + { + onViewNote: '&', + } +); diff --git a/app/assets/javascripts/components/SessionsModal.tsx b/app/assets/javascripts/components/SessionsModal.tsx index 67c534a9e..e00b07a26 100644 --- a/app/assets/javascripts/components/SessionsModal.tsx +++ b/app/assets/javascripts/components/SessionsModal.tsx @@ -171,7 +171,7 @@ const SessionsModal: FunctionComponent<{ {formatter.format(session.updated_at)}

- diff --git a/app/assets/javascripts/components/utils.ts b/app/assets/javascripts/components/utils.ts index 96fa8a4f8..f1918328f 100644 --- a/app/assets/javascripts/components/utils.ts +++ b/app/assets/javascripts/components/utils.ts @@ -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( + component: FunctionComponent, + scope: Record = {} ) { // 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, }, }; }; diff --git a/app/assets/javascripts/directives/views/index.ts b/app/assets/javascripts/directives/views/index.ts index 99931e2bb..386e123d1 100644 --- a/app/assets/javascripts/directives/views/index.ts +++ b/app/assets/javascripts/directives/views/index.ts @@ -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'; diff --git a/app/assets/javascripts/directives/views/permissionsModal.ts b/app/assets/javascripts/directives/views/permissionsModal.ts deleted file mode 100644 index b547fec05..000000000 --- a/app/assets/javascripts/directives/views/permissionsModal.ts +++ /dev/null @@ -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: '=' - }; - } -} diff --git a/app/assets/javascripts/index.ts b/app/assets/javascripts/index.ts index d623c79f5..592300a31 100644 --- a/app/assets/javascripts/index.ts +++ b/app/assets/javascripts/index.ts @@ -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'; diff --git a/app/assets/javascripts/views/account_switcher/account-switcher.pug b/app/assets/javascripts/views/account_switcher/account-switcher.pug index 8596611a7..b65e05fa9 100644 --- a/app/assets/javascripts/views/account_switcher/account-switcher.pug +++ b/app/assets/javascripts/views/account_switcher/account-switcher.pug @@ -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 \ No newline at end of file + ) Rename diff --git a/app/assets/javascripts/views/application/application-view.pug b/app/assets/javascripts/views/application/application-view.pug index b428a9fab..34d47c37e 100644 --- a/app/assets/javascripts/views/application/application-view.pug +++ b/app/assets/javascripts/views/application/application-view.pug @@ -1,4 +1,4 @@ -.main-ui-view( +.main-ui-view.sn-component( ng-class='self.platformString' ) #app.app( diff --git a/app/assets/javascripts/views/challenge_modal/challenge_modal.tsx b/app/assets/javascripts/views/challenge_modal/challenge_modal.tsx index a1f486b7c..d5564f59d 100644 --- a/app/assets/javascripts/views/challenge_modal/challenge_modal.tsx +++ b/app/assets/javascripts/views/challenge_modal/challenge_modal.tsx @@ -279,18 +279,16 @@ function ChallengeModalView({ ctrl }: { ctrl: ChallengeModalCtrl }) {
-
ctrl.submit()} > -
- {ctrl.state.processing ? 'Generating Keys…' : 'Submit'} -
-
+ {ctrl.state.processing ? 'Generating Keys…' : 'Submit'} + {ctrl.challenge.cancelable && ( <>
diff --git a/app/assets/javascripts/views/editor/editor-view.pug b/app/assets/javascripts/views/editor/editor-view.pug index 4784a9151..fd59d0ba9 100644 --- a/app/assets/javascripts/views/editor/editor-view.pug +++ b/app/assets/javascripts/views/editor/editor-view.pug @@ -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' + ) diff --git a/app/assets/javascripts/views/editor/editor_view.ts b/app/assets/javascripts/views/editor/editor_view.ts index 5f36183d7..ee841f627 100644 --- a/app/assets/javascripts/views/editor/editor_view.ts +++ b/app/assets/javascripts/views/editor/editor_view.ts @@ -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 { textareaUnloading: false, mutable: { tagsString: '' - } + }, + showEditor: false, } as EditorState; } @@ -272,15 +274,17 @@ class EditorViewCtrl extends PureViewCtrl { 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 { 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, diff --git a/app/assets/javascripts/views/editor_group/editor-group-view.pug b/app/assets/javascripts/views/editor_group/editor-group-view.pug index 22f7e72ec..96a0517e0 100644 --- a/app/assets/javascripts/views/editor_group/editor-group-view.pug +++ b/app/assets/javascripts/views/editor_group/editor-group-view.pug @@ -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' ) diff --git a/app/assets/stylesheets/_sn.scss b/app/assets/stylesheets/_sn.scss deleted file mode 100644 index 420dd8b24..000000000 --- a/app/assets/stylesheets/_sn.scss +++ /dev/null @@ -1,16 +0,0 @@ -/* Generic UI controls that have yet to be extracted into Stylekit */ - -.sn-btn { - @extend .border-0; - @extend .bg-main; - @extend .cursor-pointer; - @extend .capitalize; - @extend .font-bold; - @extend .py-2; - @extend .px-3; - @extend .rounded; - @extend .text-info-contrast; - @extend .text-sm; - - @extend .hover\:brightness-130; -} diff --git a/app/assets/stylesheets/_ui.scss b/app/assets/stylesheets/_ui.scss index 2b44ab40f..e4785998d 100644 --- a/app/assets/stylesheets/_ui.scss +++ b/app/assets/stylesheets/_ui.scss @@ -81,14 +81,6 @@ $screen-md-max: ($screen-lg-min - 1) !default; opacity: 0.5; } -.flex { - display: flex; -} - -.flex-column { - flex-direction: column; -} - .self-start { align-self: flex-start; } @@ -226,6 +218,12 @@ $screen-md-max: ($screen-lg-min - 1) !default; .grid-template-cols-1fr { grid-template-columns: 1fr; } +.col-span-all { + grid-column: 1 / -1; +} +.grid-col-2 { + grid-column: 2; +} .relative { position: relative; diff --git a/app/assets/stylesheets/index.css.scss b/app/assets/stylesheets/index.css.scss index 2dc340e5e..52ca8b997 100644 --- a/app/assets/stylesheets/index.css.scss +++ b/app/assets/stylesheets/index.css.scss @@ -11,4 +11,3 @@ @import "ionicons"; @import "reach-sub"; @import "sessions-modal"; -@import "sn"; diff --git a/app/assets/templates/directives/account-menu.pug b/app/assets/templates/directives/account-menu.pug index bde3c0f21..1f797c0ad 100644 --- a/app/assets/templates/directives/account-menu.pug +++ b/app/assets/templates/directives/account-menu.pug @@ -12,12 +12,11 @@ ) .sk-panel-row .sk-h1 Sign in or register to enable sync and end-to-end encryption. - .sk-panel-row - .sk-button-group.stretch - .sk-button.info.featured(ng-click='self.state.formData.showLogin = true') - .sk-label Sign In - .sk-button.info.featured(ng-click='self.showRegister()') - .sk-label Register + .flex.gap-3.my-1 + button.sn-button.info.flex-grow.text-base.py-3(ng-click='self.state.formData.showLogin = true') + | Sign In + button.sn-button.info.flex-grow.text-base.py-3(ng-click='self.showRegister()') + | Register .sk-panel-row.sk-p | Standard Notes is free on every platform, and comes | standard with sync and encryption. @@ -95,12 +94,10 @@ target='_blank' ) (Learn more) .sk-panel-section.form-submit(ng-if='!self.state.formData.authenticating') - .sk-button-group.stretch - .sk-button.info.featured( - ng-click='self.submitAuthForm()', - ng-disabled='self.state.formData.authenticating' - ) - .sk-label {{self.state.formData.showLogin ? "Sign In" : "Register"}} + button.sn-button.info.text-base.py-3.text-center( + ng-click='self.submitAuthForm()', + ng-disabled='self.state.formData.authenticating' + ) {{self.state.formData.showLogin ? "Sign In" : "Register"}} .sk-notification.neutral(ng-if='self.state.formData.showRegister') .sk-notification-title No Password Reset. .sk-notification-text @@ -174,17 +171,16 @@ | or revoking an active session, require additional authentication | like entering your account password or application passcode. .sk-panel-row(ng-if="self.state.protectionsDisabledUntil") - button.sk-button.info(ng-click="self.enableProtections()") - span.sk-label.capitalize Enable protections + button.sn-button.info(ng-click="self.enableProtections()") + | Enable protections .sk-panel-section .sk-panel-section-title Passcode Lock div(ng-if='!self.state.hasPasscode') div(ng-if='self.state.canAddPasscode') .sk-panel-row(ng-if='!self.state.formData.showPasscodeForm') - .sk-button.info( + button.sn-button.info( ng-click='self.addPasscodeClicked(); $event.stopPropagation();' - ) - .sk-label Add Passcode + ) Add Passcode p.sk-p | Add a passcode to lock the application and | encrypt on-device key storage. @@ -211,12 +207,10 @@ placeholder='Confirm Passcode', type='password' ) - .sk-button-group.stretch.sk-panel-row.form-submit - button.sk-button.info(type='submit') - .sk-label Set Passcode - a.neutral.sk-a.sk-panel-row( + button.sn-button.info.mt-2(type='submit') Set Passcode + button.sn-button.outlined.ml-2( ng-click='self.state.formData.showPasscodeForm = false' - ) Cancel + ) Cancel div(ng-if='self.state.hasPasscode && !self.state.formData.showPasscodeForm') .sk-panel-section-subtitle.info Passcode lock is enabled .sk-notification.contrast @@ -245,7 +239,6 @@ .sk-panel-section-title Data Backups .sk-p | Download a backup of all your data. - .sk-panel-row form.sk-panel-form.sk-panel-row(ng-if='self.state.encryptionEnabled') .sk-input-group label.sk-horizontal-group.tight @@ -265,17 +258,17 @@ ) p.sk-p Decrypted .sk-panel-row - .sk-button-group.sk-panel-row.justify-left - .sk-button.info(ng-click='self.downloadDataArchive()') - .sk-label Download Backup - label.sk-button.info + .flex + button.sn-button.info(ng-click='self.downloadDataArchive()') + | Download Backup + label.sn-button.info.ml-2 input( file-change='->', handler='self.importFileSelected(files)', style='display: none;', type='file' - ) - .sk-label Import Backup + ) + | Import Backup span(ng-if='self.isDesktopApplication()') | Backups are automatically created on desktop and can be managed | via the "Backups" top-level menu. @@ -296,8 +289,8 @@ | local storage, and a new identifier will be created should you | decide to enable error reporting again in the future. .sk-panel-row - button(ng-click="self.toggleErrorReportingEnabled()").sk-button.info - span.sk-label {{ self.state.errorReportingEnabled ? 'Disable' : 'Enable'}} Error Reporting + button(ng-click="self.toggleErrorReportingEnabled()").sn-button.info + | {{ self.state.errorReportingEnabled ? 'Disable' : 'Enable'}} Error Reporting .sk-panel-row a(ng-click="self.openErrorReportingDialog()").sk-a What data is being sent? .sk-panel-footer @@ -313,7 +306,7 @@ ng-if='self.state.formData.showLogin || self.state.formData.showRegister' ) | Cancel - a.sk-a.right.danger( + a.sk-a.right.danger.capitalize( ng-click='self.destroyLocalData()', ng-if=` !self.state.formData.showLogin && diff --git a/app/assets/templates/directives/component-view.pug b/app/assets/templates/directives/component-view.pug index f31383027..4ae471f85 100644 --- a/app/assets/templates/directives/component-view.pug +++ b/app/assets/templates/directives/component-view.pug @@ -5,8 +5,7 @@ .sk-label.warning There was an issue loading {{ctrl.component.name}}. .right .sk-app-bar-item(ng-click='ctrl.reloadIframe()') - .sk-button.info - .sk-label Reload + button.sn-button.info Reload .sn-component(ng-if='ctrl.expired') .sk-app-bar.no-edges.no-top-edge.dynamic-height .left @@ -26,16 +25,14 @@ | Extensions are in a read-only state. .right .sk-app-bar-item(ng-click='ctrl.reloadStatus(true)') - .sk-button.info - .sk-label Reload + button.sn-button.info Reload .sk-app-bar-item .sk-app-bar-item-column - .sk-button.warning - a.sk-label( - href='https://standardnotes.org/help/41/expired', - rel='noopener', - target='_blank' - ) Help + a.sn-button.warning( + href='https://standardnotes.org/help/41/expired', + rel='noopener', + target='_blank' + ) Help .sn-component(ng-if="ctrl.error == 'offline-restricted'") .sk-panel.static @@ -57,11 +54,10 @@ li.sk-p strong Use the Desktop application. .sk-panel-row - .sk-button.info( + button.sn-button.info( ng-click='ctrl.reloadStatus()', ng-if='!ctrl.reloading' - ) - .sk-label Reload + ) Reload .sk-spinner.info.small(ng-if='ctrl.reloading') .sn-component(ng-if="ctrl.error == 'url-missing'") .sk-panel.static diff --git a/app/assets/templates/directives/menu-row.pug b/app/assets/templates/directives/menu-row.pug index 25b7a18ea..6714228cd 100644 --- a/app/assets/templates/directives/menu-row.pug +++ b/app/assets/templates/directives/menu-row.pug @@ -30,10 +30,9 @@ .sk-menu-panel-column(ng-if="ctrl.circle && ctrl.circleAlign == 'right'") .sk-circle.small(ng-class='ctrl.circle') .sk-menu-panel-column(ng-if='ctrl.hasButton') - .sk-button( + button.sn-button.small( ng-class='ctrl.buttonClass', ng-click='ctrl.clickAccessoryButton($event)' - ) - .sk-label {{ctrl.buttonText}} + ) {{ctrl.buttonText}} .sk-menu-panel-column(ng-if='ctrl.spinnerClass') .sk-spinner.small(ng-class='ctrl.spinnerClass') diff --git a/app/assets/templates/directives/password-wizard.pug b/app/assets/templates/directives/password-wizard.pug index 2fde1edc6..52a58940f 100644 --- a/app/assets/templates/directives/password-wizard.pug +++ b/app/assets/templates/directives/password-wizard.pug @@ -41,8 +41,7 @@ | Please ensure you are running the latest version of Standard Notes | on all platforms to ensure maximum compatibility. .sk-panel-footer - .sk-button.info( + button.sn-button.info( ng-click='ctrl.nextStep()', ng-disabled='ctrl.state.lockContinue' - ) - .sk-label {{ctrl.state.continueTitle}} + ) {{ctrl.state.continueTitle}} diff --git a/app/assets/templates/directives/permissions-modal.pug b/app/assets/templates/directives/permissions-modal.pug deleted file mode 100644 index d401c97b1..000000000 --- a/app/assets/templates/directives/permissions-modal.pug +++ /dev/null @@ -1,25 +0,0 @@ -.sk-modal-background(ng-click='ctrl.deny()') -#permissions-modal.sk-modal-content - .sn-component - .sk-panel - .sk-panel-header - .sk-panel-header-title Activate Extension - a.sk-a.info.close-button(ng-click='ctrl.deny()') Cancel - .sk-panel-content - .sk-panel-section - .sk-panel-row - .sk-h2 - strong {{ctrl.component.name}} - | would like to interact with your - | {{ctrl.permissionsString}} - .sk-panel-row - p.sk-p - | Extensions use an offline messaging system to communicate. Learn more at - a.sk-a.info( - href='https://standardnotes.org/permissions', - rel='noopener', - target='_blank' - ) https://standardnotes.org/permissions. - .sk-panel-footer - .sk-button.info.big.block.font-bold(ng-click='ctrl.accept()') - .sk-label Continue diff --git a/app/assets/templates/directives/sync-resolution-menu.pug b/app/assets/templates/directives/sync-resolution-menu.pug index 471944349..46b18ca16 100644 --- a/app/assets/templates/directives/sync-resolution-menu.pug +++ b/app/assets/templates/directives/sync-resolution-menu.pug @@ -6,44 +6,41 @@ .sk-panel-content .sk-panel-section .sk-panel-row.sk-p - | We've detected that the data on the server may not match + | We've detected that the data on the server may not match | the data in the current application session. .sk-p.sk-panel-row .sk-panel-column strong.sk-panel-row Option 1 — Restart App: - .sk-p - | Quit the application and re-open it. + .sk-p + | Quit the application and re-open it. | Sometimes, this may resolve the issue. .sk-p.sk-panel-row .sk-panel-column strong.sk-panel-row Option 2 (recommended) — Sign Out: .sk-p - | Sign out of your account, then sign back in. + | Sign out of your account, then sign back in. | This will ensure your data is consistent with the server. | Be sure to download a backup of your data before doing so. .sk-p.sk-panel-row .sk-panel-column strong.sk-panel-row Option 3 — Sync Resolution: .sk-p - | We can attempt to reconcile changes by downloading all data from the - | server. No existing data will be overwritten. If the local contents of + | We can attempt to reconcile changes by downloading all data from the + | server. No existing data will be overwritten. If the local contents of | an item differ from what the server has, a conflicted copy will be created. div(ng-if='!ctrl.status.backupFinished') .sk-p.sk-panel-row - | Please download a backup before we attempt to + | Please download a backup before we attempt to | perform a full account sync resolution. .sk-panel-row - .sk-button-group - .sk-button.info(ng-click='ctrl.downloadBackup(true)') - .sk-label Encrypted - .sk-button.info(ng-click='ctrl.downloadBackup(false)') - .sk-label Decrypted - .sk-button.danger(ng-click='ctrl.skipBackup()') - .sk-label Skip + .flex.gap-2 + button.sn-button.info(ng-click='ctrl.downloadBackup(true)') Encrypted + button.sn-button.info(ng-click='ctrl.downloadBackup(false)') Decrypted + button.sn-button.danger(ng-click='ctrl.skipBackup()') Skip div(ng-if='ctrl.status.backupFinished') .sk-panel-row(ng-if='!ctrl.status.resolving && !ctrl.status.attemptedResolution') - .sk-button.info(ng-click='ctrl.performSyncResolution()') - .sk-label Perform Sync Resolution + button.sn-button.info(ng-click='ctrl.performSyncResolution()') + | Perform Sync Resolution .sk-panel-row.justify-left(ng-if='ctrl.status.resolving') .sk-horizontal-group .sk-spinner.small.info @@ -51,8 +48,8 @@ .sk-panel-column(ng-if='ctrl.status.fail') .sk-panel-row.sk-label.danger Sync Resolution Failed .sk-p.sk-panel-row - | We attempted to reconcile local content and server content, but were - | unable to do so. At this point, we recommend signing out of your account + | We attempted to reconcile local content and server content, but were + | unable to do so. At this point, we recommend signing out of your account | and signing back in. You may wish to download a data backup before doing so. .sk-panel-column(ng-if='ctrl.status.success') .sk-panel-row.sk-label.success Sync Resolution Success diff --git a/package.json b/package.json index e453f4715..daeda2096 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pug-loader": "^2.4.0", "sass-loader": "^8.0.2", "serve-static": "^1.14.1", - "sn-stylekit": "^2.2.1", + "sn-stylekit": "github:standardnotes/StyleKit#e3bfad37d29168bcc15e96399734ffaae1e618ba", "ts-loader": "^8.0.17", "typescript": "^4.1.5", "typescript-eslint": "0.0.1-alpha.0", diff --git a/yarn.lock b/yarn.lock index 415e03bb0..1f4e36486 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7808,10 +7808,9 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -sn-stylekit@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/sn-stylekit/-/sn-stylekit-2.2.1.tgz#4a81a05b2b2d67a11af9d06f3964ac1ece3aa84a" - integrity sha512-mrvUbf2HbWOfxbNglo7RXa5JBe9UV9rurupeGoX/Kh4/lVlB2n/56ZT103xk/4tp0/mVCpxjD7Dt1stKFxsvFA== +"sn-stylekit@github:standardnotes/StyleKit#e3bfad37d29168bcc15e96399734ffaae1e618ba": + version "3.0.0" + resolved "https://codeload.github.com/standardnotes/StyleKit/tar.gz/e3bfad37d29168bcc15e96399734ffaae1e618ba" snapdragon-node@^2.0.1: version "2.1.1"