From 882216922e0475e74cb69341a7f161e33ffcb8e7 Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Wed, 22 Apr 2026 12:54:02 +0300 Subject: [PATCH] =?UTF-8?q?UI=20-=20=D0=9C=D0=95=D0=96=D0=9F=D0=A0=D0=9E?= =?UTF-8?q?=D0=95=D0=9A=D0=A2=D0=9D=D0=90=D0=AF=20=D0=9A=D0=9E=D0=9C=D0=9C?= =?UTF-8?q?=D0=A3=D0=9D=D0=98=D0=9A=D0=90=D0=A6=D0=98=D0=AF:=20=D0=BC?= =?UTF-8?q?=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D1=8F=20desktop=20sorting?= =?UTF-8?q?=20dropdown=20=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=89=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=BA=D0=B0=D0=BD=D0=BE=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/sorting-dropdown.tsx | 70 ++++++++++ .../inbox/inbox-filter/sorting/order-by.tsx | 55 ++++---- .../filters/header/helpers/filter-option.tsx | 6 +- .../spreadsheet/columns/header-column.tsx | 129 +++++++++--------- .../components/modules/dropdowns/order-by.tsx | 87 ++++++------ .../core/components/pages/list/order-by.tsx | 93 +++++++------ .../components/project/dropdowns/order-by.tsx | 105 +++++++------- .../project/member-header-column.tsx | 114 ++++++++-------- .../components/views/filters/order-by.tsx | 78 +++++------ 9 files changed, 395 insertions(+), 342 deletions(-) create mode 100644 plane-src/apps/web/core/components/common/sorting-dropdown.tsx diff --git a/plane-src/apps/web/core/components/common/sorting-dropdown.tsx b/plane-src/apps/web/core/components/common/sorting-dropdown.tsx new file mode 100644 index 0000000..b9297d5 --- /dev/null +++ b/plane-src/apps/web/core/components/common/sorting-dropdown.tsx @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2023-present Plane Software, Inc. and contributors + * SPDX-License-Identifier: AGPL-3.0-only + * See the LICENSE file for details. + */ + +import type { ReactNode } from "react"; +import type { Placement } from "@popperjs/core"; +import { FiltersDropdown, FilterOption } from "@/components/issues/issue-layouts/filters/header"; + +export type TSortingDropdownOption = { + key: string; + title: ReactNode; + icon?: ReactNode; + isChecked: boolean; + onClick: () => void; + shouldRender?: boolean; + disabled?: boolean; +}; + +export type TSortingDropdownSection = { + key: string; + options: TSortingDropdownOption[]; +}; + +type Props = { + disabled?: boolean; + menuButton: ReactNode; + placement?: Placement; + sections: TSortingDropdownSection[]; + title?: ReactNode; +}; + +export function SortingDropdown(props: Props) { + const { disabled = false, menuButton, placement = "bottom-end", sections, title = "Order by" } = props; + + const renderedSections = sections + .map((section) => ({ + ...section, + options: section.options.filter((option) => option.shouldRender !== false), + })) + .filter((section) => section.options.length > 0); + + return ( + +
+
+ {title} +
+ {renderedSections.map((section, index) => ( +
+ {section.options.map((option) => ( + + ))} +
+ ))} +
+
+ ); +} diff --git a/plane-src/apps/web/core/components/inbox/inbox-filter/sorting/order-by.tsx b/plane-src/apps/web/core/components/inbox/inbox-filter/sorting/order-by.tsx index adbba4a..212303f 100644 --- a/plane-src/apps/web/core/components/inbox/inbox-filter/sorting/order-by.tsx +++ b/plane-src/apps/web/core/components/inbox/inbox-filter/sorting/order-by.tsx @@ -10,7 +10,7 @@ import { INBOX_ISSUE_ORDER_BY_OPTIONS, INBOX_ISSUE_SORT_BY_OPTIONS } from "@plan import { useTranslation } from "@plane/i18n"; import { CheckIcon, ChevronDownIcon } from "@plane/propel/icons"; import type { TInboxIssueSortingOrderByKeys, TInboxIssueSortingSortByKeys } from "@plane/types"; -import { CustomMenu } from "@plane/ui"; +import { SortingDropdown } from "@/components/common/sorting-dropdown"; // constants // helpers import { cn } from "@plane/utils"; @@ -59,33 +59,32 @@ export const InboxIssueOrderByDropdown = observer(function InboxIssueOrderByDrop ); return ( - - {INBOX_ISSUE_ORDER_BY_OPTIONS.map((option) => ( - handleInboxIssueSorting("order_by", option.key as TInboxIssueSortingOrderByKeys)} - > - {t(option.i18n_label)} - {inboxSorting?.order_by?.includes(option.key) && } - - ))} -
- {INBOX_ISSUE_SORT_BY_OPTIONS.map((option) => ( - handleInboxIssueSorting("sort_by", option.key as TInboxIssueSortingSortByKeys)} - > - {t(option.i18n_label)} - {inboxSorting?.sort_by?.includes(option.key) && } - - ))} -
+ title={t("common.order_by.label")} + sections={[ + { + key: "field", + options: INBOX_ISSUE_ORDER_BY_OPTIONS.map((option) => ({ + key: option.key, + title: t(option.i18n_label), + isChecked: !!inboxSorting?.order_by?.includes(option.key), + onClick: () => handleInboxIssueSorting("order_by", option.key as TInboxIssueSortingOrderByKeys), + icon: inboxSorting?.order_by?.includes(option.key) ? : undefined, + })), + }, + { + key: "direction", + options: INBOX_ISSUE_SORT_BY_OPTIONS.map((option) => ({ + key: option.key, + title: t(option.i18n_label), + isChecked: !!inboxSorting?.sort_by?.includes(option.key), + onClick: () => handleInboxIssueSorting("sort_by", option.key as TInboxIssueSortingSortByKeys), + icon: inboxSorting?.sort_by?.includes(option.key) ? : undefined, + })), + }, + ]} + /> ); }); diff --git a/plane-src/apps/web/core/components/issues/issue-layouts/filters/header/helpers/filter-option.tsx b/plane-src/apps/web/core/components/issues/issue-layouts/filters/header/helpers/filter-option.tsx index 6f97e2c..7626b12 100644 --- a/plane-src/apps/web/core/components/issues/issue-layouts/filters/header/helpers/filter-option.tsx +++ b/plane-src/apps/web/core/components/issues/issue-layouts/filters/header/helpers/filter-option.tsx @@ -7,6 +7,7 @@ import { CheckIcon } from "@plane/propel/icons"; type Props = { + disabled?: boolean; icon?: React.ReactNode; isChecked: boolean; title: React.ReactNode; @@ -16,13 +17,14 @@ type Props = { }; export function FilterOption(props: Props) { - const { icon, isChecked, onClick, title, activePulse = false } = props; + const { disabled = false, icon, isChecked, onClick, title, activePulse = false } = props; return (