R: Refactor layout definitions
This commit is contained in:
parent
aea9dececf
commit
3d63c25845
|
@ -1,3 +1,5 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { HelpTopic } from '@/features/help';
|
import { HelpTopic } from '@/features/help';
|
||||||
import { BadgeHelp } from '@/features/help/components';
|
import { BadgeHelp } from '@/features/help/components';
|
||||||
import { useRoleStore, UserRole } from '@/features/users';
|
import { useRoleStore, UserRole } from '@/features/users';
|
||||||
|
@ -20,9 +22,11 @@ interface ToolbarItemAccessProps {
|
||||||
toggleReadOnly: () => void;
|
toggleReadOnly: () => void;
|
||||||
schema: ILibraryItem;
|
schema: ILibraryItem;
|
||||||
isAttachedToOSS: boolean;
|
isAttachedToOSS: boolean;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ToolbarItemAccess({
|
export function ToolbarItemAccess({
|
||||||
|
className,
|
||||||
visible,
|
visible,
|
||||||
toggleVisible,
|
toggleVisible,
|
||||||
readOnly,
|
readOnly,
|
||||||
|
@ -40,7 +44,7 @@ export function ToolbarItemAccess({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='absolute z-bottom top-18 right-0 w-48 flex pr-2'>
|
<div className={clsx('w-46 flex', className)}>
|
||||||
<Label text='Доступ' className='self-center select-none' />
|
<Label text='Доступ' className='self-center select-none' />
|
||||||
<div className='ml-auto cc-icons'>
|
<div className='ml-auto cc-icons'>
|
||||||
<SelectAccessPolicy
|
<SelectAccessPolicy
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { urls, useConceptNavigation } from '@/app';
|
import { urls, useConceptNavigation } from '@/app';
|
||||||
import { HelpTopic } from '@/features/help';
|
import { HelpTopic } from '@/features/help';
|
||||||
import { BadgeHelp } from '@/features/help/components';
|
import { BadgeHelp } from '@/features/help/components';
|
||||||
|
@ -18,13 +20,14 @@ import { useMutatingLibrary } from '../backend/useMutatingLibrary';
|
||||||
import { MiniSelectorOSS } from './MiniSelectorOSS';
|
import { MiniSelectorOSS } from './MiniSelectorOSS';
|
||||||
|
|
||||||
interface ToolbarItemCardProps {
|
interface ToolbarItemCardProps {
|
||||||
|
className?: string;
|
||||||
onSubmit: () => void;
|
onSubmit: () => void;
|
||||||
isMutable: boolean;
|
isMutable: boolean;
|
||||||
schema: ILibraryItem;
|
schema: ILibraryItem;
|
||||||
deleteSchema: () => void;
|
deleteSchema: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ToolbarItemCard({ schema, onSubmit, isMutable, deleteSchema }: ToolbarItemCardProps) {
|
export function ToolbarItemCard({ className, schema, onSubmit, isMutable, deleteSchema }: ToolbarItemCardProps) {
|
||||||
const role = useRoleStore(state => state.role);
|
const role = useRoleStore(state => state.role);
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const { isModified } = useModificationStore();
|
const { isModified } = useModificationStore();
|
||||||
|
@ -48,7 +51,7 @@ export function ToolbarItemCard({ schema, onSubmit, isMutable, deleteSchema }: T
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='cc-tab-tools cc-icons'>
|
<div className={clsx('cc-icons', className)}>
|
||||||
{ossSelector}
|
{ossSelector}
|
||||||
{isMutable || isModified ? (
|
{isMutable || isModified ? (
|
||||||
<MiniButton
|
<MiniButton
|
||||||
|
|
|
@ -34,7 +34,13 @@ export function EditorOssCard() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ToolbarItemCard onSubmit={initiateSubmit} schema={schema} isMutable={isMutable} deleteSchema={deleteSchema} />
|
<ToolbarItemCard
|
||||||
|
className='cc-tab-tools'
|
||||||
|
onSubmit={initiateSubmit}
|
||||||
|
schema={schema}
|
||||||
|
isMutable={isMutable}
|
||||||
|
deleteSchema={deleteSchema}
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
onKeyDown={handleInput}
|
onKeyDown={handleInput}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -48,7 +54,7 @@ export function EditorOssCard() {
|
||||||
<EditorLibraryItem schema={schema} isAttachedToOSS={false} />
|
<EditorLibraryItem schema={schema} isAttachedToOSS={false} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<OssStats stats={schema.stats} />
|
<OssStats className='mt-3 md:mt-8 md:ml-5 w-56 md:w-48 mx-auto h-min' stats={schema.stats} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -78,6 +78,7 @@ export function FormOSS() {
|
||||||
error={errors.alias}
|
error={errors.alias}
|
||||||
/>
|
/>
|
||||||
<ToolbarItemAccess
|
<ToolbarItemAccess
|
||||||
|
className='absolute top-18 right-2'
|
||||||
visible={visible}
|
visible={visible}
|
||||||
toggleVisible={() => setValue('visible', !visible, { shouldDirty: true })}
|
toggleVisible={() => setValue('visible', !visible, { shouldDirty: true })}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
|
|
|
@ -6,17 +6,13 @@ import { ValueStats } from '@/components/View';
|
||||||
import { type IOperationSchemaStats } from '../../../models/oss';
|
import { type IOperationSchemaStats } from '../../../models/oss';
|
||||||
|
|
||||||
interface OssStatsProps {
|
interface OssStatsProps {
|
||||||
|
className?: string;
|
||||||
stats: IOperationSchemaStats;
|
stats: IOperationSchemaStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OssStats({ stats }: OssStatsProps) {
|
export function OssStats({ className, stats }: OssStatsProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={clsx('grid grid-cols-3 gap-1 justify-items-end', className)}>
|
||||||
className={clsx(
|
|
||||||
'mt-3 md:ml-5 md:mt-8 md:w-48 w-56 h-min mx-auto', //
|
|
||||||
'grid grid-cols-3 gap-1 justify-items-end'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div id='count_operations' className='w-fit flex gap-3 hover:cursor-default '>
|
<div id='count_operations' className='w-fit flex gap-3 hover:cursor-default '>
|
||||||
<span>Всего</span>
|
<span>Всего</span>
|
||||||
<span>{stats.count_operations}</span>
|
<span>{stats.count_operations}</span>
|
||||||
|
|
|
@ -85,11 +85,13 @@ export function EditorConstituenta() {
|
||||||
onKeyDown={handleInput}
|
onKeyDown={handleInput}
|
||||||
>
|
>
|
||||||
<ToolbarConstituenta
|
<ToolbarConstituenta
|
||||||
|
className='cc-tab-tools right-1/2 translate-x-0 xs:right-4 xs:-translate-x-1/2 md:right-1/2 md:translate-x-0 cc-animate-position'
|
||||||
activeCst={activeCst}
|
activeCst={activeCst}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onSubmit={initiateSubmit}
|
onSubmit={initiateSubmit}
|
||||||
onReset={() => setToggleReset(prev => !prev)}
|
onReset={() => setToggleReset(prev => !prev)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='mx-0 md:mx-auto pt-8 md:w-195 shrink-0 xs:pt-0'>
|
<div className='mx-0 md:mx-auto pt-8 md:w-195 shrink-0 xs:pt-0'>
|
||||||
{activeCst ? (
|
{activeCst ? (
|
||||||
<FormConstituenta
|
<FormConstituenta
|
||||||
|
@ -102,7 +104,11 @@ export function EditorConstituenta() {
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<ViewConstituents isMounted={showList} isBottom={isNarrow} />
|
<ViewConstituents
|
||||||
|
className={isNarrow ? 'mt-3 mx-6 overflow-hidden' : 'mt-9 h-fit overflow-visible'}
|
||||||
|
isMounted={showList}
|
||||||
|
isBottom={isNarrow}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { MiniButton } from '@/components/Control';
|
|
||||||
import { IconEdit } from '@/components/Icons';
|
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
|
||||||
import { useModificationStore } from '@/stores/modification';
|
|
||||||
import { tooltipText } from '@/utils/labels';
|
|
||||||
|
|
||||||
import { useMutatingRSForm } from '../../../backend/useMutatingRSForm';
|
|
||||||
import { type IConstituenta } from '../../../models/rsform';
|
|
||||||
import { useRSEdit } from '../RSEditContext';
|
|
||||||
|
|
||||||
interface EditorControlsProps {
|
|
||||||
constituenta: IConstituenta;
|
|
||||||
disabled: boolean;
|
|
||||||
onEditTerm: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EditorControls({ constituenta, disabled, onEditTerm }: EditorControlsProps) {
|
|
||||||
const schema = useRSEdit().schema;
|
|
||||||
const { isModified } = useModificationStore();
|
|
||||||
const isProcessing = useMutatingRSForm();
|
|
||||||
|
|
||||||
const showRenameCst = useDialogsStore(state => state.showRenameCst);
|
|
||||||
|
|
||||||
function handleRenameCst() {
|
|
||||||
showRenameCst({ schema: schema, target: constituenta });
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='absolute z-pop top-0 left-19 flex select-none'>
|
|
||||||
{!disabled || isProcessing ? (
|
|
||||||
<MiniButton
|
|
||||||
title={isModified ? tooltipText.unsaved : `Редактировать словоформы термина`}
|
|
||||||
noHover
|
|
||||||
onClick={onEditTerm}
|
|
||||||
icon={<IconEdit size='1rem' className='icon-primary' />}
|
|
||||||
disabled={isModified}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<div
|
|
||||||
className={clsx(
|
|
||||||
'pt-1 sm:pl-5 pl-1',
|
|
||||||
'text-sm font-medium whitespace-nowrap',
|
|
||||||
'select-text cursor-default',
|
|
||||||
disabled && !isProcessing && 'pl-6 sm:pl-11'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span>Имя </span>
|
|
||||||
<span className='ml-1'>{constituenta?.alias ?? ''}</span>
|
|
||||||
</div>
|
|
||||||
{!disabled || isProcessing ? (
|
|
||||||
<MiniButton
|
|
||||||
noHover
|
|
||||||
title={isModified ? tooltipText.unsaved : 'Переименовать конституенту'}
|
|
||||||
onClick={handleRenameCst}
|
|
||||||
icon={<IconEdit size='1rem' className='icon-primary' />}
|
|
||||||
disabled={isModified}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -6,13 +6,13 @@ import { Controller, useForm } from 'react-hook-form';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
|
||||||
import { SubmitButton } from '@/components/Control';
|
import { MiniButton, SubmitButton } from '@/components/Control';
|
||||||
import { IconChild, IconPredecessor, IconSave } from '@/components/Icons';
|
import { IconChild, IconEdit, IconPredecessor, IconSave } from '@/components/Icons';
|
||||||
import { TextArea } from '@/components/Input';
|
import { TextArea } from '@/components/Input';
|
||||||
import { Indicator } from '@/components/View';
|
import { Indicator } from '@/components/View';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
import { useModificationStore } from '@/stores/modification';
|
import { useModificationStore } from '@/stores/modification';
|
||||||
import { errorMsg } from '@/utils/labels';
|
import { errorMsg, tooltipText } from '@/utils/labels';
|
||||||
import { promptUnsaved } from '@/utils/utils';
|
import { promptUnsaved } from '@/utils/utils';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -30,8 +30,6 @@ import { type IConstituenta, type IRSForm } from '../../../models/rsform';
|
||||||
import { isBaseSet, isBasicConcept, isFunctional } from '../../../models/rsformAPI';
|
import { isBaseSet, isBasicConcept, isFunctional } from '../../../models/rsformAPI';
|
||||||
import { EditorRSExpression } from '../EditorRSExpression';
|
import { EditorRSExpression } from '../EditorRSExpression';
|
||||||
|
|
||||||
import { EditorControls } from './EditorControls';
|
|
||||||
|
|
||||||
interface FormConstituentaProps {
|
interface FormConstituentaProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
|
@ -57,6 +55,7 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
||||||
const { cstUpdate } = useCstUpdate();
|
const { cstUpdate } = useCstUpdate();
|
||||||
const showTypification = useDialogsStore(state => state.showShowTypeGraph);
|
const showTypification = useDialogsStore(state => state.showShowTypeGraph);
|
||||||
const showEditTerm = useDialogsStore(state => state.showEditWordForms);
|
const showEditTerm = useDialogsStore(state => state.showEditWordForms);
|
||||||
|
const showRenameCst = useDialogsStore(state => state.showRenameCst);
|
||||||
|
|
||||||
const [localParse, setLocalParse] = useState<IExpressionParseDTO | null>(null);
|
const [localParse, setLocalParse] = useState<IExpressionParseDTO | null>(null);
|
||||||
|
|
||||||
|
@ -129,9 +128,38 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
||||||
showEditTerm({ itemID: schema.id, target: activeCst });
|
showEditTerm({ itemID: schema.id, target: activeCst });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleRenameCst() {
|
||||||
|
showRenameCst({ schema: schema, target: activeCst });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id={id} className='relative cc-column mt-1 px-6 py-1' onSubmit={event => void handleSubmit(onSubmit)(event)}>
|
<form id={id} className='relative cc-column mt-1 px-6 py-1' onSubmit={event => void handleSubmit(onSubmit)(event)}>
|
||||||
<EditorControls disabled={disabled} constituenta={activeCst} onEditTerm={handleEditTermForms} />
|
{!disabled || isProcessing ? (
|
||||||
|
<MiniButton
|
||||||
|
title={isModified ? tooltipText.unsaved : `Редактировать словоформы термина`}
|
||||||
|
noHover
|
||||||
|
onClick={handleEditTermForms}
|
||||||
|
className='absolute z-pop top-0 left-[calc(7ch+4px)]'
|
||||||
|
icon={<IconEdit size='1rem' className='icon-primary' />}
|
||||||
|
disabled={isModified}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<div className='absolute z-pop top-0 left-[calc(7ch+4px+3rem)] flex select-none'>
|
||||||
|
<div className='pt-1 text-sm font-medium whitespace-nowrap select-text cursor-default'>
|
||||||
|
<span>Имя </span>
|
||||||
|
<span className='ml-1'>{activeCst?.alias ?? ''}</span>
|
||||||
|
</div>
|
||||||
|
{!disabled || isProcessing ? (
|
||||||
|
<MiniButton
|
||||||
|
noHover
|
||||||
|
title={isModified ? tooltipText.unsaved : 'Переименовать конституенту'}
|
||||||
|
onClick={handleRenameCst}
|
||||||
|
icon={<IconEdit size='1rem' className='icon-primary' />}
|
||||||
|
disabled={isModified}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import { type IConstituenta } from '../../../models/rsform';
|
||||||
import { RSTabID, useRSEdit } from '../RSEditContext';
|
import { RSTabID, useRSEdit } from '../RSEditContext';
|
||||||
|
|
||||||
interface ToolbarConstituentaProps {
|
interface ToolbarConstituentaProps {
|
||||||
|
className?: string;
|
||||||
activeCst: IConstituenta | null;
|
activeCst: IConstituenta | null;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ interface ToolbarConstituentaProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ToolbarConstituenta({
|
export function ToolbarConstituenta({
|
||||||
|
className,
|
||||||
activeCst,
|
activeCst,
|
||||||
disabled,
|
disabled,
|
||||||
|
|
||||||
|
@ -78,14 +80,7 @@ export function ToolbarConstituenta({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={clsx('px-1 rounded-b-2xl cc-blur cc-icons cc-animate-position outline-hidden', className)}>
|
||||||
className={clsx(
|
|
||||||
'absolute z-pop right-1/2 translate-x-0 xs:right-4 xs:-translate-x-1/2 md:right-1/2 md:translate-x-0',
|
|
||||||
'px-1 rounded-b-2xl',
|
|
||||||
'cc-blur',
|
|
||||||
'cc-tab-tools cc-icons cc-animate-position outline-hidden'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{schema.oss.length > 0 ? (
|
{schema.oss.length > 0 ? (
|
||||||
<MiniSelectorOSS
|
<MiniSelectorOSS
|
||||||
items={schema.oss}
|
items={schema.oss}
|
||||||
|
|
|
@ -155,9 +155,15 @@ export function EditorRSExpression({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative cc-fade-in'>
|
<div className='relative cc-fade-in'>
|
||||||
<ToolbarRSExpression disabled={disabled} showAST={handleShowAST} showTypeGraph={onShowTypeGraph} />
|
<ToolbarRSExpression
|
||||||
|
className='absolute -top-2 right-0'
|
||||||
|
disabled={disabled}
|
||||||
|
showAST={handleShowAST}
|
||||||
|
showTypeGraph={onShowTypeGraph}
|
||||||
|
/>
|
||||||
|
|
||||||
<StatusBar
|
<StatusBar
|
||||||
|
className='absolute -top-2 right-1/2 translate-x-1/2'
|
||||||
processing={isPending}
|
processing={isPending}
|
||||||
isModified={isModified}
|
isModified={isModified}
|
||||||
activeCst={activeCst}
|
activeCst={activeCst}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { ExpressionStatus, type IConstituenta } from '../../../models/rsform';
|
||||||
import { inferStatus } from '../../../models/rsformAPI';
|
import { inferStatus } from '../../../models/rsformAPI';
|
||||||
|
|
||||||
interface StatusBarProps {
|
interface StatusBarProps {
|
||||||
|
className?: string;
|
||||||
processing: boolean;
|
processing: boolean;
|
||||||
isModified: boolean;
|
isModified: boolean;
|
||||||
parseData: IExpressionParseDTO | null;
|
parseData: IExpressionParseDTO | null;
|
||||||
|
@ -25,7 +26,7 @@ interface StatusBarProps {
|
||||||
onAnalyze: () => void;
|
onAnalyze: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function StatusBar({ isModified, processing, activeCst, parseData, onAnalyze }: StatusBarProps) {
|
export function StatusBar({ className, isModified, processing, activeCst, parseData, onAnalyze }: StatusBarProps) {
|
||||||
const status = (() => {
|
const status = (() => {
|
||||||
if (isModified) {
|
if (isModified) {
|
||||||
return ExpressionStatus.UNKNOWN;
|
return ExpressionStatus.UNKNOWN;
|
||||||
|
@ -38,12 +39,7 @@ export function StatusBar({ isModified, processing, activeCst, parseData, onAnal
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={clsx('pl-34 xs:pl-8 flex gap-1', className)}>
|
||||||
className={clsx(
|
|
||||||
'absolute z-pop -top-2 right-1/2 translate-x-1/2 w-fit', //
|
|
||||||
'pl-34 xs:pl-8 flex gap-1'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { MiniButton } from '@/components/Control';
|
import { MiniButton } from '@/components/Control';
|
||||||
import { IconControls, IconTree, IconTypeGraph } from '@/components/Icons';
|
import { IconControls, IconTree, IconTypeGraph } from '@/components/Icons';
|
||||||
import { usePreferencesStore } from '@/stores/preferences';
|
import { usePreferencesStore } from '@/stores/preferences';
|
||||||
|
@ -5,18 +7,19 @@ import { usePreferencesStore } from '@/stores/preferences';
|
||||||
import { useMutatingRSForm } from '../../../backend/useMutatingRSForm';
|
import { useMutatingRSForm } from '../../../backend/useMutatingRSForm';
|
||||||
|
|
||||||
interface ToolbarRSExpressionProps {
|
interface ToolbarRSExpressionProps {
|
||||||
|
className?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
showAST: (event: React.MouseEvent<Element>) => void;
|
showAST: (event: React.MouseEvent<Element>) => void;
|
||||||
showTypeGraph: (event: React.MouseEvent<Element>) => void;
|
showTypeGraph: (event: React.MouseEvent<Element>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ToolbarRSExpression({ disabled, showTypeGraph, showAST }: ToolbarRSExpressionProps) {
|
export function ToolbarRSExpression({ className, disabled, showTypeGraph, showAST }: ToolbarRSExpressionProps) {
|
||||||
const isProcessing = useMutatingRSForm();
|
const isProcessing = useMutatingRSForm();
|
||||||
const showControls = usePreferencesStore(state => state.showExpressionControls);
|
const showControls = usePreferencesStore(state => state.showExpressionControls);
|
||||||
const toggleControls = usePreferencesStore(state => state.toggleShowExpressionControls);
|
const toggleControls = usePreferencesStore(state => state.toggleShowExpressionControls);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='absolute z-pop -top-2 right-0 cc-icons'>
|
<div className={clsx('cc-icons', className)}>
|
||||||
{!disabled || isProcessing ? (
|
{!disabled || isProcessing ? (
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Отображение специальной клавиатуры'
|
title='Отображение специальной клавиатуры'
|
||||||
|
|
|
@ -42,14 +42,24 @@ export function EditorRSFormCard() {
|
||||||
'flex flex-row flex-wrap px-6 pt-8'
|
'flex flex-row flex-wrap px-6 pt-8'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<ToolbarItemCard onSubmit={initiateSubmit} schema={schema} isMutable={isMutable} deleteSchema={deleteSchema} />
|
<ToolbarItemCard
|
||||||
|
className='cc-tab-tools'
|
||||||
|
onSubmit={initiateSubmit}
|
||||||
|
schema={schema}
|
||||||
|
isMutable={isMutable}
|
||||||
|
deleteSchema={deleteSchema}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className='cc-column shrink'>
|
<div className='cc-column shrink'>
|
||||||
<FormRSForm />
|
<FormRSForm />
|
||||||
<EditorLibraryItem schema={schema} isAttachedToOSS={isAttachedToOSS} />
|
<EditorLibraryItem schema={schema} isAttachedToOSS={isAttachedToOSS} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<RSFormStats stats={schema.stats} isArchive={isArchive} />
|
<RSFormStats
|
||||||
|
className='mt-3 md:mt-8 md:ml-5 w-80 md:w-56 mx-auto h-min'
|
||||||
|
stats={schema.stats}
|
||||||
|
isArchive={isArchive}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,17 +90,13 @@ export function FormRSForm() {
|
||||||
disabled={!isContentEditable}
|
disabled={!isContentEditable}
|
||||||
error={errors.alias}
|
error={errors.alias}
|
||||||
/>
|
/>
|
||||||
<div className='relative flex flex-col'>
|
<div className='relative flex flex-col gap-2'>
|
||||||
<ToolbarVersioning blockReload={schema.oss.length > 0} />
|
<ToolbarVersioning
|
||||||
<ToolbarItemAccess
|
className='absolute -top-2 right-2' //
|
||||||
visible={visible}
|
blockReload={schema.oss.length > 0}
|
||||||
toggleVisible={() => setValue('visible', !visible, { shouldDirty: true })}
|
|
||||||
readOnly={readOnly}
|
|
||||||
toggleReadOnly={() => setValue('read_only', !readOnly, { shouldDirty: true })}
|
|
||||||
schema={schema}
|
|
||||||
isAttachedToOSS={isAttachedToOSS}
|
|
||||||
/>
|
/>
|
||||||
<Label text='Версия' className='mb-2 select-none' />
|
|
||||||
|
<Label text='Версия' className='select-none w-fit' />
|
||||||
<SelectVersion
|
<SelectVersion
|
||||||
id='schema_version'
|
id='schema_version'
|
||||||
className='select-none'
|
className='select-none'
|
||||||
|
@ -108,6 +104,16 @@ export function FormRSForm() {
|
||||||
items={schema.versions}
|
items={schema.versions}
|
||||||
onChange={handleSelectVersion}
|
onChange={handleSelectVersion}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ToolbarItemAccess
|
||||||
|
className='absolute top-18 right-2'
|
||||||
|
visible={visible}
|
||||||
|
toggleVisible={() => setValue('visible', !visible, { shouldDirty: true })}
|
||||||
|
readOnly={readOnly}
|
||||||
|
toggleReadOnly={() => setValue('read_only', !readOnly, { shouldDirty: true })}
|
||||||
|
schema={schema}
|
||||||
|
isAttachedToOSS={isAttachedToOSS}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -24,18 +24,14 @@ import { ValueStats } from '@/components/View';
|
||||||
import { type IRSFormStats } from '../../../models/rsform';
|
import { type IRSFormStats } from '../../../models/rsform';
|
||||||
|
|
||||||
interface RSFormStatsProps {
|
interface RSFormStatsProps {
|
||||||
|
className?: string;
|
||||||
isArchive: boolean;
|
isArchive: boolean;
|
||||||
stats: IRSFormStats;
|
stats: IRSFormStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RSFormStats({ stats, isArchive }: RSFormStatsProps) {
|
export function RSFormStats({ className, stats, isArchive }: RSFormStatsProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={clsx('grid grid-cols-4 gap-1 justify-items-end', className)}>
|
||||||
className={clsx(
|
|
||||||
'mt-3 md:ml-5 md:mt-8 md:w-56 w-80 h-min mx-auto', //
|
|
||||||
'grid grid-cols-4 gap-1 justify-items-end'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div id='count_all' className='col-span-2 w-fit flex gap-3 hover:cursor-default '>
|
<div id='count_all' className='col-span-2 w-fit flex gap-3 hover:cursor-default '>
|
||||||
<span>Всего</span>
|
<span>Всего</span>
|
||||||
<span>{stats.count_all}</span>
|
<span>{stats.count_all}</span>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { HelpTopic } from '@/features/help';
|
import { HelpTopic } from '@/features/help';
|
||||||
import { BadgeHelp } from '@/features/help/components';
|
import { BadgeHelp } from '@/features/help/components';
|
||||||
import { useVersionRestore } from '@/features/library/backend/useVersionRestore';
|
import { useVersionRestore } from '@/features/library/backend/useVersionRestore';
|
||||||
|
@ -15,9 +17,10 @@ import { useRSEdit } from '../RSEditContext';
|
||||||
|
|
||||||
interface ToolbarVersioningProps {
|
interface ToolbarVersioningProps {
|
||||||
blockReload?: boolean;
|
blockReload?: boolean;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ToolbarVersioning({ blockReload }: ToolbarVersioningProps) {
|
export function ToolbarVersioning({ blockReload, className }: ToolbarVersioningProps) {
|
||||||
const { isModified } = useModificationStore();
|
const { isModified } = useModificationStore();
|
||||||
const { versionRestore } = useVersionRestore();
|
const { versionRestore } = useVersionRestore();
|
||||||
const { schema, isMutable, isContentEditable, navigateVersion, activeVersion, selected } = useRSEdit();
|
const { schema, isMutable, isContentEditable, navigateVersion, activeVersion, selected } = useRSEdit();
|
||||||
|
@ -55,7 +58,7 @@ export function ToolbarVersioning({ blockReload }: ToolbarVersioningProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='absolute z-bottom -top-2 right-0 pr-2 cc-icons'>
|
<div className={clsx('cc-icons', className)}>
|
||||||
{isMutable ? (
|
{isMutable ? (
|
||||||
<>
|
<>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
|
|
|
@ -127,7 +127,9 @@ export function EditorRSList() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div tabIndex={-1} onKeyDown={handleKeyDown} className='relative cc-fade-in pt-8'>
|
<div tabIndex={-1} onKeyDown={handleKeyDown} className='relative cc-fade-in pt-8'>
|
||||||
{isContentEditable ? <ToolbarRSList /> : null}
|
{isContentEditable ? (
|
||||||
|
<ToolbarRSList className='cc-tab-tools right-4 md:right-1/2 -translate-x-1/2 md:translate-x-0 cc-animate-position' />
|
||||||
|
) : null}
|
||||||
{isContentEditable ? (
|
{isContentEditable ? (
|
||||||
<div className='flex items-center border-b'>
|
<div className='flex items-center border-b'>
|
||||||
<div className='px-2'>
|
<div className='px-2'>
|
||||||
|
|
|
@ -24,7 +24,11 @@ import { IconCstType } from '../../../components/IconCstType';
|
||||||
import { getCstTypeShortcut, labelCstType } from '../../../labels';
|
import { getCstTypeShortcut, labelCstType } from '../../../labels';
|
||||||
import { useRSEdit } from '../RSEditContext';
|
import { useRSEdit } from '../RSEditContext';
|
||||||
|
|
||||||
export function ToolbarRSList() {
|
interface ToolbarRSListProps {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ToolbarRSList({ className }: ToolbarRSListProps) {
|
||||||
const isProcessing = useMutatingRSForm();
|
const isProcessing = useMutatingRSForm();
|
||||||
const insertMenu = useDropdown();
|
const insertMenu = useDropdown();
|
||||||
const {
|
const {
|
||||||
|
@ -42,13 +46,7 @@ export function ToolbarRSList() {
|
||||||
} = useRSEdit();
|
} = useRSEdit();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={clsx('cc-icons items-start outline-hidden', className)}>
|
||||||
className={clsx(
|
|
||||||
'cc-tab-tools right-4 md:right-1/2 -translate-x-1/2 md:translate-x-0',
|
|
||||||
'cc-icons items-start',
|
|
||||||
'outline-hidden cc-animate-position'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{schema.oss.length > 0 ? (
|
{schema.oss.length > 0 ? (
|
||||||
<MiniSelectorOSS
|
<MiniSelectorOSS
|
||||||
items={schema.oss}
|
items={schema.oss}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import {
|
||||||
useReactFlow,
|
useReactFlow,
|
||||||
useStoreApi
|
useStoreApi
|
||||||
} from 'reactflow';
|
} from 'reactflow';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { useMainHeight } from '@/stores/appLayout';
|
import { useMainHeight } from '@/stores/appLayout';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
@ -181,13 +180,7 @@ export function TGFlow() {
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div className='absolute z-pop top-18 sm:top-16 left-2 sm:left-3 w-54 flex flex-col pointer-events-none'>
|
||||||
className={clsx(
|
|
||||||
'absolute z-pop top-18 sm:top-16 left-2 sm:left-3 w-54',
|
|
||||||
'flex flex-col',
|
|
||||||
'pointer-events-none'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span className='px-2 pb-1 select-none whitespace-nowrap cc-blur rounded-xl'>
|
<span className='px-2 pb-1 select-none whitespace-nowrap cc-blur rounded-xl'>
|
||||||
Выбор {selected.length} из {schema.stats?.count_all ?? 0}
|
Выбор {selected.length} из {schema.stats?.count_all ?? 0}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -15,21 +15,26 @@ import { TableSideConstituents } from './TableSideConstituents';
|
||||||
const COLUMN_DENSE_SEARCH_THRESHOLD = 1100;
|
const COLUMN_DENSE_SEARCH_THRESHOLD = 1100;
|
||||||
|
|
||||||
interface ViewConstituentsProps {
|
interface ViewConstituentsProps {
|
||||||
|
className?: string;
|
||||||
isBottom?: boolean;
|
isBottom?: boolean;
|
||||||
isMounted: boolean;
|
isMounted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ViewConstituents({ isBottom, isMounted }: ViewConstituentsProps) {
|
export function ViewConstituents({ className, isBottom, isMounted }: ViewConstituentsProps) {
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
const role = useRoleStore(state => state.role);
|
const role = useRoleStore(state => state.role);
|
||||||
const listHeight = useFitHeight(!isBottom ? '8.2rem' : role !== UserRole.READER ? '42rem' : '35rem', '10rem');
|
const listHeight = useFitHeight(!isBottom ? '8.2rem' : role !== UserRole.READER ? '42rem' : '35rem', '10rem');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
className={clsx('border', {
|
className={clsx(
|
||||||
'mt-9 rounded-l-md rounded-r-none h-fit overflow-visible': !isBottom,
|
'border',
|
||||||
'mt-3 mx-6 rounded-md overflow-hidden': isBottom
|
{
|
||||||
})}
|
'rounded-l-md rounded-r-none': !isBottom,
|
||||||
|
'rounded-md': isBottom
|
||||||
|
},
|
||||||
|
className
|
||||||
|
)}
|
||||||
style={{
|
style={{
|
||||||
willChange: 'opacity, max-width',
|
willChange: 'opacity, max-width',
|
||||||
transitionProperty: 'opacity, max-width',
|
transitionProperty: 'opacity, max-width',
|
||||||
|
|
|
@ -35,7 +35,7 @@ export function EditorPassword() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
className='max-w-64 px-6 py-2 flex flex-col justify-between border-l-2'
|
className='max-w-64 px-6 py-2 flex flex-col gap-2 justify-between border-l-2'
|
||||||
onSubmit={event => void handleSubmit(onSubmit)(event)}
|
onSubmit={event => void handleSubmit(onSubmit)(event)}
|
||||||
onChange={resetErrors}
|
onChange={resetErrors}
|
||||||
>
|
>
|
||||||
|
@ -69,7 +69,7 @@ export function EditorPassword() {
|
||||||
/>
|
/>
|
||||||
{serverError ? <ServerError error={serverError} /> : null}
|
{serverError ? <ServerError error={serverError} /> : null}
|
||||||
</div>
|
</div>
|
||||||
<SubmitButton text='Сменить пароль' className='self-center mt-2' loading={isPending} />
|
<SubmitButton text='Сменить пароль' className='self-center' loading={isPending} />
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user