F: Add hide button for stats

This commit is contained in:
Ivan 2025-06-24 22:13:26 +03:00
parent dae47716ea
commit 2d2c0290e3
16 changed files with 162 additions and 56 deletions

View File

@ -25,6 +25,10 @@ export { LuQrCode as IconQR } from 'react-icons/lu';
export { LuFilterX as IconFilterReset } from 'react-icons/lu'; export { LuFilterX as IconFilterReset } from 'react-icons/lu';
export {BiDownArrowCircle as IconOpenList } from 'react-icons/bi'; export {BiDownArrowCircle as IconOpenList } from 'react-icons/bi';
export { LuTriangleAlert as IconAlert } from 'react-icons/lu'; export { LuTriangleAlert as IconAlert } from 'react-icons/lu';
export { LuPanelLeftOpen as IconLeftOpen } from 'react-icons/lu';
export { LuPanelLeftClose as IconLeftClose } from 'react-icons/lu';
export { LuPanelBottomOpen as IconBottomOpen } from 'react-icons/lu';
export { LuPanelBottomClose as IconBottomClose } from 'react-icons/lu';
// ===== UI elements ======= // ===== UI elements =======
export { BiX as IconClose } from 'react-icons/bi'; export { BiX as IconClose } from 'react-icons/bi';
@ -97,9 +101,7 @@ export { LuDatabase as IconDatabase } from 'react-icons/lu';
export { LuView as IconDBStructure } from 'react-icons/lu'; export { LuView as IconDBStructure } from 'react-icons/lu';
export { LuPlaneTakeoff as IconRESTapi } from 'react-icons/lu'; export { LuPlaneTakeoff as IconRESTapi } from 'react-icons/lu';
export { LuImage as IconImage } from 'react-icons/lu'; export { LuImage as IconImage } from 'react-icons/lu';
export { TbColumns as IconList } from 'react-icons/tb';
export { GoVersions as IconVersions } from 'react-icons/go'; export { GoVersions as IconVersions } from 'react-icons/go';
export { TbColumnsOff as IconListOff } from 'react-icons/tb';
export { LuAtSign as IconTerm } from 'react-icons/lu'; export { LuAtSign as IconTerm } from 'react-icons/lu';
export { LuSubscript as IconAlias } from 'react-icons/lu'; export { LuSubscript as IconAlias } from 'react-icons/lu';
export { TbMathFunction as IconFormula } from 'react-icons/tb'; export { TbMathFunction as IconFormula } from 'react-icons/tb';

View File

