F: Improve layout by reworking dropdowns

This commit is contained in:
Ivan 2025-03-07 02:46:19 +03:00
parent 442f86f99a
commit 293f1cad6f
25 changed files with 122 additions and 83 deletions

View File

@ -58,11 +58,10 @@ export function Navigation() {
> >
<Logo /> <Logo />
</div> </div>
<div className='flex gap-1 py-[0.3rem]'> <div className='flex gap-2 items-center'>
<NavigationButton text='Новая схема' icon={<IconNewItem2 size='1.5rem' />} onClick={navigateCreateNew} /> <NavigationButton text='Новая схема' icon={<IconNewItem2 size='1.5rem' />} onClick={navigateCreateNew} />
<NavigationButton text='Библиотека' icon={<IconLibrary2 size='1.5rem' />} onClick={navigateLibrary} /> <NavigationButton text='Библиотека' icon={<IconLibrary2 size='1.5rem' />} onClick={navigateLibrary} />
<NavigationButton text='Справка' icon={<IconManuals size='1.5rem' />} onClick={navigateHelp} /> <NavigationButton text='Справка' icon={<IconManuals size='1.5rem' />} onClick={navigateHelp} />
<UserMenu /> <UserMenu />
</div> </div>
</div> </div>

View File

@ -6,30 +6,29 @@ import { globalIDs } from '@/utils/constants';
interface NavigationButtonProps extends Styling { interface NavigationButtonProps extends Styling {
text?: string; text?: string;
title?: string; title?: string;
hideTitle?: boolean;
icon: React.ReactNode; icon: React.ReactNode;
onClick?: (event: React.MouseEvent<Element>) => void; onClick?: (event: React.MouseEvent<Element>) => void;
} }
export function NavigationButton({ icon, title, className, style, onClick, text }: NavigationButtonProps) { export function NavigationButton({ icon, title, hideTitle, className, style, onClick, text }: NavigationButtonProps) {
return ( return (
<button <button
type='button' type='button'
tabIndex={-1} tabIndex={-1}
aria-label={title} aria-label={title}
data-tooltip-id={!!title ? globalIDs.tooltip : undefined} data-tooltip-id={!!title ? globalIDs.tooltip : undefined}
data-tooltip-hidden={hideTitle}
data-tooltip-content={title} data-tooltip-content={title}
onClick={onClick} onClick={onClick}
className={clsx( className={clsx(
'mr-1 h-full', 'p-2 h-min',
'flex items-center gap-1', 'flex items-center gap-1',
'cursor-pointer', 'cursor-pointer',
'clr-btn-nav cc-animate-color duration-500', 'clr-btn-nav cc-animate-color duration-500',
'rounded-xl', 'rounded-xl',
'font-controls whitespace-nowrap', 'font-controls whitespace-nowrap',
{
'px-2': text,
'px-4': !text
},
className className
)} )}
style={style} style={style}

View File

@ -2,6 +2,7 @@ import { useAuthSuspense } from '@/features/auth';
import { IconLogin, IconUser2 } from '@/components/Icons'; import { IconLogin, IconUser2 } from '@/components/Icons';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { globalIDs } from '@/utils/constants';
import { NavigationButton } from './NavigationButton'; import { NavigationButton } from './NavigationButton';
@ -28,8 +29,10 @@ export function UserButton({ onLogin, onClickUser, isOpen }: UserButtonProps) {
<NavigationButton <NavigationButton
className='cc-fade-in' className='cc-fade-in'
title='Пользователь' title='Пользователь'
hideTitle={isOpen}
aria-haspopup='true' aria-haspopup='true'
aria-expanded={isOpen} aria-expanded={isOpen}
aria-controls={globalIDs.user_dropdown}
icon={<IconUser2 size='1.5rem' className={adminMode && user.is_staff ? 'icon-primary' : ''} />} icon={<IconUser2 size='1.5rem' className={adminMode && user.is_staff ? 'icon-primary' : ''} />}
onClick={onClickUser} onClick={onClickUser}
/> />

View File

@ -17,6 +17,7 @@ import {
IconUser IconUser
} from '@/components/Icons'; } from '@/components/Icons';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { globalIDs } from '@/utils/constants';
import { urls } from '../urls'; import { urls } from '../urls';
@ -75,7 +76,7 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
} }
return ( return (
<Dropdown className='mt-[1.5rem] min-w-[18ch] max-w-[12rem]' stretchLeft isOpen={isOpen}> <Dropdown id={globalIDs.user_dropdown} className='min-w-[18ch] max-w-[12rem]' stretchLeft isOpen={isOpen}>
<DropdownButton <DropdownButton
text={user.username} text={user.username}
title='Профиль пользователя' title='Профиль пользователя'

View File

@ -13,7 +13,7 @@ export function UserMenu() {
const router = useConceptNavigation(); const router = useConceptNavigation();
const menu = useDropdown(); const menu = useDropdown();
return ( return (
<div ref={menu.ref} className='h-full w-[4rem] flex items-center justify-center'> <div ref={menu.ref} className='flex items-center justify-start relative h-full pr-2'>
<Suspense fallback={<Loader circular scale={1.5} />}> <Suspense fallback={<Loader circular scale={1.5} />}>
<UserButton <UserButton
onLogin={() => router.push({ path: urls.login, force: true })} onLogin={() => router.push({ path: urls.login, force: true })}

View File

@ -5,6 +5,12 @@ import { PARAMETER } from '@/utils/constants';
import { type Styling } from '../props'; import { type Styling } from '../props';
interface DropdownProps extends Styling { interface DropdownProps extends Styling {
/** Unique ID for the dropdown. */
id?: string;
/** Margin for the dropdown. */
margin?: string;
/** Indicates whether the dropdown should stretch to the left. */ /** Indicates whether the dropdown should stretch to the left. */
stretchLeft?: boolean; stretchLeft?: boolean;
@ -22,18 +28,18 @@ export function Dropdown({
isOpen, isOpen,
stretchLeft, stretchLeft,
stretchTop, stretchTop,
margin,
className, className,
children, children,
style, style,
...restProps ...restProps
}: React.PropsWithChildren<DropdownProps>) { }: React.PropsWithChildren<DropdownProps>) {
return ( return (
<div className='relative'>
<div <div
tabIndex={-1} tabIndex={-1}
className={clsx( className={clsx(
'z-topmost', 'z-topmost',
'absolute mt-3', 'absolute',
'flex flex-col', 'flex flex-col',
'border rounded-md shadow-lg', 'border rounded-md shadow-lg',
'text-sm', 'text-sm',
@ -41,8 +47,10 @@ export function Dropdown({
{ {
'right-0': stretchLeft, 'right-0': stretchLeft,
'left-0': !stretchLeft, 'left-0': !stretchLeft,
'bottom-[2rem]': stretchTop 'bottom-0': stretchTop,
'top-full': !stretchTop
}, },
margin,
className className
)} )}
style={{ style={{
@ -59,6 +67,5 @@ export function Dropdown({
> >
{children} {children}
</div> </div>
</div>
); );
} }

View File

@ -44,7 +44,7 @@ export function MenuRole({ isOwned, isEditor }: MenuRoleProps) {
} }
return ( return (
<div ref={accessMenu.ref}> <div ref={accessMenu.ref} className='relative'>
<Button <Button
dense dense
noBorder noBorder
@ -56,7 +56,7 @@ export function MenuRole({ isOwned, isEditor }: MenuRoleProps) {
icon={<IconRole role={role} size='1.25rem' />} icon={<IconRole role={role} size='1.25rem' />}
onClick={accessMenu.toggle} onClick={accessMenu.toggle}
/> />
<Dropdown isOpen={accessMenu.isOpen}> <Dropdown isOpen={accessMenu.isOpen} margin='mt-3'>
<DropdownButton <DropdownButton
text={labelUserRole(UserRole.READER)} text={labelUserRole(UserRole.READER)}
title={describeUserRole(UserRole.READER)} title={describeUserRole(UserRole.READER)}

View File

@ -28,7 +28,7 @@ export function MiniSelectorOSS({ items, onSelect, className, ...restProps }: Mi
} }
return ( return (
<div ref={ossMenu.ref} className={clsx('flex items-center', className)} {...restProps}> <div ref={ossMenu.ref} className={clsx('relative flex items-center', className)} {...restProps}>
<MiniButton <MiniButton
icon={<IconOSS size='1.25rem' className='icon-primary' />} icon={<IconOSS size='1.25rem' className='icon-primary' />}
title='Операционные схемы' title='Операционные схемы'
@ -36,7 +36,7 @@ export function MiniSelectorOSS({ items, onSelect, className, ...restProps }: Mi
onClick={onToggle} onClick={onToggle}
/> />
{items.length > 1 ? ( {items.length > 1 ? (
<Dropdown isOpen={ossMenu.isOpen}> <Dropdown isOpen={ossMenu.isOpen} margin='mt-1'>
<Label text='Список ОСС' className='border-b px-3 py-1' /> <Label text='Список ОСС' className='border-b px-3 py-1' />
{items.map((reference, index) => ( {items.map((reference, index) => (
<DropdownButton <DropdownButton

View File

@ -113,14 +113,14 @@ export function PickSchema({
query={filterText} query={filterText}
onChangeQuery={newValue => setFilterText(newValue)} onChangeQuery={newValue => setFilterText(newValue)}
/> />
<div ref={locationMenu.ref}> <div className='relative' ref={locationMenu.ref}>
<MiniButton <MiniButton
icon={<IconFolderTree size='1.25rem' className={!!filterLocation ? 'icon-green' : 'icon-primary'} />} icon={<IconFolderTree size='1.25rem' className={!!filterLocation ? 'icon-green' : 'icon-primary'} />}
title='Фильтр по расположению' title='Фильтр по расположению'
className='mt-1' className='mt-1'
onClick={() => locationMenu.toggle()} onClick={() => locationMenu.toggle()}
/> />
<Dropdown isOpen={locationMenu.isOpen} stretchLeft className='w-[20rem] h-[12.5rem] z-modal-tooltip mt-0'> <Dropdown isOpen={locationMenu.isOpen} stretchLeft className='w-[20rem] h-[12.5rem] z-modal-tooltip'>
<SelectLocation <SelectLocation
value={filterLocation} value={filterLocation}
prefix={prefixes.folders_list} prefix={prefixes.folders_list}

View File

@ -1,5 +1,7 @@
'use client'; 'use client';
import clsx from 'clsx';
import { MiniButton } from '@/components/Control'; import { MiniButton } from '@/components/Control';
import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown'; import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown';
import { type Styling } from '@/components/props'; import { type Styling } from '@/components/props';
@ -18,7 +20,14 @@ interface SelectAccessPolicyProps extends Styling {
stretchLeft?: boolean; stretchLeft?: boolean;
} }
export function SelectAccessPolicy({ value, disabled, stretchLeft, onChange, ...restProps }: SelectAccessPolicyProps) { export function SelectAccessPolicy({
value,
disabled,
className,
stretchLeft,
onChange,
...restProps
}: SelectAccessPolicyProps) {
const menu = useDropdown(); const menu = useDropdown();
function handleChange(newValue: AccessPolicy) { function handleChange(newValue: AccessPolicy) {
@ -29,7 +38,7 @@ export function SelectAccessPolicy({ value, disabled, stretchLeft, onChange, ...
} }
return ( return (
<div ref={menu.ref} {...restProps}> <div ref={menu.ref} className={clsx('relative', className)} {...restProps}>
<MiniButton <MiniButton
title={`Доступ: ${labelAccessPolicy(value)}`} title={`Доступ: ${labelAccessPolicy(value)}`}
hideTitle={menu.isOpen} hideTitle={menu.isOpen}
@ -38,7 +47,7 @@ export function SelectAccessPolicy({ value, disabled, stretchLeft, onChange, ...
onClick={menu.toggle} onClick={menu.toggle}
disabled={disabled} disabled={disabled}
/> />
<Dropdown isOpen={menu.isOpen} stretchLeft={stretchLeft}> <Dropdown isOpen={menu.isOpen} stretchLeft={stretchLeft} margin='mt-1'>
{Object.values(AccessPolicy).map((item, index) => ( {Object.values(AccessPolicy).map((item, index) => (
<DropdownButton <DropdownButton
key={`${prefixes.policy_list}${index}`} key={`${prefixes.policy_list}${index}`}

View File

@ -1,5 +1,7 @@
'use client'; 'use client';
import clsx from 'clsx';
import { SelectorButton } from '@/components/Control'; import { SelectorButton } from '@/components/Control';
import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown'; import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown';
import { type Styling } from '@/components/props'; import { type Styling } from '@/components/props';
@ -17,7 +19,14 @@ interface SelectItemTypeProps extends Styling {
stretchLeft?: boolean; stretchLeft?: boolean;
} }
export function SelectItemType({ value, disabled, stretchLeft, onChange, ...restProps }: SelectItemTypeProps) { export function SelectItemType({
value,
disabled,
className,
stretchLeft,
onChange,
...restProps
}: SelectItemTypeProps) {
const menu = useDropdown(); const menu = useDropdown();
function handleChange(newValue: LibraryItemType) { function handleChange(newValue: LibraryItemType) {
@ -28,7 +37,7 @@ export function SelectItemType({ value, disabled, stretchLeft, onChange, ...rest
} }
return ( return (
<div ref={menu.ref} {...restProps}> <div ref={menu.ref} className={clsx('relative', className)} {...restProps}>
<SelectorButton <SelectorButton
transparent transparent
title={describeLibraryItemType(value)} title={describeLibraryItemType(value)}
@ -39,7 +48,7 @@ export function SelectItemType({ value, disabled, stretchLeft, onChange, ...rest
onClick={menu.toggle} onClick={menu.toggle}
disabled={disabled} disabled={disabled}
/> />
<Dropdown isOpen={menu.isOpen} stretchLeft={stretchLeft}> <Dropdown isOpen={menu.isOpen} stretchLeft={stretchLeft} margin='mt-1'>
{Object.values(LibraryItemType).map((item, index) => ( {Object.values(LibraryItemType).map((item, index) => (
<DropdownButton <DropdownButton
key={`${prefixes.policy_list}${index}`} key={`${prefixes.policy_list}${index}`}

View File

@ -14,7 +14,7 @@ interface SelectLocationContextProps extends Styling {
value: string; value: string;
onChange: (newValue: string) => void; onChange: (newValue: string) => void;
title?: string; title?: string;
stretchTop?: boolean; dropdownHeight?: string;
} }
export function SelectLocationContext({ export function SelectLocationContext({
@ -22,7 +22,8 @@ export function SelectLocationContext({
title = 'Проводник...', title = 'Проводник...',
onChange, onChange,
className, className,
style dropdownHeight,
...restProps
}: SelectLocationContextProps) { }: SelectLocationContextProps) {
const menu = useDropdown(); const menu = useDropdown();
@ -34,7 +35,11 @@ export function SelectLocationContext({
} }
return ( return (
<div ref={menu.ref} className='h-full text-right self-start mt-[-0.25rem] ml-[-1.5rem]'> <div
ref={menu.ref}
className={clsx('relative h-full mt-[-0.25rem] ml-[-1.5rem]', 'text-right self-start', className)}
{...restProps}
>
<MiniButton <MiniButton
title={title} title={title}
hideTitle={menu.isOpen} hideTitle={menu.isOpen}
@ -43,8 +48,8 @@ export function SelectLocationContext({
/> />
<Dropdown <Dropdown
isOpen={menu.isOpen} isOpen={menu.isOpen}
className={clsx('w-[20rem] h-[12.5rem] z-modal-tooltip mt-[-0.25rem]', className)} className={clsx('w-[20rem] h-[12.5rem] z-modal-tooltip', dropdownHeight)}
style={style} margin='mt-[-0.25rem]'
> >
<SelectLocation <SelectLocation
value={value} value={value}

View File

@ -33,7 +33,7 @@ export function SelectLocationHead({
} }
return ( return (
<div ref={menu.ref} className={clsx('h-full text-right', className)} {...restProps}> <div ref={menu.ref} className={clsx('h-full text-right relative', className)} {...restProps}>
<SelectorButton <SelectorButton
transparent transparent
tabIndex={-1} tabIndex={-1}
@ -45,7 +45,7 @@ export function SelectLocationHead({
onClick={menu.toggle} onClick={menu.toggle}
/> />
<Dropdown isOpen={menu.isOpen} className='z-modal-tooltip'> <Dropdown isOpen={menu.isOpen} className='z-modal-tooltip' margin='mt-2'>
{Object.values(LocationHead) {Object.values(LocationHead)
.filter(head => !excluded.includes(head)) .filter(head => !excluded.includes(head))
.map((head, index) => { .map((head, index) => {

View File

@ -70,9 +70,10 @@ export function ToolbarItemAccess({
onClick={toggleReadOnly} onClick={toggleReadOnly}
disabled={role === UserRole.READER || isProcessing} disabled={role === UserRole.READER || isProcessing}
/> />
<div className='pt-[0.125rem]'>
<BadgeHelp topic={HelpTopic.ACCESS} className={PARAMETER.TOOLTIP_WIDTH} offset={4} /> <BadgeHelp topic={HelpTopic.ACCESS} className={PARAMETER.TOOLTIP_WIDTH} offset={4} />
</div> </div>
</div>
</Overlay> </Overlay>
); );
} }

View File

@ -77,7 +77,7 @@ export function DlgChangeLocation() {
control={control} control={control}
name='location' name='location'
render={({ field }) => ( render={({ field }) => (
<SelectLocationContext className='max-h-[9.2rem]' value={field.value} onChange={field.onChange} /> <SelectLocationContext dropdownHeight='max-h-[9.2rem]' value={field.value} onChange={field.onChange} />
)} )}
/> />
<Controller <Controller

View File

@ -103,14 +103,14 @@ export function ToolbarSearch({ total, filtered }: ToolbarSearchProps) {
onClick={toggleVisible} onClick={toggleVisible}
/> />
<div ref={userMenu.ref} className='flex'> <div ref={userMenu.ref} className='relative flex'>
<MiniButton <MiniButton
title='Поиск пользователя' title='Поиск пользователя'
hideTitle={userMenu.isOpen} hideTitle={userMenu.isOpen}
icon={<IconUserSearch size='1.25rem' className={userActive ? 'icon-green' : 'icon-primary'} />} icon={<IconUserSearch size='1.25rem' className={userActive ? 'icon-green' : 'icon-primary'} />}
onClick={userMenu.toggle} onClick={userMenu.toggle}
/> />
<Dropdown isOpen={userMenu.isOpen}> <Dropdown isOpen={userMenu.isOpen} margin='mt-[0.2rem]'>
<DropdownButton <DropdownButton
text='Я - Владелец' text='Я - Владелец'
icon={<IconOwner size='1.25rem' className={tripleToggleColor(isOwned)} />} icon={<IconOwner size='1.25rem' className={tripleToggleColor(isOwned)} />}
@ -149,7 +149,7 @@ export function ToolbarSearch({ total, filtered }: ToolbarSearchProps) {
onChangeQuery={setQuery} onChangeQuery={setQuery}
/> />
{!folderMode ? ( {!folderMode ? (
<div ref={headMenu.ref} className='flex items-center h-full py-1 select-none'> <div ref={headMenu.ref} className='relative flex items-center h-full py-1 select-none'>
<SelectorButton <SelectorButton
transparent transparent
className='h-full rounded-lg' className='h-full rounded-lg'

View File

@ -172,6 +172,7 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
isOpen={isOpen} isOpen={isOpen}
stretchLeft={cursorX >= window.innerWidth - MENU_WIDTH} stretchLeft={cursorX >= window.innerWidth - MENU_WIDTH}
stretchTop={cursorY >= window.innerHeight - MENU_HEIGHT} stretchTop={cursorY >= window.innerHeight - MENU_HEIGHT}
margin={cursorY >= window.innerHeight - MENU_HEIGHT ? 'mb-3' : 'mt-3'}
> >
<DropdownButton <DropdownButton
text='Редактировать' text='Редактировать'

View File

@ -31,7 +31,7 @@ export function MenuEditOss() {
} }
return ( return (
<div ref={editMenu.ref}> <div ref={editMenu.ref} className='relative'>
<Button <Button
dense dense
noBorder noBorder
@ -43,7 +43,7 @@ export function MenuEditOss() {
icon={<IconEdit2 size='1.25rem' className={isMutable ? 'icon-green' : 'icon-red'} />} icon={<IconEdit2 size='1.25rem' className={isMutable ? 'icon-green' : 'icon-red'} />}
onClick={editMenu.toggle} onClick={editMenu.toggle}
/> />
<Dropdown isOpen={editMenu.isOpen}> <Dropdown isOpen={editMenu.isOpen} margin='mt-3'>
<DropdownButton <DropdownButton
text='Конституенты' text='Конституенты'
titleHtml='Перенос конституент</br>между схемами' titleHtml='Перенос конституент</br>между схемами'

View File

@ -46,7 +46,7 @@ export function MenuMain() {
} }
return ( return (
<div ref={schemaMenu.ref}> <div ref={schemaMenu.ref} className='relative'>
<Button <Button
dense dense
noBorder noBorder
@ -58,7 +58,7 @@ export function MenuMain() {
className='h-full pl-2' className='h-full pl-2'
onClick={schemaMenu.toggle} onClick={schemaMenu.toggle}
/> />
<Dropdown isOpen={schemaMenu.isOpen}> <Dropdown isOpen={schemaMenu.isOpen} margin='mt-3'>
<DropdownButton <DropdownButton
text='Поделиться' text='Поделиться'
icon={<IconShare size='1rem' className='icon-primary' />} icon={<IconShare size='1rem' className='icon-primary' />}

View File

@ -69,7 +69,7 @@ export function ToolbarRSList() {
disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length} disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length}
onClick={moveDown} onClick={moveDown}
/> />
<div ref={insertMenu.ref}> <div ref={insertMenu.ref} className='relative'>
<MiniButton <MiniButton
title='Добавить пустую конституенту' title='Добавить пустую конституенту'
hideTitle={insertMenu.isOpen} hideTitle={insertMenu.isOpen}
@ -77,7 +77,7 @@ export function ToolbarRSList() {
disabled={isProcessing} disabled={isProcessing}
onClick={insertMenu.toggle} onClick={insertMenu.toggle}
/> />
<Dropdown isOpen={insertMenu.isOpen} className='-translate-x-1/2 md:translate-x-0'> <Dropdown isOpen={insertMenu.isOpen} className='-translate-x-1/2'>
{Object.values(CstType).map(typeStr => ( {Object.values(CstType).map(typeStr => (
<DropdownButton <DropdownButton
key={`${prefixes.csttype_list}${typeStr}`} key={`${prefixes.csttype_list}${typeStr}`}

View File

@ -118,7 +118,7 @@ export function MenuEditSchema() {
} }
return ( return (
<div ref={editMenu.ref}> <div ref={editMenu.ref} className='relative'>
<Button <Button
dense dense
noBorder noBorder
@ -130,7 +130,7 @@ export function MenuEditSchema() {
icon={<IconEdit2 size='1.25rem' className={isContentEditable ? 'icon-green' : 'icon-red'} />} icon={<IconEdit2 size='1.25rem' className={isContentEditable ? 'icon-green' : 'icon-red'} />}
onClick={editMenu.toggle} onClick={editMenu.toggle}
/> />
<Dropdown isOpen={editMenu.isOpen}> <Dropdown isOpen={editMenu.isOpen} margin='mt-3'>
<DropdownButton <DropdownButton
text='Шаблоны' text='Шаблоны'
title='Создать конституенту из шаблона' title='Создать конституенту из шаблона'

View File

@ -113,7 +113,7 @@ export function MenuMain() {
} }
return ( return (
<div ref={schemaMenu.ref}> <div ref={schemaMenu.ref} className='relative'>
<Button <Button
dense dense
noBorder noBorder
@ -125,7 +125,7 @@ export function MenuMain() {
className='h-full pl-2' className='h-full pl-2'
onClick={schemaMenu.toggle} onClick={schemaMenu.toggle}
/> />
<Dropdown isOpen={schemaMenu.isOpen}> <Dropdown isOpen={schemaMenu.isOpen} margin='mt-3'>
<DropdownButton <DropdownButton
text='Поделиться' text='Поделиться'
titleHtml={tooltipText.shareItem(schema.access_policy === AccessPolicy.PUBLIC)} titleHtml={tooltipText.shareItem(schema.access_policy === AccessPolicy.PUBLIC)}

View File

@ -1,5 +1,7 @@
'use client'; 'use client';
import clsx from 'clsx';
import { SelectorButton } from '@/components/Control'; import { SelectorButton } from '@/components/Control';
import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown'; import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown';
import { type Styling } from '@/components/props'; import { type Styling } from '@/components/props';
@ -16,7 +18,7 @@ interface SelectGraphFilterProps extends Styling {
dense?: boolean; dense?: boolean;
} }
export function SelectGraphFilter({ value, dense, onChange, ...restProps }: SelectGraphFilterProps) { export function SelectGraphFilter({ value, dense, className, onChange, ...restProps }: SelectGraphFilterProps) {
const menu = useDropdown(); const menu = useDropdown();
const size = useWindowSize(); const size = useWindowSize();
@ -26,7 +28,7 @@ export function SelectGraphFilter({ value, dense, onChange, ...restProps }: Sele
} }
return ( return (
<div ref={menu.ref} {...restProps}> <div ref={menu.ref} className={clsx('relative', className)} {...restProps}>
<SelectorButton <SelectorButton
transparent transparent
tabIndex={-1} tabIndex={-1}
@ -37,7 +39,7 @@ export function SelectGraphFilter({ value, dense, onChange, ...restProps }: Sele
text={!dense && !size.isSmall ? labelCstSource(value) : undefined} text={!dense && !size.isSmall ? labelCstSource(value) : undefined}
onClick={menu.toggle} onClick={menu.toggle}
/> />
<Dropdown stretchLeft isOpen={menu.isOpen}> <Dropdown stretchLeft isOpen={menu.isOpen} margin='mt-3'>
{Object.values(DependencyMode) {Object.values(DependencyMode)
.filter(value => !isNaN(Number(value))) .filter(value => !isNaN(Number(value)))
.map((value, index) => { .map((value, index) => {

View File

@ -1,5 +1,7 @@
'use client'; 'use client';
import clsx from 'clsx';
import { SelectorButton } from '@/components/Control'; import { SelectorButton } from '@/components/Control';
import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown'; import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown';
import { type Styling } from '@/components/props'; import { type Styling } from '@/components/props';
@ -16,7 +18,7 @@ interface SelectMatchModeProps extends Styling {
dense?: boolean; dense?: boolean;
} }
export function SelectMatchMode({ value, dense, onChange, ...restProps }: SelectMatchModeProps) { export function SelectMatchMode({ value, dense, className, onChange, ...restProps }: SelectMatchModeProps) {
const menu = useDropdown(); const menu = useDropdown();
const size = useWindowSize(); const size = useWindowSize();
@ -26,7 +28,7 @@ export function SelectMatchMode({ value, dense, onChange, ...restProps }: Select
} }
return ( return (
<div ref={menu.ref} {...restProps}> <div ref={menu.ref} className={clsx('relative', className)} {...restProps}>
<SelectorButton <SelectorButton
transparent transparent
titleHtml='Настройка фильтрации <br/>по проверяемым атрибутам' titleHtml='Настройка фильтрации <br/>по проверяемым атрибутам'
@ -36,7 +38,7 @@ export function SelectMatchMode({ value, dense, onChange, ...restProps }: Select
text={dense || size.isSmall ? undefined : labelCstMatchMode(value)} text={dense || size.isSmall ? undefined : labelCstMatchMode(value)}
onClick={menu.toggle} onClick={menu.toggle}
/> />
<Dropdown stretchLeft isOpen={menu.isOpen}> <Dropdown stretchLeft isOpen={menu.isOpen} margin='mt-3'>
{Object.values(CstMatchMode) {Object.values(CstMatchMode)
.filter(value => !isNaN(Number(value))) .filter(value => !isNaN(Number(value)))
.map((value, index) => { .map((value, index) => {

View File

@ -102,7 +102,8 @@ export const globalIDs = {
email_tooltip: 'email_tooltip', email_tooltip: 'email_tooltip',
library_item_editor: 'library_item_editor', library_item_editor: 'library_item_editor',
constituenta_editor: 'constituenta_editor', constituenta_editor: 'constituenta_editor',
graph_schemas: 'graph_schemas_tooltip' graph_schemas: 'graph_schemas_tooltip',
user_dropdown: 'user_dropdown'
}; };
/** /**