From b5053c5292237534c91aff404fb2175229fcd878 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Mon, 12 Oct 2020 09:37:53 -0700 Subject: [PATCH] Show sort direction on sort menu --- src/client/components/boardComponent.tsx | 29 +----------------- src/client/components/tableComponent.tsx | 29 +----------------- src/client/menu.ts | 15 +++++++++ src/client/octoUtils.tsx | 39 +++++++++++++++++++++--- src/static/images.css | 25 ++++++++++++++- 5 files changed, 76 insertions(+), 61 deletions(-) diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index ba5343b1c..885953c1e 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -4,7 +4,6 @@ import { Block } from "../block" import { BlockIcons } from "../blockIcons" import { IPropertyOption } from "../board" import { BoardTree } from "../boardTree" -import { ISortOption } from "../boardView" import { CardFilter } from "../cardFilter" import { Constants } from "../constants" import { Menu } from "../menu" @@ -96,7 +95,7 @@ class BoardComponent extends React.Component { Group by {boardTree.groupByProperty?.name}
{ this.filterClicked(e) }}>Filter
-
{ this.sortClicked(e) }}>Sort
+
{ OctoUtils.showSortMenu(e, mutator, boardTree) }}>Sort
{this.state.isSearching ? { pageController.showFilter(e.target as HTMLElement) } - private async sortClicked(e: React.MouseEvent) { - const { mutator, boardTree } = this.props - const { activeView } = boardTree - const { sortOptions } = activeView - const sortOption = sortOptions.length > 0 ? sortOptions[0] : undefined - - const propertyTemplates = boardTree.board.cardProperties - Menu.shared.options = propertyTemplates.map((o) => { return { id: o.id, name: o.name } }) - Menu.shared.onMenuClicked = async (propertyId: string) => { - let newSortOptions: ISortOption[] = [] - if (sortOption && sortOption.propertyId === propertyId) { - // Already sorting by name, so reverse it - newSortOptions = [ - { propertyId, reversed: !sortOption.reversed } - ] - } else { - newSortOptions = [ - { propertyId, reversed: false } - ] - } - - await mutator.changeViewSortOptions(activeView, newSortOptions) - } - Menu.shared.showAtElement(e.target as HTMLElement) - } - private async optionsClicked(e: React.MouseEvent) { const { boardTree } = this.props diff --git a/src/client/components/tableComponent.tsx b/src/client/components/tableComponent.tsx index bd05ea44c..795ba6e39 100644 --- a/src/client/components/tableComponent.tsx +++ b/src/client/components/tableComponent.tsx @@ -4,7 +4,6 @@ import { Block } from "../block" import { BlockIcons } from "../blockIcons" import { IPropertyTemplate } from "../board" import { BoardTree } from "../boardTree" -import { ISortOption } from "../boardView" import { CsvExporter } from "../csvExporter" import { Menu } from "../menu" import { Mutator } from "../mutator" @@ -90,7 +89,7 @@ class TableComponent extends React.Component {
{ this.propertiesClicked(e) }}>Properties
{ this.filterClicked(e) }}>Filter
-
{ this.sortClicked(e) }}>Sort
+
{ OctoUtils.showSortMenu(e, mutator, boardTree) }}>Sort
{this.state.isSearching ? { pageController.showFilter(e.target as HTMLElement) } - private async sortClicked(e: React.MouseEvent) { - const { mutator, boardTree } = this.props - const { activeView } = boardTree - const { sortOptions } = activeView - const sortOption = sortOptions.length > 0 ? sortOptions[0] : undefined - - const propertyTemplates = boardTree.board.cardProperties - Menu.shared.options = propertyTemplates.map((o) => { return { id: o.id, name: o.name } }) - Menu.shared.onMenuClicked = async (propertyId: string) => { - let newSortOptions: ISortOption[] = [] - if (sortOption && sortOption.propertyId === propertyId) { - // Already sorting by name, so reverse it - newSortOptions = [ - { propertyId, reversed: !sortOption.reversed } - ] - } else { - newSortOptions = [ - { propertyId, reversed: false } - ] - } - - await mutator.changeViewSortOptions(activeView, newSortOptions) - } - Menu.shared.showAtElement(e.target as HTMLElement) - } - private async optionsClicked(e: React.MouseEvent) { const { boardTree } = this.props diff --git a/src/client/menu.ts b/src/client/menu.ts index 58912321c..35f86763b 100644 --- a/src/client/menu.ts +++ b/src/client/menu.ts @@ -4,6 +4,7 @@ type MenuOption = { id: string, name: string, isOn?: boolean, + icon?: "checked" | "sortUp" | "sortDown" | undefined, type?: "separator" | "color" | "submenu" | "switch" | undefined } @@ -54,6 +55,20 @@ class Menu { this.showSubMenu(rect.right - bodyRect.left, rect.top - bodyRect.top, option.id) } } else { + + if (option.icon) { + let iconName: string + switch (option.icon) { + case "checked": { iconName = "imageMenuCheck"; break } + case "sortUp": { iconName = "imageMenuSortUp"; break } + case "sortDown": { iconName = "imageMenuSortDown"; break } + default: { Utils.assertFailure(`Unsupported menu icon: ${option.icon}`) } + } + if (iconName) { + optionElement.appendChild(Utils.htmlToElement(`
`)) + } + } + optionElement.onmouseenter = () => { this.hideSubMenu() } diff --git a/src/client/octoUtils.tsx b/src/client/octoUtils.tsx index 10b388ada..8ed264a82 100644 --- a/src/client/octoUtils.tsx +++ b/src/client/octoUtils.tsx @@ -1,7 +1,7 @@ import React from "react" import { IPropertyTemplate } from "./board" import { BoardTree } from "./boardTree" -import { BoardView } from "./boardView" +import { BoardView, ISortOption } from "./boardView" import { Editable } from "./components/editable" import { Menu, MenuOption } from "./menu" import { Mutator } from "./mutator" @@ -143,7 +143,7 @@ class OctoUtils { showMenu(e.target as HTMLElement) } } : undefined} - onFocus={mutator ? () => { Menu.shared.hide() } : undefined } + onFocus={mutator ? () => { Menu.shared.hide() } : undefined} > {finalDisplayValue} @@ -176,7 +176,7 @@ class OctoUtils { if (index === 0) { return block.order / 2 } - const previousBlock = blocks[index-1] + const previousBlock = blocks[index - 1] return (block.order + previousBlock.order) / 2 } @@ -185,9 +185,40 @@ class OctoUtils { if (index === blocks.length - 1) { return block.order + 1000 } - const nextBlock = blocks[index+1] + const nextBlock = blocks[index + 1] return (block.order + nextBlock.order) / 2 } + + static showSortMenu(e: React.MouseEvent, mutator: Mutator, boardTree: BoardTree) { + const { activeView } = boardTree + const { sortOptions } = activeView + const sortOption = sortOptions.length > 0 ? sortOptions[0] : undefined + + const propertyTemplates = boardTree.board.cardProperties + Menu.shared.options = propertyTemplates.map((o) => { + return { + id: o.id, + name: o.name, + icon: (sortOption.propertyId === o.id) ? sortOption.reversed ? "sortUp" : "sortDown" : undefined + } + }) + Menu.shared.onMenuClicked = async (propertyId: string) => { + let newSortOptions: ISortOption[] = [] + if (sortOption && sortOption.propertyId === propertyId) { + // Already sorting by name, so reverse it + newSortOptions = [ + { propertyId, reversed: !sortOption.reversed } + ] + } else { + newSortOptions = [ + { propertyId, reversed: false } + ] + } + + await mutator.changeViewSortOptions(activeView, newSortOptions) + } + Menu.shared.showAtElement(e.target as HTMLElement) + } } export { OctoUtils } diff --git a/src/static/images.css b/src/static/images.css index 23d5390ea..4640988b5 100644 --- a/src/static/images.css +++ b/src/static/images.css @@ -6,7 +6,7 @@ } .imageAdd { - background-image: url('data:image/svg+xml,'); + background-image: url('data:image/svg+xml,'); background-size: 100% 100%; min-width: 24px; min-height: 24px; @@ -19,9 +19,32 @@ min-height: 24px; } +/*-- Menu images --*/ + .imageSubmenuTriangle { background-image: url('data:image/svg+xml,'); background-size: 100% 100%; min-width: 24px; min-height: 24px; } + +.imageMenuCheck { + background-image: url('data:image/svg+xml,'); + background-size: 100% 100%; + min-width: 24px; + min-height: 24px; +} + +.imageMenuSortUp { + background-image: url('data:image/svg+xml,'); + background-size: 100% 100%; + min-width: 24px; + min-height: 24px; +} + +.imageMenuSortDown { + background-image: url('data:image/svg+xml,'); + background-size: 100% 100%; + min-width: 24px; + min-height: 24px; +}