@ -1,9 +1,8 @@
import { import {
IconClone,
IconDestroy, IconDestroy,
IconDownload,
IconEditor, IconEditor,
IconImmutable, IconImmutable,
IconLeftOpen,
IconOSS, IconOSS,
IconOwner, IconOwner,
IconPublic, IconPublic,
@ -49,15 +48,12 @@ export function HelpRSCard() {
<li> <li>
<IconImmutable className='inline-icon' /> Неизменные схемы <IconImmutable className='inline-icon' /> Неизменные схемы
</li> </li>
<li>
<IconClone className='inline-icon icon-green' /> Клонировать создать копию схемы
</li>
<li>
<IconDownload className='inline-icon' /> Загрузить/Выгрузить взаимодействие с Экстеор
</li>
<li> <li>
<IconDestroy className='inline-icon icon-red' /> Удалить полностью удаляет схему из базы Портала <IconDestroy className='inline-icon icon-red' /> Удалить полностью удаляет схему из базы Портала
</li> </li>
<li>
<IconLeftOpen className='inline-icon' /> Отображение статистики
</li>
</ul> </ul>
</div> </div>
); );

View File

@ -5,7 +5,7 @@ import {
IconEdit, IconEdit,
IconFilter, IconFilter,
IconKeyboard, IconKeyboard,
IconList, IconLeftOpen,
IconMoveDown, IconMoveDown,
IconMoveUp, IconMoveUp,
IconNewItem, IconNewItem,
@ -37,7 +37,7 @@ export function HelpRSEditor() {
<IconPredecessor className='inline-icon' /> переход к исходной <IconPredecessor className='inline-icon' /> переход к исходной
</li> </li>
<li> <li>
<IconList className='inline-icon' /> список конституент <IconLeftOpen className='inline-icon' /> список конституент
</li> </li>
<li> <li>
<IconSave className='inline-icon' /> сохранить: <kbd>Ctrl + S</kbd> <IconSave className='inline-icon' /> сохранить: <kbd>Ctrl + S</kbd>

View File

@ -0,0 +1,23 @@
import { type DomIconProps, IconBottomClose, IconBottomOpen, IconLeftClose, IconLeftOpen } from '@/components/icons';
/** Icon for sidebar visibility. */
export function IconShowSidebar({
value,
size = '1.25rem',
className,
isBottom
}: DomIconProps<boolean> & { isBottom: boolean }) {
if (isBottom) {
if (value) {
return <IconBottomClose size={size} className={className ?? 'icon-primary'} />;
} else {
return <IconBottomOpen size={size} className={className ?? 'icon-primary'} />;
}
} else {
if (value) {
return <IconLeftClose size={size} className={className ?? 'icon-primary'} />;
} else {
return <IconLeftOpen size={size} className={className ?? 'icon-primary'} />;
}
}
}

View File

@ -10,29 +10,46 @@ import { MiniButton } from '@/components/control';
import { IconDestroy, IconSave, IconShare } from '@/components/icons'; import { IconDestroy, IconSave, IconShare } from '@/components/icons';
import { cn } from '@/components/utils'; import { cn } from '@/components/utils';
import { useModificationStore } from '@/stores/modification'; import { useModificationStore } from '@/stores/modification';
import { usePreferencesStore } from '@/stores/preferences';
import { tooltipText } from '@/utils/labels'; import { tooltipText } from '@/utils/labels';
import { prepareTooltip, sharePage } from '@/utils/utils'; import { prepareTooltip, sharePage } from '@/utils/utils';
import { AccessPolicy, type ILibraryItem, LibraryItemType } from '../backend/types'; import { AccessPolicy, type ILibraryItem, LibraryItemType } from '../backend/types';
import { useMutatingLibrary } from '../backend/use-mutating-library'; import { useMutatingLibrary } from '../backend/use-mutating-library';
import { IconShowSidebar } from './icon-show-sidebar';
import { MiniSelectorOSS } from './mini-selector-oss'; import { MiniSelectorOSS } from './mini-selector-oss';
interface ToolbarItemCardProps { interface ToolbarItemCardProps {
className?: string; className?: string;
isNarrow: boolean;
onSubmit: () => void; onSubmit: () => void;
isMutable: boolean; isMutable: boolean;
schema: ILibraryItem; schema: ILibraryItem;
deleteSchema: () => void; deleteSchema: () => void;
} }
export function ToolbarItemCard({ className, schema, onSubmit, isMutable, deleteSchema }: ToolbarItemCardProps) { export function ToolbarItemCard({
className,
isNarrow,
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();
const isProcessing = useMutatingLibrary(); const isProcessing = useMutatingLibrary();
const canSave = isModified && !isProcessing; const canSave = isModified && !isProcessing;
const showRSFormStats = usePreferencesStore(state => state.showRSFormStats);
const toggleShowRSFormStats = usePreferencesStore(state => state.toggleShowRSFormStats);
const showOSSStats = usePreferencesStore(state => state.showOSSStats);
const toggleShowOSSStats = usePreferencesStore(state => state.toggleShowOSSStats);
const isRSForm = schema.item_type === LibraryItemType.RSFORM;
const isOSS = schema.item_type === LibraryItemType.OSS;
const ossSelector = (() => { const ossSelector = (() => {
if (schema.item_type !== LibraryItemType.RSFORM) { if (schema.item_type !== LibraryItemType.RSFORM) {
return null; return null;
@ -76,6 +93,15 @@ export function ToolbarItemCard({ className, schema, onSubmit, isMutable, delete
disabled={!isMutable || isProcessing || role < UserRole.OWNER} disabled={!isMutable || isProcessing || role < UserRole.OWNER}
/> />
) : null} ) : null}
{(isRSForm || isOSS) && (
<MiniButton
title='Отображение статистики'
icon={
<IconShowSidebar value={isRSForm ? showRSFormStats : showOSSStats} isBottom={isNarrow} size='1.25rem' />
}
onClick={isRSForm ? toggleShowRSFormStats : toggleShowOSSStats}
/>
)}
<BadgeHelp topic={HelpTopic.UI_RS_CARD} offset={4} /> <BadgeHelp topic={HelpTopic.UI_RS_CARD} offset={4} />
</div> </div>
); );

View File

@ -4,7 +4,9 @@ import clsx from 'clsx';
import { EditorLibraryItem, ToolbarItemCard } from '@/features/library/components'; import { EditorLibraryItem, ToolbarItemCard } from '@/features/library/components';
import { useWindowSize } from '@/hooks/use-window-size';
import { useModificationStore } from '@/stores/modification'; import { useModificationStore } from '@/stores/modification';
import { usePreferencesStore } from '@/stores/preferences';
import { globalIDs } from '@/utils/constants'; import { globalIDs } from '@/utils/constants';
import { useOssEdit } from '../oss-edit-context'; import { useOssEdit } from '../oss-edit-context';
@ -12,9 +14,14 @@ import { useOssEdit } from '../oss-edit-context';
import { FormOSS } from './form-oss'; import { FormOSS } from './form-oss';
import { OssStats } from './oss-stats'; import { OssStats } from './oss-stats';
const SIDELIST_LAYOUT_THRESHOLD = 768; // px
export function EditorOssCard() { export function EditorOssCard() {
const { schema, isMutable, deleteSchema } = useOssEdit(); const { schema, isMutable, deleteSchema } = useOssEdit();
const { isModified } = useModificationStore(); const { isModified } = useModificationStore();
const showOSSStats = usePreferencesStore(state => state.showOSSStats);
const windowSize = useWindowSize();
const isNarrow = !!windowSize.width && windowSize.width <= SIDELIST_LAYOUT_THRESHOLD;
function initiateSubmit() { function initiateSubmit() {
const element = document.getElementById(globalIDs.library_item_editor) as HTMLFormElement; const element = document.getElementById(globalIDs.library_item_editor) as HTMLFormElement;
@ -33,25 +40,29 @@ export function EditorOssCard() {
} }
return ( return (
<> <div
onKeyDown={handleInput}
className={clsx(
'relative md:w-fit md:max-w-fit max-w-128',
'flex px-6 pt-8',
isNarrow && 'flex-col md:items-center'
)}
>
<ToolbarItemCard <ToolbarItemCard
className='cc-tab-tools' className='cc-tab-tools'
onSubmit={initiateSubmit} onSubmit={initiateSubmit}
schema={schema} schema={schema}
isMutable={isMutable} isMutable={isMutable}
deleteSchema={deleteSchema} deleteSchema={deleteSchema}
isNarrow={isNarrow}
/> />
<div
onKeyDown={handleInput}
className={clsx('md:max-w-fit max-w-128 min-w-fit', 'flex flex-row flex-wrap pt-8 px-6 justify-center')}
>
<div className='cc-column px-3'>
<FormOSS key={schema.id} />
<EditorLibraryItem schema={schema} isAttachedToOSS={false} />
</div>
<OssStats className='mt-3 md:mt-8 md:ml-5 w-80 md:w-56 mx-auto h-min' stats={schema.stats} /> <div className='cc-column px-3 mx-0 md:mx-auto'>
<FormOSS key={schema.id} />
<EditorLibraryItem schema={schema} isAttachedToOSS={false} />
</div> </div>
</>
<OssStats className='w-80 md:w-56 mt-3 md:mt-8 md:ml-5 mx-auto' stats={schema.stats} isMounted={showOSSStats} />
</div>
); );
} }

View File

@ -13,12 +13,20 @@ import { type IOperationSchemaStats } from '../../../models/oss';
interface OssStatsProps { interface OssStatsProps {
className?: string; className?: string;
isMounted: boolean;
stats: IOperationSchemaStats; stats: IOperationSchemaStats;
} }
export function OssStats({ className, stats }: OssStatsProps) { export function OssStats({ className, isMounted, stats }: OssStatsProps) {
return ( return (
<div className={cn('grid grid-cols-4 gap-1 justify-items-end', className)}> <aside
className={cn(
'grid grid-cols-4 gap-1 justify-items-end h-min',
'cc-animate-sidebar',
isMounted ? 'max-w-full' : 'opacity-0 max-w-0',
className
)}
>
<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_all}</span> <span>{stats.count_all}</span>
@ -55,6 +63,6 @@ export function OssStats({ className, stats }: OssStatsProps) {
icon={<IconRSFormImported size='1.25rem' />} icon={<IconRSFormImported size='1.25rem' />}
value={stats.count_schemas - stats.count_owned} value={stats.count_schemas - stats.count_owned}
/> />
</div> </aside>
); );
} }

View File

@ -96,6 +96,7 @@ export function EditorConstituenta() {
onSubmit={initiateSubmit} onSubmit={initiateSubmit}
onReset={() => setToggleReset(prev => !prev)} onReset={() => setToggleReset(prev => !prev)}
disabled={disabled} disabled={disabled}
isNarrow={isNarrow}
/> />
<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'>
@ -112,7 +113,7 @@ export function EditorConstituenta() {
) : null} ) : null}
</div> </div>
<ViewConstituents <ViewConstituents
className={isNarrow ? 'mt-3 mx-6 overflow-hidden' : 'mt-9 h-fit overflow-visible'} className={isNarrow ? 'mt-3 mx-6 overflow-hidden' : 'mt-9 overflow-visible'}
isMounted={showList} isMounted={showList}
isBottom={isNarrow} isBottom={isNarrow}
/> />

View File

@ -1,19 +1,16 @@
'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';
import { MiniSelectorOSS } from '@/features/library/components'; import { MiniSelectorOSS } from '@/features/library/components';
import { IconShowSidebar } from '@/features/library/components/icon-show-sidebar';
import { useFindPredecessor } from '@/features/oss/backend/use-find-predecessor'; import { useFindPredecessor } from '@/features/oss/backend/use-find-predecessor';
import { MiniButton } from '@/components/control'; import { MiniButton } from '@/components/control';
import { import {
IconClone, IconClone,
IconDestroy, IconDestroy,
IconList,
IconListOff,
IconMoveDown, IconMoveDown,
IconMoveUp, IconMoveUp,
IconNewItem, IconNewItem,
@ -21,6 +18,7 @@ import {
IconReset, IconReset,
IconSave IconSave
} from '@/components/icons'; } from '@/components/icons';
import { cn } from '@/components/utils';
import { useModificationStore } from '@/stores/modification'; import { useModificationStore } from '@/stores/modification';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { tooltipText } from '@/utils/labels'; import { tooltipText } from '@/utils/labels';
@ -34,6 +32,7 @@ interface ToolbarConstituentaProps {
className?: string; className?: string;
activeCst: IConstituenta | null; activeCst: IConstituenta | null;
disabled: boolean; disabled: boolean;
isNarrow: boolean;
onSubmit: () => void; onSubmit: () => void;
onReset: () => void; onReset: () => void;
@ -43,6 +42,7 @@ export function ToolbarConstituenta({
className, className,
activeCst, activeCst,
disabled, disabled,
isNarrow,
onSubmit, onSubmit,
onReset onReset
@ -80,7 +80,7 @@ export function ToolbarConstituenta({
} }
return ( return (
<div className={clsx('px-1 rounded-b-2xl backdrop-blur-xs cc-icons cc-animate-position outline-hidden', className)}> <div className={cn('px-1 rounded-b-2xl backdrop-blur-xs cc-icons outline-hidden', className)}>
{schema.oss.length > 0 ? ( {schema.oss.length > 0 ? (
<MiniSelectorOSS <MiniSelectorOSS
items={schema.oss} items={schema.oss}
@ -152,13 +152,7 @@ export function ToolbarConstituenta({
<MiniButton <MiniButton
title='Отображение списка конституент' title='Отображение списка конституент'
icon={ icon={<IconShowSidebar size='1.25rem' value={showList} isBottom={isNarrow} />}
showList ? (
<IconList size='1.25rem' className='icon-primary' />
) : (
<IconListOff size='1.25rem' className='icon-primary' />
)
}
onClick={toggleList} onClick={toggleList}
/> />
<BadgeHelp topic={HelpTopic.UI_RS_EDITOR} offset={4} contentClass='sm:max-w-160' /> <BadgeHelp topic={HelpTopic.UI_RS_EDITOR} offset={4} contentClass='sm:max-w-160' />

View File

@ -1,8 +1,12 @@
'use client'; 'use client';
import clsx from 'clsx';
import { EditorLibraryItem, ToolbarItemCard } from '@/features/library/components'; import { EditorLibraryItem, ToolbarItemCard } from '@/features/library/components';
import { useWindowSize } from '@/hooks/use-window-size';
import { useModificationStore } from '@/stores/modification'; import { useModificationStore } from '@/stores/modification';
import { usePreferencesStore } from '@/stores/preferences';
import { globalIDs } from '@/utils/constants'; import { globalIDs } from '@/utils/constants';
import { useRSEdit } from '../rsedit-context'; import { useRSEdit } from '../rsedit-context';
@ -10,9 +14,14 @@ import { useRSEdit } from '../rsedit-context';
import { FormRSForm } from './form-rsform'; import { FormRSForm } from './form-rsform';
import { RSFormStats } from './rsform-stats'; import { RSFormStats } from './rsform-stats';
const SIDELIST_LAYOUT_THRESHOLD = 768; // px
export function EditorRSFormCard() { export function EditorRSFormCard() {
const { schema, isArchive, isMutable, deleteSchema, isAttachedToOSS } = useRSEdit(); const { schema, isArchive, isMutable, deleteSchema, isAttachedToOSS } = useRSEdit();
const { isModified } = useModificationStore(); const { isModified } = useModificationStore();
const showRSFormStats = usePreferencesStore(state => state.showRSFormStats);
const windowSize = useWindowSize();
const isNarrow = !!windowSize.width && windowSize.width <= SIDELIST_LAYOUT_THRESHOLD;
function initiateSubmit() { function initiateSubmit() {
const element = document.getElementById(globalIDs.library_item_editor) as HTMLFormElement; const element = document.getElementById(globalIDs.library_item_editor) as HTMLFormElement;
@ -31,24 +40,33 @@ export function EditorRSFormCard() {
} }
return ( return (
<div onKeyDown={handleInput} className='relative md:w-fit md:max-w-fit max-w-128 flex flex-row flex-wrap px-6 pt-8'> <div
onKeyDown={handleInput}
className={clsx(
'relative md:w-fit md:max-w-fit max-w-128',
'flex px-6 pt-8',
isNarrow && 'flex-col md:items-center'
)}
>
<ToolbarItemCard <ToolbarItemCard
className='cc-tab-tools' className='cc-tab-tools'
onSubmit={initiateSubmit} onSubmit={initiateSubmit}
schema={schema} schema={schema}
isMutable={isMutable} isMutable={isMutable}
deleteSchema={deleteSchema} deleteSchema={deleteSchema}
isNarrow={isNarrow}
/> />
<div className='cc-column shrink'> <div className='cc-column mx-0 md:mx-auto'>
<FormRSForm key={schema.id} /> <FormRSForm key={schema.id} />
<EditorLibraryItem schema={schema} isAttachedToOSS={isAttachedToOSS} /> <EditorLibraryItem schema={schema} isAttachedToOSS={isAttachedToOSS} />
</div> </div>
<RSFormStats <RSFormStats
className='mt-3 md:mt-8 md:ml-5 w-80 md:w-56 mx-auto h-min' className='w-80 md:w-56 mt-3 md:mt-8 md:ml-5 mx-auto'
stats={schema.stats} stats={schema.stats}
isArchive={isArchive} isArchive={isArchive}
isMounted={showRSFormStats}
/> />
</div> </div>
); );

View File

@ -1,5 +1,3 @@
import clsx from 'clsx';
import { import {
IconChild, IconChild,
IconConvention, IconConvention,
@ -19,6 +17,7 @@ import {
IconStatusProperty, IconStatusProperty,
IconTerminology IconTerminology
} from '@/components/icons'; } from '@/components/icons';
import { cn } from '@/components/utils';
import { ValueStats } from '@/components/view'; import { ValueStats } from '@/components/view';
import { type IRSFormStats } from '../../../models/rsform'; import { type IRSFormStats } from '../../../models/rsform';
@ -26,13 +25,22 @@ import { type IRSFormStats } from '../../../models/rsform';
interface RSFormStatsProps { interface RSFormStatsProps {
className?: string; className?: string;
isArchive: boolean; isArchive: boolean;
isMounted: boolean;
stats: IRSFormStats; stats: IRSFormStats;
} }
export function RSFormStats({ className, stats, isArchive }: RSFormStatsProps) { export function RSFormStats({ className, stats, isArchive, isMounted }: RSFormStatsProps) {
return ( return (
<div className={clsx('grid grid-cols-4 gap-1 justify-items-end', className)}> <aside
<div id='count_all' className='col-span-2 w-fit flex gap-3 hover:cursor-default '> className={cn(
'cc-animate-sidebar',
'h-min',
'grid grid-cols-4 gap-1 justify-items-end ',
isMounted ? 'max-w-full' : 'opacity-0 max-w-0',
className
)}
>
<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>
</div> </div>
@ -140,6 +148,6 @@ export function RSFormStats({ className, stats, isArchive }: RSFormStatsProps) {
} }
value={stats.count_convention} value={stats.count_convention}
/> />
</div> </aside>
); );
} }

View File

@ -1,4 +1,4 @@
import clsx from 'clsx'; 'use client';
import { HelpTopic } from '@/features/help'; import { HelpTopic } from '@/features/help';
import { BadgeHelp } from '@/features/help/components'; import { BadgeHelp } from '@/features/help/components';
@ -15,6 +15,7 @@ import {
IconOpenList, IconOpenList,
IconReset IconReset
} from '@/components/icons'; } from '@/components/icons';
import { cn } from '@/components/utils';
import { prefixes } from '@/utils/constants'; import { prefixes } from '@/utils/constants';
import { prepareTooltip } from '@/utils/utils'; import { prepareTooltip } from '@/utils/utils';
@ -46,7 +47,7 @@ export function ToolbarRSList({ className }: ToolbarRSListProps) {
} = useRSEdit(); } = useRSEdit();
return ( return (
<div className={clsx('cc-icons items-start outline-hidden', className)}> <div className={cn('cc-icons items-start outline-hidden', className)}>
{schema.oss.length > 0 ? ( {schema.oss.length > 0 ? (
<MiniSelectorOSS <MiniSelectorOSS
items={schema.oss} items={schema.oss}

View File

@ -1,9 +1,8 @@
'use client'; 'use client';
import clsx from 'clsx';
import { useRoleStore, UserRole } from '@/features/users'; import { useRoleStore, UserRole } from '@/features/users';
import { cn } from '@/components/utils';
import { useWindowSize } from '@/hooks/use-window-size'; import { useWindowSize } from '@/hooks/use-window-size';
import { useFitHeight } from '@/stores/app-layout'; import { useFitHeight } from '@/stores/app-layout';
@ -26,11 +25,11 @@ export function ViewConstituents({ className, isBottom, isMounted }: ViewConstit
return ( return (
<aside <aside
className={clsx( className={cn(
'cc-animate-sidebar',
'border', 'border',
isBottom ? 'rounded-md' : 'rounded-l-md rounded-r-none', isBottom ? 'rounded-md' : 'rounded-l-md rounded-r-none h-fit',
isMounted ? 'max-w-full' : 'opacity-0 max-w-0', isMounted ? 'max-w-full' : 'opacity-0 max-w-0',
'ease-in-out duration-1000 transition-[opacity,max-width]',
className className
)} )}
> >

View File

@ -91,6 +91,7 @@
--duration-modal: 300ms; --duration-modal: 300ms;
--duration-fade: 300ms; --duration-fade: 300ms;
--duration-move: 500ms; --duration-move: 500ms;
--duration-transform: 1000ms;
--duration-cycle: 1000ms; --duration-cycle: 1000ms;
/* Custom animations */ /* Custom animations */

View File

@ -20,6 +20,12 @@ interface PreferencesStore {
showCstSideList: boolean; showCstSideList: boolean;
toggleShowCstSideList: () => void; toggleShowCstSideList: () => void;
showRSFormStats: boolean;
toggleShowRSFormStats: () => void;
showOSSStats: boolean;
toggleShowOSSStats: () => void;
showExpressionControls: boolean; showExpressionControls: boolean;
toggleShowExpressionControls: () => void; toggleShowExpressionControls: () => void;
} }
@ -63,6 +69,12 @@ export const usePreferencesStore = create<PreferencesStore>()(
showCstSideList: true, showCstSideList: true,
toggleShowCstSideList: () => set(state => ({ showCstSideList: !state.showCstSideList })), toggleShowCstSideList: () => set(state => ({ showCstSideList: !state.showCstSideList })),
showRSFormStats: true,
toggleShowRSFormStats: () => set(state => ({ showRSFormStats: !state.showRSFormStats })),
showOSSStats: true,
toggleShowOSSStats: () => set(state => ({ showOSSStats: !state.showOSSStats })),
showExpressionControls: true, showExpressionControls: true,
toggleShowExpressionControls: () => set(state => ({ showExpressionControls: !state.showExpressionControls })) toggleShowExpressionControls: () => set(state => ({ showExpressionControls: !state.showExpressionControls }))
}), }),

View File

@ -142,6 +142,12 @@
} }
} }
@utility cc-animate-sidebar {
transition-property: max-width, opacity;
transition-timing-function: var(--ease-in-out);
transition-duration: var(--duration-transform);
}
@utility cc-animate-position { @utility cc-animate-position {
transition-property: transform top left bottom right margin padding; transition-property: transform top left bottom right margin padding;
transition-timing-function: var(--ease-bezier); transition-timing-function: var(--ease-bezier);