UI improvements and fixes

This commit is contained in:
IRBorisov 2024-05-12 13:58:28 +03:00
parent 2d9c4936b3
commit e9f62a0abc
17 changed files with 43 additions and 24 deletions

View File

@ -10,9 +10,7 @@ function Logo() {
return ( return (
<img <img
alt='Логотип КонцептПортал' alt='Логотип КонцептПортал'
className={clsx('max-h-[1.6rem] w-fit', { className={clsx('max-h-[1.6rem] w-fit')}
'min-w-[11.5rem]': size.isSmall
})}
src={size.isSmall ? '/logo_sign.svg' : !darkMode ? '/logo_full.svg' : '/logo_full_dark.svg'} src={size.isSmall ? '/logo_sign.svg' : !darkMode ? '/logo_full.svg' : '/logo_full_dark.svg'}
/> />
); );

View File

@ -49,6 +49,7 @@ function Checkbox({
className={clsx( className={clsx(
'flex items-center gap-2', // prettier: split lines 'flex items-center gap-2', // prettier: split lines
'outline-none', 'outline-none',
'focus-frame',
cursor, cursor,
className className
)} )}

View File

@ -53,6 +53,7 @@ function CheckboxTristate({
className={clsx( className={clsx(
'flex items-center gap-2', // prettier: split lines 'flex items-center gap-2', // prettier: split lines
'outline-none', 'outline-none',
'focus-frame',
cursor, cursor,
className className
)} )}

View File

@ -21,7 +21,7 @@ function SearchBar({ id, value, onChange, noBorder, ...restProps }: SearchBarPro
noOutline noOutline
placeholder='Поиск' placeholder='Поиск'
type='search' type='search'
className='w-full pl-10' className='w-full pl-10 outline-none'
noBorder={noBorder} noBorder={noBorder}
value={value} value={value}
onChange={event => (onChange ? onChange(event.target.value) : undefined)} onChange={event => (onChange ? onChange(event.target.value) : undefined)}

View File

@ -55,6 +55,10 @@ function SelectMulti<Option, Group extends GroupBase<Option> = GroupBase<Option>
const adjustedStyles: StylesConfig<Option, true, Group> = useMemo( const adjustedStyles: StylesConfig<Option, true, Group> = useMemo(
() => ({ () => ({
container: defaultStyles => ({
...defaultStyles,
borderRadius: '0.25rem'
}),
control: (styles, { isDisabled }) => ({ control: (styles, { isDisabled }) => ({
...styles, ...styles,
borderRadius: '0.25rem', borderRadius: '0.25rem',
@ -118,6 +122,7 @@ function SelectMulti<Option, Group extends GroupBase<Option> = GroupBase<Option>
})} })}
menuPortalTarget={!noPortal ? document.body : null} menuPortalTarget={!noPortal ? document.body : null}
styles={adjustedStyles} styles={adjustedStyles}
classNames={{ container: () => 'focus-frame' }}
{...restProps} {...restProps}
/> />
); );

View File

@ -57,6 +57,10 @@ function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option
const adjustedStyles: StylesConfig<Option, false, Group> = useMemo( const adjustedStyles: StylesConfig<Option, false, Group> = useMemo(
() => ({ () => ({
container: defaultStyles => ({
...defaultStyles,
borderRadius: '0.25rem'
}),
control: (defaultStyles, { isDisabled }) => ({ control: (defaultStyles, { isDisabled }) => ({
...defaultStyles, ...defaultStyles,
borderRadius: '0.25rem', borderRadius: '0.25rem',
@ -116,6 +120,7 @@ function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option
})} })}
menuPortalTarget={!noPortal ? document.body : null} menuPortalTarget={!noPortal ? document.body : null}
styles={adjustedStyles} styles={adjustedStyles}
classNames={{ container: () => 'focus-frame' }}
{...restProps} {...restProps}
/> />
); );

View File

@ -19,8 +19,10 @@ function TabLabel({ label, title, titleHtml, hideTitle, className, ...otherProps
'clr-tab', 'clr-tab',
'text-sm whitespace-nowrap font-controls', 'text-sm whitespace-nowrap font-controls',
'select-none hover:cursor-pointer', 'select-none hover:cursor-pointer',
'outline-none',
className className
)} )}
tabIndex='-1'
data-tooltip-id={!!title || !!titleHtml ? globals.tooltip : undefined} data-tooltip-id={!!title || !!titleHtml ? globals.tooltip : undefined}
data-tooltip-html={titleHtml} data-tooltip-html={titleHtml}
data-tooltip-content={title} data-tooltip-content={title}

View File

@ -5,6 +5,7 @@ import Label from './Label';
export interface TextAreaProps extends CProps.Editor, CProps.Colors, CProps.TextArea { export interface TextAreaProps extends CProps.Editor, CProps.Colors, CProps.TextArea {
dense?: boolean; dense?: boolean;
noResize?: boolean;
} }
function TextArea({ function TextArea({
@ -15,6 +16,7 @@ function TextArea({
dense, dense,
noBorder, noBorder,
noOutline, noOutline,
noResize,
className, className,
colors = 'clr-input', colors = 'clr-input',
...restProps ...restProps
@ -35,7 +37,9 @@ function TextArea({
className={clsx( className={clsx(
'px-3 py-2', 'px-3 py-2',
'leading-tight', 'leading-tight',
'overflow-x-hidden overflow-y-auto',
{ {
'resize-none': noResize,
'border': !noBorder, 'border': !noBorder,
'flex-grow max-w-full': dense, 'flex-grow max-w-full': dense,
'clr-outline': !noOutline 'clr-outline': !noOutline

View File

@ -208,6 +208,7 @@ export enum RSErrorType {
missingParenthesis = 33798, missingParenthesis = 33798,
missingCurlyBrace = 33799, missingCurlyBrace = 33799,
invalidQuantifier = 33800, invalidQuantifier = 33800,
invalidImperative = 33801,
expectedArgDeclaration = 33812, expectedArgDeclaration = 33812,
expectedLocal = 33813, expectedLocal = 33813,
localDoubleDeclare = 10241, localDoubleDeclare = 10241,

View File

@ -9,7 +9,6 @@ import { IconSave } from '@/components/Icons';
import RefsInput from '@/components/RefsInput'; import RefsInput from '@/components/RefsInput';
import SubmitButton from '@/components/ui/SubmitButton'; import SubmitButton from '@/components/ui/SubmitButton';
import TextArea from '@/components/ui/TextArea'; import TextArea from '@/components/ui/TextArea';
import TextInput from '@/components/ui/TextInput';
import AnimateFade from '@/components/wrap/AnimateFade'; import AnimateFade from '@/components/wrap/AnimateFade';
import { useRSForm } from '@/context/RSFormContext'; import { useRSForm } from '@/context/RSFormContext';
import { CstType, IConstituenta, ICstUpdateData } from '@/models/rsform'; import { CstType, IConstituenta, ICstUpdateData } from '@/models/rsform';
@ -155,9 +154,11 @@ function FormConstituenta({
disabled={disabled} disabled={disabled}
onChange={newValue => setTerm(newValue)} onChange={newValue => setTerm(newValue)}
/> />
<TextInput <TextArea
id='cst_typification' id='cst_typification'
rows={typification.length > ROW_SIZE_IN_CHARACTERS ? 2 : 1}
dense dense
noResize
noBorder noBorder
disabled={true} disabled={true}
label='Типизация' label='Типизация'

View File

@ -50,11 +50,7 @@ function EditorRSForm({ isModified, onDestroy, setIsModified }: EditorRSFormProp
onSubmit={initiateSubmit} onSubmit={initiateSubmit}
onDestroy={onDestroy} onDestroy={onDestroy}
/> />
<AnimateFade <AnimateFade onKeyDown={handleInput} className={clsx('sm:w-fit w-full', 'flex flex-col sm:flex-row')}>
tabIndex={-1}
onKeyDown={handleInput}
className={clsx('flex flex-col sm:flex-row', 'sm:w-fit w-full')}
>
<FlexColumn className='px-4 pb-2'> <FlexColumn className='px-4 pb-2'>
<FormRSForm id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} /> <FormRSForm id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} />

View File

@ -154,7 +154,6 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
/> />
<div className='flex justify-between whitespace-nowrap'> <div className='flex justify-between whitespace-nowrap'>
<Checkbox <Checkbox
tabIndex={-1}
id='schema_common' id='schema_common'
label='Общедоступная схема' label='Общедоступная схема'
title='Общедоступные схемы видны всем пользователям и могут быть изменены' title='Общедоступные схемы видны всем пользователям и могут быть изменены'
@ -163,7 +162,6 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
setValue={value => setCommon(value)} setValue={value => setCommon(value)}
/> />
<Checkbox <Checkbox
tabIndex={-1}
id='schema_immutable' id='schema_immutable'
label='Неизменная схема' label='Неизменная схема'
title='Только администраторы могут присваивать схемам неизменный статус' title='Только администраторы могут присваивать схемам неизменный статус'

View File

@ -18,7 +18,7 @@ interface GraphSelectorsProps {
function GraphSelectors({ coloring, setColoring, layout, setLayout, sizing, setSizing }: GraphSelectorsProps) { function GraphSelectors({ coloring, setColoring, layout, setLayout, sizing, setSizing }: GraphSelectorsProps) {
return ( return (
<div className='select-none border rounded-t-md rounded-b-none divide-y'> <div className='border rounded-b-none select-none clr-input rounded-t-md'>
<SelectSingle <SelectSingle
noBorder noBorder
placeholder='Способ расположения' placeholder='Способ расположения'
@ -27,11 +27,12 @@ function GraphSelectors({ coloring, setColoring, layout, setLayout, sizing, setS
value={layout ? { value: layout, label: mapLabelLayout.get(layout) } : null} value={layout ? { value: layout, label: mapLabelLayout.get(layout) } : null}
onChange={data => setLayout(data?.value ?? SelectorGraphLayout[0].value)} onChange={data => setLayout(data?.value ?? SelectorGraphLayout[0].value)}
/> />
<Overlay position='right-[2.5rem] top-[0.3rem]'> <Overlay position='right-[2.5rem] top-[0.5rem]'>
{coloring === 'status' ? <BadgeHelp topic={HelpTopic.CST_STATUS} className='min-w-[25rem]' /> : null} {coloring === 'status' ? <BadgeHelp topic={HelpTopic.CST_STATUS} className='min-w-[25rem]' /> : null}
{coloring === 'type' ? <BadgeHelp topic={HelpTopic.CST_CLASS} className='min-w-[25rem]' /> : null} {coloring === 'type' ? <BadgeHelp topic={HelpTopic.CST_CLASS} className='min-w-[25rem]' /> : null}
</Overlay> </Overlay>
<SelectSingle <SelectSingle
className='my-1'
noBorder noBorder
placeholder='Цветовая схема' placeholder='Цветовая схема'
options={SelectorGraphColoring} options={SelectorGraphColoring}

View File

@ -43,10 +43,10 @@ function ViewConstituents({ expression, schema, activeID, isBottom, onOpenEdit }
return ( return (
<motion.div <motion.div
className={clsx( className={clsx(
'border', // prettier: split-lines 'border overflow-hidden', // prettier: split-lines
{ {
'mt-[2.25rem]': !isBottom, // prettier: split-lines 'mt-[2.2rem] rounded-l-md rounded-r-none': !isBottom, // prettier: split-lines
'mt-3 mx-6': isBottom 'mt-3 mx-6 rounded-md': isBottom
} }
)} )}
initial={{ ...animateSideView.initial }} initial={{ ...animateSideView.initial }}

View File

@ -62,16 +62,14 @@ html {
} }
} }
:focus { :focus,
:focus-visible,
:focus-within {
outline-width: 2px; outline-width: 2px;
outline-style: solid; outline-style: solid;
outline-color: transparent; outline-color: transparent;
} }
:focus-visible {
outline: 0;
}
::selection { ::selection {
background: var(--cl-prim-bg-60); background: var(--cl-prim-bg-60);
.dark & { .dark & {

View File

@ -16,6 +16,11 @@
font-weight: 600; font-weight: 600;
font-variant: small-caps; font-variant: small-caps;
} }
@supports (-moz-appearance: none) {
.font-controls {
font-size: 0.85rem;
}
}
.font-math { .font-math {
font-family: var(--font-math); font-family: var(--font-math);
} }
@ -113,7 +118,8 @@
} }
} }
:is(.clr-outline, .clr-btn-primary):focus-visible { :is(.clr-outline, .clr-btn-primary, .focus-frame):focus-visible,
.focus-frame:has(:focus-visible) {
outline-width: 2px; outline-width: 2px;
outline-style: solid; outline-style: solid;
outline-color: var(--cl-prim-bg-100); outline-color: var(--cl-prim-bg-100);

View File

@ -665,6 +665,8 @@ export function describeRSError(error: IRSErrorDescription): string {
return "Пропущен символ '}'"; return "Пропущен символ '}'";
case RSErrorType.invalidQuantifier: case RSErrorType.invalidQuantifier:
return 'Некорректная кванторная декларация'; return 'Некорректная кванторная декларация';
case RSErrorType.invalidImperative:
return 'Использование императивного синтаксиса вне императивного блока';
case RSErrorType.expectedArgDeclaration: case RSErrorType.expectedArgDeclaration:
return 'Ожидалось объявление аргументов терм-функции'; return 'Ожидалось объявление аргументов терм-функции';
case RSErrorType.expectedLocal: case RSErrorType.expectedLocal: