Skip to content

Commit

Permalink
feat: implement Help & feedback for Preferences screen
Browse files Browse the repository at this point in the history
  • Loading branch information
gorjan5sk committed Jul 8, 2021
1 parent b7a9329 commit 8d1f205
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 35 deletions.
107 changes: 107 additions & 0 deletions app/assets/javascripts/components/preferences/help-feedback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { FunctionalComponent } from 'preact';
import { PreferencesGroup, PreferencesPane, PreferencesSegment } from './pane';

export const HelpAndFeedback: FunctionalComponent = () => (
<PreferencesPane>
<PreferencesGroup>
<PreferencesSegment>
<h2>Frequently asked questions</h2>
<h4>Who can read my private notes?</h4>
<p>
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{' '}
<a target="_blank" href="https://standardnotes.com/privacy">
Privacy Manifesto.
</a>
</p>
</PreferencesSegment>
<PreferencesSegment>
<h4>Can I collaborate with others on a note?</h4>
<p>
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.
</p>
</PreferencesSegment>
<PreferencesSegment>
<h4>Can I use Standard Notes totally offline?</h4>
<p>
Standard Notes can be used totally offline without an account, and
without an internet connection. You can find{' '}
<a
target="_blank"
href="https://standardnotes.com/help/59/can-i-use-standard-notes-totally-offline"
>
more details here.
</a>
</p>
</PreferencesSegment>
<PreferencesSegment>
<h4>Can’t find your question here?</h4>
<button
onClick={() =>
window.open('https://standardnotes.com/help', '_blank')
}
>
Open FAQ
</button>
</PreferencesSegment>
</PreferencesGroup>
<PreferencesGroup>
<PreferencesSegment>
<h2>Community forum</h2>
<p>
If you have an issue, found a bug or want to suggest a feature, you
can browse or post to the forum. It’s recommended for non-account
related issues. Please read our{' '}
<a target="_blank" href="https://standardnotes.com/longevity/">
Longevity statement
</a>{' '}
before advocating for a feature request.
</p>
<button
onClick={() =>
window.open('https://forum.standardnotes.org/', '_blank')
}
>
Go to the forum
</button>
</PreferencesSegment>
</PreferencesGroup>
<PreferencesGroup>
<PreferencesSegment>
<h2>Slack group</h2>
<p>
Want to meet other passionate note-takers and privacy enthusiasts?
Want to share your feedback with us? Join the Standard Notes Slack
group for discussions on security, themes, editors and more.
</p>
<button
onClick={() =>
window.open('https://standardnotes.com/slack', '_blank')
}
>
Join our Slack group
</button>
</PreferencesSegment>
</PreferencesGroup>
<PreferencesGroup>
<PreferencesSegment>
<h2>Account related issue?</h2>
<p>Send an email to [email protected] and we’ll sort it out.</p>
<button
onClick={() =>
window.open('mailto: [email protected]', '_blank')
}
>
Email us
</button>
</PreferencesSegment>
</PreferencesGroup>
</PreferencesPane>
);
12 changes: 6 additions & 6 deletions app/assets/javascripts/components/preferences/menu.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import { PreferencesMenuItem } from '../PreferencesMenuItem';
import { MockState } from './mock-state';
import { Preferences } from './preferences';

interface PreferencesMenuProps {
store: MockState;
preferences: Preferences;
}

