F: Rework inline styles and improve animations

This commit is contained in:
Ivan 2025-03-13 14:42:48 +03:00
parent 26976c806a
commit 8208adab96
63 changed files with 408 additions and 490 deletions

View File

@ -1,5 +1,6 @@
import { Suspense } from 'react';
import { Outlet } from 'react-router';
import clsx from 'clsx';
import { ModalLoader } from '@/components/modal';
import { useAppLayoutStore, useMainHeight, useViewportHeight } from '@/stores/app-layout';
@ -17,7 +18,6 @@ import { Navigation } from './navigation';
export function ApplicationLayout() {
const mainHeight = useMainHeight();
const viewportHeight = useViewportHeight();
const showScroll = useAppLayoutStore(state => !state.noScroll);
const noNavigationAnimation = useAppLayoutStore(state => state.noNavigationAnimation);
const noNavigation = useAppLayoutStore(state => state.noNavigation);
const noFooter = useAppLayoutStore(state => state.noFooter);
@ -27,8 +27,7 @@ export function ApplicationLayout() {
<NavigationState>
<div className='min-w-80 antialiased h-full max-w-480 mx-auto'>
<ToasterThemed
className='text-[14px]'
style={{ marginTop: noNavigationAnimation ? '1.5rem' : '3.5rem' }}
className={clsx('text-[14px]/[20px]', noNavigationAnimation ? 'mt-6' : 'mt-14')}
autoClose={3000}
draggable={false}
pauseOnFocusLoss={false}
@ -46,7 +45,7 @@ export function ApplicationLayout() {
style={{ maxHeight: viewportHeight }}
inert={activeDialog !== null}
>
<main className='cc-scroll-y' style={{ overflowY: showScroll ? 'scroll' : 'auto', minHeight: mainHeight }}>
<main className='cc-scroll-y overflow-y-auto' style={{ minHeight: mainHeight }}>
<GlobalLoader />
<MutationErrors />
<Outlet />

View File

@ -1,7 +1,8 @@
import clsx from 'clsx';
import { IconLibrary2, IconManuals, IconNewItem2 } from '@/components/icons';
import { useWindowSize } from '@/hooks/use-window-size';
import { useAppLayoutStore } from '@/stores/app-layout';
import { PARAMETER } from '@/utils/constants';
import { urls } from '../urls';
@ -29,14 +30,11 @@ export function Navigation() {
<nav className='z-navigation sticky top-0 left-0 right-0 select-none bg-prim-100'>
<ToggleNavigation />
<div
className='pl-2 pr-6 sm:pr-4 h-12 flex cc-shadow-border'
style={{
transitionProperty: 'max-height, translate',
transitionDuration: `${PARAMETER.moveDuration}ms`,
transitionTimingFunction: 'ease-in-out',
maxHeight: noNavigationAnimation ? '0rem' : '3rem',
translate: noNavigationAnimation ? '0 -1.5rem' : '0'
}}
className={clsx(
'pl-2 pr-6 sm:pr-4 h-12 flex cc-shadow-border',
'transition-[max-height,translate] ease-bezier duration-(--duration-move)',
noNavigationAnimation ? '-translate-y-6 max-h-0' : 'max-h-12'
)}
>
<div className='flex items-center mr-auto cursor-pointer' onClick={!size.isSmall ? navigateHome : undefined}>
<Logo />

View File

@ -17,12 +17,9 @@ export function Divider({ vertical, margins = 'mx-2', className, ...restProps }:
return (
<div
className={clsx(
margins, //
className,
{
'border-x': vertical,
'border-y': !vertical
}
vertical ? 'border-x' : 'border-y', //
margins,
className
)}
{...restProps}
/>

View File

@ -26,7 +26,6 @@ export function Tooltip({
layer = 'z-tooltip',
place = 'bottom',
className,
style,
...restProps
}: TooltipProps) {
const darkMode = usePreferencesStore(state => state.darkMode);
@ -40,6 +39,7 @@ export function Tooltip({
opacity={1}
className={clsx(
'relative',
'py-0.5! px-2!',
'max-h-[calc(100svh-6rem)]',
'overflow-y-auto overflow-x-hidden sm:overflow-hidden overscroll-contain',
'border shadow-md',
@ -48,7 +48,6 @@ export function Tooltip({
className
)}
classNameArrow={layer}
style={{ ...{ paddingTop: '2px', paddingBottom: '2px', paddingLeft: '8px', paddingRight: '8px' }, ...style }}
variant={darkMode ? 'dark' : 'light'}
place={place}
{...restProps}

View File

@ -43,15 +43,10 @@ export function Button({
'inline-flex gap-2 items-center justify-center',
'font-medium select-none disabled:cursor-auto',
'clr-btn-default cc-animate-color',
{
'border rounded-sm': !noBorder,
'px-1': dense,
'px-3 py-1': !dense,
'cursor-progress': loading,
'cursor-pointer': !loading,
'outline-hidden': noOutline,
'clr-outline': !noOutline
},
dense ? 'px-1' : 'px-3 py-1',
loading ? 'cursor-progress' : 'cursor-pointer',
noOutline ? 'outline-hidden' : 'clr-outline',
!noBorder && 'border rounded-sm',
className
)}
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}

View File

@ -41,11 +41,8 @@ export function MiniButton({
'rounded-lg',
'clr-text-controls cc-animate-color',
'cursor-pointer disabled:cursor-auto',
{
'px-1 py-1': !noPadding,
'outline-hidden': noHover,
'clr-hover': !noHover
},
noHover ? 'outline-hidden' : 'clr-hover',
!noPadding && 'px-1 py-1',
className
)}
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}

View File

@ -38,10 +38,7 @@ export function SelectorButton({
'text-btn clr-text-controls',
'disabled:cursor-auto cursor-pointer',
'cc-animate-color',
{
'clr-hover': transparent,
'clr-btn-default border': !transparent
},
transparent ? 'clr-hover' : 'clr-btn-default border',
className
)}
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}

View File

@ -120,15 +120,15 @@ export function DataTable<TData extends RowData>({
onRowDoubleClicked,
noDataComponent,
paginationPerPage,
paginationOptions = [10, 20, 30, 40, 50],
...restProps
}: DataTableProps<TData>) {
const [lastSelected, setLastSelected] = useState<string | null>(null);
const table = useDataTable({ ...restProps });
const table = useDataTable({ paginationPerPage, ...restProps });
const isPaginationEnabled = typeof table.getCanNextPage === 'function';
const isEmpty = table.getRowModel().rows.length === 0;
const fixedSize = useMemo(() => {
@ -178,7 +178,7 @@ export function DataTable<TData extends RowData>({
{!noFooter ? <TableFooter table={table} /> : null}
</table>
{isPaginationEnabled && !isEmpty ? (
{!!paginationPerPage && !isEmpty ? (
<PaginationTools
id={id ? `${id}__pagination` : undefined}
table={table}

View File

@ -93,11 +93,12 @@ export function TableBody<TData>({
{row.getVisibleCells().map((cell: Cell<TData, unknown>) => (
<td
key={cell.id}
className='px-2 align-middle border-y'
className={clsx(
'px-2 align-middle border-y',
dense ? 'py-1' : 'py-2',
onRowClicked || onRowDoubleClicked ? 'cursor-pointer' : 'cursor-auto'
)}
style={{
cursor: onRowClicked || onRowDoubleClicked ? 'pointer' : 'auto',
paddingBottom: dense ? '0.25rem' : '0.5rem',
paddingTop: dense ? '0.25rem' : '0.5rem',
width: noHeader && index === 0 ? `calc(var(--col-${cell.column.id}-size) * 1px)` : undefined
}}
>

View File

@ -1,6 +1,7 @@
'use no memo';
import { flexRender, type Header, type HeaderGroup, type Table } from '@tanstack/react-table';
import clsx from 'clsx';
import { SelectAll } from './select-all';
import { SortingIcon } from './sorting-icon';
@ -13,13 +14,7 @@ interface TableHeaderProps<TData> {
export function TableHeader<TData>({ table, headPosition, resetLastSelected }: TableHeaderProps<TData>) {
return (
<thead
className='bg-prim-100 cc-shadow-border'
style={{
top: headPosition,
position: 'sticky'
}}
>
<thead className='sticky bg-prim-100 cc-shadow-border' style={{ top: headPosition }}>
{table.getHeaderGroups().map((headerGroup: HeaderGroup<TData>) => (
<tr key={headerGroup.id}>
{table.options.enableRowSelection ? (
@ -32,11 +27,11 @@ export function TableHeader<TData>({ table, headPosition, resetLastSelected }: T
key={header.id}
colSpan={header.colSpan}
scope='col'
className='cc-table-header group'
style={{
width: `calc(var(--header-${header?.id}-size) * 1px)`,
cursor: table.options.enableSorting && header.column.getCanSort() ? 'pointer' : 'auto'
}}
className={clsx(
'cc-table-header group',
table.options.enableSorting && header.column.getCanSort() ? 'cursor-pointer' : 'cursor-auto'
)}
style={{ width: `calc(var(--header-${header?.id}-size) * 1px)` }}
onClick={table.options.enableSorting ? header.column.getToggleSortingHandler() : undefined}
>
{!header.isPlaceholder ? (

View File

@ -39,11 +39,7 @@ export function DropdownButton({
'text-left text-sm text-ellipsis whitespace-nowrap',
'disabled:clr-text-controls',
'cc-animate-color',
{
'clr-hover': onClick,
'cursor-pointer disabled:cursor-auto': onClick,
'cursor-default': !onClick
},
!!onClick ? 'clr-hover cursor-pointer disabled:cursor-auto' : 'clr-btn-default',
className
)}
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}

View File

@ -1,8 +1,6 @@
import React from 'react';
import clsx from 'clsx';
import { PARAMETER } from '@/utils/constants';
import { type Styling } from '../props';
interface DropdownProps extends Styling {
@ -36,36 +34,19 @@ export function Dropdown({
margin,
className,
children,
style,
...restProps
}: React.PropsWithChildren<DropdownProps>) {
return (
<div
tabIndex={-1}
className={clsx(
'z-topmost absolute',
{
'right-0': stretchLeft,
'left-0': !stretchLeft,
'bottom-0': stretchTop,
'top-full': !stretchTop
},
'grid',
'border rounded-md shadow-lg',
'clr-input',
'text-sm',
'cc-dropdown isolate z-topmost absolute grid bg-prim-0 border rounded-md shadow-lg text-sm',
stretchLeft ? 'right-0' : 'left-0',
stretchTop ? 'bottom-0' : 'top-full',
isOpen && 'open',
margin,
className
)}
style={{
willChange: 'clip-path, transform',
transitionProperty: 'clip-path, transform',
transitionDuration: `${PARAMETER.dropdownDuration}ms`,
transitionTimingFunction: 'ease-in-out',
transform: isOpen ? 'translateY(0)' : 'translateY(-10%)',
clipPath: isOpen ? 'inset(0% 0% 0% 0%)' : 'inset(10% 0% 90% 0%)',
...style
}}
aria-hidden={!isOpen}
{...restProps}
>

View File

@ -33,18 +33,7 @@ export function DescribeError({ error }: { error: ErrorData }) {
<p>
<b>Message:</b> {error.message}
</p>
{error.stack && (
<pre
style={{
whiteSpace: 'pre-wrap',
wordWrap: 'break-word',
padding: '6px',
overflowX: 'auto'
}}
>
{error.stack}
</pre>
)}
{error.stack && <pre className='whitespace-pre-wrap p-2 overflow-x-auto break-words'>{error.stack}</pre>}
</div>
);
}

View File

@ -67,10 +67,7 @@ export function CheckboxTristate({
className={clsx(
'w-4 h-4', //
'border rounded-sm',
{
'bg-sec-600 text-sec-0': value !== false,
'bg-prim-100': value === false
}
value === false ? 'bg-prim-100' : 'bg-sec-600 text-sec-0'
)}
>
{value ? <CheckboxChecked /> : null}

View File

@ -66,10 +66,7 @@ export function Checkbox({
className={clsx(
'w-4 h-4', //
'border rounded-sm',
{
'bg-sec-600 text-sec-0': value !== false,
'bg-prim-100': value === false
}
value === false ? 'bg-prim-100' : 'bg-sec-600 text-sec-0'
)}
>
{value ? <CheckboxChecked /> : null}

View File

@ -46,7 +46,7 @@ export function FileInput({ id, label, acceptType, title, className, style, onCh
id={id}
type='file'
ref={inputRef}
style={{ display: 'none' }}
className='hidden'
accept={acceptType}
onChange={handleFileChange}
{...restProps}

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import clsx from 'clsx';
import { globalIDs, PARAMETER } from '@/utils/constants';
import { globalIDs } from '@/utils/constants';
import { MiniButton } from '../control';
import { IconDropArrow, IconPageRight } from '../icons';
@ -89,27 +89,13 @@ export function SelectTree<ItemType>({
<div
key={`${prefix}${index}`}
className={clsx(
'relative',
'pr-3 pl-6 border-b',
'cc-scroll-row',
'bg-prim-200 clr-hover cc-animate-color',
'cursor-pointer',
value === item && 'clr-selected',
!isActive && 'pointer-events-none'
'cc-tree-item relative cc-scroll-row clr-hover',
isActive ? 'max-h-7 py-1 border-b' : 'max-h-0 opacity-0 pointer-events-none',
value === item && 'clr-selected'
)}
data-tooltip-id={globalIDs.tooltip}
data-tooltip-html={getDescription(item)}
onClick={event => handleClickItem(event, item)}
style={{
borderBottomWidth: isActive ? '1px' : '0px',
willChange: 'max-height, opacity, padding',
transitionProperty: 'max-height, opacity, padding',
transitionDuration: `${PARAMETER.moveDuration}ms`,
paddingTop: isActive ? '0.25rem' : '0',
paddingBottom: isActive ? '0.25rem' : '0',
maxHeight: isActive ? '1.75rem' : '0',
opacity: isActive ? '1' : '0'
}}
>
{foldable.has(item) ? (
<MiniButton

View File

@ -40,11 +40,8 @@ export function TextArea({
return (
<div
className={clsx(
'w-full',
{
'flex flex-col': !dense,
'flex grow items-center gap-3': dense
},
'w-full', //
dense ? 'flex grow items-center gap-3' : 'flex flex-col',
dense && className
)}
>
@ -55,16 +52,13 @@ export function TextArea({
'px-3 py-2',
'leading-tight',
'overflow-x-hidden overflow-y-auto',
{
'field-sizing-content': fitContent,
'resize-none': noResize,
'border': !noBorder,
'grow max-w-full': dense,
'mt-2': !dense && !!label,
'clr-outline': !noOutline,
'bg-transparent': transparent,
'clr-input': !transparent
},
!noBorder && 'border',
fitContent && 'field-sizing-content',
noResize && 'resize-none',
transparent ? 'bg-transparent' : 'clr-input',
!noOutline && 'clr-outline',
dense && 'grow max-w-full',
!dense && !!label && 'mt-2',
!dense && className
)}
rows={rows}

View File

@ -42,10 +42,7 @@ export function TextInput({
return (
<div
className={clsx(
{
'flex flex-col': !dense,
'flex items-center gap-3': dense
},
dense ? 'flex items-center gap-3' : 'flex flex-col', //
dense && className
)}
>
@ -55,15 +52,12 @@ export function TextInput({
className={clsx(
'min-w-0 py-2',
'leading-tight truncate hover:text-clip',
{
'px-3': !noBorder || !disabled,
'grow max-w-full': dense,
'mt-2': !dense && !!label,
'border': !noBorder,
'clr-outline': !noOutline,
'bg-transparent': transparent,
'clr-input': !transparent
},
transparent ? 'bg-transparent' : 'clr-input',
!noBorder && 'border',
!noOutline && 'clr-outline',
(!noBorder || !disabled) && 'px-3',
dense && 'grow max-w-full',
!dense && !!label && 'mt-2',
!dense && className
)}
onKeyDown={!allowEnter && !onKeyDown ? preventEnterCapture : onKeyDown}

View File

@ -124,10 +124,7 @@ export function ModalForm({
'@container/modal',
'max-h-[calc(100svh-8rem)] max-w-[100svw] xs:max-w-[calc(100svw-2rem)]',
'overscroll-contain outline-hidden',
{
'overflow-auto': !overflowVisible,
'overflow-visible': overflowVisible
},
overflowVisible ? 'overflow-visible' : 'overflow-auto',
className
)}
{...restProps}

View File

@ -61,7 +61,7 @@ export function ModalView({
<h1
className={clsx(
'px-12 py-2 select-none',
fullScreen && 'z-pop absolute top-0 right-1/2 translate-x-1/2 cc-blur bg-prim-100/90 rounded-2xl'
fullScreen && 'z-pop absolute top-0 right-1/2 translate-x-1/2 backdrop-blur-xs bg-prim-100/90 rounded-2xl'
)}
>
{header}
@ -73,10 +73,7 @@ export function ModalView({
'@container/modal',
'max-h-[calc(100svh-8rem)] max-w-[100svw] xs:max-w-[calc(100svw-2rem)]',
'overscroll-contain outline-hidden',
{
'overflow-auto': !overflowVisible,
'overflow-visible': overflowVisible
},
overflowVisible ? 'overflow-visible' : 'overflow-auto',
className
)}
{...restProps}
@ -90,12 +87,12 @@ export function ModalView({
aria-label='Закрыть'
className={clsx(
'my-2 mx-auto text-sm min-w-28',
fullScreen && 'z-pop absolute bottom-0 right-1/2 translate-x-1/2 cc-blur'
fullScreen && 'z-pop absolute bottom-0 right-1/2 translate-x-1/2'
)}
onClick={hideDialog}
/>
) : (
<div className='z-pop absolute bottom-0 right-1/2 translate-x-1/2 bg-prim-100/90 cc-blur p-3 rounded-xl'>
<div className='z-pop absolute bottom-0 right-1/2 translate-x-1/2 p-3 rounded-xl bg-prim-100/90 backdrop-blur-xs'>
{' '}
<Button text='Закрыть' aria-label='Закрыть' className='text-sm min-w-28' onClick={hideDialog} />
</div>

View File

@ -18,9 +18,8 @@ export function EmbedYoutube({ videoID, pxHeight, pxWidth }: EmbedYoutubeProps)
}
return (
<div
className='relative'
className='relative h-0'
style={{
height: 0,
paddingBottom: `${pxHeight}px`,
paddingLeft: `${pxWidth}px`
}}

View File

@ -18,11 +18,9 @@ export function Indicator({ icon, title, titleHtml, hideTitle, noPadding, classN
return (
<div
className={clsx(
'clr-text-controls',
'clr-text-controls', //
'outline-hidden',
{
'px-1 py-1': !noPadding
},
!noPadding && 'px-1 py-1',
className
)}
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}

View File

@ -57,7 +57,7 @@ export function ValueIcon({
'flex items-center',
'text-right',
'hover:cursor-default',
{ 'justify-between gap-6': !dense, 'gap-1': dense },
dense ? 'gap-1' : 'justify-between gap-6',
className
)}
{...restProps}

View File

@ -7,7 +7,6 @@ import { IconHelp } from '@/components/icons';
import { Loader } from '@/components/loader';
import { type Styling } from '@/components/props';
import { usePreferencesStore } from '@/stores/preferences';
import { PARAMETER } from '@/utils/constants';
import { type HelpTopic } from '../models/help-topic';
@ -48,7 +47,7 @@ export function BadgeHelp({ topic, padding = 'p-1', className, contentClass, sty
clickable
anchorSelect={`#help-${topic}`}
layer='z-topmost'
className={clsx(PARAMETER.TOOLTIP_WIDTH, contentClass)}
className={clsx('max-w-120', contentClass)}
{...restProps}
>
<Suspense fallback={<Loader />}>

View File

@ -1,5 +1,3 @@
import { APP_COLORS } from '@/styling/colors';
export function HelpFormulaTree() {
return (
<div>
@ -12,22 +10,22 @@ export function HelpFormulaTree() {
<h2>Виды узлов</h2>
<li>
<span style={{ backgroundColor: APP_COLORS.bgGreen }}>объявление идентификатора</span>
<span className='bg-(--acc-bg-green)'>объявление идентификатора</span>
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgTeal }}>глобальный идентификатор</span>
<span className='bg-(--acc-bg-teal)'>глобальный идентификатор</span>
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgOrange }}>логическое выражение</span>
<span className='bg-(--acc-bg-orange)'>логическое выражение</span>
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgBlue }}>типизированное выражение</span>
<span className='bg-(--acc-bg-blue)'>типизированное выражение</span>
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgRed }}>присвоение и итерация</span>
<span className='bg-(--acc-bg-red)'>присвоение и итерация</span>
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgDisabled }}>составные выражения</span>
<span className='bg-prim-300'>составные выражения</span>
</li>
</div>
);

View File

@ -16,7 +16,6 @@ import {
IconSubfolders,
IconUserSearch
} from '@/components/icons';
import { APP_COLORS } from '@/styling/colors';
import { LinkTopic } from '../../components/link-topic';
import { HelpTopic } from '../../models/help-topic';
@ -33,7 +32,7 @@ export function HelpLibrary() {
</p>
<li>
<span style={{ color: APP_COLORS.fgGreen }}>зеленым текстом</span> выделены ОСС
<span className='text-(--acc-fg-green)'>зеленым текстом</span> выделены ОСС
</li>
<li>клик по строке - переход к редактированию схемы</li>
<li>Ctrl + клик по строке откроет схему в новой вкладке</li>

View File

@ -18,7 +18,6 @@ import {
IconTree,
IconTypeGraph
} from '@/components/icons';
import { APP_COLORS } from '@/styling/colors';
import { LinkTopic } from '../../components/link-topic';
import { HelpTopic } from '../../models/help-topic';
@ -69,15 +68,15 @@ export function HelpRSEditor() {
<IconChild className='inline-icon' /> отображение наследованных
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgSelected }}>текущая конституента</span>
<span className='bg-sec-200'>текущая конституента</span>
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgGreen50 }}>
<span className='bg-(--acc-bg-green50)'>
<LinkTopic text='основа' topic={HelpTopic.CC_RELATIONS} /> текущей
</span>
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgOrange50 }}>
<span className='bg-(--acc-bg-orange50)'>
<LinkTopic text='порожденные' topic={HelpTopic.CC_RELATIONS} /> текущей
</span>
</li>

View File

@ -19,7 +19,6 @@ import {
IconText,
IconTypeGraph
} from '@/components/icons';
import { APP_COLORS } from '@/styling/colors';
import { LinkTopic } from '../../components/link-topic';
import { HelpTopic } from '../../models/help-topic';
@ -49,7 +48,7 @@ export function HelpRSGraphTerm() {
<h1>Изменение узлов</h1>
<li>Клик на узел выделение</li>
<li>
Левый клик выбор <span style={{ color: APP_COLORS.fgPurple }}>фокус-конституенты</span>
Левый клик выбор <span className='text-(--acc-fg-purple)'>фокус-конституенты</span>
</li>
<li>
<IconReset className='inline-icon' /> Esc сбросить выделение

View File

@ -1,5 +1,3 @@
import { APP_COLORS } from '@/styling/colors';
import { LinkTopic } from '../../components/link-topic';
import { HelpTopic } from '../../models/help-topic';
@ -21,13 +19,13 @@ export function HelpTypeGraph() {
<h2>Виды узлов</h2>
<li>
<span style={{ backgroundColor: APP_COLORS.bgControls }}>ступень-основание</span>
<span className='bg-prim-200'>ступень-основание</span>
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgTeal }}>ступень-булеан</span>
<span className='bg-(--acc-bg-teal)'>ступень-булеан</span>
</li>
<li>
<span style={{ backgroundColor: APP_COLORS.bgOrange }}>ступень декартова произведения</span>
<span className='bg-(--acc-bg-orange)'>ступень декартова произведения</span>
</li>
</div>
);

View File

@ -7,7 +7,7 @@ import { useDropdown } from '@/components/dropdown';
import { IconMenuFold, IconMenuUnfold } from '@/components/icons';
import { SelectTree } from '@/components/input';
import { useAppLayoutStore, useFitHeight } from '@/stores/app-layout';
import { PARAMETER, prefixes } from '@/utils/constants';
import { prefixes } from '@/utils/constants';
import { describeHelpTopic, labelHelpTopic } from '../../labels';
import { HelpTopic, topicParent } from '../../models/help-topic';
@ -32,14 +32,11 @@ export function TopicsDropdown({ activeTopic, onChangeTopic }: TopicsDropdownPro
ref={menu.ref}
className={clsx(
'absolute left-0 w-54', //
noNavigation ? 'top-0' : 'top-12',
'flex flex-col',
'z-topmost',
'text-xs sm:text-sm',
'select-none',
{
'top-0': noNavigation,
'top-12': !noNavigation
}
'select-none'
)}
>
<Button
@ -59,14 +56,11 @@ export function TopicsDropdown({ activeTopic, onChangeTopic }: TopicsDropdownPro
getParent={item => topicParent.get(item) ?? item}
getLabel={labelHelpTopic}
getDescription={describeHelpTopic}
className='border-r border-t rounded-none cc-scroll-y bg-prim-200'
style={{
maxHeight: treeHeight,
willChange: 'clip-path',
transitionProperty: 'clip-path',
transitionDuration: `${PARAMETER.moveDuration}ms`,
clipPath: menu.isOpen ? 'inset(0% 0% 0% 0%)' : 'inset(0% 100% 0% 0%)'
}}
className={clsx(
'cc-topic-dropdown border-r border-t rounded-none cc-scroll-y bg-prim-200',
menu.isOpen && 'open'
)}
style={{ maxHeight: treeHeight }}
/>
</div>
);

View File

@ -113,7 +113,8 @@ export function FormCreateItem() {
id='schema_file'
ref={inputRef}
type='file'
style={{ display: 'none' }}
aria-hidden
className='hidden'
accept={EXTEOR_TRS_FILE}
onChange={handleFileChange}
/>

View File

@ -60,7 +60,7 @@ export function TableLibraryItems({ items }: TableLibraryItemsProps) {
columns={columns}
data={items}
headPosition='0'
className={clsx('cc-scroll-y h-fit text-xs sm:text-sm border-b', { 'border-l': folderMode })}
className={clsx('cc-scroll-y h-fit text-xs sm:text-sm border-b', folderMode && 'border-l')}
style={{ maxHeight: tableHeight }}
noDataComponent={
<div className='cc-column dense p-3 items-center min-h-24'>

View File

@ -1,4 +1,5 @@
import { toast } from 'react-toastify';
import clsx from 'clsx';
import { useAuthSuspense } from '@/features/auth';
import { HelpTopic } from '@/features/help';
@ -6,9 +7,8 @@ import { BadgeHelp } from '@/features/help/components';
import { MiniButton } from '@/components/control';
import { IconFolderEdit, IconFolderTree } from '@/components/icons';
import { useWindowSize } from '@/hooks/use-window-size';
import { useFitHeight } from '@/stores/app-layout';
import { PARAMETER, prefixes } from '@/utils/constants';
import { prefixes } from '@/utils/constants';
import { infoMsg } from '@/utils/labels';
import { useLibrary } from '../../backend/use-library';
@ -25,7 +25,6 @@ interface ViewSideLocationProps {
export function ViewSideLocation({ isVisible, onRenameLocation }: ViewSideLocationProps) {
const { user, isAnonymous } = useAuthSuspense();
const { items } = useLibrary();
const { isSmall } = useWindowSize();
const location = useLibrarySearchStore(state => state.location);
const setLocation = useLibrarySearchStore(state => state.setLocation);
@ -62,15 +61,10 @@ export function ViewSideLocation({ isVisible, onRenameLocation }: ViewSideLocati
return (
<div
className='max-w-40 sm:max-w-60 flex flex-col text:xs sm:text-sm select-none'
style={{
transitionProperty: 'width, min-width, opacity',
transitionDuration: `${PARAMETER.moveDuration}ms`,
transitionTimingFunction: 'ease-out',
minWidth: isVisible ? (isSmall ? '10rem' : '15rem') : '0',
width: isVisible ? '100%' : '0',
opacity: isVisible ? 1 : 0
}}
className={clsx(
'max-w-40 sm:max-w-60 flex flex-col text:xs sm:text-sm select-none cc-side-location',
isVisible && 'open min-w-[10rem] sm:min-w-[15rem]'
)}
>
<div className='h-8 flex justify-between items-center pr-1 pl-0.5'>
<BadgeHelp topic={HelpTopic.UI_LIBRARY} contentClass='text-sm' offset={5} place='right-start' />

View File

@ -74,7 +74,7 @@ export function InfoOperation({ operation }: InfoOperationProps) {
dense
noHeader
noFooter
className='text-sm border select-none mb-2'
className='text-sm border-x select-none mb-2'
data={operation.substitutions}
columns={columns}
/>

View File

@ -12,8 +12,7 @@ export function OperationTooltip() {
clickable
id={globalIDs.operation_tooltip}
layer='z-topmost'
className='max-w-140 dense'
style={{ maxHeight: '30rem', overflowY: 'auto' }}
className='max-w-140 dense max-h-120! overflow-y-auto!'
hidden={!hoverOperation}
>
{hoverOperation ? <InfoOperation operation={hoverOperation} /> : null}

View File

@ -107,10 +107,7 @@ export function PickMultiOperation({ rows, items, value, onChange, className, ..
];
return (
<div
className={clsx('flex flex-col gap-1', ' border-t border-x rounded-md', 'clr-input', className)}
{...restProps}
>
<div className={clsx('flex flex-col gap-1 border-t border-x rounded-md clr-input', className)} {...restProps}>
<SelectOperation
noBorder
items={nonSelectedItems} //

View File

@ -7,7 +7,6 @@ import { PickSubstitutions } from '@/features/rsform/components';
import { TextArea } from '@/components/input';
import { useDialogsStore } from '@/stores/dialogs';
import { APP_COLORS } from '@/styling/colors';
import { type IOperationUpdateDTO } from '../../backend/types';
import { SubstitutionValidator } from '../../models/oss-api';
@ -45,12 +44,7 @@ export function TabSynthesis() {
)}
/>
<TextArea
disabled
value={validator.msg}
rows={4}
style={{ borderColor: isCorrect ? undefined : APP_COLORS.fgRed, borderWidth: isCorrect ? undefined : '2px' }}
/>
<TextArea disabled value={validator.msg} rows={4} className={isCorrect ? '' : 'border-(--acc-fg-red) border-2'} />
</div>
);
}

View File

@ -1,5 +1,7 @@
'use client';
import clsx from 'clsx';
import { IconConsolidation, IconRSForm } from '@/components/icons';
import { Indicator } from '@/components/view';
import { globalIDs } from '@/utils/constants';
@ -52,13 +54,10 @@ export function NodeCore({ node }: NodeCoreProps) {
) : null}
<div
className='text-center line-clamp-2'
style={{
fontSize: longLabel ? '12px' : '14px',
lineHeight: longLabel ? '16px' : '20px',
paddingLeft: '4px',
paddingRight: longLabel ? '10px' : '4px'
}}
className={clsx(
'text-center line-clamp-2 pl-[4px]',
longLabel ? 'text-[12px]/[16px] pr-[10px]' : 'text-[14px]/[20px] pr-[4px]'
)}
>
{node.data.label}
</div>

View File

@ -131,8 +131,7 @@ export function ToolbarOssGraph({
className={clsx(
'flex flex-col items-center pt-1',
'rounded-b-2xl',
'cc-blur',
'hover:bg-prim-100 hover:bg-opacity-50',
'hover:bg-prim-100 hover:bg-opacity-50 backdrop-blur-xs',
className
)}
{...restProps}

View File

@ -1,5 +1,3 @@
import { APP_COLORS } from '@/styling/colors';
import { colorFgGrammeme } from '../colors';
import { labelGrammeme } from '../labels';
import { type GramData } from '../models/language';
@ -15,11 +13,10 @@ interface BadgeGrammemeProps {
export function BadgeGrammeme({ grammeme }: BadgeGrammemeProps) {
return (
<div
className='min-w-12 px-1 border rounded-md text-sm font-medium text-center whitespace-nowrap'
className='min-w-12 px-1 border rounded-md text-sm font-medium text-center whitespace-nowrap bg-prim-0'
style={{
borderColor: colorFgGrammeme(grammeme),
color: colorFgGrammeme(grammeme),
backgroundColor: APP_COLORS.bgInput
color: colorFgGrammeme(grammeme)
}}
>
{labelGrammeme(grammeme)}

View File

@ -98,7 +98,7 @@ export function PickMultiConstituenta({
];
return (
<div className={clsx(noBorder ? '' : 'border', className)} {...restProps}>
<div className={clsx(!noBorder && 'border', className)} {...restProps}>
<div className='px-3 flex justify-between items-center clr-input border-b rounded-t-md'>
<div className='w-[24ch] select-none whitespace-nowrap'>
{items.length > 0 ? `Выбраны ${value.length} из ${items.length}` : 'Конституенты'}

View File

@ -35,7 +35,7 @@ export function DlgShowAST() {
className={clsx(
'absolute z-pop top-2 right-1/2 translate-x-1/2 max-w-[60ch]',
'px-2 rounded-2xl',
'cc-blur bg-prim-100/90',
'backdrop-blur-xs bg-prim-100/90',
'text-lg text-center'
)}
>

View File

@ -1,16 +1,12 @@
'use client';
import { Handle, Position } from 'reactflow';
import { APP_COLORS } from '@/styling/colors';
import clsx from 'clsx';
import { colorBgSyntaxTree } from '../../../colors';
import { labelSyntaxTree } from '../../../labels';
import { type ISyntaxTreeNode } from '../../../models/rslang';
const FONT_SIZE_MAX = 14;
const FONT_SIZE_MED = 12;
const LABEL_THRESHOLD = 3;
/**
@ -30,24 +26,20 @@ export function ASTNode(node: ASTNodeInternal) {
return (
<>
<Handle type='target' position={Position.Top} style={{ opacity: 0 }} />
<Handle type='target' position={Position.Top} className='opacity-0' />
<div
className='w-full h-full cursor-default flex items-center justify-center rounded-full'
style={{ backgroundColor: colorBgSyntaxTree(node.data) }}
/>
<Handle type='source' position={Position.Bottom} style={{ opacity: 0 }} />
<Handle type='source' position={Position.Bottom} className='opacity-0' />
<div
className='font-math mt-1 w-fit text-center translate-x-[calc(-50%+20px)]'
style={{ fontSize: label.length > LABEL_THRESHOLD ? FONT_SIZE_MED : FONT_SIZE_MAX }}
className={clsx(
'font-math mt-1 w-fit text-center translate-x-[calc(-50%+20px)]',
label.length > LABEL_THRESHOLD ? 'text-[12px]/[16px]' : 'text-[14px]/[20px]'
)}
>
<div className='absolute top-0 left-0 text-center w-full'>{label}</div>
<div
aria-hidden='true'
style={{
WebkitTextStrokeWidth: 2,
WebkitTextStrokeColor: APP_COLORS.bgDefault
}}
>
<div aria-hidden className='cc-ast-label-outline'>
{label}
</div>
</div>

View File

@ -2,7 +2,6 @@
import { Handle, Position } from 'reactflow';
import { APP_COLORS } from '@/styling/colors';
import { globalIDs } from '@/utils/constants';
import { colorBgTMGraphNode } from '../../../colors';
@ -26,21 +25,16 @@ export function MGraphNode(node: MGraphNodeInternal) {
return (
<>
<Handle type='source' position={Position.Top} style={{ opacity: 0 }} />
<Handle type='source' position={Position.Top} className='opacity-0' />
<div
className='w-full h-full cursor-default flex items-center justify-center rounded-full'
className='cc-node-label w-full h-full cursor-default flex items-center justify-center rounded-full'
data-tooltip-id={globalIDs.tooltip}
data-tooltip-html={tooltipText}
style={{
backgroundColor: colorBgTMGraphNode(node.data),
fontWeight: 600,
WebkitTextStrokeWidth: '0.6px',
WebkitTextStrokeColor: APP_COLORS.bgDefault
}}
style={{ backgroundColor: colorBgTMGraphNode(node.data) }}
>
{node.data.rank === 0 ? node.data.text : node.data.annotations.length > 0 ? node.data.annotations.length : ''}
</div>
<Handle type='target' position={Position.Bottom} style={{ opacity: 0 }} />
<Handle type='target' position={Position.Bottom} className='opacity-0' />
</>
);
}

View File

@ -79,7 +79,7 @@ export function EditorConstituenta() {
'min-h-80 max-w-[calc(min(100vw,95rem))] mx-auto',
'flex pt-8',
'overflow-y-auto overflow-x-clip',
{ 'flex-col md:items-center': isNarrow }
isNarrow && 'flex-col md:items-center'
)}
style={{ maxHeight: mainHeight }}
onKeyDown={handleInput}

View File

@ -80,7 +80,7 @@ export function ToolbarConstituenta({
}
return (
<div className={clsx('px-1 rounded-b-2xl cc-blur cc-icons cc-animate-position outline-hidden', className)}>
<div className={clsx('px-1 rounded-b-2xl backdrop-blur-xs cc-icons cc-animate-position outline-hidden', className)}>
{schema.oss.length > 0 ? (
<MiniSelectorOSS
items={schema.oss}

View File

@ -1,3 +1,5 @@
import clsx from 'clsx';
import { type IExpressionParseDTO, type IRSErrorDescription } from '../../../backend/types';
import { describeRSError } from '../../../labels';
import { getRSErrorPrefix } from '../../../models/rslang-api';
@ -14,17 +16,7 @@ export function ParsingResult({ isOpen, data, disabled, onShowError }: ParsingRe
const warningsCount = data ? data.errors.length - errorCount : 0;
return (
<div
tabIndex={-1}
className='text-sm border dense cc-scroll-y transition-all duration-300'
style={{
clipPath: isOpen ? 'inset(0% 0% 0% 0%)' : 'inset(0% 0% 100% 0%)',
marginTop: isOpen ? '0.75rem' : '0rem',
padding: isOpen ? '0.25rem 0.5rem 0.25rem 0.5rem' : '0rem 0rem 0rem 0rem',
borderWidth: isOpen ? '1px' : '0px',
height: isOpen ? '4.5rem' : '0rem'
}}
>
<div tabIndex={-1} className={clsx('cc-parsing-result text-sm border dense cc-scroll-y', isOpen && 'open')}>
<p>
Ошибок: <b>{errorCount}</b> | Предупреждений: <b>{warningsCount}</b>
</p>

View File

@ -1,6 +1,6 @@
import clsx from 'clsx';
import { PARAMETER, prefixes } from '@/utils/constants';
import { prefixes } from '@/utils/constants';
import { TokenID } from '../../../backend/types';
@ -91,19 +91,14 @@ export function RSEditorControls({ isOpen, disabled, onEdit }: RSEditorControlsP
return (
<div
className={clsx(
'cc-rs-edit-controls',
'max-w-112 min-w-112 xs:max-w-154 xs:min-w-154 sm:max-w-160 sm:min-w-160 md:max-w-fit mx-1 sm:mx-0',
'flex-wrap',
'divide-solid',
'flex flex-wrap',
'text-xs md:text-sm',
'select-none'
'select-none',
isOpen && 'open'
)}
style={{
clipPath: isOpen ? 'inset(0% 0% 0% 0%)' : 'inset(0% 0% 100% 0%)',
marginTop: isOpen ? '0.25rem' : '0rem',
transitionProperty: 'max-height',
transitionDuration: `${PARAMETER.moveDuration}ms`,
maxHeight: isOpen ? '4.5rem' : '0rem'
}}
aria-hidden={!isOpen}
>
{MAIN_FIRST_ROW.map(token => (
<RSTokenButton key={`${prefixes.rsedit_btn}${token}`} token={token} onInsert={onEdit} disabled={disabled} />

View File

@ -26,10 +26,7 @@ export function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps)
'clr-hover clr-text-controls cc-animate-color',
'font-math',
'cursor-pointer disabled:cursor-default',
{
'w-14.5 md:w-18': label.length > 3,
'w-7.25 md:w-9': label.length <= 3
}
label.length > 3 ? 'w-14.5 md:w-18' : 'w-7.25 md:w-9'
)}
data-tooltip-id={globalIDs.tooltip}
data-tooltip-html={describeToken(token)}

View File

@ -1,7 +1,5 @@
'use client';
import clsx from 'clsx';
import { EditorLibraryItem, ToolbarItemCard } from '@/features/library/components';
import { useModificationStore } from '@/stores/modification';
@ -35,12 +33,7 @@ export function EditorRSFormCard() {
return (
<div
onKeyDown={handleInput}
className={clsx(
'relative', //
'cc-fade-in',
'md:w-fit md:max-w-fit max-w-128',
'flex flex-row flex-wrap px-6 pt-8'
)}
className='relative cc-fade-in md:w-fit md:max-w-fit max-w-128 flex flex-row flex-wrap px-6 pt-8'
>
<ToolbarItemCard
className='cc-tab-tools'

View File

@ -1,6 +1,7 @@
'use client';
import { Handle, Position } from 'reactflow';
import clsx from 'clsx';
import { APP_COLORS } from '@/styling/colors';
import { globalIDs } from '@/utils/constants';
@ -13,10 +14,6 @@ import { useRSEdit } from '../../rsedit-context';
const DESCRIPTION_THRESHOLD = 15;
const LABEL_THRESHOLD = 3;
const FONT_SIZE_MAX = 14;
const FONT_SIZE_MED = 12;
const FONT_SIZE_MIN = 10;
/**
* Represents graph AST node internal data.
*/
@ -52,18 +49,19 @@ export function TGNode(node: TGNodeInternal) {
return (
<>
<Handle type='target' position={Position.Top} style={{ opacity: 0 }} />
<Handle type='target' position={Position.Top} className='opacity-0' />
<div
className='w-full h-full cursor-default flex items-center justify-center rounded-full'
className={clsx(
'w-full h-full cursor-default flex items-center justify-center rounded-full',
isFocused && 'border-2 border-sec-200',
label.length > LABEL_THRESHOLD ? 'text-[12px]/[16px]' : 'text-[14px]/[20px]'
)}
style={{
backgroundColor: node.selected
? APP_COLORS.bgActiveSelection
: isFocused
? APP_COLORS.bgPurple
: colorBgGraphNode(node.data, coloring),
fontSize: label.length > LABEL_THRESHOLD ? FONT_SIZE_MED : FONT_SIZE_MAX,
borderWidth: isFocused ? '2px' : '0px',
borderColor: isFocused ? APP_COLORS.bgSelected : 'transparent'
: colorBgGraphNode(node.data, coloring)
}}
data-tooltip-id={globalIDs.tooltip}
data-tooltip-html={describeCstNode(node.data)}
@ -71,37 +69,22 @@ export function TGNode(node: TGNodeInternal) {
onContextMenu={handleContextMenu}
onDoubleClick={handleDoubleClick}
>
<div
style={{
fontWeight: 600,
WebkitTextStrokeWidth: '0.6px',
WebkitTextStrokeColor: APP_COLORS.bgDefault
}}
>
{label}
</div>
<div className='cc-node-label'>{label}</div>
</div>
<Handle type='source' position={Position.Bottom} style={{ opacity: 0 }} />
<Handle type='source' position={Position.Bottom} className='opacity-0' />
{description ? (
<div
className='mt-1 w-[150px] px-1 text-center translate-x-[calc(-50%+20px)]'
style={{
fontSize: description.length > DESCRIPTION_THRESHOLD ? FONT_SIZE_MIN : FONT_SIZE_MED
}}
className={clsx(
'mt-1 w-[150px] px-1 text-center translate-x-[calc(-50%+20px)]',
description.length > DESCRIPTION_THRESHOLD ? 'text-[10px]/[12px]' : 'text-[12px]/[16px]'
)}
onContextMenu={handleContextMenu}
onDoubleClick={handleDoubleClick}
>
<div className='absolute top-0 px-1 left-0 text-center w-full line-clamp-3 hover:line-clamp-none'>
{description}
</div>
<div
aria-hidden='true'
className='line-clamp-3 hover:line-clamp-none'
style={{
WebkitTextStrokeWidth: '3px',
WebkitTextStrokeColor: APP_COLORS.bgDefault
}}
>
<div aria-hidden className='line-clamp-3 hover:line-clamp-none cc-text-outline'>
{description}
</div>
</div>

View File

@ -163,7 +163,7 @@ export function TGFlow() {
return (
<div className='cc-fade-in relative' tabIndex={-1} onKeyDown={handleKeyDown}>
<div className='cc-tab-tools flex flex-col items-center rounded-b-2xl cc-blur'>
<div className='cc-tab-tools flex flex-col items-center rounded-b-2xl backdrop-blur-xs'>
<ToolbarTermGraph />
<ToolbarFocusedCst />
{!focusCst ? (
@ -181,7 +181,7 @@ export function TGFlow() {
</div>
<div className='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 backdrop-blur-xs rounded-xl'>
Выбор {selected.length} из {schema.stats?.count_all ?? 0}
</span>
<GraphSelectors />

View File

@ -2,7 +2,6 @@
import { MiniButton } from '@/components/control';
import { IconGraphInputs, IconGraphOutputs, IconReset } from '@/components/icons';
import { APP_COLORS } from '@/styling/colors';
import { useTermGraphStore } from '../../../stores/term-graph';
import { useRSEdit } from '../rsedit-context';
@ -37,7 +36,7 @@ export function ToolbarFocusedCst() {
return (
<div className='flex items-center cc-icons'>
<div className='w-31 mt-0.5 text-right select-none' style={{ color: APP_COLORS.fgPurple }}>
<div className='w-31 mt-0.5 text-right select-none color-(--acc-fg-purple)'>
<span>
Фокус
<b className='pr-1'> {focusCst.alias} </b>

View File

@ -6,8 +6,7 @@ import { MiniButton } from '@/components/control';
import { IconDropArrow, IconDropArrowUp } from '@/components/icons';
import { useWindowSize } from '@/hooks/use-window-size';
import { useFitHeight } from '@/stores/app-layout';
import { APP_COLORS } from '@/styling/colors';
import { globalIDs, PARAMETER, prefixes } from '@/utils/constants';
import { globalIDs, prefixes } from '@/utils/constants';
import { colorBgGraphNode } from '../../../colors';
import { type IConstituenta } from '../../../models/rsform';
@ -56,16 +55,8 @@ export function ViewHidden({ items }: ViewHiddenProps) {
onClick={toggleFolded}
/>
<div className={clsx('py-2 clr-input border-x', { 'border-b rounded-b-md': isFolded })}>
<div
className='w-fit select-none'
style={{
transitionProperty: 'translate',
transitionDuration: `${PARAMETER.fastAnimation}ms`,
transitionTimingFunction: 'ease-out',
translate: isFolded ? '0.75rem' : 'calc(6.5rem - 50%)'
}}
>
<div className={clsx('py-2 clr-input border-x', isFolded && 'border-b rounded-b-md')}>
<div className={clsx('w-fit select-none cc-view-hidden-header', !isFolded && 'open')}>
{`Скрытые [${localSelected.length} | ${items.length}]`}
</div>
</div>
@ -73,19 +64,14 @@ export function ViewHidden({ items }: ViewHiddenProps) {
<div
tabIndex={-1}
className={clsx(
'flex flex-wrap justify-center gap-2 py-2 -mt-2',
'clr-input border-x border-b rounded-b-md',
'cc-view-hidden-list flex flex-wrap gap-2 justify-center py-2 -mt-2',
'border-x border-b rounded-b-md bg-prim-0',
'text-sm',
'cc-scroll-y'
'cc-scroll-y',
!isFolded && 'open'
)}
style={{
pointerEvents: isFolded ? 'none' : 'auto',
maxHeight: hiddenHeight,
transitionProperty: 'clip-path',
transitionDuration: `${PARAMETER.fastAnimation}ms`,
transitionTimingFunction: 'ease-out',
clipPath: isFolded ? 'inset(10% 0% 90% 0%)' : 'inset(0% 0% 0% 0%)'
}}
aria-hidden={isFolded}
style={{ maxHeight: hiddenHeight }}
>
{items.map(cstID => {
const cst = schema.cstByID.get(cstID)!;
@ -93,17 +79,12 @@ export function ViewHidden({ items }: ViewHiddenProps) {
<button
key={`${prefixes.cst_hidden_list}${cst.alias}`}
type='button'
className='w-12 rounded-md text-center select-none'
style={{
backgroundColor: colorBgGraphNode(cst, coloring),
...(localSelected.includes(cstID)
? {
outlineWidth: '2px',
outlineStyle: cst.is_inherited ? 'dashed' : 'solid',
outlineColor: APP_COLORS.fgDefault
}
: {})
}}
className={clsx(
'cc-view-hidden-item w-12 rounded-md text-center select-none',
localSelected.includes(cstID) && 'selected',
cst.is_inherited && 'inherited'
)}
style={{ backgroundColor: colorBgGraphNode(cst, coloring) }}
onClick={event => handleClick(event, cstID)}
onContextMenu={event => handleContextMenu(event, cst)}
onDoubleClick={() => navigateCst(cstID)}

View File

@ -6,7 +6,6 @@ import { useRoleStore, UserRole } from '@/features/users';
import { useWindowSize } from '@/hooks/use-window-size';
import { useFitHeight } from '@/stores/app-layout';
import { PARAMETER } from '@/utils/constants';
import { ConstituentsSearch } from './constituents-search';
import { TableSideConstituents } from './table-side-constituents';
@ -29,19 +28,11 @@ export function ViewConstituents({ className, isBottom, isMounted }: ViewConstit
<aside
className={clsx(
'border',
{
'rounded-l-md rounded-r-none': !isBottom,
'rounded-md': isBottom
},
isBottom ? 'rounded-md' : 'rounded-l-md rounded-r-none',
isMounted ? 'max-w-full' : 'opacity-0 max-w-0',
'ease-in-out duration-1000 transition-[opacity,max-width]',
className
)}
style={{
transitionProperty: 'opacity, max-width',
transitionDuration: `${2 * PARAMETER.moveDuration}ms`,
transitionTimingFunction: 'ease-in-out',
opacity: isMounted ? 1 : 0,
maxWidth: isMounted ? '100%' : '0'
}}
>
<ConstituentsSearch dense={!!windowSize.width && windowSize.width < COLUMN_DENSE_SEARCH_THRESHOLD} />
<TableSideConstituents maxHeight={listHeight} autoScroll={!isBottom} />

View File

@ -2,7 +2,8 @@
@import './styling/setup.css';
@import './styling/overrides.css';
@import './styling/styles.css';
@import './styling/utilities.css';
@import './styling/components.css';
@custom-variant dark (&:is(.dark *));
@ -50,4 +51,12 @@
--breakpoint-lg: 1024px;
--breakpoint-xl: 1280px;
--breakpoint-2xl: 1536px;
--ease-bezier: cubic-bezier(0.4, 0, 0.2, 1);
--duration-move: 500ms;
--duration-modal: 300ms;
--duration-fade: 300ms;
--duration-dropdown: 200ms;
--duration-select: 100ms;
}

View File

@ -10,9 +10,6 @@ interface AppLayoutStore {
noFooter: boolean;
hideFooter: (value?: boolean) => void;
noScroll: boolean;
hideScroll: (value?: boolean) => void;
}
export const useAppLayoutStore = create<AppLayoutStore>()(set => ({
@ -29,10 +26,7 @@ export const useAppLayoutStore = create<AppLayoutStore>()(set => ({
}),
noFooter: false,
hideFooter: value => set({ noFooter: value ?? true }),
noScroll: true,
hideScroll: value => set({ noScroll: value ?? true })
hideFooter: value => set({ noFooter: value ?? true })
}));
/** Utility function that returns the height of the main area. */

View File

@ -0,0 +1,202 @@
/**
* Module: Utility classes for specific react components.
*/
@utility cc-tab-tools {
z-index: var(--z-index-pop);
position: absolute;
top: 1.7rem;
right: 50%;
padding-top: 0.4rem;
transform: translate(50%, 0%);
}
@utility cc-label {
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 500;
cursor: default;
user-select: text;
white-space: nowrap;
}
@utility cc-tree-item {
padding-left: 1.5rem;
padding-right: 0.75rem;
cursor: pointer;
will-change: max-height, opacity, padding, border;
transition-property: max-height, opacity, padding, border, color, background-color;
transition-timing-function: var(--ease-bezier);
transition-duration: var(--duration-dropdown);
}
@utility cc-badge-constituenta {
width: 3rem;
padding-inline: 0.25rem;
border-width: 1px;
border-radius: 0.5rem;
text-align: center;
font-weight: 500;
white-space: nowrap;
}
@utility cc-table-header {
text-align: start;
padding: 0.5rem;
font-size: var(--text-xs);
line-height: var(--tw-leading, var(--text-xs--line-height));
font-weight: 500;
white-space: nowrap;
-webkit-user-select: none;
user-select: none;
}
@utility cc-modal-wrapper {
isolation: isolate;
z-index: var(--z-index-modal);
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
@utility cc-node-label {
font-weight: 600;
-webkit-text-stroke-width: 0.6px;
-webkit-text-stroke-color: var(--clr-prim-100);
}
@utility cc-text-outline {
-webkit-text-stroke-width: 3px;
-webkit-text-stroke-color: var(--clr-prim-100);
}
@utility cc-ast-label-outline {
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: var(--clr-prim-100);
}
@utility cc-dropdown {
transition-property: clip-path, transform;
transition-duration: var(--duration-dropdown);
transition-timing-function: var(--ease-in-out);
transform: translateY(-10%);
clip-path: inset(10% 0% 90% 0%);
&.open {
transform: translateY(0);
clip-path: inset(0% 0% 0% 0%);
}
}
@utility cc-side-location {
transition-property: width, min-width, opacity;
transition-duration: var(--duration-move);
transition-timing-function: var(--ease-bezier);
opacity: 0;
width: 0;
min-width: 0;
&.open {
opacity: 1;
width: 100%;
}
}
@utility cc-view-hidden-header {
transition-property: transform;
transition-duration: var(--duration-dropdown);
transition-timing-function: var(--ease-out);
transform: translateX(0.75rem);
&.open {
transform: translateX(calc(6.5rem - 50%));
}
}
@utility cc-view-hidden-list {
transition-property: clip-path;
transition-duration: var(--duration-dropdown);
transition-timing-function: var(--ease-out);
clip-path: inset(10% 0% 90% 0%);
pointer-events: none;
&.open {
clip-path: inset(0% 0% 0% 0%);
pointer-events: auto;
}
}
@utility cc-view-hidden-item {
outline-width: 0px;
outline-color: transparent;
&.selected {
outline-width: 2px;
outline-color: var(--clr-prim-999);
outline-style: solid;
}
&.inherited {
outline-style: dashed;
}
}
@utility cc-rs-edit-controls {
transition-property: max-height;
transition-duration: var(--duration-move);
transition-timing-function: var(--ease-in-out);
clip-path: inset(0% 0% 100% 0%);
max-height: 0;
margin-top: 0;
&.open {
clip-path: inset(0% 0% 0% 0%);
max-height: 4.5rem;
margin-top: 0.25rem;
}
}
@utility cc-parsing-result {
transition-property: clip-path, padding, margin, border, height;
transition-duration: var(--duration-move);
transition-timing-function: var(--ease-in-out);
clip-path: inset(0% 0% 100% 0%);
height: 0;
margin-top: 0;
padding: 0;
border-width: 0;
&.open {
clip-path: inset(0% 0% 0% 0%);
height: 4.5rem;
margin-top: 0.75rem;
padding: 0.25rem 0.5rem 0.25rem 0.5rem;
}
}
@utility cc-topic-dropdown {
will-change: clip-path;
transition-property: clip-path;
transition-duration: var(--duration-move);
transition-timing-function: var(--ease-in-out);
clip-path: inset(0% 100% 0% 0%);
&.open {
clip-path: inset(0% 0% 0% 0%);
}
}

View File

@ -15,13 +15,6 @@
--text-max-width: 75ch;
--scroll-padding: 3rem;
--duration-move: 500ms;
--duration-modal: 300ms;
--duration-fade: 300ms;
--duration-select: 100ms;
--transition-bezier: cubic-bezier(0.4, 0, 0.2, 1);
}
/* Light Theme */

View File

@ -169,7 +169,3 @@
@utility border {
border-radius: 0.25rem;
}
@utility sticky {
z-index: 20;
}

View File

@ -1,3 +1,7 @@
/**
* Module: Utility classes for stlye features.
*/
@utility font-main {
font-family: var(--font-main);
}
@ -143,24 +147,6 @@
color: var(--clr-sec-800);
}
@utility cc-tab-tools {
z-index: var(--z-index-pop);
position: absolute;
top: 1.7rem;
right: 50%;
padding-top: 0.4rem;
transform: translate(50%, 0%);
}
@utility cc-label {
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 500;
cursor: default;
user-select: text;
white-space: nowrap;
}
@utility cc-column {
display: flex;
flex-direction: column;
@ -183,10 +169,6 @@
scroll-snap-type: y mandatory;
}
@utility cc-blur {
backdrop-filter: blur(3px);
}
@utility cc-shadow-border {
box-shadow: 0 1px 2px 0 var(--clr-prim-400);
}
@ -195,7 +177,7 @@
opacity: 1;
transition-property: opacity;
transition-timing-function: var(--transition-bezier);
transition-timing-function: var(--ease-bezier);
transition-duration: var(--duration-fade);
@starting-style {
@ -205,7 +187,7 @@
@utility cc-animate-position {
transition-property: transform top left bottom right margin padding;
transition-timing-function: var(--transition-bezier);
transition-timing-function: var(--ease-bezier);
transition-duration: var(--duration-move);
}
@ -214,7 +196,7 @@
opacity: 1;
transition-property: clip-path, opacity;
transition-timing-function: var(--transition-bezier);
transition-timing-function: var(--ease-bezier);
transition-duration: var(--duration-modal);
@starting-style {
@ -225,46 +207,10 @@
@utility cc-animate-color {
transition-property: color, background-color;
transition-timing-function: var(--transition-bezier);
transition-timing-function: var(--ease-bezier);
transition-duration: var(--duration-select);
}
@utility cc-badge-constituenta {
width: 3rem;
padding-inline: 0.25rem;
border-width: 1px;
border-radius: 0.5rem;
text-align: center;
font-weight: 500;
white-space: nowrap;
}
@utility cc-table-header {
text-align: start;
padding: 0.5rem;
font-size: var(--text-xs);
line-height: var(--tw-leading, var(--text-xs--line-height));
font-weight: 500;
white-space: nowrap;
-webkit-user-select: none;
user-select: none;
}
@utility cc-modal-wrapper {
isolation: isolate;
z-index: var(--z-index-modal);
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
@utility cc-mask-sides {
--mask-border-size: 2rem;

View File

@ -7,33 +7,25 @@
*/
export const PARAMETER = {
smallScreen: 640, // == tailwind:sm
smallTreeNodes: 50, // amount of nodes threshold for size increase for large graphs
minimalTimeout: 10, // milliseconds delay for fast updates
refreshTimeout: 100, // milliseconds delay for post-refresh actions
notificationDelay: 300, // milliseconds delay for notifications
minimalTimeout: 10, // milliseconds delay for fast updates
zoomDuration: 500, // milliseconds animation duration
moveDuration: 500, // milliseconds - duration of move animation
dropdownDuration: 200, // milliseconds - duration of dropdown animation
navigationDuration: 300, // milliseconds navigation duration
navigationPopupDelay: 300, // milliseconds delay for navigation popup
graphPopupDelay: 500, // milliseconds delay for graph popup selections
graphRefreshDelay: 10, // milliseconds delay for graph viewpoint reset
fastAnimation: 200, // milliseconds - duration of fast animation
fadeDuration: 300, // milliseconds - duration of fade animation
moveDuration: 500, // milliseconds - duration of move animation
ossImageWidth: 1280, // pixels - size of OSS image
ossImageHeight: 960, // pixels - size of OSS image
graphHandleSize: 3, // pixels - size of graph connection handle
graphNodeRadius: 20, // pixels - radius of graph node
graphNodePadding: 5, // pixels - padding of graph node
graphNodeRadius: 20, // pixels - radius of graph node
logicLabel: 'LOGIC',
errorNodeLabel: '[ERROR]',
exteorVersion: '4.9.7',
TOOLTIP_WIDTH: 'max-w-120'
exteorVersion: '4.9.7'
};
/**