feat: Add "Export" and "Duplicate" buttons in notes options menu. (#688)

Co-authored-by: Mough <mo@standardnotes.org>
This commit is contained in:
Aman Harwara
2021-10-19 21:13:20 +05:30
committed by GitHub
parent f9b15262c7
commit 3a4e2509af
9 changed files with 72 additions and 50 deletions

View File

@@ -1,3 +1,3 @@
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.66724 3.66626C1.66724 2.56169 2.56267 1.66626 3.66724 1.66626H11.3339C12.4385 1.66626 13.3339 2.56169 13.3339 3.66626V13.3329H3.66724C2.56267 13.3329 1.66724 12.4375 1.66724 11.3329V3.66626ZM16.3339 6.66626C17.4385 6.66626 18.3339 7.56169 18.3339 8.66626V16.3329C18.3339 17.4375 17.4385 18.3329 16.3339 18.3329H8.66724C7.56267 18.3329 6.66724 17.4375 6.66724 16.3329V14.9996H15.0006V6.66626H16.3339ZM3.3339 3.33293V11.6663H11.6672V3.33293H3.3339Z" fill="#72767E"/> <path d="M1.66724 3.66626C1.66724 2.56169 2.56267 1.66626 3.66724 1.66626H11.3339C12.4385 1.66626 13.3339 2.56169 13.3339 3.66626V13.3329H3.66724C2.56267 13.3329 1.66724 12.4375 1.66724 11.3329V3.66626ZM16.3339 6.66626C17.4385 6.66626 18.3339 7.56169 18.3339 8.66626V16.3329C18.3339 17.4375 17.4385 18.3329 16.3339 18.3329H8.66724C7.56267 18.3329 6.66724 17.4375 6.66724 16.3329V14.9996H15.0006V6.66626H16.3339ZM3.3339 3.33293V11.6663H11.6672V3.33293H3.3339Z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 557 B

After

Width:  |  Height:  |  Size: 542 B

View File

@@ -1,3 +1,3 @@
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 3.5V9.5H12.17L10 11.67L7.83 9.5H9V3.5H11ZM13 1.5H7V7.5H3L10 14.5L17 7.5H13V1.5ZM17 16.5H3V18.5H17V16.5Z" fill="#72767E"/> <path d="M11 3.5V9.5H12.17L10 11.67L7.83 9.5H9V3.5H11ZM13 1.5H7V7.5H3L10 14.5L17 7.5H13V1.5ZM17 16.5H3V18.5H17V16.5Z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 215 B

After

Width:  |  Height:  |  Size: 200 B

View File

@@ -205,6 +205,26 @@ export const NotesOptions = observer(
setTagsMenuOpen(!tagsMenuOpen); 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 ( return (
<> <>
<Switch <Switch
@@ -329,6 +349,22 @@ export const NotesOptions = observer(
Unpin Unpin
</button> </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 && ( {unarchived && (
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}

View File

@@ -20,5 +20,5 @@ export enum HtmlInputTypes {
Text = 'text', Text = 'text',
Time = 'time', Time = 'time',
Url = 'url', Url = 'url',
Week = 'week' Week = 'week',
} }

View File

@@ -94,7 +94,6 @@ export const Extensions: FunctionComponent<{
<PreferencesGroup> <PreferencesGroup>
{ {
extensions extensions
.filter(extension => extension.package_info.identifier !== 'org.standardnotes.extensions-manager')
.sort((e1, e2) => e1.name.toLowerCase().localeCompare(e2.name.toLowerCase())) .sort((e1, e2) => e1.name.toLowerCase().localeCompare(e2.name.toLowerCase()))
.map((extension, i) => ( .map((extension, i) => (
<ExtensionItem <ExtensionItem

View File

@@ -1,5 +1,6 @@
import { Dropdown, DropdownItem } from '@/components/Dropdown'; import { Dropdown, DropdownItem } from '@/components/Dropdown';
import { IconType } from '@/components/Icon'; import { IconType } from '@/components/Icon';
import { FeatureIdentifier } from '@standardnotes/snjs';
import { import {
PreferencesGroup, PreferencesGroup,
PreferencesSegment, PreferencesSegment,
@@ -20,37 +21,29 @@ type Props = {
application: WebApplication; application: WebApplication;
}; };
enum EditorIdentifier { type EditorOption = {
PlainEditor = 'plain-editor', icon?: IconType;
BoldEditor = 'org.standardnotes.bold-editor', label: string;
CodeEditor = 'org.standardnotes.code-editor', value: FeatureIdentifier | 'plain-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 => { const getEditorIconType = (identifier: string): IconType | null => {
switch (identifier) { switch (identifier) {
case EditorIdentifier.BoldEditor: case FeatureIdentifier.BoldEditor:
case EditorIdentifier.PlusEditor: case FeatureIdentifier.PlusEditor:
return 'rich-text'; return 'rich-text';
case EditorIdentifier.MarkdownBasic: case FeatureIdentifier.MarkdownBasicEditor:
case EditorIdentifier.MarkdownMath: case FeatureIdentifier.MarkdownMathEditor:
case EditorIdentifier.MarkdownMinimist: case FeatureIdentifier.MarkdownMinimistEditor:
case EditorIdentifier.MarkdownPro: case FeatureIdentifier.MarkdownProEditor:
return 'markdown'; return 'markdown';
case EditorIdentifier.TokenVault: case FeatureIdentifier.TokenVaultEditor:
return 'authenticator'; return 'authenticator';
case EditorIdentifier.SecureSpreadsheets: case FeatureIdentifier.SheetsEditor:
return 'spreadsheets'; return 'spreadsheets';
case EditorIdentifier.TaskEditor: case FeatureIdentifier.TaskEditor:
return 'tasks'; return 'tasks';
case EditorIdentifier.CodeEditor: case FeatureIdentifier.CodeEditor:
return 'code'; return 'code';
} }
return null; return null;
@@ -90,14 +83,13 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
const [editorItems, setEditorItems] = useState<DropdownItem[]>([]); const [editorItems, setEditorItems] = useState<DropdownItem[]>([]);
const [defaultEditorValue] = useState( const [defaultEditorValue] = useState(
() => () =>
getDefaultEditor(application)?.package_info?.identifier || getDefaultEditor(application)?.package_info?.identifier || 'plain-editor'
EditorIdentifier.PlainEditor
); );
useEffect(() => { useEffect(() => {
const editors = application.componentManager const editors = application.componentManager
.componentsForArea(ComponentArea.Editor) .componentsForArea(ComponentArea.Editor)
.map((editor) => { .map((editor): EditorOption => {
const identifier = editor.package_info.identifier; const identifier = editor.package_info.identifier;
const iconType = getEditorIconType(identifier); const iconType = getEditorIconType(identifier);
@@ -111,7 +103,7 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
{ {
icon: 'plain-text', icon: 'plain-text',
label: 'Plain Editor', label: 'Plain Editor',
value: EditorIdentifier.PlainEditor, value: 'plain-editor',
}, },
]) ])
.sort((a, b) => { .sort((a, b) => {
@@ -127,7 +119,7 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
); );
const currentDefault = getDefaultEditor(application); const currentDefault = getDefaultEditor(application);
if (value !== EditorIdentifier.PlainEditor) { if (value !== 'plain-editor') {
const editorComponent = editors.filter( const editorComponent = editors.filter(
(e) => e.package_info.identifier === value (e) => e.package_info.identifier === value
)[0]; )[0];

View File

@@ -49,6 +49,8 @@ type NotesCtrlState = {
[PrefKey.EditorMonospaceEnabled]?: boolean [PrefKey.EditorMonospaceEnabled]?: boolean
[PrefKey.EditorSpellcheck]?: boolean [PrefKey.EditorSpellcheck]?: boolean
[PrefKey.EditorResizersEnabled]?: boolean [PrefKey.EditorResizersEnabled]?: boolean
[PrefKey.NotesShowTrashed]?: boolean
[PrefKey.NotesHideProtected]?: boolean
} }
type NoteFlag = { type NoteFlag = {

View File

@@ -71,9 +71,9 @@
"@reach/checkbox": "^0.13.2", "@reach/checkbox": "^0.13.2",
"@reach/dialog": "^0.13.0", "@reach/dialog": "^0.13.0",
"@reach/listbox": "^0.16.1", "@reach/listbox": "^0.16.1",
"@standardnotes/features": "1.6.1", "@standardnotes/features": "1.7.2",
"@standardnotes/sncrypto-web": "1.5.2", "@standardnotes/sncrypto-web": "1.5.2",
"@standardnotes/snjs": "2.14.14", "@standardnotes/snjs": "2.15.2",
"mobx": "^6.3.2", "mobx": "^6.3.2",
"mobx-react-lite": "^3.2.0", "mobx-react-lite": "^3.2.0",
"preact": "^10.5.12", "preact": "^10.5.12",

View File

@@ -2117,17 +2117,10 @@
dependencies: dependencies:
"@standardnotes/auth" "^3.7.0" "@standardnotes/auth" "^3.7.0"
"@standardnotes/features@1.6.1": "@standardnotes/features@1.7.2":
version "1.6.1" version "1.7.2"
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.6.1.tgz#bfa227bd231dc1b54449936663731f5132b08e23" resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.7.2.tgz#7a45a947f56c55d191614f7293af553c5209705a"
integrity sha512-IC6fEotUqs23JdZx96JnEgARxwYzjmPz3UwU/uVn8hHjxPev/W0nyZFRiSlj4v+dod0jSa6FTR8iLLsOQ6M4Ug== integrity sha512-zFTHzYAC+08Lbeni5x3RalR5FT8qVORgv3T/z6/Ye4mGvDyXSAddgDPn+o/NmzirwBTpaF6ogSzwZocsElm8zg==
dependencies:
"@standardnotes/common" "^1.1.0"
"@standardnotes/features@1.6.2":
version "1.6.2"
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.6.2.tgz#98c5998426d9f93e06c2846c5bc7b6aef8d31063"
integrity sha512-s/rqRyG7mrrgxJOzckPSYlB68wsRpM9jlFwDE+7zQO5/xKh+37ueWfy3RoqOgkKLey6lMpnTurofIJCvqLM3dQ==
dependencies: dependencies:
"@standardnotes/common" "^1.1.0" "@standardnotes/common" "^1.1.0"
@@ -2149,15 +2142,15 @@
"@standardnotes/sncrypto-common" "^1.5.2" "@standardnotes/sncrypto-common" "^1.5.2"
libsodium-wrappers "^0.7.8" libsodium-wrappers "^0.7.8"
"@standardnotes/snjs@2.14.14": "@standardnotes/snjs@2.15.2":
version "2.14.14" version "2.15.2"
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.14.14.tgz#02886f431570a19a7dc5de0411fb19bb864281f2" resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.15.2.tgz#4502a02333529434d2c8c00830652cce31c57d25"
integrity sha512-IQVsRLFhbmRtF2kB9mXnccjY2lBCb+k1biLmM6lF5ZpanxPPeW/Z5H398QWgCFzfKu70nocSXO+SqmLswKxnLQ== integrity sha512-n0R6wSJfwYoBVtChPbBssvvPQEyYufP7AD+IEibjjbmZImFQky/7x45hsoEsFti0EL5FheAHHKFCC//4jD4fiA==
dependencies: dependencies:
"@standardnotes/auth" "3.7.2" "@standardnotes/auth" "3.7.2"
"@standardnotes/common" "1.2.0" "@standardnotes/common" "1.2.0"
"@standardnotes/domain-events" "2.1.0" "@standardnotes/domain-events" "2.1.0"
"@standardnotes/features" "1.6.2" "@standardnotes/features" "1.7.2"
"@standardnotes/settings" "1.2.0" "@standardnotes/settings" "1.2.0"
"@standardnotes/sncrypto-common" "1.5.2" "@standardnotes/sncrypto-common" "1.5.2"