diff --git a/.env.sample b/.env.sample index 03888379e..66af6248e 100644 --- a/.env.sample +++ b/.env.sample @@ -16,6 +16,7 @@ SF_NEXT_VERSION_SERVER=http://localhost:3000 DEV_DEFAULT_SYNC_SERVER=https://sync.standardnotes.org DEV_NEXT_VERSION_SYNC_SERVER=https://api.standardnotes.com DEV_EXTENSIONS_MANAGER_LOCATION=public/extensions/extensions-manager/dist/index.html +ENABLE_UNFINISHED_FEATURES=false # NewRelic (Optional) NEW_RELIC_ENABLED=false diff --git a/app/assets/icons/ic-accessibility.svg b/app/assets/icons/ic-accessibility.svg new file mode 100644 index 000000000..de1e6249e --- /dev/null +++ b/app/assets/icons/ic-accessibility.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-help.svg b/app/assets/icons/ic-help.svg new file mode 100644 index 000000000..c312b7255 --- /dev/null +++ b/app/assets/icons/ic-help.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-keyboard.svg b/app/assets/icons/ic-keyboard.svg new file mode 100644 index 000000000..9a18af39c --- /dev/null +++ b/app/assets/icons/ic-keyboard.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-listed.svg b/app/assets/icons/ic-listed.svg new file mode 100644 index 000000000..03e347717 --- /dev/null +++ b/app/assets/icons/ic-listed.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-security.svg b/app/assets/icons/ic-security.svg new file mode 100644 index 000000000..badc9d1ad --- /dev/null +++ b/app/assets/icons/ic-security.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-settings.svg b/app/assets/icons/ic-settings.svg new file mode 100644 index 000000000..cc14f94a8 --- /dev/null +++ b/app/assets/icons/ic-settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-star.svg b/app/assets/icons/ic-star.svg new file mode 100644 index 000000000..638dae331 --- /dev/null +++ b/app/assets/icons/ic-star.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-themes.svg b/app/assets/icons/ic-themes.svg new file mode 100644 index 000000000..88606ca76 --- /dev/null +++ b/app/assets/icons/ic-themes.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-user.svg b/app/assets/icons/ic-user.svg new file mode 100644 index 000000000..65ac58800 --- /dev/null +++ b/app/assets/icons/ic-user.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/javascripts/app.ts b/app/assets/javascripts/app.ts index 579500b6f..a4969b733 100644 --- a/app/assets/javascripts/app.ts +++ b/app/assets/javascripts/app.ts @@ -65,6 +65,7 @@ import { NotesContextMenuDirective } from './components/NotesContextMenu'; import { NotesOptionsPanelDirective } from './components/NotesOptionsPanel'; import { IconDirective } from './components/Icon'; import { NoteTagsContainerDirective } from './components/NoteTagsContainer'; +import { PreferencesDirective } from './components/preferences'; function reloadHiddenFirefoxTab(): boolean { /** @@ -90,7 +91,7 @@ function reloadHiddenFirefoxTab(): boolean { const startApplication: StartApplication = async function startApplication( defaultSyncServerHost: string, bridge: Bridge, - nextVersionSyncServerHost: string, + nextVersionSyncServerHost: string ) { if (reloadHiddenFirefoxTab()) { return; @@ -161,7 +162,8 @@ const startApplication: StartApplication = async function startApplication( .directive('notesContextMenu', NotesContextMenuDirective) .directive('notesOptionsPanel', NotesOptionsPanelDirective) .directive('icon', IconDirective) - .directive('noteTagsContainer', NoteTagsContainerDirective); + .directive('noteTagsContainer', NoteTagsContainerDirective) + .directive('preferences', PreferencesDirective); // Filters angular.module('app').filter('trusted', ['$sce', trusted]); @@ -174,10 +176,12 @@ const startApplication: StartApplication = async function startApplication( Object.defineProperties(window, { application: { get: () => - (angular - .element(document) - .injector() - .get('mainApplicationGroup') as any).primaryApplication, + ( + angular + .element(document) + .injector() + .get('mainApplicationGroup') as any + ).primaryApplication, }, }); } diff --git a/app/assets/javascripts/components/Icon.tsx b/app/assets/javascripts/components/Icon.tsx index 67c0aa592..e9c9a8b1e 100644 --- a/app/assets/javascripts/components/Icon.tsx +++ b/app/assets/javascripts/components/Icon.tsx @@ -13,41 +13,60 @@ import PasswordIcon from '../../icons/ic-textbox-password.svg'; import TrashSweepIcon from '../../icons/ic-trash-sweep.svg'; import MoreIcon from '../../icons/ic-more.svg'; import TuneIcon from '../../icons/ic-tune.svg'; + +import AccessibilityIcon from '../../icons/ic-accessibility.svg'; +import HelpIcon from '../../icons/ic-help.svg'; +import KeyboardIcon from '../../icons/ic-keyboard.svg'; +import ListedIcon from '../../icons/ic-listed.svg'; +import SecurityIcon from '../../icons/ic-security.svg'; +import SettingsIcon from '../../icons/ic-settings.svg'; +import StarIcon from '../../icons/ic-star.svg'; +import ThemesIcon from '../../icons/ic-themes.svg'; +import UserIcon from '../../icons/ic-user.svg'; + import { toDirective } from './utils'; import { FunctionalComponent } from 'preact'; const ICONS = { 'pencil-off': PencilOffIcon, 'rich-text': RichTextIcon, - 'trash': TrashIcon, - 'pin': PinIcon, - 'unpin': UnpinIcon, - 'archive': ArchiveIcon, - 'unarchive': UnarchiveIcon, - 'hashtag': HashtagIcon, + trash: TrashIcon, + pin: PinIcon, + unpin: UnpinIcon, + archive: ArchiveIcon, + unarchive: UnarchiveIcon, + hashtag: HashtagIcon, 'chevron-right': ChevronRightIcon, - 'restore': RestoreIcon, - 'close': CloseIcon, - 'password': PasswordIcon, + restore: RestoreIcon, + close: CloseIcon, + password: PasswordIcon, 'trash-sweep': TrashSweepIcon, - 'more': MoreIcon, - 'tune': TuneIcon, + more: MoreIcon, + tune: TuneIcon, + accessibility: AccessibilityIcon, + help: HelpIcon, + keyboard: KeyboardIcon, + listed: ListedIcon, + security: SecurityIcon, + settings: SettingsIcon, + star: StarIcon, + themes: ThemesIcon, + user: UserIcon, }; +export type IconType = keyof typeof ICONS; + type Props = { - type: keyof (typeof ICONS); - className: string; -} + type: IconType; + className?: string; +}; export const Icon: FunctionalComponent = ({ type, className }) => { const IconComponent = ICONS[type]; return ; }; -export const IconDirective = toDirective( - Icon, - { - type: '@', - className: '@', - } -); +export const IconDirective = toDirective(Icon, { + type: '@', + className: '@', +}); diff --git a/app/assets/javascripts/components/IconButton.tsx b/app/assets/javascripts/components/IconButton.tsx new file mode 100644 index 000000000..93d826c4e --- /dev/null +++ b/app/assets/javascripts/components/IconButton.tsx @@ -0,0 +1,53 @@ +import { FunctionComponent } from 'preact'; +import { Icon, IconType } from './Icon'; + +const ICON_BUTTON_TYPES: { + [type: string]: { className: string }; +} = { + normal: { + className: '', + }, + primary: { + className: 'info', + }, +}; + +export type IconButtonType = keyof typeof ICON_BUTTON_TYPES; + +interface IconButtonProps { + /** + * onClick - preventDefault is handled within the component + */ + onClick: () => void; + + type: IconButtonType; + + className?: string; + + iconType: IconType; +} + +/** + * CircleButton component with an icon for SPA + * preventDefault is already handled within the component + */ +export const IconButton: FunctionComponent = ({ + onClick, + type, + className, + iconType, +}) => { + const click = (e: MouseEvent) => { + e.preventDefault(); + onClick(); + }; + const typeProps = ICON_BUTTON_TYPES[type]; + return ( + + ); +}; diff --git a/app/assets/javascripts/components/PreferencesMenuItem.tsx b/app/assets/javascripts/components/PreferencesMenuItem.tsx new file mode 100644 index 000000000..eb872053a --- /dev/null +++ b/app/assets/javascripts/components/PreferencesMenuItem.tsx @@ -0,0 +1,23 @@ +import { Icon, IconType } from '@/components/Icon'; +import { FunctionComponent } from 'preact'; + +interface PreferencesMenuItemProps { + iconType: IconType; + label: string; + selected: boolean; + onClick: () => void; +} + +export const PreferencesMenuItem: FunctionComponent = + ({ iconType, label, selected, onClick }) => ( +
{ + e.preventDefault(); + onClick(); + }} + > + + {label} +
+ ); diff --git a/app/assets/javascripts/components/TitleBar.tsx b/app/assets/javascripts/components/TitleBar.tsx new file mode 100644 index 000000000..8cf9e9208 --- /dev/null +++ b/app/assets/javascripts/components/TitleBar.tsx @@ -0,0 +1,13 @@ +import { FunctionComponent } from 'preact'; + +export const TitleBar: FunctionComponent<{ className?: string }> = ({ + children, + className, +}) =>
{children}
; + +export const Title: FunctionComponent<{ className?: string }> = ({ + children, + className, +}) => { + return
{children}
; +}; diff --git a/app/assets/javascripts/components/preferences/content.tsx b/app/assets/javascripts/components/preferences/content.tsx new file mode 100644 index 000000000..efdaa7109 --- /dev/null +++ b/app/assets/javascripts/components/preferences/content.tsx @@ -0,0 +1,28 @@ +import { FunctionalComponent } from 'preact'; + +export const Title: FunctionalComponent = ({ children }) => ( +

{children}

+); + +export const Subtitle: FunctionalComponent = ({ children }) => ( +

{children}

+); + +export const Text: FunctionalComponent = ({ children }) => ( +

{children}

+); + +export const Button: FunctionalComponent<{ label: string; link: string }> = ({ + label, + link, +}) => ( + + {label} + +); diff --git a/app/assets/javascripts/components/preferences/help-feedback.tsx b/app/assets/javascripts/components/preferences/help-feedback.tsx new file mode 100644 index 000000000..0f9ead7a9 --- /dev/null +++ b/app/assets/javascripts/components/preferences/help-feedback.tsx @@ -0,0 +1,92 @@ +import { FunctionalComponent } from 'preact'; +import { PreferencesGroup, PreferencesPane, PreferencesSegment } from './pane'; +import { Title, Subtitle, Text, Button } from './content'; + +export const HelpAndFeedback: FunctionalComponent = () => ( + + + + Frequently asked questions + Who can read my private notes? + + Quite simply: no one but you. Not us, not your ISP, not a hacker, and + not a government agency. As long as you keep your password safe, and + your password is reasonably strong, then you are the only person in + the world with the ability to decrypt your notes. For more on how we + handle your privacy and security, check out our easy to read{' '} + + Privacy Manifesto. + + + + + Can I collaborate with others on a note? + + Because of our encrypted architecture, Standard Notes does not + currently provide a real-time collaboration solution. Multiple users + can share the same account however, but editing at the same time may + result in sync conflicts, which may result in the duplication of + notes. + + + + Can I use Standard Notes totally offline? + + Standard Notes can be used totally offline without an account, and + without an internet connection. You can find{' '} + + more details here. + + + + + Can’t find your question here? +