feat: Add "Export" and "Duplicate" buttons in notes options menu. (#688)
Co-authored-by: Mough <mo@standardnotes.org>
This commit is contained in:
@@ -205,6 +205,26 @@ export const NotesOptions = observer(
|
||||
setTagsMenuOpen(!tagsMenuOpen);
|
||||
};
|
||||
|
||||
const downloadSelectedItems = () => {
|
||||
notes.forEach((note) => {
|
||||
const editor = application.componentManager.editorForNote(note);
|
||||
const format = editor?.package_info?.file_type || 'txt';
|
||||
const downloadAnchor = document.createElement('a');
|
||||
downloadAnchor.setAttribute(
|
||||
'href',
|
||||
'data:text/plain;charset=utf-8,' + encodeURIComponent(note.text)
|
||||
);
|
||||
downloadAnchor.setAttribute('download', `${note.title}.${format}`);
|
||||
downloadAnchor.click();
|
||||
});
|
||||
};
|
||||
|
||||
const duplicateSelectedItems = () => {
|
||||
notes.forEach((note) => {
|
||||
application.duplicateItem(note);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Switch
|
||||
@@ -329,6 +349,22 @@ export const NotesOptions = observer(
|
||||
Unpin
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={downloadSelectedItems}
|
||||
>
|
||||
<Icon type="download" className={iconClass} />
|
||||
Export
|
||||
</button>
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={duplicateSelectedItems}
|
||||
>
|
||||
<Icon type="copy" className={iconClass} />
|
||||
Duplicate
|
||||
</button>
|
||||
{unarchived && (
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
|
||||
@@ -20,5 +20,5 @@ export enum HtmlInputTypes {
|
||||
Text = 'text',
|
||||
Time = 'time',
|
||||
Url = 'url',
|
||||
Week = 'week'
|
||||
Week = 'week',
|
||||
}
|
||||
|
||||
@@ -94,7 +94,6 @@ export const Extensions: FunctionComponent<{
|
||||
<PreferencesGroup>
|
||||
{
|
||||
extensions
|
||||
.filter(extension => extension.package_info.identifier !== 'org.standardnotes.extensions-manager')
|
||||
.sort((e1, e2) => e1.name.toLowerCase().localeCompare(e2.name.toLowerCase()))
|
||||
.map((extension, i) => (
|
||||
<ExtensionItem
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Dropdown, DropdownItem } from '@/components/Dropdown';
|
||||
import { IconType } from '@/components/Icon';
|
||||
import { FeatureIdentifier } from '@standardnotes/snjs';
|
||||
import {
|
||||
PreferencesGroup,
|
||||
PreferencesSegment,
|
||||
@@ -20,37 +21,29 @@ 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',
|
||||
}
|
||||
type EditorOption = {
|
||||
icon?: IconType;
|
||||
label: string;
|
||||
value: FeatureIdentifier | 'plain-editor';
|
||||
};
|
||||
|
||||
const getEditorIconType = (identifier: string): IconType | null => {
|
||||
switch (identifier) {
|
||||
case EditorIdentifier.BoldEditor:
|
||||
case EditorIdentifier.PlusEditor:
|
||||
case FeatureIdentifier.BoldEditor:
|
||||
case FeatureIdentifier.PlusEditor:
|
||||
return 'rich-text';
|
||||
case EditorIdentifier.MarkdownBasic:
|
||||
case EditorIdentifier.MarkdownMath:
|
||||
case EditorIdentifier.MarkdownMinimist:
|
||||
case EditorIdentifier.MarkdownPro:
|
||||
case FeatureIdentifier.MarkdownBasicEditor:
|
||||
case FeatureIdentifier.MarkdownMathEditor:
|
||||
case FeatureIdentifier.MarkdownMinimistEditor:
|
||||
case FeatureIdentifier.MarkdownProEditor:
|
||||
return 'markdown';
|
||||
case EditorIdentifier.TokenVault:
|
||||
case FeatureIdentifier.TokenVaultEditor:
|
||||
return 'authenticator';
|
||||
case EditorIdentifier.SecureSpreadsheets:
|
||||
case FeatureIdentifier.SheetsEditor:
|
||||
return 'spreadsheets';
|
||||
case EditorIdentifier.TaskEditor:
|
||||
case FeatureIdentifier.TaskEditor:
|
||||
return 'tasks';
|
||||
case EditorIdentifier.CodeEditor:
|
||||
case FeatureIdentifier.CodeEditor:
|
||||
return 'code';
|
||||
}
|
||||
return null;
|
||||
@@ -90,14 +83,13 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
const [editorItems, setEditorItems] = useState<DropdownItem[]>([]);
|
||||
const [defaultEditorValue] = useState(
|
||||
() =>
|
||||
getDefaultEditor(application)?.package_info?.identifier ||
|
||||
EditorIdentifier.PlainEditor
|
||||
getDefaultEditor(application)?.package_info?.identifier || 'plain-editor'
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const editors = application.componentManager
|
||||
.componentsForArea(ComponentArea.Editor)
|
||||
.map((editor) => {
|
||||
.map((editor): EditorOption => {
|
||||
const identifier = editor.package_info.identifier;
|
||||
const iconType = getEditorIconType(identifier);
|
||||
|
||||
@@ -111,7 +103,7 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
{
|
||||
icon: 'plain-text',
|
||||
label: 'Plain Editor',
|
||||
value: EditorIdentifier.PlainEditor,
|
||||
value: 'plain-editor',
|
||||
},
|
||||
])
|
||||
.sort((a, b) => {
|
||||
@@ -127,7 +119,7 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
);
|
||||
const currentDefault = getDefaultEditor(application);
|
||||
|
||||
if (value !== EditorIdentifier.PlainEditor) {
|
||||
if (value !== 'plain-editor') {
|
||||
const editorComponent = editors.filter(
|
||||
(e) => e.package_info.identifier === value
|
||||
)[0];
|
||||
|
||||
@@ -49,6 +49,8 @@ type NotesCtrlState = {
|
||||
[PrefKey.EditorMonospaceEnabled]?: boolean
|
||||
[PrefKey.EditorSpellcheck]?: boolean
|
||||
[PrefKey.EditorResizersEnabled]?: boolean
|
||||
[PrefKey.NotesShowTrashed]?: boolean
|
||||
[PrefKey.NotesHideProtected]?: boolean
|
||||
}
|
||||
|
||||
type NoteFlag = {
|
||||
|
||||
Reference in New Issue
Block a user