Revert "feat: New notes list design (#780)"
This reverts commit 7dd4a60595.
This commit is contained in:
@@ -13,7 +13,6 @@ import { useState } from 'preact/hooks';
|
||||
|
||||
export type DropdownItem = {
|
||||
icon?: IconType;
|
||||
iconClassName?: string;
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
@@ -26,7 +25,10 @@ type DropdownProps = {
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
type ListboxButtonProps = DropdownItem & {
|
||||
type ListboxButtonProps = {
|
||||
icon?: IconType;
|
||||
value: string | null;
|
||||
label: string;
|
||||
isExpanded: boolean;
|
||||
};
|
||||
|
||||
@@ -34,13 +36,12 @@ const CustomDropdownButton: FunctionComponent<ListboxButtonProps> = ({
|
||||
label,
|
||||
isExpanded,
|
||||
icon,
|
||||
iconClassName = '',
|
||||
}) => (
|
||||
<>
|
||||
<div className="sn-dropdown-button-label">
|
||||
{icon ? (
|
||||
<div className="flex mr-2">
|
||||
<Icon type={icon} className={`sn-icon--small ${iconClassName}`} />
|
||||
<Icon type={icon} className="sn-icon--small" />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="dropdown-selected-label">{label}</div>
|
||||
@@ -84,13 +85,11 @@ export const Dropdown: FunctionComponent<DropdownProps> = ({
|
||||
children={({ value, label, isExpanded }) => {
|
||||
const current = items.find((item) => item.value === value);
|
||||
const icon = current ? current?.icon : null;
|
||||
const iconClassName = current ? current?.iconClassName : null;
|
||||
return CustomDropdownButton({
|
||||
value: value ? value : label.toLowerCase(),
|
||||
value,
|
||||
label,
|
||||
isExpanded,
|
||||
...(icon ? { icon } : null),
|
||||
...(iconClassName ? { iconClassName } : null),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -105,10 +104,7 @@ export const Dropdown: FunctionComponent<DropdownProps> = ({
|
||||
>
|
||||
{item.icon ? (
|
||||
<div className="flex mr-3">
|
||||
<Icon
|
||||
type={item.icon}
|
||||
className={`sn-icon--small ${item.iconClassName ?? ''}`}
|
||||
/>
|
||||
<Icon type={item.icon} className="sn-icon--small" />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="text-input">{item.label}</div>
|
||||
|
||||
@@ -3,9 +3,7 @@ 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 TrashFilledIcon from '../../icons/ic-trash-filled.svg';
|
||||
import PinIcon from '../../icons/ic-pin.svg';
|
||||
import PinFilledIcon from '../../icons/ic-pin-filled.svg';
|
||||
import UnpinIcon from '../../icons/ic-pin-off.svg';
|
||||
import ArchiveIcon from '../../icons/ic-archive.svg';
|
||||
import UnarchiveIcon from '../../icons/ic-unarchive.svg';
|
||||
@@ -54,7 +52,6 @@ import ServerIcon from '../../icons/ic-server.svg';
|
||||
import EyeIcon from '../../icons/ic-eye.svg';
|
||||
import EyeOffIcon from '../../icons/ic-eye-off.svg';
|
||||
import LockIcon from '../../icons/ic-lock.svg';
|
||||
import LockFilledIcon from '../../icons/ic-lock-filled.svg';
|
||||
import ArrowsSortUpIcon from '../../icons/ic-arrows-sort-up.svg';
|
||||
import ArrowsSortDownIcon from '../../icons/ic-arrows-sort-down.svg';
|
||||
import WindowIcon from '../../icons/ic-window.svg';
|
||||
@@ -72,7 +69,6 @@ const ICONS = {
|
||||
'arrows-sort-up': ArrowsSortUpIcon,
|
||||
'arrows-sort-down': ArrowsSortDownIcon,
|
||||
lock: LockIcon,
|
||||
'lock-filled': LockFilledIcon,
|
||||
eye: EyeIcon,
|
||||
'eye-off': EyeOffIcon,
|
||||
server: ServerIcon,
|
||||
@@ -93,9 +89,7 @@ const ICONS = {
|
||||
spreadsheets: SpreadsheetsIcon,
|
||||
tasks: TasksIcon,
|
||||
trash: TrashIcon,
|
||||
'trash-filled': TrashFilledIcon,
|
||||
pin: PinIcon,
|
||||
'pin-filled': PinFilledIcon,
|
||||
unpin: UnpinIcon,
|
||||
archive: ArchiveIcon,
|
||||
unarchive: UnarchiveIcon,
|
||||
@@ -136,22 +130,11 @@ export type IconType = keyof typeof ICONS;
|
||||
type Props = {
|
||||
type: IconType;
|
||||
className?: string;
|
||||
ariaLabel?: string;
|
||||
};
|
||||
|
||||
export const Icon: FunctionalComponent<Props> = ({
|
||||
type,
|
||||
className = '',
|
||||
ariaLabel,
|
||||
}) => {
|
||||
export const Icon: FunctionalComponent<Props> = ({ type, className = '' }) => {
|
||||
const IconComponent = ICONS[type];
|
||||
return (
|
||||
<IconComponent
|
||||
className={`sn-icon ${className}`}
|
||||
role="img"
|
||||
{...(ariaLabel ? { 'aria-label': ariaLabel } : {})}
|
||||
/>
|
||||
);
|
||||
return <IconComponent className={`sn-icon ${className}`} />;
|
||||
};
|
||||
|
||||
export const IconDirective = toDirective<Props>(Icon, {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { KeyboardKey } from '@/services/ioService';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { DisplayOptions } from '@/ui_models/app_state/notes_view_state';
|
||||
@@ -8,7 +7,6 @@ import { FunctionComponent } from 'preact';
|
||||
import { NotesListItem } from './NotesListItem';
|
||||
|
||||
type Props = {
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
notes: SNNote[];
|
||||
selectedNotes: Record<string, SNNote>;
|
||||
@@ -20,30 +18,23 @@ const FOCUSABLE_BUT_NOT_TABBABLE = -1;
|
||||
const NOTES_LIST_SCROLL_THRESHOLD = 200;
|
||||
|
||||
export const NotesList: FunctionComponent<Props> = observer(
|
||||
({
|
||||
application,
|
||||
appState,
|
||||
notes,
|
||||
selectedNotes,
|
||||
displayOptions,
|
||||
paginate,
|
||||
}) => {
|
||||
({ appState, notes, selectedNotes, displayOptions, paginate }) => {
|
||||
const { selectPreviousNote, selectNextNote } = appState.notesView;
|
||||
const { hideTags, hideDate, hideNotePreview, sortBy } = displayOptions;
|
||||
|
||||
const tagsForNote = (note: SNNote): string[] => {
|
||||
const tagsStringForNote = (note: SNNote): string => {
|
||||
if (hideTags) {
|
||||
return [];
|
||||
return '';
|
||||
}
|
||||
const selectedTag = appState.selectedTag;
|
||||
if (!selectedTag) {
|
||||
return [];
|
||||
return '';
|
||||
}
|
||||
const tags = appState.getNoteTags(note);
|
||||
if (!selectedTag.isSmartTag && tags.length === 1) {
|
||||
return [];
|
||||
return '';
|
||||
}
|
||||
return tags.map((tag) => tag.title);
|
||||
return tags.map((tag) => `#${tag.title}`).join(' ');
|
||||
};
|
||||
|
||||
const openNoteContextMenu = (posX: number, posY: number) => {
|
||||
@@ -55,9 +46,11 @@ export const NotesList: FunctionComponent<Props> = observer(
|
||||
appState.notes.setContextMenuOpen(true);
|
||||
};
|
||||
|
||||
const onContextMenu = (note: SNNote, posX: number, posY: number) => {
|
||||
appState.notes.selectNote(note.uuid, true);
|
||||
openNoteContextMenu(posX, posY);
|
||||
const onContextMenu = async (note: SNNote, posX: number, posY: number) => {
|
||||
await appState.notes.selectNote(note.uuid, true);
|
||||
if (selectedNotes[note.uuid]) {
|
||||
openNoteContextMenu(posX, posY);
|
||||
}
|
||||
};
|
||||
|
||||
const onScroll = (e: Event) => {
|
||||
@@ -91,10 +84,9 @@ export const NotesList: FunctionComponent<Props> = observer(
|
||||
>
|
||||
{notes.map((note) => (
|
||||
<NotesListItem
|
||||
application={application}
|
||||
key={note.uuid}
|
||||
note={note}
|
||||
tags={tagsForNote(note)}
|
||||
tags={tagsStringForNote(note)}
|
||||
selected={!!selectedNotes[note.uuid]}
|
||||
hideDate={hideDate}
|
||||
hidePreview={hideNotePreview}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import { getIconAndTintForEditor } from '@/preferences/panes/general-segments';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import {
|
||||
CollectionSort,
|
||||
sanitizeHtmlString,
|
||||
SNNote,
|
||||
} from '@standardnotes/snjs';
|
||||
import { FunctionComponent } from 'preact';
|
||||
import { Icon } from './Icon';
|
||||
|
||||
type Props = {
|
||||
application: WebApplication;
|
||||
note: SNNote;
|
||||
tags: string[];
|
||||
tags: string;
|
||||
hideDate: boolean;
|
||||
hidePreview: boolean;
|
||||
hideTags: boolean;
|
||||
@@ -28,6 +24,30 @@ type NoteFlag = {
|
||||
|
||||
const flagsForNote = (note: SNNote) => {
|
||||
const flags = [] as NoteFlag[];
|
||||
if (note.pinned) {
|
||||
flags.push({
|
||||
text: 'Pinned',
|
||||
class: 'info',
|
||||
});
|
||||
}
|
||||
if (note.archived) {
|
||||
flags.push({
|
||||
text: 'Archived',
|
||||
class: 'warning',
|
||||
});
|
||||
}
|
||||
if (note.locked) {
|
||||
flags.push({
|
||||
text: 'Editing Disabled',
|
||||
class: 'neutral',
|
||||
});
|
||||
}
|
||||
if (note.trashed) {
|
||||
flags.push({
|
||||
text: 'Deleted',
|
||||
class: 'danger',
|
||||
});
|
||||
}
|
||||
if (note.conflictOf) {
|
||||
flags.push({
|
||||
text: 'Conflicted Copy',
|
||||
@@ -57,7 +77,6 @@ const flagsForNote = (note: SNNote) => {
|
||||
};
|
||||
|
||||
export const NotesListItem: FunctionComponent<Props> = ({
|
||||
application,
|
||||
hideDate,
|
||||
hidePreview,
|
||||
hideTags,
|
||||
@@ -70,9 +89,6 @@ 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] = getIconAndTintForEditor(editorForNote?.identifier);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -81,107 +97,52 @@ export const NotesListItem: FunctionComponent<Props> = ({
|
||||
onClick={onClick}
|
||||
onContextMenu={onContextMenu}
|
||||
>
|
||||
<div className="icon">
|
||||
<Icon
|
||||
ariaLabel={`Icon for ${editorName}`}
|
||||
type={icon}
|
||||
className={`color-accessory-tint-${tint}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="meta">
|
||||
<div className="name">
|
||||
<div>{note.title}</div>
|
||||
<div className="flag-icons">
|
||||
{note.locked && (
|
||||
<span title="Editing Disabled">
|
||||
<Icon
|
||||
ariaLabel="Editing Disabled"
|
||||
type="pencil-off"
|
||||
className="sn-icon--small color-info"
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
{note.trashed && (
|
||||
<span title="Trashed">
|
||||
<Icon
|
||||
ariaLabel="Trashed"
|
||||
type="trash-filled"
|
||||
className="sn-icon--small color-danger"
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
{note.archived && (
|
||||
<span title="Archived">
|
||||
<Icon
|
||||
ariaLabel="Archived"
|
||||
type="archive"
|
||||
className="sn-icon--mid color-accessory-tint-3"
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
{note.pinned && (
|
||||
<span title="Pinned">
|
||||
<Icon
|
||||
ariaLabel="Pinned"
|
||||
type="pin-filled"
|
||||
className="sn-icon--small color-info"
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{flags && flags.length > 0 ? (
|
||||
<div className="note-flags flex flex-wrap">
|
||||
{flags.map((flag) => (
|
||||
<div className={`flag ${flag.class}`}>
|
||||
<div className="label">{flag.text}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{!hidePreview && !note.hidePreview && !note.protected && (
|
||||
<div className="note-preview">
|
||||
{note.preview_html && (
|
||||
<div
|
||||
className="html-preview"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: sanitizeHtmlString(note.preview_html),
|
||||
}}
|
||||
></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>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{!hideDate || note.protected ? (
|
||||
<div className="bottom-info faded">
|
||||
{note.protected && <span>Protected {hideDate ? '' : ' • '}</span>}
|
||||
{!hideDate && showModifiedDate && (
|
||||
<span>Modified {note.updatedAtString || 'Now'}</span>
|
||||
)}
|
||||
{!hideDate && !showModifiedDate && (
|
||||
<span>{note.createdAtString || 'Now'}</span>
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
{!hideTags && tags.length ? (
|
||||
<div className="tags-string">
|
||||
{tags.map((tag) => (
|
||||
<span className="tag color-foreground">
|
||||
<Icon
|
||||
type="hashtag"
|
||||
className="sn-icon--small color-grey-1 mr-1"
|
||||
/>
|
||||
<span>{tag}</span>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
{flags.length ? (
|
||||
<div className="note-flags flex flex-wrap">
|
||||
{flags.map((flag) => (
|
||||
<div className={`flag ${flag.class}`}>
|
||||
<div className="label">{flag.text}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="name">{note.title}</div>
|
||||
{!hidePreview && !note.hidePreview && !note.protected ? (
|
||||
<div className="note-preview">
|
||||
{note.preview_html ? (
|
||||
<div
|
||||
className="html-preview"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: sanitizeHtmlString(note.preview_html),
|
||||
}}
|
||||
></div>
|
||||
) : null}
|
||||
{!note.preview_html && note.preview_plain ? (
|
||||
<div className="plain-preview">{note.preview_plain}</div>
|
||||
) : null}
|
||||
{!note.preview_html && !note.preview_plain ? (
|
||||
<div className="default-preview">{note.text}</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
{!hideDate || note.protected ? (
|
||||
<div className="bottom-info faded">
|
||||
{note.protected ? (
|
||||
<span>Protected {hideDate ? '' : ' • '}</span>
|
||||
) : null}
|
||||
{!hideDate && showModifiedDate ? (
|
||||
<span>Modified {note.updatedAtString || 'Now'}</span>
|
||||
) : null}
|
||||
{!hideDate && !showModifiedDate ? (
|
||||
<span>{note.createdAtString || 'Now'}</span>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
{!hideTags && (
|
||||
<div className="tags-string">
|
||||
<div className="faded">{tags}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -230,7 +230,6 @@ const NotesView: FunctionComponent<Props> = observer(
|
||||
<NotesList
|
||||
notes={renderedNotes}
|
||||
selectedNotes={selectedNotes}
|
||||
application={application}
|
||||
appState={appState}
|
||||
displayOptions={displayOptions}
|
||||
paginate={paginate}
|
||||
|
||||
@@ -21,33 +21,32 @@ type Props = {
|
||||
application: WebApplication;
|
||||
};
|
||||
|
||||
type EditorOption = DropdownItem & {
|
||||
type EditorOption = {
|
||||
icon?: IconType;
|
||||
label: string;
|
||||
value: FeatureIdentifier | 'plain-editor';
|
||||
};
|
||||
|
||||
export const getIconAndTintForEditor = (
|
||||
identifier: FeatureIdentifier | undefined
|
||||
): [IconType, number] => {
|
||||
const getEditorIconType = (identifier: string): IconType | null => {
|
||||
switch (identifier) {
|
||||
case FeatureIdentifier.BoldEditor:
|
||||
case FeatureIdentifier.PlusEditor:
|
||||
return ['rich-text', 1];
|
||||
return 'rich-text';
|
||||
case FeatureIdentifier.MarkdownBasicEditor:
|
||||
case FeatureIdentifier.MarkdownMathEditor:
|
||||
case FeatureIdentifier.MarkdownMinimistEditor:
|
||||
case FeatureIdentifier.MarkdownProEditor:
|
||||
return ['markdown', 2];
|
||||
return 'markdown';
|
||||
case FeatureIdentifier.TokenVaultEditor:
|
||||
return ['authenticator', 6];
|
||||
return 'authenticator';
|
||||
case FeatureIdentifier.SheetsEditor:
|
||||
return ['spreadsheets', 5];
|
||||
return 'spreadsheets';
|
||||
case FeatureIdentifier.TaskEditor:
|
||||
return ['tasks', 3];
|
||||
return 'tasks';
|
||||
case FeatureIdentifier.CodeEditor:
|
||||
return ['code', 4];
|
||||
default:
|
||||
return ['plain-text', 1];
|
||||
return 'code';
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const makeEditorDefault = (
|
||||
@@ -92,19 +91,17 @@ export const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
.componentsForArea(ComponentArea.Editor)
|
||||
.map((editor): EditorOption => {
|
||||
const identifier = editor.package_info.identifier;
|
||||
const [iconType, tint] = getIconAndTintForEditor(identifier);
|
||||
const iconType = getEditorIconType(identifier);
|
||||
|
||||
return {
|
||||
label: editor.name,
|
||||
value: identifier,
|
||||
...(iconType ? { icon: iconType } : null),
|
||||
...(tint ? { iconClassName: `color-accessory-tint-${tint}` } : null),
|
||||
};
|
||||
})
|
||||
.concat([
|
||||
{
|
||||
icon: 'plain-text',
|
||||
iconClassName: `color-accessory-tint-1`,
|
||||
label: 'Plain Editor',
|
||||
value: 'plain-editor',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user