UI topics list refactoring

This commit is contained in:
IRBorisov 2024-05-14 19:16:04 +03:00
parent 18336cebe3
commit 22ef6b1886
9 changed files with 66 additions and 51 deletions

View File

@ -19,7 +19,7 @@ For more specific TODOs see comments in code
- User notifications on edit - consider spam prevention and change aggregation - User notifications on edit - consider spam prevention and change aggregation
- Static analyzer for RSForm - Static analyzer for RSForm
- Content based search in Library - Content based search in Library
- User profile: Settings - User profile: Settings + settings persistency
- Export PDF (Items list, Graph) - Export PDF (Items list, Graph)
- ARIA (accessibility considerations) - for now machine reading not supported - ARIA (accessibility considerations) - for now machine reading not supported

View File

@ -1,6 +1,7 @@
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import HelpAPI from '../man/HelpAPI'; import HelpAPI from '../man/HelpAPI';
import HelpConcept from '../man/HelpConcept';
import HelpConceptRelations from '../man/HelpConceptRelations'; import HelpConceptRelations from '../man/HelpConceptRelations';
import HelpConceptSystem from '../man/HelpConceptSystem'; import HelpConceptSystem from '../man/HelpConceptSystem';
import HelpCstAttributes from '../man/HelpCstAttributes'; import HelpCstAttributes from '../man/HelpCstAttributes';
@ -42,10 +43,12 @@ function InfoTopic({ topic }: InfoTopicProps) {
if (topic === HelpTopic.CST_STATUS) return <HelpCstStatus />; if (topic === HelpTopic.CST_STATUS) return <HelpCstStatus />;
if (topic === HelpTopic.CST_CLASS) return <HelpCstClass />; if (topic === HelpTopic.CST_CLASS) return <HelpCstClass />;
if (topic === HelpTopic.RSLANG) return <HelpRSLang />; if (topic === HelpTopic.CONCEPTUAL) return <HelpConcept />;
if (topic === HelpTopic.CC_SYSTEM) return <HelpConceptSystem />; if (topic === HelpTopic.CC_SYSTEM) return <HelpConceptSystem />;
if (topic === HelpTopic.CC_CONSTITUENTA) return <HelpCstAttributes />; if (topic === HelpTopic.CC_CONSTITUENTA) return <HelpCstAttributes />;
if (topic === HelpTopic.CC_RELATIONS) return <HelpConceptRelations />; if (topic === HelpTopic.CC_RELATIONS) return <HelpConceptRelations />;
if (topic === HelpTopic.RSLANG) return <HelpRSLang />;
if (topic === HelpTopic.RSL_TYPES) return <HelpRSLangTypes />; if (topic === HelpTopic.RSL_TYPES) return <HelpRSLangTypes />;
if (topic === HelpTopic.RSL_CORRECT) return <HelpRSLangCorrect />; if (topic === HelpTopic.RSL_CORRECT) return <HelpRSLangCorrect />;
if (topic === HelpTopic.RSL_INTERPRET) return <HelpRSLangInterpret />; if (topic === HelpTopic.RSL_INTERPRET) return <HelpRSLangInterpret />;

View File

@ -7,7 +7,7 @@ function HelpCstAttributes() {
// prettier-ignore // prettier-ignore
return ( return (
<div className='dense'> <div className='dense'>
<h1>Аттрибуты конституенты</h1> <h1>Атрибуты конституенты</h1>
<p><b>Термин</b> может быть присвоен любой конституенте. Он используется в других Терминах и в Текстовых определениях</p> <p><b>Термин</b> может быть присвоен любой конституенте. Он используется в других Терминах и в Текстовых определениях</p>
<p><b>Формальное определение</b> строится с помощью формального аппарата <TextURL text='родоструктурной экспликации' href={urls.help_topic(HelpTopic.RSLANG)}/></p> <p><b>Формальное определение</b> строится с помощью формального аппарата <TextURL text='родоструктурной экспликации' href={urls.help_topic(HelpTopic.RSLANG)}/></p>
<p><b>Типизация</b> вычисляется автоматически на основе Формального определения и отражает структуру элементов множества, задаваемого этим определением</p> <p><b>Типизация</b> вычисляется автоматически на основе Формального определения и отражает структуру элементов множества, задаваемого этим определением</p>

View File

@ -71,7 +71,7 @@ function TableBody<TData>({
<tr <tr
key={row.id} key={row.id}
className={clsx( className={clsx(
'cc-table-row', 'cc-scroll-row',
!noHeader && 'scroll-mt-[calc(2px+2rem)]', !noHeader && 'scroll-mt-[calc(2px+2rem)]',
row.getIsSelected() row.getIsSelected()
? 'clr-selected clr-hover' ? 'clr-selected clr-hover'

View File

@ -10,17 +10,17 @@ import { useConceptOptions } from '@/context/OptionsContext';
import useDropdown from '@/hooks/useDropdown'; import useDropdown from '@/hooks/useDropdown';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { animateSlideLeft } from '@/styling/animations'; import { animateSlideLeft } from '@/styling/animations';
import { prefixes } from '@/utils/constants';
import { describeHelpTopic, labelHelpTopic } from '@/utils/labels';
interface TopicsListDropDownProps { import TopicsTree from './TopicsTree';
interface TopicsDropdownProps {
activeTopic: HelpTopic; activeTopic: HelpTopic;
onChangeTopic: (newTopic: HelpTopic) => void; onChangeTopic: (newTopic: HelpTopic) => void;
} }
function TopicsListDropDown({ activeTopic, onChangeTopic }: TopicsListDropDownProps) { function TopicsDropdown({ activeTopic, onChangeTopic }: TopicsDropdownProps) {
const menu = useDropdown(); const menu = useDropdown();
const { noNavigation } = useConceptOptions(); const { noNavigation, calculateHeight } = useConceptOptions();
const selectTheme = useCallback( const selectTheme = useCallback(
(topic: HelpTopic) => { (topic: HelpTopic) => {
@ -34,7 +34,7 @@ function TopicsListDropDown({ activeTopic, onChangeTopic }: TopicsListDropDownPr
<div <div
ref={menu.ref} ref={menu.ref}
className={clsx( className={clsx(
'absolute left-0', // prettier: split-lines 'absolute left-0 w-[13rem]', // prettier: split-lines
'flex flex-col', 'flex flex-col',
'z-modal-tooltip', 'z-modal-tooltip',
'text-xs sm:text-sm', 'text-xs sm:text-sm',
@ -51,34 +51,20 @@ function TopicsListDropDown({ activeTopic, onChangeTopic }: TopicsListDropDownPr
title='Список тем' title='Список тем'
hideTitle={menu.isOpen} hideTitle={menu.isOpen}
icon={!menu.isOpen ? <IconMenuUnfold size='1.25rem' /> : <IconMenuFold size='1.25rem' />} icon={!menu.isOpen ? <IconMenuUnfold size='1.25rem' /> : <IconMenuFold size='1.25rem' />}
className='w-[3rem] h-7' className='w-[3rem] h-7 rounded-none'
onClick={menu.toggle} onClick={menu.toggle}
/> />
<motion.div <motion.div
className='border-x' className='border divide-y rounded-none cc-scroll-y'
style={{ maxHeight: calculateHeight('4rem + 2px') }}
initial={false} initial={false}
animate={menu.isOpen ? 'open' : 'closed'} animate={menu.isOpen ? 'open' : 'closed'}
variants={animateSlideLeft} variants={animateSlideLeft}
> >
{Object.values(HelpTopic).map((topic, index) => ( <TopicsTree activeTopic={activeTopic} onChangeTopic={selectTheme} />
<div
key={`${prefixes.topic_list}${index}`}
className={clsx(
'px-3 py-1',
'border-y',
'clr-controls clr-hover',
'cursor-pointer',
activeTopic === topic && 'clr-selected'
)}
title={describeHelpTopic(topic)}
onClick={() => selectTheme(topic)}
>
{labelHelpTopic(topic)}
</div>
))}
</motion.div> </motion.div>
</div> </div>
); );
} }
export default TopicsListDropDown; export default TopicsDropdown;

View File

@ -3,8 +3,8 @@
import useWindowSize from '@/hooks/useWindowSize'; import useWindowSize from '@/hooks/useWindowSize';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import TopicsListDropDown from './TopicsListDropdown'; import TopicsDropdown from './TopicsDropdown';
import TopicsListStatic from './TopicsListStatic'; import TopicsStatic from './TopicsStatic';
interface TopicsListProps { interface TopicsListProps {
activeTopic: HelpTopic; activeTopic: HelpTopic;
@ -15,9 +15,9 @@ function TopicsList({ activeTopic, onChangeTopic }: TopicsListProps) {
const size = useWindowSize(); const size = useWindowSize();
if (!size.isSmall) { if (!size.isSmall) {
return <TopicsListStatic activeTopic={activeTopic} onChangeTopic={onChangeTopic} />; return <TopicsStatic activeTopic={activeTopic} onChangeTopic={onChangeTopic} />;
} else { } else {
return <TopicsListDropDown activeTopic={activeTopic} onChangeTopic={onChangeTopic} />; return <TopicsDropdown activeTopic={activeTopic} onChangeTopic={onChangeTopic} />;
} }
} }

View File

@ -0,0 +1,33 @@
import clsx from 'clsx';
import { useConceptOptions } from '@/context/OptionsContext';
import { HelpTopic } from '@/models/miscellaneous';
import TopicsTree from './TopicsTree';
interface TopicsStaticProps {
activeTopic: HelpTopic;
onChangeTopic: (newTopic: HelpTopic) => void;
}
function TopicsStatic({ activeTopic, onChangeTopic }: TopicsStaticProps) {
const { calculateHeight } = useConceptOptions();
return (
<div
className={clsx(
'sticky top-0 left-0',
'w-[14rem] cc-scroll-y',
'self-start',
'border divide-y rounded-none',
'clr-controls',
'text-xs sm:text-sm',
'select-none'
)}
style={{ maxHeight: calculateHeight('2.25rem + 2px') }}
>
<TopicsTree activeTopic={activeTopic} onChangeTopic={onChangeTopic} />
</div>
);
}
export default TopicsStatic;

View File

@ -1,33 +1,26 @@
'use client';
import clsx from 'clsx'; import clsx from 'clsx';
import { AnimatePresence } from 'framer-motion';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { prefixes } from '@/utils/constants'; import { prefixes } from '@/utils/constants';
import { describeHelpTopic, labelHelpTopic } from '@/utils/labels'; import { describeHelpTopic, labelHelpTopic } from '@/utils/labels';
interface TopicsListStaticProps { interface TopicsTreeProps {
activeTopic: HelpTopic; activeTopic: HelpTopic;
onChangeTopic: (newTopic: HelpTopic) => void; onChangeTopic: (newTopic: HelpTopic) => void;
} }
function TopicsListStatic({ activeTopic, onChangeTopic }: TopicsListStaticProps) { function TopicsTree({ activeTopic, onChangeTopic }: TopicsTreeProps) {
return ( return (
<div <AnimatePresence initial={false}>
className={clsx(
'sticky top-0 left-0',
'self-start',
'border-x',
'clr-controls',
'text-xs sm:text-sm',
'select-none'
)}
>
{Object.values(HelpTopic).map((topic, index) => ( {Object.values(HelpTopic).map((topic, index) => (
<div <div
key={`${prefixes.topic_list}${index}`} key={`${prefixes.topic_list}${index}`}
className={clsx( className={clsx(
'px-3 py-1', 'px-3 py-1 cc-scroll-row',
'border-y', 'clr-controls clr-hover',
'clr-hover',
'cursor-pointer', 'cursor-pointer',
activeTopic === topic && 'clr-selected' activeTopic === topic && 'clr-selected'
)} )}
@ -37,8 +30,8 @@ function TopicsListStatic({ activeTopic, onChangeTopic }: TopicsListStaticProps)
{labelHelpTopic(topic)} {labelHelpTopic(topic)}
</div> </div>
))} ))}
</div> </AnimatePresence>
); );
} }
export default TopicsListStatic; export default TopicsTree;

View File

@ -231,7 +231,7 @@
@apply flex gap-1; @apply flex gap-1;
} }
.cc-table-row { .cc-scroll-row {
scroll-snap-align: start; scroll-snap-align: start;
scroll-snap-stop: always; scroll-snap-stop: always;
} }