Skip to content

Commit

Permalink
refactor: smart tags to views (#902)
Browse files Browse the repository at this point in the history
* refactor: smart tags to views

* chore: upgrade snjs
  • Loading branch information
moughxyz authored Feb 27, 2022
1 parent 4db8ca8 commit 16fc3eb
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 171 deletions.
4 changes: 2 additions & 2 deletions app/assets/javascripts/components/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SmartTagsSection } from '@/components/Tags/SmartTagsSection';
import { SmartViewsSection } from '@/components/Tags/SmartViewsSection';
import { TagsSection } from '@/components/Tags/TagsSection';
import { WebApplication } from '@/ui_models/application';
import { PANEL_NAME_NAVIGATION } from '@/constants';
Expand Down Expand Up @@ -65,7 +65,7 @@ export const Navigation: FunctionComponent<Props> = observer(
</div>
</div>
<div className="scrollable">
<SmartTagsSection appState={appState} />
<SmartViewsSection appState={appState} />
<TagsSection appState={appState} />
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions app/assets/javascripts/components/NotesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ 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';
import { SNNote } from '@standardnotes/snjs';
import { SNNote, SNTag } from '@standardnotes/snjs';
import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import { NotesListItem } from './NotesListItem';
Expand Down Expand Up @@ -42,7 +42,7 @@ export const NotesList: FunctionComponent<Props> = observer(
return [];
}
const tags = appState.getNoteTags(note);
if (!selectedTag.isSmartTag && tags.length === 1) {
if (selectedTag instanceof SNTag && tags.length === 1) {
return [];
}
return tags.map((tag) => tag.title).sort();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { AppState } from '@/ui_models/app_state';
import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import { SmartTagsListItem } from './SmartTagsListItem';
import { SmartViewsListItem } from './SmartViewsListItem';

type Props = {
appState: AppState;
};

export const SmartTagsList: FunctionComponent<Props> = observer(
export const SmartViewsList: FunctionComponent<Props> = observer(
({ appState }) => {
const allTags = appState.tags.smartTags;
const allViews = appState.tags.smartViews;

return (
<>
{allTags.map((tag) => {
{allViews.map((view) => {
return (
<SmartTagsListItem
key={tag.uuid}
tag={tag}
<SmartViewsListItem
key={view.uuid}
view={view}
tagsState={appState.tags}
features={appState.features}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,59 @@ import { Icon } from '@/components/Icon';
import { FeaturesState } from '@/ui_models/app_state/features_state';
import { TagsState } from '@/ui_models/app_state/tags_state';
import '@reach/tooltip/styles.css';
import { SNSmartTag, IconType } from '@standardnotes/snjs';
import {
SmartView,
SystemViewId,
IconType,
isSystemView,
} from '@standardnotes/snjs';
import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';

type Props = {
tag: SNSmartTag;
view: SmartView;
tagsState: TagsState;
features: FeaturesState;
};

const PADDING_BASE_PX = 14;
const PADDING_PER_LEVEL_PX = 21;

const smartTagIconType = (tag: SNSmartTag): IconType => {
if (tag.isAllTag) {
const smartViewIconType = (view: SmartView): IconType => {
if (view.uuid === SystemViewId.AllNotes) {
return 'notes';
}
if (tag.isArchiveTag) {
if (view.uuid === SystemViewId.ArchivedNotes) {
return 'archive';
}
if (tag.isTrashTag) {
if (view.uuid === SystemViewId.TrashedNotes) {
return 'trash';
}
return 'hashtag';
};

export const SmartTagsListItem: FunctionComponent<Props> = observer(
({ tag, tagsState, features }) => {
const [title, setTitle] = useState(tag.title || '');
export const SmartViewsListItem: FunctionComponent<Props> = observer(
({ view, tagsState }) => {
const [title, setTitle] = useState(view.title || '');
const inputRef = useRef<HTMLInputElement>(null);

const level = 0;
const isSelected = tagsState.selected === tag;
const isEditing = tagsState.editingTag === tag;
const isSelected = tagsState.selected === view;
const isEditing = tagsState.editingTag === view;

useEffect(() => {
setTitle(tag.title || '');
}, [setTitle, tag]);
setTitle(view.title || '');
}, [setTitle, view]);

const selectCurrentTag = useCallback(() => {
tagsState.selected = tag;
}, [tagsState, tag]);
tagsState.selected = view;
}, [tagsState, view]);

const onBlur = useCallback(() => {
tagsState.save(tag, title);
setTitle(tag.title);
}, [tagsState, tag, title, setTitle]);
tagsState.save(view, title);
setTitle(view.title);
}, [tagsState, view, title, setTitle]);

const onInput = useCallback(
(e: Event) => {
Expand All @@ -76,19 +81,19 @@ export const SmartTagsListItem: FunctionComponent<Props> = observer(
}, [inputRef, isEditing]);

const onClickRename = useCallback(() => {
tagsState.editingTag = tag;
}, [tagsState, tag]);
tagsState.editingTag = view;
}, [tagsState, view]);

const onClickSave = useCallback(() => {
inputRef.current?.blur();
}, [inputRef]);

const onClickDelete = useCallback(() => {
tagsState.remove(tag, true);
}, [tagsState, tag]);
tagsState.remove(view, true);
}, [tagsState, view]);

const isFaded = !tag.isAllTag;
const iconType = smartTagIconType(tag);
const isFaded = false;
const iconType = smartViewIconType(view);

return (
<>
Expand All @@ -101,7 +106,7 @@ export const SmartTagsListItem: FunctionComponent<Props> = observer(
paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
}}
>
{!tag.errorDecrypting ? (
{!view.errorDecrypting ? (
<div className="tag-info">
<div className={`tag-icon mr-1`}>
<Icon
Expand All @@ -112,7 +117,7 @@ export const SmartTagsListItem: FunctionComponent<Props> = observer(
<input
className={`title ${isEditing ? 'editing' : ''}`}
disabled={!isEditing}
id={`react-tag-${tag.uuid}`}
id={`react-tag-${view.uuid}`}
onBlur={onBlur}
onInput={onInput}
value={title}
Expand All @@ -121,21 +126,21 @@ export const SmartTagsListItem: FunctionComponent<Props> = observer(
ref={inputRef}
/>
<div className="count">
{tag.isAllTag && tagsState.allNotesCount}
{view.uuid === SystemViewId.AllNotes && tagsState.allNotesCount}
</div>
</div>
) : null}
{!tag.isSystemSmartTag && (
{!isSystemView(view) && (
<div className="meta">
{tag.conflictOf && (
{view.conflictOf && (
<div className="danger small-text font-bold">
Conflicted Copy {tag.conflictOf}
Conflicted Copy {view.conflictOf}
</div>
)}
{tag.errorDecrypting && !tag.waitingForKey && (
{view.errorDecrypting && !view.waitingForKey && (
<div className="danger small-text font-bold">Missing Keys</div>
)}
{tag.errorDecrypting && tag.waitingForKey && (
{view.errorDecrypting && view.waitingForKey && (
<div className="info small-text font-bold">
Waiting For Keys
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { AppState } from '@/ui_models/app_state';
import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import { SmartTagsList } from './SmartTagsList';
import { SmartViewsList } from './SmartViewsList';

type Props = {
appState: AppState;
};

export const SmartTagsSection: FunctionComponent<Props> = observer(
export const SmartViewsSection: FunctionComponent<Props> = observer(
({ appState }) => {
return (
<section>
<SmartTagsList appState={appState} />
<SmartViewsList appState={appState} />
</section>
);
}
Expand Down
3 changes: 2 additions & 1 deletion app/assets/javascripts/components/Tags/TagContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Menu } from '../menu/Menu';
import { MenuItem, MenuItemType } from '../menu/MenuItem';
import { usePremiumModal } from '../Premium';
import { useCloseOnBlur } from '../utils';
import { SNTag } from '@standardnotes/snjs';

type Props = {
appState: AppState;
Expand All @@ -17,7 +18,7 @@ export const TagsContextMenu: FunctionComponent<Props> = observer(
const premiumModal = usePremiumModal();
const selectedTag = appState.tags.selected;

if (!selectedTag) {
if (!selectedTag || !(selectedTag instanceof SNTag)) {
return null;
}

Expand Down
21 changes: 15 additions & 6 deletions app/assets/javascripts/ui_models/app_state/app_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import {
PayloadSource,
PrefKey,
SNNote,
SNSmartTag,
SmartView,
SNTag,
SystemViewId,
} from '@standardnotes/snjs';
import pull from 'lodash/pull';
import {
Expand Down Expand Up @@ -241,7 +242,9 @@ export class AppState {
const selectedTag = this.selectedTag;

const activeRegularTagUuid =
selectedTag && !selectedTag.isSmartTag ? selectedTag.uuid : undefined;
selectedTag && selectedTag instanceof SNTag
? selectedTag.uuid
: undefined;

await this.application.noteControllerGroup.createNoteView(
undefined,
Expand Down Expand Up @@ -313,11 +316,11 @@ export class AppState {
);
}

public get selectedTag(): SNTag | SNSmartTag | undefined {
public get selectedTag(): SNTag | SmartView | undefined {
return this.tags.selected;
}

public set selectedTag(tag: SNTag | SNSmartTag | undefined) {
public set selectedTag(tag: SNTag | SmartView | undefined) {
this.tags.selected = tag;
}

Expand All @@ -341,13 +344,19 @@ export class AppState {
this.closeNoteController(noteController);
} else if (
note.trashed &&
!selectedTag?.isTrashTag &&
!(
selectedTag instanceof SmartView &&
selectedTag.uuid === SystemViewId.TrashedNotes
) &&
!this.searchOptions.includeTrashed
) {
this.closeNoteController(noteController);
} else if (
note.archived &&
!selectedTag?.isArchiveTag &&
!(
selectedTag instanceof SmartView &&
selectedTag.uuid === SystemViewId.ArchivedNotes
) &&
!this.searchOptions.includeArchived &&
!this.application.getPreference(PrefKey.NotesShowArchived, false)
) {
Expand Down
14 changes: 7 additions & 7 deletions app/assets/javascripts/ui_models/app_state/features_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ export class FeaturesState {
window?.enabledUnfinishedFeatures;

_hasFolders = false;
_hasSmartTags = false;
_hasSmartViews = false;
_premiumAlertFeatureName: string | undefined;

private unsub: () => void;

constructor(private application: WebApplication) {
this._hasFolders = this.hasNativeFolders();
this._hasSmartTags = this.hasNativeSmartTags();
this._hasSmartViews = this.hasNativeSmartViews();
this._premiumAlertFeatureName = undefined;

makeObservable(this, {
_hasFolders: observable,
_hasSmartTags: observable,
_hasSmartViews: observable,
hasFolders: computed,
_premiumAlertFeatureName: observable,
showPremiumAlert: action,
Expand All @@ -56,7 +56,7 @@ export class FeaturesState {
case ApplicationEvent.Launched:
runInAction(() => {
this._hasFolders = this.hasNativeFolders();
this._hasSmartTags = this.hasNativeSmartTags();
this._hasSmartViews = this.hasNativeSmartViews();
});
break;
default:
Expand All @@ -73,8 +73,8 @@ export class FeaturesState {
return this._hasFolders;
}

public get hasSmartTags(): boolean {
return this._hasSmartTags;
public get hasSmartViews(): boolean {
return this._hasSmartViews;
}

public async showPremiumAlert(featureName: string): Promise<void> {
Expand All @@ -94,7 +94,7 @@ export class FeaturesState {
return status === FeatureStatus.Entitled;
}

private hasNativeSmartTags(): boolean {
private hasNativeSmartViews(): boolean {
const status = this.application.getFeatureStatus(
FeatureIdentifier.SmartFilters
);
Expand Down
Loading

0 comments on commit 16fc3eb

Please sign in to comment.