mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
F: Improve layout by reworking dropdowns
This commit is contained in:
parent
442f86f99a
commit
293f1cad6f
|
@ -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>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -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='Профиль пользователя'
|
||||||
|
|
|
@ -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 })}
|
||||||
|
|
|
@ -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,43 +28,44 @@ 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',
|
||||||
'absolute mt-3',
|
'flex flex-col',
|
||||||
'flex flex-col',
|
'border rounded-md shadow-lg',
|
||||||
'border rounded-md shadow-lg',
|
'text-sm',
|
||||||
'text-sm',
|
'clr-input',
|
||||||
'clr-input',
|
{
|
||||||
{
|
'right-0': stretchLeft,
|
||||||
'right-0': stretchLeft,
|
'left-0': !stretchLeft,
|
||||||
'left-0': !stretchLeft,
|
'bottom-0': stretchTop,
|
||||||
'bottom-[2rem]': stretchTop
|
'top-full': !stretchTop
|
||||||
},
|
},
|
||||||
className
|
margin,
|
||||||
)}
|
className
|
||||||
style={{
|
)}
|
||||||
willChange: 'clip-path, transform',
|
style={{
|
||||||
transitionProperty: 'clip-path, transform',
|
willChange: 'clip-path, transform',
|
||||||
transitionDuration: `${PARAMETER.dropdownDuration}ms`,
|
transitionProperty: 'clip-path, transform',
|
||||||
transitionTimingFunction: 'ease-in-out',
|
transitionDuration: `${PARAMETER.dropdownDuration}ms`,
|
||||||
transform: isOpen ? 'translateY(0)' : 'translateY(-10%)',
|
transitionTimingFunction: 'ease-in-out',
|
||||||
clipPath: isOpen ? 'inset(0% 0% 0% 0%)' : 'inset(10% 0% 90% 0%)',
|
transform: isOpen ? 'translateY(0)' : 'translateY(-10%)',
|
||||||
...style
|
clipPath: isOpen ? 'inset(0% 0% 0% 0%)' : 'inset(10% 0% 90% 0%)',
|
||||||
}}
|
...style
|
||||||
aria-hidden={!isOpen}
|
}}
|
||||||
{...restProps}
|
aria-hidden={!isOpen}
|
||||||
>
|
{...restProps}
|
||||||
{children}
|
>
|
||||||
</div>
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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}`}
|
||||||
|
|
|
@ -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}`}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -70,8 +70,9 @@ 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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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='Редактировать'
|
||||||
|
|
|
@ -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>между схемами'
|
||||||
|
|
|
@ -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' />}
|
||||||
|
|
|
@ -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}`}
|
||||||
|
|
|
@ -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='Создать конституенту из шаблона'
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue
Block a user