mirror of
https://github.com/standardnotes/app.git
synced 2026-01-16 23:01:30 +00:00
feat: Add "Export" and "Duplicate" buttons in notes options menu. (#688)
Co-authored-by: Mough <mo@standardnotes.org>
This commit is contained in:
parent
f9b15262c7
commit
3a4e2509af
9 changed files with 72 additions and 50 deletions
|
|
@ -1,3 +1,3 @@
|
|||
<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>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 557 B After Width: | Height: | Size: 542 B |
|
|
@ -1,3 +1,3 @@
|
|||
<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>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 200 B |
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@
|
|||
"@reach/checkbox": "^0.13.2",
|
||||
"@reach/dialog": "^0.13.0",
|
||||
"@reach/listbox": "^0.16.1",
|
||||
"@standardnotes/features": "1.6.1",
|
||||
"@standardnotes/features": "1.7.2",
|
||||
"@standardnotes/sncrypto-web": "1.5.2",
|
||||
"@standardnotes/snjs": "2.14.14",
|
||||
"@standardnotes/snjs": "2.15.2",
|
||||
"mobx": "^6.3.2",
|
||||
"mobx-react-lite": "^3.2.0",
|
||||
"preact": "^10.5.12",
|
||||
|
|
|
|||
25
yarn.lock
25
yarn.lock
|
|
@ -2117,17 +2117,10 @@
|
|||
dependencies:
|
||||
"@standardnotes/auth" "^3.7.0"
|
||||
|
||||
"@standardnotes/features@1.6.1":
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.6.1.tgz#bfa227bd231dc1b54449936663731f5132b08e23"
|
||||
integrity sha512-IC6fEotUqs23JdZx96JnEgARxwYzjmPz3UwU/uVn8hHjxPev/W0nyZFRiSlj4v+dod0jSa6FTR8iLLsOQ6M4Ug==
|
||||
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==
|
||||
"@standardnotes/features@1.7.2":
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.7.2.tgz#7a45a947f56c55d191614f7293af553c5209705a"
|
||||
integrity sha512-zFTHzYAC+08Lbeni5x3RalR5FT8qVORgv3T/z6/Ye4mGvDyXSAddgDPn+o/NmzirwBTpaF6ogSzwZocsElm8zg==
|
||||
dependencies:
|
||||
"@standardnotes/common" "^1.1.0"
|
||||
|
||||
|
|
@ -2149,15 +2142,15 @@
|
|||
"@standardnotes/sncrypto-common" "^1.5.2"
|
||||
libsodium-wrappers "^0.7.8"
|
||||
|
||||
"@standardnotes/snjs@2.14.14":
|
||||
version "2.14.14"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.14.14.tgz#02886f431570a19a7dc5de0411fb19bb864281f2"
|
||||
integrity sha512-IQVsRLFhbmRtF2kB9mXnccjY2lBCb+k1biLmM6lF5ZpanxPPeW/Z5H398QWgCFzfKu70nocSXO+SqmLswKxnLQ==
|
||||
"@standardnotes/snjs@2.15.2":
|
||||
version "2.15.2"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.15.2.tgz#4502a02333529434d2c8c00830652cce31c57d25"
|
||||
integrity sha512-n0R6wSJfwYoBVtChPbBssvvPQEyYufP7AD+IEibjjbmZImFQky/7x45hsoEsFti0EL5FheAHHKFCC//4jD4fiA==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "3.7.2"
|
||||
"@standardnotes/common" "1.2.0"
|
||||
"@standardnotes/domain-events" "2.1.0"
|
||||
"@standardnotes/features" "1.6.2"
|
||||
"@standardnotes/features" "1.7.2"
|
||||
"@standardnotes/settings" "1.2.0"
|
||||
"@standardnotes/sncrypto-common" "1.5.2"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue