Merge pull request #662 from amanharwara/feat/prefs-defaults
feat: Dropdown component and default editor section in preferences
3
app/assets/icons/ic-authenticator.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 14C8 14.2652 8.10536 14.5196 8.29289 14.7071C8.48043 14.8946 8.73478 15 9 15C9.26522 15 9.51957 14.8946 9.70711 14.7071C9.89464 14.5196 10 14.2652 10 14C10 13.7348 9.89464 13.4804 9.70711 13.2929C9.51957 13.1054 9.26522 13 9 13C8.73478 13 8.48043 13.1054 8.29289 13.2929C8.10536 13.4804 8 13.7348 8 14ZM8 0V4H10V2.08C13.39 2.57 16 5.47 16 9C16 10.8565 15.2625 12.637 13.9497 13.9497C12.637 15.2625 10.8565 16 9 16C7.14348 16 5.36301 15.2625 4.05025 13.9497C2.7375 12.637 2 10.8565 2 9C2 7.32 2.59 5.78 3.58 4.58L9 10L10.41 8.59L3.61 1.79V1.81C1.42 3.45 0 6.05 0 9C0 11.3869 0.948211 13.6761 2.63604 15.364C4.32387 17.0518 6.61305 18 9 18C11.3869 18 13.6761 17.0518 15.364 15.364C17.0518 13.6761 18 11.3869 18 9C18 6.61305 17.0518 4.32387 15.364 2.63604C13.6761 0.948211 11.3869 0 9 0H8ZM15 9C15 8.73478 14.8946 8.48043 14.7071 8.29289C14.5196 8.10536 14.2652 8 14 8C13.7348 8 13.4804 8.10536 13.2929 8.29289C13.1054 8.48043 13 8.73478 13 9C13 9.26522 13.1054 9.51957 13.2929 9.70711C13.4804 9.89464 13.7348 10 14 10C14.2652 10 14.5196 9.89464 14.7071 9.70711C14.8946 9.51957 15 9.26522 15 9ZM3 9C3 9.26522 3.10536 9.51957 3.29289 9.70711C3.48043 9.89464 3.73478 10 4 10C4.26522 10 4.51957 9.89464 4.70711 9.70711C4.89464 9.51957 5 9.26522 5 9C5 8.73478 4.89464 8.48043 4.70711 8.29289C4.51957 8.10536 4.26522 8 4 8C3.73478 8 3.48043 8.10536 3.29289 8.29289C3.10536 8.48043 3 8.73478 3 9Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
3
app/assets/icons/ic-code.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 22 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.89 0L13.85 0.4L10.11 18L8.15002 17.6L11.89 0ZM18.59 9L15 5.41V2.58L21.42 9L15 15.41V12.58L18.59 9ZM0.580017 9L7.00002 2.58V5.41L3.41002 9L7.00002 12.58V15.41L0.580017 9Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 267 B |
3
app/assets/icons/ic-markdown.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 0V2H14V14H11V16H16V0H11ZM0 0V16H5V14H2V2H5V0H0Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 144 B |
4
app/assets/icons/ic-menu-arrow-down.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 8 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.666656 0.666504L3.99999 3.99984L7.33332 0.666504H0.666656Z" />
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 157 B |
3
app/assets/icons/ic-spreadsheets.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1.8 0.600098H16.2C16.6774 0.600098 17.1352 0.786413 17.4728 1.11806C17.8104 1.4497 18 1.8995 18 2.36852V15.6317C18 16.1007 17.8104 16.5505 17.4728 16.8821C17.1352 17.2138 16.6774 17.4001 16.2 17.4001H1.8C1.32261 17.4001 0.864773 17.2138 0.527208 16.8821C0.189642 16.5505 0 16.1007 0 15.6317V2.36852C0 1.8995 0.189642 1.4497 0.527208 1.11806C0.864773 0.786413 1.32261 0.600098 1.8 0.600098ZM1.8 4.13694V6.78957H5.4V4.13694H1.8ZM7.2 4.13694V6.78957H10.8V4.13694H7.2ZM16.2 6.78957V4.13694H12.6V6.78957H16.2ZM1.8 8.55799V11.2106H5.4V8.55799H1.8ZM1.8 15.6317H5.4V12.979H1.8V15.6317ZM7.2 8.55799V11.2106H10.8V8.55799H7.2ZM7.2 15.6317H10.8V12.979H7.2V15.6317ZM16.2 15.6317V12.979H12.6V15.6317H16.2ZM16.2 8.55799H12.6V11.2106H16.2V8.55799Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 826 B |
3
app/assets/icons/ic-tasks.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16 16H2V2H12V0H2C0.89 0 0 0.89 0 2V16C0 16.5304 0.210714 17.0391 0.585786 17.4142C0.960859 17.7893 1.46957 18 2 18H16C16.5304 18 17.0391 17.7893 17.4142 17.4142C17.7893 17.0391 18 16.5304 18 16V8H16V16ZM4.91 7.08L3.5 8.5L8 13L18 3L16.59 1.58L8 10.17L4.91 7.08Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 355 B |
4
app/assets/icons/ic-text-paragraph.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.4 0V2H0.599976V0H17.4ZM0.599976 12H8.99998V10H0.599976V12ZM0.599976 7H17.4V5H0.599976V7Z" />
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 190 B |
119
app/assets/javascripts/components/Dropdown.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
import {
|
||||
ListboxArrow,
|
||||
ListboxButton,
|
||||
ListboxInput,
|
||||
ListboxList,
|
||||
ListboxOption,
|
||||
ListboxPopover,
|
||||
} from '@reach/listbox';
|
||||
import VisuallyHidden from '@reach/visually-hidden';
|
||||
import { FunctionComponent } from 'preact';
|
||||
import { IconType, Icon } from './Icon';
|
||||
import { useState } from 'preact/hooks';
|
||||
|
||||
export type DropdownItem = {
|
||||
icon?: IconType;
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
type DropdownProps = {
|
||||
id: string;
|
||||
label: string;
|
||||
items: DropdownItem[];
|
||||
defaultValue: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
type ListboxButtonProps = {
|
||||
icon?: IconType;
|
||||
value: string | null;
|
||||
label: string;
|
||||
isExpanded: boolean;
|
||||
};
|
||||
|
||||
const CustomDropdownButton: FunctionComponent<ListboxButtonProps> = ({
|
||||
label,
|
||||
isExpanded,
|
||||
icon,
|
||||
}) => (
|
||||
<>
|
||||
<div className="sn-dropdown-button-label">
|
||||
{icon ? (
|
||||
<div className="flex mr-2">
|
||||
<Icon type={icon} className="sn-icon--small" />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="dropdown-selected-label">{label}</div>
|
||||
</div>
|
||||
<ListboxArrow
|
||||
className={`sn-dropdown-arrow ${
|
||||
isExpanded ? 'sn-dropdown-arrow-flipped' : ''
|
||||
}`}
|
||||
>
|
||||
<Icon type="menu-arrow-down" className="sn-icon--small color-grey-1" />
|
||||
</ListboxArrow>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Dropdown: FunctionComponent<DropdownProps> = ({
|
||||
id,
|
||||
label,
|
||||
items,
|
||||
defaultValue,
|
||||
onChange,
|
||||
}) => {
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
|
||||
const labelId = `${id}-label`;
|
||||
|
||||
const handleChange = (value: string) => {
|
||||
setValue(value);
|
||||
onChange(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<VisuallyHidden id={labelId}>{label}</VisuallyHidden>
|
||||
<ListboxInput
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
aria-labelledby={labelId}
|
||||
>
|
||||
<ListboxButton
|
||||
className="sn-dropdown-button"
|
||||
children={({ value, label, isExpanded }) => {
|
||||
const current = items.find((item) => item.value === value);
|
||||
const icon = current ? current?.icon : null;
|
||||
return CustomDropdownButton({
|
||||
value,
|
||||
label,
|
||||
isExpanded,
|
||||
...(icon ? { icon } : null),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<ListboxPopover className="sn-dropdown sn-dropdown-popover">
|
||||
<div className="sn-component">
|
||||
<ListboxList>
|
||||
{items.map((item) => (
|
||||
<ListboxOption
|
||||
className="sn-dropdown-item"
|
||||
value={item.value}
|
||||
label={item.label}
|
||||
>
|
||||
{item.icon ? (
|
||||
<div className="flex mr-3">
|
||||
<Icon type={item.icon} className="sn-icon--small" />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="text-input">{item.label}</div>
|
||||
</ListboxOption>
|
||||
))}
|
||||
</ListboxList>
|
||||
</div>
|
||||
</ListboxPopover>
|
||||
</ListboxInput>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import PencilOffIcon from '../../icons/ic-pencil-off.svg';
|
||||
import PlainTextIcon from '../../icons/ic-text-paragraph.svg';
|
||||
import RichTextIcon from '../../icons/ic-text-rich.svg';
|
||||
import TrashIcon from '../../icons/ic-trash.svg';
|
||||
import PinIcon from '../../icons/ic-pin.svg';
|
||||
@@ -13,6 +14,12 @@ 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 MenuArrowDownIcon from '../../icons/ic-menu-arrow-down.svg';
|
||||
import AuthenticatorIcon from '../../icons/ic-authenticator.svg';
|
||||
import SpreadsheetsIcon from '../../icons/ic-spreadsheets.svg';
|
||||
import TasksIcon from '../../icons/ic-tasks.svg';
|
||||
import MarkdownIcon from '../../icons/ic-markdown.svg';
|
||||
import CodeIcon from '../../icons/ic-code.svg';
|
||||
|
||||
import AccessibilityIcon from '../../icons/ic-accessibility.svg';
|
||||
import HelpIcon from '../../icons/ic-help.svg';
|
||||
@@ -35,7 +42,13 @@ import { FunctionalComponent } from 'preact';
|
||||
|
||||
const ICONS = {
|
||||
'pencil-off': PencilOffIcon,
|
||||
'plain-text': PlainTextIcon,
|
||||
'rich-text': RichTextIcon,
|
||||
code: CodeIcon,
|
||||
markdown: MarkdownIcon,
|
||||
authenticator: AuthenticatorIcon,
|
||||
spreadsheets: SpreadsheetsIcon,
|
||||
tasks: TasksIcon,
|
||||
trash: TrashIcon,
|
||||
pin: PinIcon,
|
||||
unpin: UnpinIcon,
|
||||
@@ -64,6 +77,7 @@ const ICONS = {
|
||||
check: CheckIcon,
|
||||
'check-bold': CheckBoldIcon,
|
||||
'account-circle': AccountCircleIcon,
|
||||
'menu-arrow-down': MenuArrowDownIcon,
|
||||
};
|
||||
|
||||
export type IconType = keyof typeof ICONS;
|
||||
|
||||
@@ -4,53 +4,44 @@ import { SNComponent, SNItem, ComponentArea } from '@standardnotes/snjs';
|
||||
import { isDesktopApplication } from '@/utils';
|
||||
import template from '%/directives/editor-menu.pug';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { ComponentMutator } from '@standardnotes/snjs';
|
||||
|
||||
interface EditorMenuScope {
|
||||
callback: (component: SNComponent) => void
|
||||
selectedEditorUuid: string
|
||||
currentItem: SNItem
|
||||
application: WebApplication
|
||||
callback: (component: SNComponent) => void;
|
||||
selectedEditorUuid: string;
|
||||
currentItem: SNItem;
|
||||
application: WebApplication;
|
||||
}
|
||||
|
||||
class EditorMenuCtrl extends PureViewCtrl implements EditorMenuScope {
|
||||
|
||||
callback!: () => (component: SNComponent) => void
|
||||
selectedEditorUuid!: string
|
||||
currentItem!: SNItem
|
||||
application!: WebApplication
|
||||
callback!: () => (component: SNComponent) => void;
|
||||
selectedEditorUuid!: string;
|
||||
currentItem!: SNItem;
|
||||
application!: WebApplication;
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$timeout: ng.ITimeoutService,
|
||||
) {
|
||||
constructor($timeout: ng.ITimeoutService) {
|
||||
super($timeout);
|
||||
this.state = {
|
||||
isDesktop: isDesktopApplication()
|
||||
isDesktop: isDesktopApplication(),
|
||||
};
|
||||
}
|
||||
|
||||
public isEditorSelected(editor: SNComponent) {
|
||||
if(!this.selectedEditorUuid) {
|
||||
if (!this.selectedEditorUuid) {
|
||||
return false;
|
||||
}
|
||||
return this.selectedEditorUuid === editor.uuid;
|
||||
}
|
||||
|
||||
public isEditorDefault(editor: SNComponent) {
|
||||
return this.state.defaultEditor?.uuid === editor.uuid;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
super.$onInit();
|
||||
const editors = this.application.componentManager!.componentsForArea(ComponentArea.Editor)
|
||||
const editors = this.application
|
||||
.componentManager!.componentsForArea(ComponentArea.Editor)
|
||||
.sort((a, b) => {
|
||||
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
|
||||
});
|
||||
const defaultEditor = editors.filter((e) => e.isDefaultEditor())[0];
|
||||
this.setState({
|
||||
editors: editors,
|
||||
defaultEditor: defaultEditor
|
||||
});
|
||||
}
|
||||
|
||||
@@ -67,46 +58,9 @@ class EditorMenuCtrl extends PureViewCtrl implements EditorMenuScope {
|
||||
});
|
||||
}
|
||||
|
||||
toggleDefaultForEditor(editor: SNComponent) {
|
||||
if (this.state.defaultEditor === editor) {
|
||||
this.removeEditorDefault(editor);
|
||||
} else {
|
||||
this.makeEditorDefault(editor);
|
||||
}
|
||||
}
|
||||
|
||||
offlineAvailableForComponent(component: SNComponent) {
|
||||
return component.local_url && this.state.isDesktop;
|
||||
}
|
||||
|
||||
makeEditorDefault(component: SNComponent) {
|
||||
const currentDefault = this.application.componentManager!
|
||||
.componentsForArea(ComponentArea.Editor)
|
||||
.filter((e) => e.isDefaultEditor())[0];
|
||||
if (currentDefault) {
|
||||
this.application.changeItem(currentDefault.uuid, (m) => {
|
||||
const mutator = m as ComponentMutator;
|
||||
mutator.defaultEditor = false;
|
||||
});
|
||||
}
|
||||
this.application.changeAndSaveItem(component.uuid, (m) => {
|
||||
const mutator = m as ComponentMutator;
|
||||
mutator.defaultEditor = true;
|
||||
});
|
||||
this.setState({
|
||||
defaultEditor: component
|
||||
});
|
||||
}
|
||||
|
||||
removeEditorDefault(component: SNComponent) {
|
||||
this.application.changeAndSaveItem(component.uuid, (m) => {
|
||||
const mutator = m as ComponentMutator;
|
||||
mutator.defaultEditor = false;
|
||||
});
|
||||
this.setState({
|
||||
defaultEditor: null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class EditorMenu extends WebDirective {
|
||||
@@ -121,7 +75,7 @@ export class EditorMenu extends WebDirective {
|
||||
callback: '&',
|
||||
selectedEditorUuid: '=',
|
||||
currentItem: '=',
|
||||
application: '='
|
||||
application: '=',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ import { WebApplication } from '@/ui_models/application';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { FunctionComponent } from 'preact';
|
||||
import { PreferencesPane } from '../components';
|
||||
import { ErrorReporting } from './general-segments';
|
||||
import { Tools } from './general-segments/Tools';
|
||||
import { ErrorReporting, Tools, Defaults } from './general-segments';
|
||||
|
||||
interface GeneralProps {
|
||||
appState: AppState;
|
||||
@@ -13,6 +12,7 @@ interface GeneralProps {
|
||||
export const General: FunctionComponent<GeneralProps> = (props) => (
|
||||
<PreferencesPane>
|
||||
<Tools application={props.application} />
|
||||
<Defaults application={props.application} />
|
||||
<ErrorReporting appState={props.appState} />
|
||||
</PreferencesPane>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
import { Dropdown, DropdownItem } from '@/components/Dropdown';
|
||||
import { IconType } from '@/components/Icon';
|
||||
import {
|
||||
PreferencesGroup,
|
||||
PreferencesSegment,
|
||||
Subtitle,
|
||||
Text,
|
||||
Title,
|
||||
} from '@/preferences/components';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import {
|
||||
ComponentArea,
|
||||
ComponentMutator,
|
||||
SNComponent,
|
||||
} from '@standardnotes/snjs';
|
||||
import { FunctionComponent } from 'preact';
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
|
||||
type Props = {
|
||||
application: WebApplication;
|
||||
};
|
||||
|
||||
enum EditorIdentifier {
|
||||
PlainEditor = 'plain-editor',
|
||||
BoldEditor = 'org.standardnotes.bold-editor',
|
||||
CodeEditor = 'org.standardnotes.code-editor',
|
||||
MarkdownBasic = 'org.standardnotes.simple-markdown-editor',
|
||||
MarkdownMath = 'org.standardnotes.fancy-markdown-editor',
|
||||
MarkdownMinimist = 'org.standardnotes.minimal-markdown-editor',
|
||||
MarkdownPro = 'org.standardnotes.advanced-markdown-editor',
|
||||
PlusEditor = 'org.standardnotes.plus-editor',
|
||||
SecureSpreadsheets = 'org.standardnotes.standard-sheets',
|
||||
TaskEditor = 'org.standardnotes.simple-task-editor',
|
||||
TokenVault = 'org.standardnotes.token-vault',
|
||||
}
|
||||
|
||||
const getEditorIconType = (identifier: string): IconType | null => {
|
||||
switch (identifier) {
|
||||
case EditorIdentifier.BoldEditor:
|
||||
case EditorIdentifier.PlusEditor:
|
||||
return 'rich-text';
|
||||
case EditorIdentifier.MarkdownBasic:
|
||||
case EditorIdentifier.MarkdownMath:
|
||||
case EditorIdentifier.MarkdownMinimist:
|
||||
case EditorIdentifier.MarkdownPro:
|
||||
return 'markdown';
|
||||
case EditorIdentifier.TokenVault:
|
||||
return 'authenticator';
|
||||
case EditorIdentifier.SecureSpreadsheets:
|
||||
return 'spreadsheets';
|
||||
case EditorIdentifier.TaskEditor:
|
||||
return 'tasks';
|
||||
case EditorIdentifier.CodeEditor:
|
||||
return 'code';
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const makeEditorDefault = (
|
||||
application: WebApplication,
|
||||
component: SNComponent,
|
||||
currentDefault: SNComponent
|
||||
) => {
|
||||
if (currentDefault) {
|
||||
removeEditorDefault(application, currentDefault);
|
||||
}
|
||||
application.changeAndSaveItem(component.uuid, (m) => {
|
||||
const mutator = m as ComponentMutator;
|
||||
mutator.defaultEditor = true;
|
||||
});
|
||||
};
|
||||
|
||||
const removeEditorDefault = (
|
||||
application: WebApplication,
|
||||
component: SNComponent
|
||||
) => {
|
||||
application.changeAndSaveItem(component.uuid, (m) => {
|
||||
const mutator = m as ComponentMutator;
|
||||
mutator.defaultEditor = false;
|
||||
});
|
||||
};
|
||||
|
||||
const getDefaultEditor = (application: WebApplication) => {
|
||||
return application.componentManager
|
||||
.componentsForArea(ComponentArea.Editor)
|
||||
.filter((e) => e.isDefaultEditor())[0];
|
||||
};
|
||||
|
||||
export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
const [editorItems, setEditorItems] = useState<DropdownItem[]>([]);
|
||||
const [defaultEditorValue] = useState(
|
||||
() =>
|
||||
getDefaultEditor(application)?.package_info?.identifier ||
|
||||
EditorIdentifier.PlainEditor
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const editors = application.componentManager
|
||||
.componentsForArea(ComponentArea.Editor)
|
||||
.map((editor) => {
|
||||
const identifier = editor.package_info.identifier;
|
||||
const iconType = getEditorIconType(identifier);
|
||||
|
||||
return {
|
||||
label: editor.name,
|
||||
value: identifier,
|
||||
...(iconType ? { icon: iconType } : null),
|
||||
};
|
||||
})
|
||||
.concat([
|
||||
{
|
||||
icon: 'plain-text',
|
||||
label: 'Plain Editor',
|
||||
value: EditorIdentifier.PlainEditor,
|
||||
},
|
||||
])
|
||||
.sort((a, b) => {
|
||||
return a.label.toLowerCase() < b.label.toLowerCase() ? -1 : 1;
|
||||
});
|
||||
|
||||
setEditorItems(editors);
|
||||
}, [application]);
|
||||
|
||||
const setDefaultEditor = (value: string) => {
|
||||
const editors = application.componentManager.componentsForArea(
|
||||
ComponentArea.Editor
|
||||
);
|
||||
const currentDefault = getDefaultEditor(application);
|
||||
|
||||
if (value !== EditorIdentifier.PlainEditor) {
|
||||
const editorComponent = editors.filter(
|
||||
(e) => e.package_info.identifier === value
|
||||
)[0];
|
||||
makeEditorDefault(application, editorComponent, currentDefault);
|
||||
} else {
|
||||
removeEditorDefault(application, currentDefault);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<Title>Defaults</Title>
|
||||
<div className="mt-2">
|
||||
<Subtitle>Default Editor</Subtitle>
|
||||
<Text>New notes will be created using this editor.</Text>
|
||||
<div className="mt-2">
|
||||
<Dropdown
|
||||
id="def-editor-dropdown"
|
||||
label="Select the default editor"
|
||||
items={editorItems}
|
||||
defaultValue={defaultEditorValue}
|
||||
onChange={setDefaultEditor}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
);
|
||||
};
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './ErrorReporting';
|
||||
export * from './Tools';
|
||||
export * from './Defaults';
|
||||
|
||||
@@ -9,14 +9,13 @@
|
||||
}
|
||||
[data-reach-dialog-overlay]::before {
|
||||
background-color: var(--sn-stylekit-contrast-background-color);
|
||||
content: "";
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
opacity: 0.75;
|
||||
|
||||
}
|
||||
|
||||
[data-reach-dialog-content] {
|
||||
|
||||
@@ -53,6 +53,41 @@
|
||||
}
|
||||
}
|
||||
|
||||
.sn-dropdown-popover {
|
||||
z-index: 3001;
|
||||
|
||||
&[data-reach-listbox-popover] {
|
||||
background: var(--sn-stylekit-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
.sn-dropdown-button {
|
||||
@extend .rounded;
|
||||
@extend .px-3\.5;
|
||||
@extend .py-1\.75;
|
||||
@extend .fit-content;
|
||||
@extend .bg-default;
|
||||
@extend .text-input;
|
||||
@extend .color-text;
|
||||
@extend .border-solid;
|
||||
@extend .border-gray-300;
|
||||
@extend .border-1;
|
||||
@extend .min-w-55;
|
||||
}
|
||||
|
||||
.sn-dropdown-button-label {
|
||||
@extend .flex;
|
||||
@extend .items-center;
|
||||
}
|
||||
|
||||
.sn-dropdown-arrow {
|
||||
@extend .flex;
|
||||
|
||||
&.sn-dropdown-arrow-flipped {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
/** Lesser specificity will give priority to reach's styles */
|
||||
[data-reach-custom-checkbox-container].sn-switch {
|
||||
@extend .duration-150;
|
||||
@@ -114,6 +149,21 @@
|
||||
&.sn-dropdown-item--no-icon {
|
||||
@extend .py-2;
|
||||
}
|
||||
|
||||
.sn-dropdown-popover & {
|
||||
@extend .bg-default;
|
||||
}
|
||||
|
||||
&[data-current-nav] {
|
||||
color: var(--sn-stylekit-contrast-foreground-color);
|
||||
@extend .bg-contrast;
|
||||
@extend .hover\:color-text;
|
||||
}
|
||||
|
||||
.sn-dropdown-popover &[data-current-selected] {
|
||||
background-color: var(--sn-stylekit-info-backdrop-color);
|
||||
@extend .color-info;
|
||||
}
|
||||
}
|
||||
|
||||
.sn-tag {
|
||||
@@ -278,4 +328,4 @@
|
||||
|
||||
.select-none {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,7 @@
|
||||
menu-row(
|
||||
ng-repeat='editor in self.state.editors track by editor.uuid'
|
||||
action='self.selectComponent(editor)',
|
||||
button-action='self.toggleDefaultForEditor(editor)',
|
||||
button-class="self.isEditorSelected(editor) ? 'warning' : 'info'",
|
||||
button-text="self.isEditorDefault(editor) ? 'Undefault' : 'Set Default'",
|
||||
circle="self.isEditorSelected(editor) && 'success'",
|
||||
has-button='self.isEditorSelected(editor) || isEditorDefault(editor)',
|
||||
label='editor.name',
|
||||
subtitle="self.isEditorSelected(editor) && 'Version ' + editor.package_info.version",
|
||||
)
|
||||
|
||||
@@ -70,8 +70,9 @@
|
||||
"@reach/alert-dialog": "^0.13.0",
|
||||
"@reach/checkbox": "^0.13.2",
|
||||
"@reach/dialog": "^0.13.0",
|
||||
"@standardnotes/sncrypto-web": "1.5.2",
|
||||
"@reach/listbox": "^0.16.1",
|
||||
"@standardnotes/features": "1.6.1",
|
||||
"@standardnotes/sncrypto-web": "1.5.2",
|
||||
"@standardnotes/snjs": "2.14.11",
|
||||
"mobx": "^6.3.2",
|
||||
"mobx-react-lite": "^3.2.0",
|
||||
|
||||
75
yarn.lock
@@ -1834,6 +1834,14 @@
|
||||
"@reach/utils" "0.15.2"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/auto-id@0.16.0":
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.16.0.tgz#dfabc3227844e8c04f8e6e45203a8e14a8edbaed"
|
||||
integrity sha512-5ssbeP5bCkM39uVsfQCwBBL+KT8YColdnMN5/Eto6Rj7929ql95R3HZUOkKIvj7mgPtEb60BLQxd1P3o6cjbmg==
|
||||
dependencies:
|
||||
"@reach/utils" "0.16.0"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/checkbox@^0.13.2":
|
||||
version "0.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@reach/checkbox/-/checkbox-0.13.2.tgz#b972b922cf6cea0c2bbabca0129c58307b566a4e"
|
||||
@@ -1853,6 +1861,14 @@
|
||||
"@reach/utils" "0.15.2"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/descendants@0.16.1":
|
||||
version "0.16.1"
|
||||
resolved "https://registry.yarnpkg.com/@reach/descendants/-/descendants-0.16.1.tgz#fa3d89c0503565369707f32985d87eef61985d9f"
|
||||
integrity sha512-3WZgRnD9O4EORKE31rrduJDiPFNMOjUkATx0zl192ZxMq3qITe4tUj70pS5IbJl/+v9zk78JwyQLvA1pL7XAPA==
|
||||
dependencies:
|
||||
"@reach/utils" "0.16.0"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/dialog@0.13.0", "@reach/dialog@^0.13.0":
|
||||
version "0.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/dialog/-/dialog-0.13.0.tgz#2110725c3b8a3c64685834cdc9f3ce5c15617809"
|
||||
@@ -1887,6 +1903,18 @@
|
||||
"@reach/utils" "0.15.2"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@reach/listbox@^0.16.1":
|
||||
version "0.16.1"
|
||||
resolved "https://registry.yarnpkg.com/@reach/listbox/-/listbox-0.16.1.tgz#8a4a13cf171e9ba3118d2e6e72f3e7f17f4c2f80"
|
||||
integrity sha512-2KQTYmxKvZW0XdBWGoV7E2gUWWBINJmfj2MDRmWbRNdTjsF9w3mTb09buTWQ2sznzF7DrLrwiBFv4b2egMfKOw==
|
||||
dependencies:
|
||||
"@reach/auto-id" "0.16.0"
|
||||
"@reach/descendants" "0.16.1"
|
||||
"@reach/machine" "0.16.0"
|
||||
"@reach/popover" "0.16.0"
|
||||
"@reach/utils" "0.16.0"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@reach/machine@0.13.2":
|
||||
version "0.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@reach/machine/-/machine-0.13.2.tgz#744302f5ce2d4e5fd0527ae0baa60d325b2325d8"
|
||||
@@ -1905,6 +1933,15 @@
|
||||
"@xstate/fsm" "1.4.0"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/machine@0.16.0":
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/machine/-/machine-0.16.0.tgz#0504ba47ac09ed495bd341bf5fdd6625bcade0e3"
|
||||
integrity sha512-c8SRQz2xGtg5M9aXuuM5pFgaV1ZW5/nyMIYpZzBwHUlNFKGO+VBhwedbnqUxO0yLcbgl3wPvjPh740O3YjqiHg==
|
||||
dependencies:
|
||||
"@reach/utils" "0.16.0"
|
||||
"@xstate/fsm" "1.4.0"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/menu-button@^0.15.1":
|
||||
version "0.15.2"
|
||||
resolved "https://registry.yarnpkg.com/@reach/menu-button/-/menu-button-0.15.2.tgz#00f91402be3ff23d3b4cfe377529f4f9e82a78fe"
|
||||
@@ -1934,6 +1971,17 @@
|
||||
tabbable "^4.0.0"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/popover@0.16.0":
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/popover/-/popover-0.16.0.tgz#82c5ab96a88c49e2451a9c04b2d4392a9055f623"
|
||||
integrity sha512-xmgiSyQwfshMkMNu6URbGrjjDTD3dnAITojvgEqfEtV1chDYqktKdDbIPrq+UGI54ey/IxbRpVzKcIjXiKoMmA==
|
||||
dependencies:
|
||||
"@reach/portal" "0.16.0"
|
||||
"@reach/rect" "0.16.0"
|
||||
"@reach/utils" "0.16.0"
|
||||
tabbable "^4.0.0"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/portal@0.13.0":
|
||||
version "0.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/portal/-/portal-0.13.0.tgz#bed220d41097deb1454a7928b22529ba10d3ea2b"
|
||||
@@ -1950,6 +1998,14 @@
|
||||
"@reach/utils" "0.15.2"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/portal@0.16.0":
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/portal/-/portal-0.16.0.tgz#1544531d978b770770b718b2872b35652a11e7e3"
|
||||
integrity sha512-vXJ0O9T+72HiSEWHPs2cx7YbSO7pQsTMhgqPc5aaddIYpo2clJx1PnYuS0lSNlVaDO0IxQhwYq43evXaXnmviw==
|
||||
dependencies:
|
||||
"@reach/utils" "0.16.0"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/rect@0.15.2":
|
||||
version "0.15.2"
|
||||
resolved "https://registry.yarnpkg.com/@reach/rect/-/rect-0.15.2.tgz#734e3f17a499d6e22bd2ea95856c801c41ed66fd"
|
||||
@@ -1961,6 +2017,17 @@
|
||||
tiny-warning "^1.0.3"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/rect@0.16.0":
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/rect/-/rect-0.16.0.tgz#78cf6acefe2e83d3957fa84f938f6e1fc5700f16"
|
||||
integrity sha512-/qO9jQDzpOCdrSxVPR6l674mRHNTqfEjkaxZHluwJ/2qGUtYsA0GSZiF/+wX/yOWeBif1ycxJDa6HusAMJZC5Q==
|
||||
dependencies:
|
||||
"@reach/observe-rect" "1.2.0"
|
||||
"@reach/utils" "0.16.0"
|
||||
prop-types "^15.7.2"
|
||||
tiny-warning "^1.0.3"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/utils@0.13.0":
|
||||
version "0.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.13.0.tgz#2da775a910d8894bb34e1e94fe95842674f71844"
|
||||
@@ -1996,6 +2063,14 @@
|
||||
tiny-warning "^1.0.3"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/utils@0.16.0":
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.16.0.tgz#5b0777cf16a7cab1ddd4728d5d02762df0ba84ce"
|
||||
integrity sha512-PCggBet3qaQmwFNcmQ/GqHSefadAFyNCUekq9RrWoaU9hh/S4iaFgf2MBMdM47eQj5i/Bk0Mm07cP/XPFlkN+Q==
|
||||
dependencies:
|
||||
tiny-warning "^1.0.3"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@reach/visually-hidden@0.13.0":
|
||||
version "0.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/visually-hidden/-/visually-hidden-0.13.0.tgz#cace36d9bb80ffb797374fcaea989391b881038f"
|
||||
|
||||