From b234b34cf4ce96884c2067707d003b9ad80c21bd Mon Sep 17 00:00:00 2001 From: mgmeyers Date: Sat, 27 Apr 2024 18:57:11 -0700 Subject: [PATCH] Use submenus for move and sort menu options --- src/components/Item/ItemMenu.ts | 44 ++++-- src/components/Lane/LaneMenu.tsx | 239 +++++++++++++++++-------------- src/lang/locale/en.ts | 1 + 3 files changed, 159 insertions(+), 125 deletions(-) diff --git a/src/components/Item/ItemMenu.ts b/src/components/Item/ItemMenu.ts index fda4436d..ad77bf5e 100644 --- a/src/components/Item/ItemMenu.ts +++ b/src/components/Item/ItemMenu.ts @@ -1,4 +1,4 @@ -import { Menu, TFile, TFolder } from 'obsidian'; +import { Menu, Platform, TFile, TFolder } from 'obsidian'; import { Dispatch, StateUpdater, useCallback } from 'preact/hooks'; import { StateManager } from 'src/StateManager'; import { Path } from 'src/dnd/types'; @@ -257,20 +257,36 @@ export function useItemMenu({ menu.addSeparator(); - const lanes = stateManager.state.children; - for (let i = 0, len = lanes.length; i < len; i++) { - menu.addItem((item) => - item + const addMoveToOptions = (menu: Menu) => { + const lanes = stateManager.state.children; + if (lanes.length <= 1) return; + for (let i = 0, len = lanes.length; i < len; i++) { + menu.addItem((item) => + item + .setIcon('lucide-square-kanban') + .setChecked(path[0] === i) + .setTitle(lanes[i].data.title) + .onClick(() => { + if (path[0] === i) return; + stateManager.setState((boardData) => { + return moveEntity(boardData, path, [i, 0]); + }); + }) + ); + } + }; + + if (Platform.isPhone) { + addMoveToOptions(menu); + } else { + menu.addItem((item) => { + const submenu = (item as any) + .setTitle(t('Move to list')) .setIcon('lucide-square-kanban') - .setChecked(path[0] === i) - .setTitle(lanes[i].data.title) - .onClick(() => { - if (path[0] === i) return; - stateManager.setState((boardData) => { - return moveEntity(boardData, path, [i, 0]); - }); - }) - ); + .setSubmenu(); + + addMoveToOptions(submenu); + }); } menu.showAtPosition(coordinates); diff --git a/src/components/Lane/LaneMenu.tsx b/src/components/Lane/LaneMenu.tsx index 1f652b79..daf1647a 100644 --- a/src/components/Lane/LaneMenu.tsx +++ b/src/components/Lane/LaneMenu.tsx @@ -1,5 +1,5 @@ import update from 'immutability-helper'; -import { Menu } from 'obsidian'; +import { Menu, Platform } from 'obsidian'; import { Dispatch, StateUpdater, useContext, useEffect, useMemo, useState } from 'preact/hooks'; import { Path } from 'src/dnd/types'; import { defaultSort } from 'src/helpers/util'; @@ -71,7 +71,7 @@ export function useSettingsMenu({ setEditState, path, lane }: UseSettingsMenuPar const [confirmAction, setConfirmAction] = useState(null); const settingsMenu = useMemo(() => { - const taskSortOptions = new Set(); + const metadataSortOptions = new Set(); let canSortDate = false; let canSortTags = false; @@ -80,7 +80,7 @@ export function useSettingsMenu({ setEditState, path, lane }: UseSettingsMenuPar if (taskData) { taskData.forEach((m) => { if (m.key === 'repeat') return; - if (!taskSortOptions.has(m.key)) taskSortOptions.add(m.key); + if (!metadataSortOptions.has(m.key)) metadataSortOptions.add(m.key); }); } @@ -103,7 +103,7 @@ export function useSettingsMenu({ setEditState, path, lane }: UseSettingsMenuPar }) .addSeparator() .addItem((i) => { - i.setIcon('corner-left-down') + i.setIcon('arrow-left-to-line') .setTitle(t('Insert list before')) .onClick(() => boardModifiers.insertLane(path, { @@ -119,7 +119,7 @@ export function useSettingsMenu({ setEditState, path, lane }: UseSettingsMenuPar ); }) .addItem((i) => { - i.setIcon('lucide-corner-right-down') + i.setIcon('arrow-right-to-line') .setTitle(t('Insert list after')) .onClick(() => { const newPath = [...path]; @@ -151,10 +151,12 @@ export function useSettingsMenu({ setEditState, path, lane }: UseSettingsMenuPar .setTitle(t('Delete list')) .onClick(() => setConfirmAction('delete')); }) - .addSeparator() - .addItem((item) => { + .addSeparator(); + + const addSortOptions = (menu: Menu) => { + menu.addItem((item) => { item - .setIcon('lucide-move-vertical') + .setIcon('arrow-down-up') .setTitle(t('Sort by card text')) .onClick(() => { const children = lane.children.slice(); @@ -187,120 +189,77 @@ export function useSettingsMenu({ setEditState, path, lane }: UseSettingsMenuPar }); }); - if (canSortDate) { - menu.addItem((item) => { - item - .setIcon('lucide-move-vertical') - .setTitle(t('Sort by date')) - .onClick(() => { - const children = lane.children.slice(); - const mod = lane.data.sorted === LaneSort.DateAsc ? -1 : 1; + if (canSortDate) { + menu.addItem((item) => { + item + .setIcon('arrow-down-up') + .setTitle(t('Sort by date')) + .onClick(() => { + const children = lane.children.slice(); + const mod = lane.data.sorted === LaneSort.DateAsc ? -1 : 1; - children.sort((a, b) => { - const aDate: moment.Moment | undefined = a.data.metadata.time || a.data.metadata.date; - const bDate: moment.Moment | undefined = b.data.metadata.time || b.data.metadata.date; + children.sort((a, b) => { + const aDate: moment.Moment | undefined = + a.data.metadata.time || a.data.metadata.date; + const bDate: moment.Moment | undefined = + b.data.metadata.time || b.data.metadata.date; - if (aDate && !bDate) return -1 * mod; - if (bDate && !aDate) return 1 * mod; - if (!aDate && !bDate) return 0; + if (aDate && !bDate) return -1 * mod; + if (bDate && !aDate) return 1 * mod; + if (!aDate && !bDate) return 0; - return (aDate.isBefore(bDate) ? -1 : 1) * mod; - }); + return (aDate.isBefore(bDate) ? -1 : 1) * mod; + }); - boardModifiers.updateLane( - path, - update(lane, { - children: { - $set: children, - }, - data: { - sorted: { - $set: - lane.data.sorted === LaneSort.DateAsc ? LaneSort.DateDsc : LaneSort.DateAsc, + boardModifiers.updateLane( + path, + update(lane, { + children: { + $set: children, }, - }, - }) - ); - }); - }); - } - - if (canSortTags) { - menu.addItem((item) => { - item - .setIcon('lucide-move-vertical') - .setTitle(t('Sort by tags')) - .onClick(() => { - const tagSortOrder = stateManager.getSetting('tag-sort'); - const children = lane.children.slice(); - const desc = lane.data.sorted === LaneSort.TagsAsc ? true : false; - - children.sort((a, b) => { - const tagsA = a.data.metadata.tags; - const tagsB = b.data.metadata.tags; - - if (!tagsA?.length && !tagsB?.length) return 0; - if (!tagsA?.length) return 1; - if (!tagsB?.length) return -1; - - const aSortOrder = tagSortOrder?.findIndex((sort) => tagsA.includes(sort.tag)) ?? -1; - const bSortOrder = tagSortOrder?.findIndex((sort) => tagsB.includes(sort.tag)) ?? -1; - - if (aSortOrder > -1 && bSortOrder < 0) return desc ? 1 : -1; - if (bSortOrder > -1 && aSortOrder < 0) return desc ? -1 : 1; - if (aSortOrder > -1 && bSortOrder > -1) { - return desc ? bSortOrder - aSortOrder : aSortOrder - bSortOrder; - } - - if (desc) return defaultSort(tagsB.join(''), tagsA.join('')); - return defaultSort(tagsA.join(''), tagsB.join('')); - }); - - boardModifiers.updateLane( - path, - update(lane, { - children: { - $set: children, - }, - data: { - sorted: { - $set: - lane.data.sorted === LaneSort.TagsAsc ? LaneSort.TagsDsc : LaneSort.TagsAsc, + data: { + sorted: { + $set: + lane.data.sorted === LaneSort.DateAsc ? LaneSort.DateDsc : LaneSort.DateAsc, + }, }, - }, - }) - ); - }); - }); - } + }) + ); + }); + }); + } - if (taskSortOptions.size) { - taskSortOptions.forEach((k) => { - menu.addItem((i) => { - i.setIcon('lucide-move-vertical') - .setTitle(t('Sort by') + ' ' + lableToName(k).toLocaleLowerCase()) + if (canSortTags) { + menu.addItem((item) => { + item + .setIcon('arrow-down-up') + .setTitle(t('Sort by tags')) .onClick(() => { + const tagSortOrder = stateManager.getSetting('tag-sort'); const children = lane.children.slice(); - const desc = lane.data.sorted === k + '-asc' ? true : false; + const desc = lane.data.sorted === LaneSort.TagsAsc ? true : false; children.sort((a, b) => { - const valA = a.data.metadata.inlineMetadata?.find((m) => m.key === k); - const valB = b.data.metadata.inlineMetadata?.find((m) => m.key === k); - - if (valA === undefined && valB === undefined) return 0; - if (valA === undefined) return 1; - if (valB === undefined) return -1; - - if (desc) { - return defaultSort( - anyToString(valB.value, stateManager), - anyToString(valA.value, stateManager) - ); + const tagsA = a.data.metadata.tags; + const tagsB = b.data.metadata.tags; + + if (!tagsA?.length && !tagsB?.length) return 0; + if (!tagsA?.length) return 1; + if (!tagsB?.length) return -1; + + const aSortOrder = + tagSortOrder?.findIndex((sort) => tagsA.includes(sort.tag)) ?? -1; + const bSortOrder = + tagSortOrder?.findIndex((sort) => tagsB.includes(sort.tag)) ?? -1; + + if (aSortOrder > -1 && bSortOrder < 0) return desc ? 1 : -1; + if (bSortOrder > -1 && aSortOrder < 0) return desc ? -1 : 1; + if (aSortOrder > -1 && bSortOrder > -1) { + return desc ? bSortOrder - aSortOrder : aSortOrder - bSortOrder; } - return defaultSort( - anyToString(valA.value, stateManager), - anyToString(valB.value, stateManager) - ); + + if (desc) return defaultSort(tagsB.join(''), tagsA.join('')); + return defaultSort(tagsA.join(''), tagsB.join('')); }); boardModifiers.updateLane( @@ -311,13 +270,71 @@ export function useSettingsMenu({ setEditState, path, lane }: UseSettingsMenuPar }, data: { sorted: { - $set: lane.data.sorted === k + '-asc' ? k + '-desc' : k + '-asc', + $set: + lane.data.sorted === LaneSort.TagsAsc ? LaneSort.TagsDsc : LaneSort.TagsAsc, }, }, }) ); }); }); + } + + if (metadataSortOptions.size) { + metadataSortOptions.forEach((k) => { + menu.addItem((i) => { + i.setIcon('arrow-down-up') + .setTitle(t('Sort by') + ' ' + lableToName(k).toLocaleLowerCase()) + .onClick(() => { + const children = lane.children.slice(); + const desc = lane.data.sorted === k + '-asc' ? true : false; + + children.sort((a, b) => { + const valA = a.data.metadata.inlineMetadata?.find((m) => m.key === k); + const valB = b.data.metadata.inlineMetadata?.find((m) => m.key === k); + + if (valA === undefined && valB === undefined) return 0; + if (valA === undefined) return 1; + if (valB === undefined) return -1; + + if (desc) { + return defaultSort( + anyToString(valB.value, stateManager), + anyToString(valA.value, stateManager) + ); + } + return defaultSort( + anyToString(valA.value, stateManager), + anyToString(valB.value, stateManager) + ); + }); + + boardModifiers.updateLane( + path, + update(lane, { + children: { + $set: children, + }, + data: { + sorted: { + $set: lane.data.sorted === k + '-asc' ? k + '-desc' : k + '-asc', + }, + }, + }) + ); + }); + }); + }); + } + }; + + if (Platform.isPhone) { + addSortOptions(menu); + } else { + menu.addItem((item) => { + const submenu = (item as any).setTitle(t('Sort by')).setIcon('arrow-down-up').setSubmenu(); + + addSortOptions(submenu); }); } diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 6651240f..30560ce4 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -232,6 +232,7 @@ const en = { 'Add label': 'Add label', 'Move to top': 'Move to top', 'Move to bottom': 'Move to bottom', + 'Move to list': 'Move to list', // components/Lane/LaneForm.tsx 'Enter list title...': 'Enter list title...',