ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: интерактивные карточки и фильтры двусторонней доски внешних контуров

This commit is contained in:
DCCONSTRUCTIONS
2026-04-20 22:57:18 +03:00
parent 6a3adcd245
commit d3b4c0689c
16 changed files with 754 additions and 224 deletions
@@ -7,6 +7,7 @@
import type { ReactNode } from "react";
import { useRef, useState } from "react";
import { observer } from "mobx-react";
import { createPortal } from "react-dom";
import { usePopper } from "react-popper";
import { Combobox } from "@headlessui/react";
// plane imports
@@ -211,60 +212,62 @@ export const WorkItemStateDropdownBase = observer(function WorkItemStateDropdown
button={comboButton}
renderByDefault={renderByDefault}
>
{isOpen && (
<Combobox.Options className="fixed z-10" static>
<div
className="nodedc-glass-modal nodedc-glass-popup-surface my-1 w-52 rounded-[1.25rem] border-0 px-3 py-3 text-12 shadow-none outline-none"
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
>
<div className="flex items-center gap-1.5 rounded-[0.95rem] border-0 bg-white/5 px-3 py-2 outline-none">
<SearchIcon className="h-3.5 w-3.5 text-placeholder" strokeWidth={1.5} />
<Combobox.Input
as="input"
ref={inputRef}
className="w-full bg-transparent py-0 text-12 text-secondary placeholder:text-placeholder outline-none focus:outline-none"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder={t("common.search.label")}
displayValue={(assigned: any) => assigned?.name}
onKeyDown={searchInputKeyDown}
/>
</div>
<div className="mt-2 max-h-56 space-y-1 overflow-y-auto">
{filteredOptions ? (
filteredOptions.length > 0 ? (
filteredOptions.map((option) => (
<Combobox.Option
key={option.value}
value={option.value}
className={({ active, selected }) =>
cn(
`flex w-full cursor-pointer items-center justify-between gap-2 truncate rounded-[0.9rem] px-2 py-2 select-none outline-none ${
active ? "bg-white/6" : ""
} ${selected ? "text-primary" : "text-secondary"}`
)
}
>
{({ selected }) => (
<>
<span className="flex-grow truncate">{option.content}</span>
{selected && <CheckIcon className="h-3.5 w-3.5 flex-shrink-0" />}
</>
)}
</Combobox.Option>
))
{isOpen &&
createPortal(
<Combobox.Options data-prevent-outside-click className="fixed z-30" static>
<div
className="nodedc-glass-modal nodedc-glass-popup-surface my-1 w-52 rounded-[1.25rem] border-0 px-3 py-3 text-12 shadow-none outline-none"
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
>
<div className="flex items-center gap-1.5 rounded-[0.95rem] border-0 bg-white/5 px-3 py-2 outline-none">
<SearchIcon className="h-3.5 w-3.5 text-placeholder" strokeWidth={1.5} />
<Combobox.Input
as="input"
ref={inputRef}
className="w-full bg-transparent py-0 text-12 text-secondary placeholder:text-placeholder outline-none focus:outline-none"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder={t("common.search.label")}
displayValue={(assigned: any) => assigned?.name}
onKeyDown={searchInputKeyDown}
/>
</div>
<div className="mt-2 max-h-56 space-y-1 overflow-y-auto">
{filteredOptions ? (
filteredOptions.length > 0 ? (
filteredOptions.map((option) => (
<Combobox.Option
key={option.value}
value={option.value}
className={({ active, selected }) =>
cn(
`flex w-full cursor-pointer items-center justify-between gap-2 truncate rounded-[0.9rem] px-2 py-2 select-none outline-none ${
active ? "bg-white/6" : ""
} ${selected ? "text-primary" : "text-secondary"}`
)
}
>
{({ selected }) => (
<>
<span className="flex-grow truncate">{option.content}</span>
{selected && <CheckIcon className="h-3.5 w-3.5 flex-shrink-0" />}
</>
)}
</Combobox.Option>
))
) : (
<p className="px-1.5 py-1 text-placeholder italic">{t("no_matching_results")}</p>
)
) : (
<p className="px-1.5 py-1 text-placeholder italic">{t("no_matching_results")}</p>
)
) : (
<p className="px-1.5 py-1 text-placeholder italic">{t("loading")}</p>
)}
<p className="px-1.5 py-1 text-placeholder italic">{t("loading")}</p>
)}
</div>
</div>
</div>
</Combobox.Options>
)}
</Combobox.Options>,
document.body
)}
</ComboDropDown>
);
});