export const PreferencesMenu: FunctionComponent<PreferencesMenuProps> =
observer(({ store }) => (
<div className="flex flex-col px-3 py-6 overflow-y-auto">
{store.items.map((pref) => (
observer(({ preferences }) => (
<div className="min-w-55 overflow-y-auto flex flex-col px-3 py-6">
{preferences.items.map((pref) => (
<PreferencesMenuItem
key={pref.id}
iconType={pref.icon}
label={pref.label}
selected={pref.selected}
onClick={() => store.select(pref.id)}
onClick={() => preferences.selectItem(pref.id)}
/>
))}
</div>
Expand Down
33 changes: 33 additions & 0 deletions app/assets/javascripts/components/preferences/pane.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { FunctionalComponent } from 'preact';

const HorizontalLine: FunctionalComponent<{ index: number; length: number }> =
({ index, length }) =>
index < length - 1 ? (
<hr className="h-1px w-full bg-border no-border" />
) : null;

export const PreferencesSegment: FunctionalComponent = ({ children }) => (
<div>{children}</div>
);

export const PreferencesGroup: FunctionalComponent = ({ children }) => (
<div className="bg-default border-1 border-solid rounded border-gray-300 px-6 py-6 flex flex-col gap-2">
{!Array.isArray(children)
? children
: children.map((c, i, arr) => (
<>
{c}
<HorizontalLine index={i} length={arr.length} />
</>
))}
</div>
);

export const PreferencesPane: FunctionalComponent = ({ children }) => (
<div className="preferences-pane flex-grow flex flex-row overflow-y-auto min-h-0">
<div className="flex-grow flex flex-col py-6 items-center">
<div className="max-w-124 flex flex-col gap-3">{children}</div>
</div>
<div className="flex-basis-55 flex-shrink-max" />
</div>
);
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,23 @@ const predefinedItems: PreferenceItem[] = [
{ label: 'Help & feedback', icon: 'help' },
];

export class MockState {
export class Preferences {
private readonly _items: PreferenceListItem[];
private _selectedId = 0;

constructor(items: PreferenceItem[] = predefinedItems) {
makeObservable<MockState, '_selectedId'>(this, {
makeObservable<Preferences, '_selectedId'>(this, {
_selectedId: observable,
selectedItem: computed,
items: computed,
select: action,
selectItem: action,
});

this._items = items.map((p, idx) => ({ ...p, id: idx }));
this._selectedId = this._items[0].id;
}

select(id: number) {
selectItem(id: number) {
this._selectedId = id;
}

Expand All @@ -47,4 +48,8 @@ export class MockState {
selected: p.id === this._selectedId,
}));
}

get selectedItem(): PreferenceListItem {
return this._items.find((item) => item.id === this._selectedId)!;
}
}
59 changes: 35 additions & 24 deletions app/assets/javascripts/components/preferences/view.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,45 @@
import { IconButton } from '@/components/IconButton';
import { TitleBar, Title } from '@/components/TitleBar';
import { FunctionComponent } from 'preact';
import { MockState } from './mock-state';
import { Preferences } from './preferences';
import { PreferencesMenu } from './menu';
import { HelpAndFeedback } from './help-feedback';
import { observer } from 'mobx-react-lite';

interface PreferencesViewProps {
close: () => void;
}

export const PreferencesView: FunctionComponent<PreferencesViewProps> = ({
close,
}) => {
const store = new MockState();
return (
<div className="sn-full-screen flex flex-col bg-contrast z-index-preferences">
<TitleBar className="items-center justify-between">
{/* div is added so flex justify-between can center the title */}
<div className="h-8 w-8" />
<Title className="text-lg">Your preferences for Standard Notes</Title>
<IconButton
onClick={() => {
close();
}}
type="normal"
iconType="close"
/>
</TitleBar>
<div className="flex flex-row flex-grow min-h-0">
<PreferencesMenu store={store}></PreferencesMenu>
export const PreferencesCanvas: FunctionComponent<{
preferences: Preferences;
}> = observer(({ preferences: prefs }) => (
<div className="flex flex-row flex-grow min-h-0 justify-between">
<PreferencesMenu preferences={prefs}></PreferencesMenu>
{/* Temporary selector until a full solution is implemented */}
{prefs.selectedItem.label === 'Help & feedback' ? (
<HelpAndFeedback />
) : null}
</div>
));

export const PreferencesView: FunctionComponent<PreferencesViewProps> =
observer(({ close }) => {
const prefs = new Preferences();
return (
<div className="sn-full-screen flex flex-col bg-contrast z-index-preferences">
<TitleBar className="items-center justify-between">
{/* div is added so flex justify-between can center the title */}
<div className="h-8 w-8" />
<Title className="text-lg">Your preferences for Standard Notes</Title>
<IconButton
onClick={() => {
close();
}}
type="normal"
iconType="close"
/>
</TitleBar>
<PreferencesCanvas preferences={prefs} />
</div>
</div>
);
};
);
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { action, computed, makeObservable, observable } from 'mobx';

export class PreferencesState {
private _open = true;
private _open = false;

constructor() {
makeObservable<PreferencesState, '_open'>(this, {
Expand Down
36 changes: 36 additions & 0 deletions app/assets/stylesheets/_preferences.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
@extend .border-gray-300;
@extend .border-solid;
@extend .border-1;
@extend .bg-default;
}
}

Expand All @@ -44,3 +45,38 @@
@extend .color-info;
}
}

.preferences-pane h2 {
@extend .text-base;
@extend .m-0;
@extend .mb-3;
}

.preferences-pane h4 {
@extend .font-medium;
@extend .text-sm;
@extend .m-0;
@extend .mb-1;
}

.preferences-pane p {
@extend .text-xs;
}

.preferences-pane button {
@extend .bg-default;
@extend .rounded;
@extend .border-solid;
@extend .border-1;
@extend .border-gray-300;
@extend .px-4;
@extend .py-2;
@extend .font-bold;
@extend .text-sm;
@extend .mt-3;

&:hover,
&:focus {
@extend .bg-contrast;
}
}

0 comments on commit 8d1f205

Please sign in to comment.