feat: note types
This commit is contained in:
@@ -72,7 +72,7 @@ export const ChangeEditorButton: FunctionComponent<Props> = observer(
|
||||
ref={buttonRef}
|
||||
className="sn-icon-button border-contrast"
|
||||
>
|
||||
<VisuallyHidden>Change editor</VisuallyHidden>
|
||||
<VisuallyHidden>Change note type</VisuallyHidden>
|
||||
<Icon type="dashboard" className="block" />
|
||||
</DisclosureButton>
|
||||
<DisclosurePanel
|
||||
|
||||
@@ -21,7 +21,8 @@ import {
|
||||
import { Fragment, FunctionComponent } from 'preact'
|
||||
import { useCallback, useEffect, useState } from 'preact/hooks'
|
||||
import { EditorMenuItem, EditorMenuGroup } from '@/Components/NotesOptions/ChangeEditorOption'
|
||||
import { createEditorMenuGroups, PLAIN_EDITOR_NAME } from './createEditorMenuGroups'
|
||||
import { createEditorMenuGroups } from './createEditorMenuGroups'
|
||||
import { PLAIN_EDITOR_NAME } from '@/Constants'
|
||||
|
||||
type ChangeEditorMenuProps = {
|
||||
application: WebApplication
|
||||
@@ -169,7 +170,7 @@ export const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Menu className="pt-0.5 pb-1" a11yLabel="Change editor menu" isOpen={isVisible}>
|
||||
<Menu className="pt-0.5 pb-1" a11yLabel="Change note type menu" isOpen={isVisible}>
|
||||
{groups
|
||||
.filter((group) => group.items && group.items.length)
|
||||
.map((group, index) => {
|
||||
@@ -194,9 +195,7 @@ export const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
|
||||
<MenuItem
|
||||
type={MenuItemType.RadioButton}
|
||||
onClick={onClickEditorItem}
|
||||
className={
|
||||
'sn-dropdown-item py-2 text-input focus:bg-info-backdrop focus:shadow-none'
|
||||
}
|
||||
className={'sn-dropdown-item py-2 text-input focus:bg-info-backdrop focus:shadow-none'}
|
||||
onBlur={closeOnBlur}
|
||||
checked={isSelectedEditor(item)}
|
||||
>
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
NoteType,
|
||||
} from '@standardnotes/snjs'
|
||||
import { EditorMenuItem, EditorMenuGroup } from '@/Components/NotesOptions/ChangeEditorOption'
|
||||
|
||||
export const PLAIN_EDITOR_NAME = 'Plain Editor'
|
||||
import { PLAIN_EDITOR_NAME } from '@/Constants'
|
||||
|
||||
type EditorGroup = NoteType | 'plain' | 'others'
|
||||
|
||||
@@ -50,10 +49,7 @@ export const createEditorMenuGroups = (application: WebApplication, editors: SNC
|
||||
}
|
||||
|
||||
GetFeatures()
|
||||
.filter(
|
||||
(feature) =>
|
||||
feature.content_type === ContentType.Component && feature.area === ComponentArea.Editor,
|
||||
)
|
||||
.filter((feature) => feature.content_type === ContentType.Component && feature.area === ComponentArea.Editor)
|
||||
.forEach((editorFeature) => {
|
||||
const notInstalled = !editors.find((editor) => editor.identifier === editorFeature.identifier)
|
||||
const isExperimental = application.features.isExperimentalFeature(editorFeature.identifier)
|
||||
@@ -69,8 +65,7 @@ export const createEditorMenuGroups = (application: WebApplication, editors: SNC
|
||||
const editorItem: EditorMenuItem = {
|
||||
name: editor.name,
|
||||
component: editor,
|
||||
isEntitled:
|
||||
application.features.getFeatureStatus(editor.identifier) === FeatureStatus.Entitled,
|
||||
isEntitled: application.features.getFeatureStatus(editor.identifier) === FeatureStatus.Entitled,
|
||||
}
|
||||
|
||||
editorItems[getEditorGroup(editor.package_info)].push(editorItem)
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import { WebApplication } from '@/UIModels/Application'
|
||||
import {
|
||||
CollectionSort,
|
||||
CollectionSortProperty,
|
||||
sanitizeHtmlString,
|
||||
SNNote,
|
||||
} from '@standardnotes/snjs'
|
||||
import { CollectionSort, CollectionSortProperty, sanitizeHtmlString, SNNote } from '@standardnotes/snjs'
|
||||
import { FunctionComponent } from 'preact'
|
||||
import { Icon } from '@/Components/Icon'
|
||||
import { PLAIN_EDITOR_NAME } from '@/Constants'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -55,10 +51,8 @@ export const NotesListItem: FunctionComponent<Props> = ({
|
||||
const flags = flagsForNote(note)
|
||||
const showModifiedDate = sortedBy === CollectionSort.UpdatedAt
|
||||
const editorForNote = application.componentManager.editorForNote(note)
|
||||
const editorName = editorForNote?.name ?? 'Plain editor'
|
||||
const [icon, tint] = application.iconsController.getIconAndTintForEditor(
|
||||
editorForNote?.identifier,
|
||||
)
|
||||
const editorName = editorForNote?.name ?? PLAIN_EDITOR_NAME
|
||||
const [icon, tint] = application.iconsController.getIconAndTintForEditor(editorForNote?.identifier)
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -69,17 +63,11 @@ export const NotesListItem: FunctionComponent<Props> = ({
|
||||
>
|
||||
{!hideEditorIcon && (
|
||||
<div className="icon">
|
||||
<Icon
|
||||
ariaLabel={`Icon for ${editorName}`}
|
||||
type={icon}
|
||||
className={`color-accessory-tint-${tint}`}
|
||||
/>
|
||||
<Icon ariaLabel={`Icon for ${editorName}`} type={icon} className={`color-accessory-tint-${tint}`} />
|
||||
</div>
|
||||
)}
|
||||
<div className={`meta ${hideEditorIcon ? 'icon-hidden' : ''}`}>
|
||||
<div className="name-container">
|
||||
{note.title.length ? <div className="name">{note.title}</div> : null}
|
||||
</div>
|
||||
<div className="name-container">{note.title.length ? <div className="name">{note.title}</div> : null}</div>
|
||||
{!hidePreview && !note.hidePreview && !note.protected && (
|
||||
<div className="note-preview">
|
||||
{note.preview_html && (
|
||||
@@ -90,9 +78,7 @@ export const NotesListItem: FunctionComponent<Props> = ({
|
||||
}}
|
||||
></div>
|
||||
)}
|
||||
{!note.preview_html && note.preview_plain && (
|
||||
<div className="plain-preview">{note.preview_plain}</div>
|
||||
)}
|
||||
{!note.preview_html && note.preview_plain && <div className="plain-preview">{note.preview_plain}</div>}
|
||||
{!note.preview_html && !note.preview_plain && note.text && (
|
||||
<div className="default-preview">{note.text}</div>
|
||||
)}
|
||||
@@ -128,11 +114,7 @@ export const NotesListItem: FunctionComponent<Props> = ({
|
||||
<div className="flag-icons">
|
||||
{note.locked && (
|
||||
<span title="Editing Disabled">
|
||||
<Icon
|
||||
ariaLabel="Editing Disabled"
|
||||
type="pencil-off"
|
||||
className="sn-icon--small color-info"
|
||||
/>
|
||||
<Icon ariaLabel="Editing Disabled" type="pencil-off" className="sn-icon--small color-info" />
|
||||
</span>
|
||||
)}
|
||||
{note.trashed && (
|
||||
@@ -142,11 +124,7 @@ export const NotesListItem: FunctionComponent<Props> = ({
|
||||
)}
|
||||
{note.archived && (
|
||||
<span title="Archived">
|
||||
<Icon
|
||||
ariaLabel="Archived"
|
||||
type="archive"
|
||||
className="sn-icon--mid color-accessory-tint-3"
|
||||
/>
|
||||
<Icon ariaLabel="Archived" type="archive" className="sn-icon--mid color-accessory-tint-3" />
|
||||
</span>
|
||||
)}
|
||||
{note.pinned && (
|
||||
|
||||
@@ -31,10 +31,7 @@ export type EditorMenuItem = {
|
||||
|
||||
export type EditorMenuGroup = AccordionMenuGroup<EditorMenuItem>
|
||||
|
||||
export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
|
||||
application,
|
||||
note,
|
||||
}) => {
|
||||
export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({ application, note }) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const [menuStyle, setMenuStyle] = useState<SubmenuStyle>({
|
||||
@@ -90,7 +87,7 @@ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<Icon type="dashboard" className="color-neutral mr-2" />
|
||||
Change editor
|
||||
Change note type
|
||||
</div>
|
||||
<Icon type="chevron-right" className="color-neutral" />
|
||||
</DisclosureButton>
|
||||
|
||||
@@ -32,6 +32,8 @@ const DeletePermanentlyButton = ({ closeOnBlur, onClick }: DeletePermanentlyButt
|
||||
)
|
||||
|
||||
const iconClass = 'color-neutral mr-2'
|
||||
const iconClassDanger = 'color-danger mr-2'
|
||||
const iconClassWarning = 'color-warning mr-2'
|
||||
|
||||
const getWordCount = (text: string) => {
|
||||
if (text.trim().length === 0) {
|
||||
@@ -88,15 +90,9 @@ const NoteAttributes: FunctionComponent<{
|
||||
application: SNApplication
|
||||
note: SNNote
|
||||
}> = ({ application, note }) => {
|
||||
const { words, characters, paragraphs } = useMemo(
|
||||
() => countNoteAttributes(note.text),
|
||||
[note.text],
|
||||
)
|
||||
const { words, characters, paragraphs } = useMemo(() => countNoteAttributes(note.text), [note.text])
|
||||
|
||||
const readTime = useMemo(
|
||||
() => (typeof words === 'number' ? calculateReadTime(words) : 'N/A'),
|
||||
[words],
|
||||
)
|
||||
const readTime = useMemo(() => (typeof words === 'number' ? calculateReadTime(words) : 'N/A'), [words])
|
||||
|
||||
const dateLastModified = useMemo(() => formatDate(note.userModifiedDate), [note.userModifiedDate])
|
||||
|
||||
@@ -168,283 +164,276 @@ const NOTE_SIZE_WARNING_THRESHOLD = 0.5 * BYTES_IN_ONE_MEGABYTE
|
||||
|
||||
const NoteSizeWarning: FunctionComponent<{
|
||||
note: SNNote
|
||||
}> = ({ note }) =>
|
||||
(new Blob([note.text]).size > NOTE_SIZE_WARNING_THRESHOLD ? (
|
||||
}> = ({ note }) => {
|
||||
return new Blob([note.text]).size > NOTE_SIZE_WARNING_THRESHOLD ? (
|
||||
<div className="flex items-center px-3 py-3.5 relative bg-note-size-warning">
|
||||
<Icon type="warning" className="color-accessory-tint-3 flex-shrink-0 mr-3" />
|
||||
<div className="color-grey-0 select-none leading-140% max-w-80%">
|
||||
This note may have trouble syncing to the mobile application due to its size.
|
||||
</div>
|
||||
</div>
|
||||
) : null)
|
||||
) : null
|
||||
}
|
||||
|
||||
export const NotesOptions = observer(
|
||||
({ application, appState, closeOnBlur }: NotesOptionsProps) => {
|
||||
const [altKeyDown, setAltKeyDown] = useState(false)
|
||||
export const NotesOptions = observer(({ application, appState, closeOnBlur }: NotesOptionsProps) => {
|
||||
const [altKeyDown, setAltKeyDown] = useState(false)
|
||||
|
||||
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
||||
const notesMatchingAttribute = notes.filter(condition)
|
||||
const notesNotMatchingAttribute = notes.filter((note) => !condition(note))
|
||||
return notesMatchingAttribute.length > notesNotMatchingAttribute.length
|
||||
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
||||
const notesMatchingAttribute = notes.filter(condition)
|
||||
const notesNotMatchingAttribute = notes.filter((note) => !condition(note))
|
||||
return notesMatchingAttribute.length > notesNotMatchingAttribute.length
|
||||
}
|
||||
|
||||
const notes = Object.values(appState.notes.selectedNotes)
|
||||
const hidePreviews = toggleOn((note) => note.hidePreview)
|
||||
const locked = toggleOn((note) => note.locked)
|
||||
const protect = toggleOn((note) => note.protected)
|
||||
const archived = notes.some((note) => note.archived)
|
||||
const unarchived = notes.some((note) => !note.archived)
|
||||
const trashed = notes.some((note) => note.trashed)
|
||||
const notTrashed = notes.some((note) => !note.trashed)
|
||||
const pinned = notes.some((note) => note.pinned)
|
||||
const unpinned = notes.some((note) => !note.pinned)
|
||||
|
||||
useEffect(() => {
|
||||
const removeAltKeyObserver = application.io.addKeyObserver({
|
||||
modifiers: [KeyboardModifier.Alt],
|
||||
onKeyDown: () => {
|
||||
setAltKeyDown(true)
|
||||
},
|
||||
onKeyUp: () => {
|
||||
setAltKeyDown(false)
|
||||
},
|
||||
})
|
||||
|
||||
return () => {
|
||||
removeAltKeyObserver()
|
||||
}
|
||||
}, [application])
|
||||
|
||||
const getNoteFileName = (note: SNNote): string => {
|
||||
const editor = application.componentManager.editorForNote(note)
|
||||
const format = editor?.package_info?.file_type || 'txt'
|
||||
return `${note.title}.${format}`
|
||||
}
|
||||
|
||||
const downloadSelectedItems = async () => {
|
||||
if (notes.length === 1) {
|
||||
application.getArchiveService().downloadData(new Blob([notes[0].text]), getNoteFileName(notes[0]))
|
||||
return
|
||||
}
|
||||
|
||||
const notes = Object.values(appState.notes.selectedNotes)
|
||||
const hidePreviews = toggleOn((note) => note.hidePreview)
|
||||
const locked = toggleOn((note) => note.locked)
|
||||
const protect = toggleOn((note) => note.protected)
|
||||
const archived = notes.some((note) => note.archived)
|
||||
const unarchived = notes.some((note) => !note.archived)
|
||||
const trashed = notes.some((note) => note.trashed)
|
||||
const notTrashed = notes.some((note) => !note.trashed)
|
||||
const pinned = notes.some((note) => note.pinned)
|
||||
const unpinned = notes.some((note) => !note.pinned)
|
||||
|
||||
useEffect(() => {
|
||||
const removeAltKeyObserver = application.io.addKeyObserver({
|
||||
modifiers: [KeyboardModifier.Alt],
|
||||
onKeyDown: () => {
|
||||
setAltKeyDown(true)
|
||||
},
|
||||
onKeyUp: () => {
|
||||
setAltKeyDown(false)
|
||||
},
|
||||
if (notes.length > 1) {
|
||||
const loadingToastId = addToast({
|
||||
type: ToastType.Loading,
|
||||
message: `Exporting ${notes.length} notes...`,
|
||||
})
|
||||
|
||||
return () => {
|
||||
removeAltKeyObserver()
|
||||
}
|
||||
}, [application])
|
||||
|
||||
const getNoteFileName = (note: SNNote): string => {
|
||||
const editor = application.componentManager.editorForNote(note)
|
||||
const format = editor?.package_info?.file_type || 'txt'
|
||||
return `${note.title}.${format}`
|
||||
}
|
||||
|
||||
const downloadSelectedItems = async () => {
|
||||
if (notes.length === 1) {
|
||||
application
|
||||
.getArchiveService()
|
||||
.downloadData(new Blob([notes[0].text]), getNoteFileName(notes[0]))
|
||||
return
|
||||
}
|
||||
|
||||
if (notes.length > 1) {
|
||||
const loadingToastId = addToast({
|
||||
type: ToastType.Loading,
|
||||
message: `Exporting ${notes.length} notes...`,
|
||||
})
|
||||
await application.getArchiveService().downloadDataAsZip(
|
||||
notes.map((note) => {
|
||||
return {
|
||||
filename: getNoteFileName(note),
|
||||
content: new Blob([note.text]),
|
||||
}
|
||||
}),
|
||||
)
|
||||
dismissToast(loadingToastId)
|
||||
addToast({
|
||||
type: ToastType.Success,
|
||||
message: `Exported ${notes.length} notes`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const duplicateSelectedItems = () => {
|
||||
notes.forEach((note) => {
|
||||
application.mutator.duplicateItem(note).catch(console.error)
|
||||
await application.getArchiveService().downloadDataAsZip(
|
||||
notes.map((note) => {
|
||||
return {
|
||||
filename: getNoteFileName(note),
|
||||
content: new Blob([note.text]),
|
||||
}
|
||||
}),
|
||||
)
|
||||
dismissToast(loadingToastId)
|
||||
addToast({
|
||||
type: ToastType.Success,
|
||||
message: `Exported ${notes.length} notes`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const openRevisionHistoryModal = () => {
|
||||
appState.notes.setShowRevisionHistoryModal(true)
|
||||
}
|
||||
const duplicateSelectedItems = () => {
|
||||
notes.forEach((note) => {
|
||||
application.mutator.duplicateItem(note).catch(console.error)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{notes.length === 1 && (
|
||||
<>
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={openRevisionHistoryModal}
|
||||
>
|
||||
<Icon type="history" className={iconClass} />
|
||||
Note history
|
||||
</button>
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
</>
|
||||
)}
|
||||
const openRevisionHistoryModal = () => {
|
||||
appState.notes.setShowRevisionHistoryModal(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{notes.length === 1 && (
|
||||
<>
|
||||
<button onBlur={closeOnBlur} className="sn-dropdown-item" onClick={openRevisionHistoryModal}>
|
||||
<Icon type="history" className={iconClass} />
|
||||
Note history
|
||||
</button>
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
</>
|
||||
)}
|
||||
<button
|
||||
className="sn-dropdown-item justify-between"
|
||||
onClick={() => {
|
||||
appState.notes.setLockSelectedNotes(!locked)
|
||||
}}
|
||||
onBlur={closeOnBlur}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<Icon type="pencil-off" className={iconClass} />
|
||||
Prevent editing
|
||||
</span>
|
||||
<Switch className="px-0" checked={locked} />
|
||||
</button>
|
||||
<button
|
||||
className="sn-dropdown-item justify-between"
|
||||
onClick={() => {
|
||||
appState.notes.setHideSelectedNotePreviews(!hidePreviews)
|
||||
}}
|
||||
onBlur={closeOnBlur}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<Icon type="rich-text" className={iconClass} />
|
||||
Show preview
|
||||
</span>
|
||||
<Switch className="px-0" checked={!hidePreviews} />
|
||||
</button>
|
||||
<button
|
||||
className="sn-dropdown-item justify-between"
|
||||
onClick={() => {
|
||||
appState.notes.setProtectSelectedNotes(!protect).catch(console.error)
|
||||
}}
|
||||
onBlur={closeOnBlur}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<Icon type="password" className={iconClass} />
|
||||
Password protect
|
||||
</span>
|
||||
<Switch className="px-0" checked={protect} />
|
||||
</button>
|
||||
{notes.length === 1 && (
|
||||
<>
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<ChangeEditorOption appState={appState} application={application} note={notes[0]} />
|
||||
</>
|
||||
)}
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
{appState.tags.tagsCount > 0 && <AddTagOption appState={appState} />}
|
||||
{unpinned && (
|
||||
<button
|
||||
className="sn-dropdown-item justify-between"
|
||||
onClick={() => {
|
||||
appState.notes.setLockSelectedNotes(!locked)
|
||||
}}
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
appState.notes.setPinSelectedNotes(true)
|
||||
}}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<Icon type="pencil-off" className={iconClass} />
|
||||
Prevent editing
|
||||
</span>
|
||||
<Switch className="px-0" checked={locked} />
|
||||
<Icon type="pin" className={iconClass} />
|
||||
Pin to top
|
||||
</button>
|
||||
)}
|
||||
{pinned && (
|
||||
<button
|
||||
className="sn-dropdown-item justify-between"
|
||||
onClick={() => {
|
||||
appState.notes.setHideSelectedNotePreviews(!hidePreviews)
|
||||
}}
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
appState.notes.setPinSelectedNotes(false)
|
||||
}}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<Icon type="rich-text" className={iconClass} />
|
||||
Show preview
|
||||
</span>
|
||||
<Switch className="px-0" checked={!hidePreviews} />
|
||||
<Icon type="unpin" className={iconClass} />
|
||||
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
|
||||
className="sn-dropdown-item justify-between"
|
||||
onClick={() => {
|
||||
appState.notes.setProtectSelectedNotes(!protect).catch(console.error)
|
||||
}}
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
appState.notes.setArchiveSelectedNotes(true).catch(console.error)
|
||||
}}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<Icon type="password" className={iconClass} />
|
||||
Protect
|
||||
</span>
|
||||
<Switch className="px-0" checked={protect} />
|
||||
<Icon type="archive" className={iconClassWarning} />
|
||||
<span className="color-warning">Archive</span>
|
||||
</button>
|
||||
{notes.length === 1 && (
|
||||
<>
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<ChangeEditorOption appState={appState} application={application} note={notes[0]} />
|
||||
</>
|
||||
)}
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
{appState.tags.tagsCount > 0 && <AddTagOption appState={appState} />}
|
||||
{unpinned && (
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
appState.notes.setPinSelectedNotes(true)
|
||||
}}
|
||||
>
|
||||
<Icon type="pin" className={iconClass} />
|
||||
Pin to top
|
||||
</button>
|
||||
)}
|
||||
{pinned && (
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
appState.notes.setPinSelectedNotes(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="unpin" className={iconClass} />
|
||||
Unpin
|
||||
</button>
|
||||
)}
|
||||
<button onBlur={closeOnBlur} className="sn-dropdown-item" onClick={downloadSelectedItems}>
|
||||
<Icon type="download" className={iconClass} />
|
||||
Export
|
||||
)}
|
||||
{archived && (
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
appState.notes.setArchiveSelectedNotes(false).catch(console.error)
|
||||
}}
|
||||
>
|
||||
<Icon type="unarchive" className={iconClassWarning} />
|
||||
<span className="color-warning">Unarchive</span>
|
||||
</button>
|
||||
<button onBlur={closeOnBlur} className="sn-dropdown-item" onClick={duplicateSelectedItems}>
|
||||
<Icon type="copy" className={iconClass} />
|
||||
Duplicate
|
||||
</button>
|
||||
{unarchived && (
|
||||
)}
|
||||
{notTrashed &&
|
||||
(altKeyDown ? (
|
||||
<DeletePermanentlyButton
|
||||
closeOnBlur={closeOnBlur}
|
||||
onClick={async () => {
|
||||
await appState.notes.deleteNotesPermanently()
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
appState.notes.setArchiveSelectedNotes(true).catch(console.error)
|
||||
onClick={async () => {
|
||||
await appState.notes.setTrashSelectedNotes(true)
|
||||
}}
|
||||
>
|
||||
<Icon type="archive" className={iconClass} />
|
||||
Archive
|
||||
<Icon type="trash" className={iconClassDanger} />
|
||||
<span className="color-danger">Move to trash</span>
|
||||
</button>
|
||||
)}
|
||||
{archived && (
|
||||
))}
|
||||
{trashed && (
|
||||
<>
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
appState.notes.setArchiveSelectedNotes(false).catch(console.error)
|
||||
onClick={async () => {
|
||||
await appState.notes.setTrashSelectedNotes(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="unarchive" className={iconClass} />
|
||||
Unarchive
|
||||
<Icon type="restore" className={iconClass} />
|
||||
Restore
|
||||
</button>
|
||||
)}
|
||||
{notTrashed &&
|
||||
(altKeyDown ? (
|
||||
<DeletePermanentlyButton
|
||||
closeOnBlur={closeOnBlur}
|
||||
onClick={async () => {
|
||||
await appState.notes.deleteNotesPermanently()
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={async () => {
|
||||
await appState.notes.setTrashSelectedNotes(true)
|
||||
}}
|
||||
>
|
||||
<Icon type="trash" className={iconClass} />
|
||||
Move to trash
|
||||
</button>
|
||||
))}
|
||||
{trashed && (
|
||||
<>
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={async () => {
|
||||
await appState.notes.setTrashSelectedNotes(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="restore" className={iconClass} />
|
||||
Restore
|
||||
</button>
|
||||
<DeletePermanentlyButton
|
||||
closeOnBlur={closeOnBlur}
|
||||
onClick={async () => {
|
||||
await appState.notes.deleteNotesPermanently()
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={async () => {
|
||||
await appState.notes.emptyTrash()
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start">
|
||||
<Icon type="trash-sweep" className="color-danger mr-2" />
|
||||
<div className="flex-row">
|
||||
<div className="color-danger">Empty Trash</div>
|
||||
<div className="text-xs">{appState.notes.trashedNotesCount} notes in Trash</div>
|
||||
</div>
|
||||
<DeletePermanentlyButton
|
||||
closeOnBlur={closeOnBlur}
|
||||
onClick={async () => {
|
||||
await appState.notes.deleteNotesPermanently()
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={async () => {
|
||||
await appState.notes.emptyTrash()
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start">
|
||||
<Icon type="trash-sweep" className="color-danger mr-2" />
|
||||
<div className="flex-row">
|
||||
<div className="color-danger">Empty Trash</div>
|
||||
<div className="text-xs">{appState.notes.trashedNotesCount} notes in Trash</div>
|
||||
</div>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{notes.length === 1 ? (
|
||||
<>
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<ListedActionsOption application={application} note={notes[0]} />
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<SpellcheckOptions appState={appState} note={notes[0]} />
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<NoteAttributes application={application} note={notes[0]} />
|
||||
<NoteSizeWarning note={notes[0]} />
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
},
|
||||
)
|
||||
</div>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{notes.length === 1 ? (
|
||||
<>
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<ListedActionsOption application={application} note={notes[0]} />
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<SpellcheckOptions appState={appState} note={notes[0]} />
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<NoteAttributes application={application} note={notes[0]} />
|
||||
<NoteSizeWarning note={notes[0]} />
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
import { Dropdown, DropdownItem } from '@/Components/Dropdown'
|
||||
import {
|
||||
FeatureIdentifier,
|
||||
PrefKey,
|
||||
ComponentArea,
|
||||
ComponentMutator,
|
||||
SNComponent,
|
||||
} from '@standardnotes/snjs'
|
||||
import { FeatureIdentifier, PrefKey, ComponentArea, ComponentMutator, SNComponent } from '@standardnotes/snjs'
|
||||
import {
|
||||
PreferencesGroup,
|
||||
PreferencesSegment,
|
||||
@@ -18,6 +12,7 @@ import { FunctionComponent } from 'preact'
|
||||
import { useEffect, useState } from 'preact/hooks'
|
||||
import { HorizontalSeparator } from '@/Components/Shared/HorizontalSeparator'
|
||||
import { Switch } from '@/Components/Switch'
|
||||
import { PLAIN_EDITOR_NAME } from '@/Constants'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -27,11 +22,7 @@ type EditorOption = DropdownItem & {
|
||||
value: FeatureIdentifier | 'plain-editor'
|
||||
}
|
||||
|
||||
const makeEditorDefault = (
|
||||
application: WebApplication,
|
||||
component: SNComponent,
|
||||
currentDefault: SNComponent,
|
||||
) => {
|
||||
const makeEditorDefault = (application: WebApplication, component: SNComponent, currentDefault: SNComponent) => {
|
||||
if (currentDefault) {
|
||||
removeEditorDefault(application, currentDefault)
|
||||
}
|
||||
@@ -53,9 +44,7 @@ const removeEditorDefault = (application: WebApplication, component: SNComponent
|
||||
}
|
||||
|
||||
const getDefaultEditor = (application: WebApplication) => {
|
||||
return application.componentManager
|
||||
.componentsForArea(ComponentArea.Editor)
|
||||
.filter((e) => e.isDefaultEditor())[0]
|
||||
return application.componentManager.componentsForArea(ComponentArea.Editor).filter((e) => e.isDefaultEditor())[0]
|
||||
}
|
||||
|
||||
export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
@@ -64,9 +53,7 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
() => getDefaultEditor(application)?.package_info?.identifier || 'plain-editor',
|
||||
)
|
||||
|
||||
const [spellcheck, setSpellcheck] = useState(() =>
|
||||
application.getPreference(PrefKey.EditorSpellcheck, true),
|
||||
)
|
||||
const [spellcheck, setSpellcheck] = useState(() => application.getPreference(PrefKey.EditorSpellcheck, true))
|
||||
|
||||
const [addNoteToParentFolders, setAddNoteToParentFolders] = useState(() =>
|
||||
application.getPreference(PrefKey.NoteAddToParentFolders, true),
|
||||
@@ -95,7 +82,7 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
{
|
||||
icon: 'plain-text',
|
||||
iconClassName: 'color-accessory-tint-1',
|
||||
label: 'Plain Editor',
|
||||
label: PLAIN_EDITOR_NAME,
|
||||
value: 'plain-editor',
|
||||
},
|
||||
])
|
||||
@@ -124,12 +111,12 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
<PreferencesSegment>
|
||||
<Title>Defaults</Title>
|
||||
<div>
|
||||
<Subtitle>Default Editor</Subtitle>
|
||||
<Text>New notes will be created using this editor.</Text>
|
||||
<Subtitle>Default Note Type</Subtitle>
|
||||
<Text>New notes will be created using this type.</Text>
|
||||
<div className="mt-2">
|
||||
<Dropdown
|
||||
id="def-editor-dropdown"
|
||||
label="Select the default editor"
|
||||
label="Select the default note type"
|
||||
items={editorItems}
|
||||
value={defaultEditorValue}
|
||||
onChange={setDefaultEditor}
|
||||
@@ -141,9 +128,8 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Spellcheck</Subtitle>
|
||||
<Text>
|
||||
The default spellcheck value for new notes. Spellcheck can be configured per note from
|
||||
the note context menu. Spellcheck may degrade overall typing performance with long
|
||||
notes.
|
||||
The default spellcheck value for new notes. Spellcheck can be configured per note from the note context
|
||||
menu. Spellcheck may degrade overall typing performance with long notes.
|
||||
</Text>
|
||||
</div>
|
||||
<Switch onChange={toggleSpellcheck} checked={spellcheck} />
|
||||
@@ -152,16 +138,11 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Add all parent tags when adding a nested tag to a note</Subtitle>
|
||||
<Text>
|
||||
When enabled, adding a nested tag to a note will automatically add all associated
|
||||
parent tags.
|
||||
</Text>
|
||||
<Text>When enabled, adding a nested tag to a note will automatically add all associated parent tags.</Text>
|
||||
</div>
|
||||
<Switch
|
||||
onChange={() => {
|
||||
application
|
||||
.setPreference(PrefKey.NoteAddToParentFolders, !addNoteToParentFolders)
|
||||
.catch(console.error)
|
||||
application.setPreference(PrefKey.NoteAddToParentFolders, !addNoteToParentFolders).catch(console.error)
|
||||
setAddNoteToParentFolders(!addNoteToParentFolders)
|
||||
}}
|
||||
checked={addNoteToParentFolders}
|
||||
|
||||
@@ -20,3 +20,5 @@ export const BYTES_IN_ONE_MEGABYTE = 1_000_000
|
||||
export const TAG_FOLDERS_FEATURE_NAME = 'Tag folders'
|
||||
export const TAG_FOLDERS_FEATURE_TOOLTIP = 'A Plus or Pro plan is required to enable Tag folders.'
|
||||
export const SMART_TAGS_FEATURE_NAME = 'Smart Tags'
|
||||
|
||||
export const PLAIN_EDITOR_NAME = 'Plain Text'
|
||||
|
||||
@@ -69,10 +69,10 @@
|
||||
"@reach/listbox": "^0.16.2",
|
||||
"@reach/tooltip": "^0.16.2",
|
||||
"@reach/visually-hidden": "^0.16.0",
|
||||
"@standardnotes/components": "1.7.15",
|
||||
"@standardnotes/components": "1.8.0",
|
||||
"@standardnotes/filepicker": "1.13.4",
|
||||
"@standardnotes/sncrypto-web": "1.9.0",
|
||||
"@standardnotes/snjs": "2.105.3",
|
||||
"@standardnotes/snjs": "2.106.0",
|
||||
"@standardnotes/stylekit": "5.25.0",
|
||||
"@zip.js/zip.js": "^2.4.10",
|
||||
"mobx": "^6.5.0",
|
||||
|
||||
110
yarn.lock
110
yarn.lock
@@ -2437,10 +2437,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.19.6.tgz#6c672f4f10d5ed123a2c392dfb35dbe3c698b3b9"
|
||||
integrity sha512-HxPrV9JhLp//S7h+QjOjlMPy0lgrjLT4iBKzr8JG8lUeWSS1mY3p1I+w0D9+yiraS2SPq2L14Z0VKds0zs9HXw==
|
||||
|
||||
"@standardnotes/components@1.7.15":
|
||||
version "1.7.15"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/components/-/components-1.7.15.tgz#3d57dd21cd4bf1f95eea7521fce7dd62e8f99455"
|
||||
integrity sha512-fZOaqi62BDhVkqH6Bd9NQhVPyPR3KARob8xm/JhMLWt1d8G1ZFEQ/IOLTMFpYQCt9IroLG/pl6GD0Xj46ISgkw==
|
||||
"@standardnotes/components@1.8.0":
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/components/-/components-1.8.0.tgz#eaeadd6c0eb36c034cd2c9d6b625f463a0188482"
|
||||
integrity sha512-mgbekII0aMVkVuNZNXspLUoTP/fTf74Mz6ic91/8ca7S/e/4TcFg9OgTBV5Fqy/ShA42fhHEfJUG4QgRR+KdOw==
|
||||
|
||||
"@standardnotes/config@^2.4.1":
|
||||
version "2.4.1"
|
||||
@@ -2450,27 +2450,27 @@
|
||||
"@typescript-eslint/eslint-plugin" "^5.12.1"
|
||||
"@typescript-eslint/parser" "^5.12.1"
|
||||
|
||||
"@standardnotes/domain-events@^2.27.13":
|
||||
version "2.27.13"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.27.13.tgz#ebe9d06b154fa8f40cbda6e4da507856f052f8d0"
|
||||
integrity sha512-Cc+bDNtHFqLnNyr3freB9DmGWDVl1zrWPHHaEahfQyA8RnBkGrQ28xz5+0Q5lKLTsBjGppi7Py/VPD+QMvdNmg==
|
||||
"@standardnotes/domain-events@^2.27.14":
|
||||
version "2.27.14"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.27.14.tgz#3d3829f51d4d88b8c64a260b719e6edbc3bfb5f3"
|
||||
integrity sha512-AsuNYvYs9L6Ib+FpLpp86OpP0p9wB0LNfwtJm4aXJtbHxi63vRO7xLZvfiFrGr9Fj8OB6aSZ6lH0TpUSk18H7w==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.18.11"
|
||||
"@standardnotes/features" "^1.39.0"
|
||||
"@standardnotes/features" "^1.40.0"
|
||||
|
||||
"@standardnotes/encryption@^1.6.1":
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/encryption/-/encryption-1.6.1.tgz#51d1d69a1c45e95d5486adfa624af4766fbb94a8"
|
||||
integrity sha512-qKg5An1ZHY+gDHb96T8zEIQl5TcRaZNPeCP2zULQBEyLzhFDlyoz8MMRiZPa6yjiCDEODfwG87gQwlaFGkFR3Q==
|
||||
"@standardnotes/encryption@^1.6.2":
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/encryption/-/encryption-1.6.2.tgz#936a1cc7c80fff06b4d960afb9e954569ef953ff"
|
||||
integrity sha512-KqM3ht58VDjQzNAlStFhUquURAHWZs3HH2agQFRGJZZop0KPQqzgs6LIXRgw0Yyo8MrnMreMobRxuINWj8ddGQ==
|
||||
dependencies:
|
||||
"@standardnotes/models" "^1.6.2"
|
||||
"@standardnotes/responses" "^1.6.13"
|
||||
"@standardnotes/services" "^1.10.1"
|
||||
"@standardnotes/models" "^1.6.3"
|
||||
"@standardnotes/responses" "^1.6.14"
|
||||
"@standardnotes/services" "^1.10.2"
|
||||
|
||||
"@standardnotes/features@^1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.39.0.tgz#d2234eec2664fbe8fc3946e2349d6d2c7348c2f1"
|
||||
integrity sha512-r5vuJoDsi6W/ZomOYMMe0DC3YJLbhYDn9NkYglsi0/F5aQUciIg9hLUb0aRrQm/q9zQ5+zEJ8ukN6f5sJGYYcw==
|
||||
"@standardnotes/features@^1.40.0":
|
||||
version "1.40.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.40.0.tgz#362f9656b6125cab61752d038981d67f12689fb6"
|
||||
integrity sha512-3C/fj7/HQ6S3HZJujB92QW6ydc0oOaCrUPtYkCMHnjBV0qpGDtpzbR3GLYqmHpmiM5H87s9BppEQleiMu1+dyA==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.18.11"
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
@@ -2483,43 +2483,43 @@
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
"@standardnotes/utils" "^1.6.3"
|
||||
|
||||
"@standardnotes/files@^1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/files/-/files-1.0.5.tgz#ed293082167555ca89ce1c2a879eb7307064db61"
|
||||
integrity sha512-ACsl9emP7S9OpCC8FcGZZxdxGJjMjZ3wvshevsjHqGtKcKQX/2/xU8FcUNg05VzvGMicV8Smekp+/6BvcNpjEA==
|
||||
"@standardnotes/files@^1.0.6":
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/files/-/files-1.0.6.tgz#6fafd7114a014c32c320ecc328f1bfdf9f8856f1"
|
||||
integrity sha512-8/+bLEQP91JQKEh0du8lRRIuHV+jB62s+jTcK+nuyFkg72JR7Qgeu+tUpV3O3vassj9ZaZhO5s1+pgOiJU+QCg==
|
||||
dependencies:
|
||||
"@standardnotes/models" "^1.6.2"
|
||||
"@standardnotes/responses" "^1.6.13"
|
||||
"@standardnotes/services" "^1.10.1"
|
||||
"@standardnotes/models" "^1.6.3"
|
||||
"@standardnotes/responses" "^1.6.14"
|
||||
"@standardnotes/services" "^1.10.2"
|
||||
"@standardnotes/utils" "^1.6.3"
|
||||
|
||||
"@standardnotes/models@^1.6.2":
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/models/-/models-1.6.2.tgz#45ae19246ba1ac476ed26bbe3f9fa6e3ce6c9271"
|
||||
integrity sha512-WJtlDi2tj+HkG10VQygFbzUfon76N7gV73wuryocJ1LE5LiJT7O+LlQvrVM96QWxDdbjUXxA4fz++W0v4c6m7w==
|
||||
"@standardnotes/models@^1.6.3":
|
||||
version "1.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/models/-/models-1.6.3.tgz#d3d344cc877fd484f87171a3465d732f15f49199"
|
||||
integrity sha512-qmOJsxgpov+VTzhJYc9uqTDP1+JvtFXjJSkhiHiA4E/ZRrejxvTl6iPu6ZF5gVHWf+93KsGhw449pc/kjj/5bA==
|
||||
dependencies:
|
||||
"@standardnotes/features" "^1.39.0"
|
||||
"@standardnotes/responses" "^1.6.13"
|
||||
"@standardnotes/features" "^1.40.0"
|
||||
"@standardnotes/responses" "^1.6.14"
|
||||
"@standardnotes/utils" "^1.6.3"
|
||||
|
||||
"@standardnotes/responses@^1.6.13":
|
||||
version "1.6.13"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.6.13.tgz#aac7da9c9f158150d23e41238eade5fa6fe98b76"
|
||||
integrity sha512-ponGQwqcZlt/5h8QzXnG5gJLiLG7uq6cYmsyQKVigLSSllv4eN/I7WLp1HWdZGcPPyh/+HCYk5z6YgSJM2Rulg==
|
||||
"@standardnotes/responses@^1.6.14":
|
||||
version "1.6.14"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.6.14.tgz#5c9cc1b2dbf36c335350c31c4dc5ef2a971365e3"
|
||||
integrity sha512-iEPt0iaYyb1SjicAaKbH3jHgrExDz3R9fzCUlB0wh61B35g/8czi0thSzTmJI2DP3/hMqWOIUDj1M1piN+Rqog==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.18.11"
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
"@standardnotes/features" "^1.39.0"
|
||||
"@standardnotes/features" "^1.40.0"
|
||||
|
||||
"@standardnotes/services@^1.10.1":
|
||||
version "1.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.10.1.tgz#ef166ead223d91b7124b9e0f134ae46e4479159c"
|
||||
integrity sha512-Q55OMJXJS/HZpQ5Iwl20u3594kkE7VF9M/yap0H9kFQJcKlyYlsSF1W7QdyFCx5keHT0JLRzjY88muBcb9o9fA==
|
||||
"@standardnotes/services@^1.10.2":
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.10.2.tgz#b21ac3596b1b9ea326dc7e99b0ac01e487c0a0db"
|
||||
integrity sha512-LGDa9OMjhSB/nu6uAIo7qG6D0cZ9jg/3dZzspBFx8Jz/eE/ZgjufNXm6iwu5FxhMtybLOw2fUkSCmA8mdCBNkA==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.18.11"
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
"@standardnotes/models" "^1.6.2"
|
||||
"@standardnotes/responses" "^1.6.13"
|
||||
"@standardnotes/models" "^1.6.3"
|
||||
"@standardnotes/responses" "^1.6.14"
|
||||
"@standardnotes/utils" "^1.6.3"
|
||||
|
||||
"@standardnotes/settings@^1.14.1":
|
||||
@@ -2541,21 +2541,21 @@
|
||||
buffer "^6.0.3"
|
||||
libsodium-wrappers "^0.7.9"
|
||||
|
||||
"@standardnotes/snjs@2.105.3":
|
||||
version "2.105.3"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.105.3.tgz#4eebce30c8cc6469ba6aada28ceb9825b47827c5"
|
||||
integrity sha512-dYzGCbljJ6x88+kJX2iMS+8hyKGSvLljJqlmeWYVnoVPs9ZR2CkfZfjugaVkNIMS9mteuAO36t0YUyhQA6yBPQ==
|
||||
"@standardnotes/snjs@2.106.0":
|
||||
version "2.106.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.106.0.tgz#2eecf2e1bfcbcd913ed993346c140fd857d93645"
|
||||
integrity sha512-EB1FXqVfe2f/Bgcl8xzi18wWkq9RWVxVDJVNJqYorALEY0yR/3ERjA8ZcV5trY4l0oLiG55rzYYTlgqDHj99/g==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.18.11"
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
"@standardnotes/domain-events" "^2.27.13"
|
||||
"@standardnotes/encryption" "^1.6.1"
|
||||
"@standardnotes/features" "^1.39.0"
|
||||
"@standardnotes/domain-events" "^2.27.14"
|
||||
"@standardnotes/encryption" "^1.6.2"
|
||||
"@standardnotes/features" "^1.40.0"
|
||||
"@standardnotes/filepicker" "^1.13.4"
|
||||
"@standardnotes/files" "^1.0.5"
|
||||
"@standardnotes/models" "^1.6.2"
|
||||
"@standardnotes/responses" "^1.6.13"
|
||||
"@standardnotes/services" "^1.10.1"
|
||||
"@standardnotes/files" "^1.0.6"
|
||||
"@standardnotes/models" "^1.6.3"
|
||||
"@standardnotes/responses" "^1.6.14"
|
||||
"@standardnotes/services" "^1.10.2"
|
||||
"@standardnotes/settings" "^1.14.1"
|
||||
"@standardnotes/sncrypto-common" "^1.8.0"
|
||||
"@standardnotes/utils" "^1.6.3"
|
||||
|
||||
Reference in New Issue
Block a user