* feat: add tag folders support basics * feat: add draggability to tags * feat: add drag & drop draft * feat: fold folders * fix: do not select on fold / unfold tags * style: clean the isValidTag call * feat: add native folder toggle * feat: add touch mobile support * ui: add nicer design & icons * style: render full-width tag items * feat: nicer looking dropzone * style: fix arguments * fix: tag template rendering in list items * feat: tag can be dragged over the whole item * fix: cancel / reset title after save * fix: disable drag completely when needed * fix: invalid tag parents * feat: add paying feature * feat: with paid feature tooltip * feat: tag has a plus feature * feat: add premium modal * style: simplif code * refactor: extract feature_state & simplif code * fix: icons and icons svg * style: remove comment * feat: tag folders naming * feat: use the feature notification * fix: tag folders copy * style: variable names * style: remove & clean comments * refactor: remove is-mobile library * feat: tags folder experimental (#10) * feat: hide native folders behind experimental flag * fix: better tags resizing * fix: merge global window * style: rename params * refactor: remove level of indirection in feature toggle * feat: recursively add tags to note on create (#9) * fix: use add tags folder hierarchy & isTemplateItem (#13) * fix: use new snjs add tag hierarchy * fix: use new snjs isTemplateItem * feat: tags folder premium (#774) * feat: upgrade premium in tags section refactor: move TagsSection to react feat: show premium on Tag section feat: keep drag and drop features always active fix: drag & drop tweak with premium feat: premium messages fix: remove fill in svg icons fix: change tag list color (temporary) style: remove dead code refactor: clarify names and modules fix: draggable behind feature toggle feat: add button in TagSection & design * feat: fix features loading with app state (#775) * fix: distinguish between app launch and start * fix: update state for footer too * fix: wait for application launch event Co-authored-by: Laurent Senta <laurent@singulargarden.com> * feat: tags folder with folder text design (#776) * feat: add folder text * fix: sn stylekit colors * fix: root drop zone * chore: upgrade stylekit * fix: hide dropzone when feature is disabled * chore: bump versions now that they are released Co-authored-by: Mo <me@bitar.io> * feat: tags folder design review (#785) * fix: upgrade design after review * fix: tweak dropzone * fix: sync after assign parent * fix: tsc error on build * fix: vertical center the fold arrows * fix: define our own hoist for react-dnd * feat: hide fold when there are no folders * fix: show children usability + resize UI * fix: use old colors for now, theme compat * fix: tweak alignment and add title * fix: meta offset with folders * fix: tweak tag size * fix: observable setup * fix: use link-off icon on dropzone * fix: more tweak on text sizes Co-authored-by: Mo <me@bitar.io>
236 lines
7.8 KiB
TypeScript
236 lines
7.8 KiB
TypeScript
'use strict';
|
|
|
|
declare global {
|
|
interface Window {
|
|
// eslint-disable-next-line camelcase
|
|
_bugsnag_api_key?: string;
|
|
// eslint-disable-next-line camelcase
|
|
_purchase_url?: string;
|
|
// eslint-disable-next-line camelcase
|
|
_plans_url?: string;
|
|
// eslint-disable-next-line camelcase
|
|
_dashboard_url?: string;
|
|
// eslint-disable-next-line camelcase
|
|
_default_sync_server: string;
|
|
// eslint-disable-next-line camelcase
|
|
_enable_unfinished_features: boolean;
|
|
// eslint-disable-next-line camelcase
|
|
_websocket_url: string;
|
|
startApplication?: StartApplication;
|
|
}
|
|
}
|
|
|
|
import { SNLog } from '@standardnotes/snjs';
|
|
import angular from 'angular';
|
|
import { configRoutes } from './routes';
|
|
|
|
import { ApplicationGroup } from './ui_models/application_group';
|
|
import { AccountSwitcher } from './views/account_switcher/account_switcher';
|
|
|
|
import {
|
|
ApplicationGroupView,
|
|
ApplicationView,
|
|
EditorGroupView,
|
|
EditorView,
|
|
TagsView,
|
|
FooterView,
|
|
ChallengeModal,
|
|
} from '@/views';
|
|
|
|
import {
|
|
autofocus,
|
|
clickOutside,
|
|
delayHide,
|
|
elemReady,
|
|
fileChange,
|
|
infiniteScroll,
|
|
lowercase,
|
|
selectOnFocus,
|
|
snEnter,
|
|
} from './directives/functional';
|
|
|
|
import {
|
|
ActionsMenu,
|
|
ComponentModal,
|
|
EditorMenu,
|
|
InputModal,
|
|
MenuRow,
|
|
PanelResizer,
|
|
PasswordWizard,
|
|
PermissionsModal,
|
|
RevisionPreviewModal,
|
|
HistoryMenu,
|
|
SyncResolutionMenu,
|
|
} from './directives/views';
|
|
|
|
import { trusted } from './filters';
|
|
import { isDev } from './utils';
|
|
import { BrowserBridge } from './services/browserBridge';
|
|
import { startErrorReporting } from './services/errorReporting';
|
|
import { StartApplication } from './startApplication';
|
|
import { Bridge } from './services/bridge';
|
|
import { SessionsModalDirective } from './components/SessionsModal';
|
|
import { NoAccountWarningDirective } from './components/NoAccountWarning';
|
|
import { ProtectedNoteOverlayDirective } from './components/ProtectedNoteOverlay';
|
|
import { SearchOptionsDirective } from './components/SearchOptions';
|
|
import { AccountMenuDirective } from './components/AccountMenu';
|
|
import { ConfirmSignoutDirective } from './components/ConfirmSignoutModal';
|
|
import { MultipleSelectedNotesDirective } from './components/MultipleSelectedNotes';
|
|
import { NotesContextMenuDirective } from './components/NotesContextMenu';
|
|
import { NotesOptionsPanelDirective } from './components/NotesOptionsPanel';
|
|
import { IconDirective } from './components/Icon';
|
|
import { NoteTagsContainerDirective } from './components/NoteTagsContainer';
|
|
import { PreferencesDirective } from './preferences';
|
|
import { AppVersion, IsWebPlatform } from '@/version';
|
|
import { NotesListOptionsDirective } from './components/NotesListOptionsMenu';
|
|
import { PurchaseFlowDirective } from './purchaseFlow';
|
|
import { QuickSettingsMenuDirective } from './components/QuickSettingsMenu/QuickSettingsMenu';
|
|
import { ComponentViewDirective } from '@/components/ComponentView';
|
|
import { TagsListDirective } from '@/components/TagsList';
|
|
import { NotesViewDirective } from './components/NotesView';
|
|
import { PinNoteButtonDirective } from '@/components/PinNoteButton';
|
|
import { TagsSectionDirective } from './components/Tags/TagsSection';
|
|
|
|
function reloadHiddenFirefoxTab(): boolean {
|
|
/**
|
|
* For Firefox pinned tab issue:
|
|
* When a new browser session is started, and SN is in a pinned tab,
|
|
* SN exhibits strange behavior until the tab is reloaded.
|
|
*/
|
|
if (
|
|
document.hidden &&
|
|
navigator.userAgent.toLowerCase().includes('firefox')
|
|
) {
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (!document.hidden) {
|
|
location.reload();
|
|
}
|
|
});
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const startApplication: StartApplication = async function startApplication(
|
|
defaultSyncServerHost: string,
|
|
bridge: Bridge,
|
|
enableUnfinishedFeatures: boolean,
|
|
webSocketUrl: string
|
|
) {
|
|
if (reloadHiddenFirefoxTab()) {
|
|
return;
|
|
}
|
|
|
|
SNLog.onLog = console.log;
|
|
startErrorReporting();
|
|
|
|
angular.module('app', ['ngSanitize']);
|
|
|
|
// Config
|
|
angular
|
|
.module('app')
|
|
.config(configRoutes)
|
|
.constant('bridge', bridge)
|
|
.constant('defaultSyncServerHost', defaultSyncServerHost)
|
|
.constant('appVersion', bridge.appVersion)
|
|
.constant('enableUnfinishedFeatures', enableUnfinishedFeatures)
|
|
.constant('webSocketUrl', webSocketUrl);
|
|
|
|
// Controllers
|
|
angular
|
|
.module('app')
|
|
.directive('applicationGroupView', () => new ApplicationGroupView())
|
|
.directive('applicationView', () => new ApplicationView())
|
|
.directive('editorGroupView', () => new EditorGroupView())
|
|
.directive('editorView', () => new EditorView())
|
|
.directive('tagsView', () => new TagsView())
|
|
.directive('footerView', () => new FooterView());
|
|
|
|
// Directives - Functional
|
|
angular
|
|
.module('app')
|
|
.directive('snAutofocus', ['$timeout', autofocus])
|
|
.directive('clickOutside', ['$document', clickOutside])
|
|
.directive('delayHide', delayHide)
|
|
.directive('elemReady', elemReady)
|
|
.directive('fileChange', fileChange)
|
|
.directive('infiniteScroll', [infiniteScroll])
|
|
.directive('lowercase', lowercase)
|
|
.directive('selectOnFocus', ['$window', selectOnFocus])
|
|
.directive('snEnter', snEnter);
|
|
|
|
// Directives - Views
|
|
angular
|
|
.module('app')
|
|
.directive('accountSwitcher', () => new AccountSwitcher())
|
|
.directive('actionsMenu', () => new ActionsMenu())
|
|
.directive('challengeModal', () => new ChallengeModal())
|
|
.directive('componentModal', () => new ComponentModal())
|
|
.directive('componentView', ComponentViewDirective)
|
|
.directive('editorMenu', () => new EditorMenu())
|
|
.directive('inputModal', () => new InputModal())
|
|
.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('accountMenu', AccountMenuDirective)
|
|
.directive('quickSettingsMenu', QuickSettingsMenuDirective)
|
|
.directive('noAccountWarning', NoAccountWarningDirective)
|
|
.directive('protectedNotePanel', ProtectedNoteOverlayDirective)
|
|
.directive('searchOptions', SearchOptionsDirective)
|
|
.directive('confirmSignout', ConfirmSignoutDirective)
|
|
.directive('multipleSelectedNotesPanel', MultipleSelectedNotesDirective)
|
|
.directive('notesContextMenu', NotesContextMenuDirective)
|
|
.directive('notesOptionsPanel', NotesOptionsPanelDirective)
|
|
.directive('notesListOptionsMenu', NotesListOptionsDirective)
|
|
.directive('icon', IconDirective)
|
|
.directive('noteTagsContainer', NoteTagsContainerDirective)
|
|
.directive('tagsList', TagsListDirective)
|
|
.directive('tagsSection', TagsSectionDirective)
|
|
.directive('preferences', PreferencesDirective)
|
|
.directive('purchaseFlow', PurchaseFlowDirective)
|
|
.directive('notesView', NotesViewDirective)
|
|
.directive('pinNoteButton', PinNoteButtonDirective);
|
|
|
|
// Filters
|
|
angular.module('app').filter('trusted', ['$sce', trusted]);
|
|
|
|
// Services
|
|
angular.module('app').service('mainApplicationGroup', ApplicationGroup);
|
|
|
|
// Debug
|
|
if (isDev) {
|
|
Object.defineProperties(window, {
|
|
application: {
|
|
get: () =>
|
|
(
|
|
angular
|
|
.element(document)
|
|
.injector()
|
|
.get('mainApplicationGroup') as any
|
|
).primaryApplication,
|
|
},
|
|
});
|
|
}
|
|
|
|
angular.element(document).ready(() => {
|
|
angular.bootstrap(document, ['app']);
|
|
});
|
|
};
|
|
|
|
if (IsWebPlatform) {
|
|
startApplication(
|
|
window._default_sync_server,
|
|
new BrowserBridge(AppVersion),
|
|
window._enable_unfinished_features,
|
|
window._websocket_url
|
|
);
|
|
} else {
|
|
window.startApplication = startApplication;
|
|
}
|