Skip to content

Commit

Permalink
Integrate tag search into new preview renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
mgmeyers committed Apr 18, 2024
1 parent 84a00f8 commit bbf9d6c
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 51 deletions.
6 changes: 4 additions & 2 deletions src/Settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -538,9 +538,11 @@ export class SettingsManager {
});

new Setting(contentEl)
.setName(t('Tag action'))
.setName(t('Tag click action'))
.setDesc(
t('This setting controls whether clicking the tags displayed below the card title opens the Obsidian search or the Kanban board search.')
t(
'This setting controls whether clicking the tags displayed below the card title opens the Obsidian search or the Kanban board search.'
)
)
.addDropdown((dropdown) => {
dropdown.addOption('kanban', t('Search Kanban Board'));
Expand Down
1 change: 1 addition & 0 deletions src/StateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ export class StateManager {
'show-set-view': this.getSettingRaw('show-set-view', suppliedSettings) ?? true,
'tag-colors': this.getSettingRaw('tag-colors', suppliedSettings) ?? [],
'date-colors': this.getSettingRaw('date-colors', suppliedSettings) ?? [],
'tag-action': this.getSettingRaw('tag-action', suppliedSettings) ?? 'obsidian',
};
}

Expand Down
1 change: 0 additions & 1 deletion src/components/Editor/dateWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ export function usePreprocessedStr(
str = str.replace(
new RegExp(`${dateTrigger}\\[\\[([^\\]]+)\\]\\]`, 'g'),
(match, content) => {
console.log(match, content);
const parsed = moment(content, dateFormat);
if (!parsed.isValid()) return match;
const linkPath = app.metadataCache.getFirstLinkpathDest(content, stateManager.file.path);
Expand Down
4 changes: 2 additions & 2 deletions src/components/Item/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export const DraggableItem = memo(function DraggableItem(props: DraggableItemPro

useDragHandle(measureRef, measureRef);

const isMatch = search ? innerProps.item.data.titleSearch.includes(search.query) : false;
const isMatch = search?.query ? innerProps.item.data.titleSearch.includes(search.query) : false;
const classModifiers: string[] = getItemClassModifiers(innerProps.item);

return (
Expand Down Expand Up @@ -189,7 +189,7 @@ export const Items = memo(function Items({ isStatic, items, shouldMarkItemsCompl
return (
<>
{items.map((item, i) => {
return search && !search.items.has(item) ? null : (
return search?.query && !search.items.has(item) ? null : (
<DraggableItem
key={item.id}
item={item}
Expand Down
10 changes: 9 additions & 1 deletion src/components/Item/ItemContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
MarkdownClonedPreviewRenderer,
MarkdownPreviewRenderer,
} from '../MarkdownRenderer/MarkdownRenderer';
import { KanbanContext } from '../context';
import { KanbanContext, SearchContext } from '../context';
import { c } from '../helpers';
import { EditState, EditingState, Item, isEditing } from '../types';
import { DateAndTime, RelativeDate } from './DateAndTime';
Expand Down Expand Up @@ -137,6 +137,7 @@ export function Tags({
isDisplay?: boolean;
}) {
const { stateManager, getTagColor } = useContext(KanbanContext);
const search = useContext(SearchContext);

const hideTagsDisplay = isDisplay && stateManager.useSetting('hide-tags-display');
if (hideTagsDisplay || !tags?.length) return null;
Expand All @@ -150,6 +151,13 @@ export function Tags({
href={tag}
onClick={(e) => {
e.preventDefault();

const tagAction = stateManager.getSetting('tag-action');
if (search && tagAction === 'kanban') {
search.search(tag, true);
return;
}

(stateManager.app as any).internalPlugins
.getPluginById('global-search')
.instance.openGlobalSearch(`tag:${tag}`);
Expand Down
14 changes: 8 additions & 6 deletions src/components/Kanban.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { Lanes } from './Lane/Lane';
import { LaneForm } from './Lane/LaneForm';
import { TableView } from './Table/Table';
import { KanbanContext, SearchContext } from './context';
import { baseClassName, c, getDateColorFn, getSearchHits, getTagColorFn } from './helpers';
import { baseClassName, c, getDateColorFn, getTagColorFn, useSearchValue } from './helpers';
import { DataTypes } from './types';

const boardScrollTiggers = [DataTypes.Item, DataTypes.Lane];
Expand Down Expand Up @@ -182,16 +182,18 @@ export const Kanban = ({ view, stateManager }: KanbanProps) => {
}

const axis = boardView === 'list' ? 'vertical' : 'horizontal';

const searchHits = useMemo(
() => getSearchHits(boardData, debouncedSearchQuery),
[boardData, debouncedSearchQuery]
const searchValue = useSearchValue(
boardData,
debouncedSearchQuery,
setSearchQuery,
setDebouncedSearchQuery,
setIsSearching
);

return (
<DndScope id={view.id}>
<KanbanContext.Provider value={kanbanContext}>
<SearchContext.Provider value={searchHits}>
<SearchContext.Provider value={searchValue}>
<div
ref={rootRef}
className={classcat([
Expand Down
6 changes: 3 additions & 3 deletions src/components/Lane/Lane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ function DraggableLaneRaw({
toggleIsCollapsed={toggleIsCollapsed}
/>

{!search && !isCollapsed && shouldPrepend && (
{!search?.query && !isCollapsed && shouldPrepend && (
<ItemForm
addItems={addItems}
hideButton={isCompactPrepend}
Expand Down Expand Up @@ -199,7 +199,7 @@ function DraggableLaneRaw({
</DroppableComponent>
)}

{!search && !isCollapsed && !shouldPrepend && (
{!search?.query && !isCollapsed && !shouldPrepend && (
<ItemForm addItems={addItems} editState={editState} setEditState={setEditState} />
)}
</CollapsedDropArea>
Expand All @@ -223,7 +223,7 @@ function LanesRaw({ lanes, collapseDir }: LanesProps) {
return (
<DraggableLane
collapseDir={collapseDir}
forceCollapse={search && !search.lanes.has(lane)}
forceCollapse={search?.query && !search.lanes.has(lane)}
key={lane.id}
lane={lane}
laneIndex={i}
Expand Down
39 changes: 31 additions & 8 deletions src/components/MarkdownRenderer/MarkdownRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
renderMarkdown,
} from '../../helpers/renderMarkdown';
import { usePreprocessedStr } from '../Editor/dateWidget';
import { KanbanContext } from '../context';
import { KanbanContext, SearchContext } from '../context';
import { c, noop } from '../helpers';

interface MarkdownRendererProps extends HTMLAttributes<HTMLDivElement> {
Expand Down Expand Up @@ -52,6 +52,7 @@ export const StaticMarkdownRenderer = memo(function StaticMarkdownRenderer({
searchQuery,
...divProps
}: MarkdownRendererProps) {
const search = useContext(SearchContext);
const { stateManager, view, filePath } = useContext(KanbanContext);
const wrapperRef = useRef<HTMLDivElement>();
const contentRef = useRef<HTMLDivElement>();
Expand Down Expand Up @@ -161,11 +162,8 @@ export const StaticMarkdownRenderer = memo(function StaticMarkdownRenderer({
const tag = closestAnchor.getAttr('href');
const tagAction = stateManager.getSetting('tag-action');

if (tagAction === 'kanban') {
setSearchQuery(tag);
setDebouncedSearchQuery(tag);
setIsSearching(true);

if (search && tagAction === 'kanban') {
search.search(tag, true);
return;
}

Expand All @@ -181,7 +179,7 @@ export const StaticMarkdownRenderer = memo(function StaticMarkdownRenderer({
window.open(closestAnchor.getAttr('href'), '_blank');
}
},
[stateManager, filePath]
[stateManager, filePath, search]
);

const onContextMenu = useCallback(
Expand Down Expand Up @@ -411,7 +409,8 @@ export function postProcessor(plugin: KanbanPlugin) {
if (!tagAs.length) return;

tagAs.forEach((a) => {
const color = tagColors.find((c) => c.tagKey === a.getAttr('href'));
const tag = a.getAttr('href');
const color = tagColors.find((c) => c.tagKey === tag);
if (!color) return;

a.setCssProps({
Expand All @@ -429,6 +428,7 @@ export const MarkdownPreviewRenderer = memo(function MarkdownPreviewRenderer({
searchQuery,
...divProps
}: MarkdownPreviewRendererProps) {
const search = useContext(SearchContext);
const { view, stateManager, getDateColor } = useContext(KanbanContext);
const markRef = useRef<Mark>();
const renderer = useRef<MarkdownRenderer>();
Expand Down Expand Up @@ -527,6 +527,28 @@ export const MarkdownPreviewRenderer = memo(function MarkdownPreviewRenderer({
}
}, []);

const onClick = useCallback(
async (e: MouseEvent) => {
if (e.type === 'auxclick' || e.button === 2) return;

const targetEl = e.targetNode as HTMLElement;
const closestAnchor = targetEl.tagName === 'A' ? targetEl : targetEl.closest('a');

if (!closestAnchor) return;
if (closestAnchor.hasClass('tag')) {
const tagAction = stateManager.getSetting('tag-action');
if (search && tagAction === 'kanban') {
e.preventDefault();
e.stopPropagation();
const tag = closestAnchor.getAttr('href');
search.search(tag, true);
return;
}
}
},
[stateManager, search]
);

let styles: CSSProperties | undefined = undefined;
if (!renderer.current && view.previewCache.has(entityId)) {
const preview = view.previewCache.get(entityId);
Expand All @@ -541,6 +563,7 @@ export const MarkdownPreviewRenderer = memo(function MarkdownPreviewRenderer({
return (
<div
style={styles}
onClickCapture={onClick}
ref={(el) => {
elRef.current = el;
const preview = renderer.current;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ function useTableColumns(boardData: Board, stateManager: StateManager) {
},
[setSortingRaw]
);
const state = useMemo(() => ({ sorting, globalFilter: search?.query }), [sorting, search]);
const state = useMemo(() => ({ sorting, globalFilter: search?.query }), [sorting, search?.query]);

const { items, metadata, fileMetadata } = useTableData(boardData, stateManager);
const withMetadata: ColumnDef<TableItem, any>[] = useMemo(() => {
Expand Down
1 change: 1 addition & 0 deletions src/components/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface SearchContextProps {
query: string;
items: Set<Item>;
lanes: Set<Lane>;
search: (query: string, immediate?: boolean) => void;
}

export const SearchContext = createContext<SearchContextProps | null>(null);
67 changes: 48 additions & 19 deletions src/components/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import update from 'immutability-helper';
import { App, MarkdownView, TFile, moment } from 'obsidian';
import Preact, { RefObject, useEffect } from 'preact/compat';
import Preact, { Dispatch, RefObject, useEffect } from 'preact/compat';
import { StateUpdater, useMemo } from 'preact/hooks';
import { StateManager } from 'src/StateManager';
import { Path } from 'src/dnd/types';
import { getEntityFromPath } from 'src/dnd/util/data';

import { SearchContextProps } from './context';
import { Board, DateColorKey, Item, Lane, TagColorKey } from './types';

export const baseClassName = 'kanban-plugin';
Expand Down Expand Up @@ -291,23 +293,50 @@ export function useOnMount(refs: RefObject<HTMLElement>[], cb: () => void, onUnm
}, []);
}

export function getSearchHits(board: Board, query: string) {
query = query.trim().toLocaleLowerCase();
if (!query) return null;

const lanes = new Set<Lane>();
const items = new Set<Item>();

board.children.forEach((lane) => {
let laneMatched = false;
lane.children.forEach((item) => {
if (item.data.titleSearch.includes(query)) {
laneMatched = true;
items.add(item);
}
});
if (laneMatched) lanes.add(lane);
});
export function useSearchValue(
board: Board,
query: string,
setSearchQuery: Dispatch<StateUpdater<string>>,
setDebouncedSearchQuery: Dispatch<StateUpdater<string>>,
setIsSearching: Dispatch<StateUpdater<boolean>>
) {
return useMemo<SearchContextProps>(() => {
query = query.trim().toLocaleLowerCase();

const lanes = new Set<Lane>();
const items = new Set<Item>();

if (query) {
board.children.forEach((lane) => {
let laneMatched = false;
lane.children.forEach((item) => {
if (item.data.titleSearch.includes(query)) {
laneMatched = true;
items.add(item);
}
});
if (laneMatched) lanes.add(lane);
});
}

return { lanes, items, query };
return {
lanes,
items,
query,
search: (query, immediate) => {
if (!query) {
setIsSearching(false);
setSearchQuery('');
setDebouncedSearchQuery('');
}
setIsSearching(true);
if (immediate) {
setSearchQuery(query);
setDebouncedSearchQuery(query);
} else {
setSearchQuery(query);
}
},
};
}, [board, query, setSearchQuery, setDebouncedSearchQuery]);
}
2 changes: 1 addition & 1 deletion src/lang/locale/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export default {
'Hide card display tags': 'Hide card display tags',
'When toggled, tags will not be displayed below the card title.':
'When toggled, tags will not be displayed below the card title.',
'Tag action': 'Tag action',
'Tag click action': 'Tag click action',
'Search Kanban Board': 'Search Kanban Board',
'Search Obsidian Vault': 'Search Obsidian Vault',
'This setting controls whether clicking the tags displayed below the card title opens the Obsidian search or the Kanban board search.':
Expand Down
14 changes: 11 additions & 3 deletions src/parsers/formats/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,17 @@ export function listItemToItemData(stateManager: StateManager, md: string, item:
let title = itemContent;
let titleSearch = '';

visit(item, ['text', 'wikilink', 'embedWikilink', 'image', 'inlineCode', 'code'], (node: any) => {
titleSearch += node.value || node.alt || '';
});
visit(
item,
['text', 'wikilink', 'embedWikilink', 'image', 'inlineCode', 'code', 'hashtag'],
(node: any) => {
if (node.type === 'hashtag') {
titleSearch += '#' + node.value;
} else {
titleSearch += node.value || node.alt || '';
}
}
);

const itemData: ItemData = {
titleRaw: dedentNewLines(replaceBrs(itemContent)),
Expand Down
8 changes: 4 additions & 4 deletions src/styles.less
Original file line number Diff line number Diff line change
Expand Up @@ -305,10 +305,6 @@ button.kanban-plugin__search-cancel-button .kanban-plugin__icon {
height: 100%;
}

.view-content:not(.is-mobile-editing) & > div {
padding-bottom: calc(1rem + var(--mobile-navbar-height));
}

&.kanban-plugin__vertical {
> div {
height: fit-content;
Expand All @@ -318,6 +314,10 @@ button.kanban-plugin__search-cancel-button .kanban-plugin__icon {
}
}

.is-mobile .view-content:not(.is-mobile-editing) .kanban-plugin__board > div {
padding-bottom: calc(1rem + var(--mobile-navbar-height));
}

.kanban-plugin__board.is-adding-lane > div {
padding-inline-end: calc(250px + 1rem);
}
Expand Down

0 comments on commit bbf9d6c

Please sign in to comment.