>(
+ new Map(
+ Object.values(HelpTopic).map(value => {
+ const topic = value as HelpTopic;
+ return [
+ topic,
+ topicParent.get(activeTopic) !== topic && topicParent.get(topicParent.get(activeTopic)!) !== topic
+ ];
+ })
+ )
+ );
const { mainHeight } = useConceptOptions();
+ const onFoldTopic = useCallback(
+ (target: HelpTopic, showChildren: boolean) => {
+ if (topicFolded.get(target) === !showChildren) {
+ return;
+ }
+ setFolded(
+ new Map(
+ Object.values(HelpTopic).map(value => {
+ const topic = value as HelpTopic;
+ if (topic === target) {
+ return [topic, !showChildren];
+ }
+ if (
+ !showChildren &&
+ (topicParent.get(topic) === target || topicParent.get(topicParent.get(topic)!) === target)
+ ) {
+ return [topic, true];
+ }
+ const oldValue = topicFolded.get(topic)!;
+ return [topic, oldValue];
+ })
+ )
+ );
+ },
+ [topicFolded]
+ );
- function onSelectTopic(newTopic: HelpTopic) {
- router.push(urls.help_topic(newTopic));
- }
+ const onSelectTopic = useCallback(
+ (newTopic: HelpTopic) => {
+ router.push(urls.help_topic(newTopic));
+ },
+ [router]
+ );
return (
- onSelectTopic(topic)} />
-
+ onSelectTopic(topic)}
+ topicFolded={topicFolded}
+ onFoldTopic={onFoldTopic}
+ />
+
);
}
diff --git a/rsconcept/frontend/src/pages/ManualsPage/TopicsDropdown.tsx b/rsconcept/frontend/src/pages/ManualsPage/TopicsDropdown.tsx
index 4b55d726..5a2f0e6b 100644
--- a/rsconcept/frontend/src/pages/ManualsPage/TopicsDropdown.tsx
+++ b/rsconcept/frontend/src/pages/ManualsPage/TopicsDropdown.tsx
@@ -15,10 +15,12 @@ import TopicsTree from './TopicsTree';
interface TopicsDropdownProps {
activeTopic: HelpTopic;
+ topicFolded: Map;
onChangeTopic: (newTopic: HelpTopic) => void;
+ onFoldTopic: (target: HelpTopic, showChildren: boolean) => void;
}
-function TopicsDropdown({ activeTopic, onChangeTopic }: TopicsDropdownProps) {
+function TopicsDropdown({ activeTopic, topicFolded, onChangeTopic, onFoldTopic }: TopicsDropdownProps) {
const menu = useDropdown();
const { noNavigation, calculateHeight } = useConceptOptions();
@@ -34,7 +36,7 @@ function TopicsDropdown({ activeTopic, onChangeTopic }: TopicsDropdownProps) {
-
+
);
diff --git a/rsconcept/frontend/src/pages/ManualsPage/TopicsList.tsx b/rsconcept/frontend/src/pages/ManualsPage/TopicsList.tsx
index 5a3b1075..e9d24004 100644
--- a/rsconcept/frontend/src/pages/ManualsPage/TopicsList.tsx
+++ b/rsconcept/frontend/src/pages/ManualsPage/TopicsList.tsx
@@ -8,16 +8,32 @@ import TopicsStatic from './TopicsStatic';
interface TopicsListProps {
activeTopic: HelpTopic;
+ topicFolded: Map;
onChangeTopic: (newTopic: HelpTopic) => void;
+ onFoldTopic: (target: HelpTopic, showChildren: boolean) => void;
}
-function TopicsList({ activeTopic, onChangeTopic }: TopicsListProps) {
+function TopicsList({ activeTopic, topicFolded, onChangeTopic, onFoldTopic }: TopicsListProps) {
const size = useWindowSize();
if (!size.isSmall) {
- return ;
+ return (
+
+ );
} else {
- return ;
+ return (
+
+ );
}
}
diff --git a/rsconcept/frontend/src/pages/ManualsPage/TopicsStatic.tsx b/rsconcept/frontend/src/pages/ManualsPage/TopicsStatic.tsx
index 3ecb6a75..a10b6b1c 100644
--- a/rsconcept/frontend/src/pages/ManualsPage/TopicsStatic.tsx
+++ b/rsconcept/frontend/src/pages/ManualsPage/TopicsStatic.tsx
@@ -7,16 +7,18 @@ import TopicsTree from './TopicsTree';
interface TopicsStaticProps {
activeTopic: HelpTopic;
+ topicFolded: Map;
onChangeTopic: (newTopic: HelpTopic) => void;
+ onFoldTopic: (target: HelpTopic, showChildren: boolean) => void;
}
-function TopicsStatic({ activeTopic, onChangeTopic }: TopicsStaticProps) {
+function TopicsStatic({ activeTopic, topicFolded, onChangeTopic, onFoldTopic }: TopicsStaticProps) {
const { calculateHeight } = useConceptOptions();
return (
-
+
);
}
diff --git a/rsconcept/frontend/src/pages/ManualsPage/TopicsTree.tsx b/rsconcept/frontend/src/pages/ManualsPage/TopicsTree.tsx
index fbaba992..da765b9b 100644
--- a/rsconcept/frontend/src/pages/ManualsPage/TopicsTree.tsx
+++ b/rsconcept/frontend/src/pages/ManualsPage/TopicsTree.tsx
@@ -1,35 +1,75 @@
'use client';
import clsx from 'clsx';
-import { AnimatePresence } from 'framer-motion';
+import { AnimatePresence, motion } from 'framer-motion';
+import { useCallback } from 'react';
-import { HelpTopic } from '@/models/miscellaneous';
+import { IconDropArrow, IconPageRight } from '@/components/Icons';
+import { CProps } from '@/components/props';
+import MiniButton from '@/components/ui/MiniButton';
+import Overlay from '@/components/ui/Overlay';
+import { foldableTopics, HelpTopic, topicParent } from '@/models/miscellaneous';
+import { animateSideAppear } from '@/styling/animations';
import { prefixes } from '@/utils/constants';
import { describeHelpTopic, labelHelpTopic } from '@/utils/labels';
interface TopicsTreeProps {
activeTopic: HelpTopic;
+ topicFolded: Map;
onChangeTopic: (newTopic: HelpTopic) => void;
+ onFoldTopic: (target: HelpTopic, showChildren: boolean) => void;
}
-function TopicsTree({ activeTopic, onChangeTopic }: TopicsTreeProps) {
+function TopicsTree({ activeTopic, topicFolded, onChangeTopic, onFoldTopic }: TopicsTreeProps) {
+ const handleClickFold = useCallback(
+ (event: CProps.EventMouse, topic: HelpTopic, showChildren: boolean) => {
+ event.preventDefault();
+ event.stopPropagation();
+ onFoldTopic(topic, showChildren);
+ },
+ [onFoldTopic]
+ );
return (
- {Object.values(HelpTopic).map((topic, index) => (
- onChangeTopic(topic)}
- >
- {labelHelpTopic(topic)}
-
- ))}
+ {Object.values(HelpTopic).map((topic, index) => {
+ const parent = topicParent.get(topic);
+ if (parent !== topic && topicFolded.get(topicParent.get(topic)!)) {
+ return null;
+ }
+ const isFoldable = !!foldableTopics.find(id => id === topic);
+ const isFolded = topicFolded.get(topic)!;
+ return (
+ onChangeTopic(topic)}
+ initial={{ ...animateSideAppear.initial }}
+ animate={{ ...animateSideAppear.animate }}
+ exit={{ ...animateSideAppear.exit }}
+ >
+ {isFoldable ? (
+
+ : }
+ onClick={event => handleClickFold(event, topic, isFolded)}
+ />
+
+ ) : null}
+ {labelHelpTopic(topic)}
+
+ );
+ })}
);
}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/ConstituentaToolbar.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/ConstituentaToolbar.tsx
index 128b3798..b699a0cb 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/ConstituentaToolbar.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/ConstituentaToolbar.tsx
@@ -74,7 +74,7 @@ function ConstituentaToolbar({
disabled={disabled || modified}
onClick={onMoveDown}
/>
-
+
);
}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx
index 8e94de4c..84f22d34 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx
@@ -205,7 +205,7 @@ function EditorRSExpression({
parseData={parser.parseData}
onAnalyze={() => handleCheckExpression()}
/>
-
+
) : null}
-
+
);
}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/RSListToolbar.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/RSListToolbar.tsx
index 9cc183b3..9f34e63b 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/RSListToolbar.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/RSListToolbar.tsx
@@ -68,7 +68,7 @@ function RSListToolbar() {
disabled={controller.isProcessing || controller.nothingSelected}
onClick={controller.deleteCst}
/>
-
+
);
}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/GraphSelectors.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/GraphSelectors.tsx
index 506b367f..5454ac6e 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/GraphSelectors.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/GraphSelectors.tsx
@@ -28,8 +28,8 @@ function GraphSelectors({ coloring, setColoring, layout, setLayout, sizing, setS
onChange={data => setLayout(data?.value ?? SelectorGraphLayout[0].value)}
/>
- {coloring === 'status' ? : null}
- {coloring === 'type' ? : null}
+ {coloring === 'status' ? : null}
+ {coloring === 'type' ? : null}
-
+
);
}
diff --git a/rsconcept/frontend/src/styling/animations.ts b/rsconcept/frontend/src/styling/animations.ts
index 4a3855fd..61dce04c 100644
--- a/rsconcept/frontend/src/styling/animations.ts
+++ b/rsconcept/frontend/src/styling/animations.ts
@@ -208,6 +208,28 @@ export const animateSideView = {
}
};
+export const animateSideAppear = {
+ initial: {
+ clipPath: 'inset(0% 100% 0% 0%)'
+ },
+ animate: {
+ clipPath: 'inset(0% 0% 0% 0%)',
+ transition: {
+ type: 'spring',
+ bounce: 0,
+ duration: 0.3
+ }
+ },
+ exit: {
+ clipPath: 'inset(0% 100% 0% 0%)',
+ transition: {
+ type: 'spring',
+ bounce: 0,
+ duration: 0.3
+ }
+ }
+};
+
export const animateModal = {
initial: {
clipPath: 'inset(50% 50% 50% 50%)',
diff --git a/rsconcept/frontend/src/utils/labels.ts b/rsconcept/frontend/src/utils/labels.ts
index b72c5d68..97f85480 100644
--- a/rsconcept/frontend/src/utils/labels.ts
+++ b/rsconcept/frontend/src/utils/labels.ts
@@ -361,14 +361,14 @@ export function labelHelpTopic(topic: HelpTopic): string {
case HelpTopic.MAIN: return 'Портал';
case HelpTopic.INTERFACE: return 'Интерфейс';
- case HelpTopic.LIBRARY: return '- библиотека';
- case HelpTopic.RSFORM_UI: return '- концептуальная схема';
- case HelpTopic.RSFORM_CARD: return '= карточка схемы';
- case HelpTopic.RSFORM_LIST: return '= список конституент';
- case HelpTopic.RSFORM_EDITOR: return '= редактор конституенты';
- case HelpTopic.GRAPH_TERM: return '= граф термов';
- case HelpTopic.CST_STATUS: return '= статус конституенты';
- case HelpTopic.CST_CLASS: return '= класс конституенты';
+ case HelpTopic.UI_LIBRARY: return '- библиотека';
+ case HelpTopic.UI_RSFORM: return '- концептуальная схема';
+ case HelpTopic.UI_RSFORM_CARD: return '= карточка схемы';
+ case HelpTopic.UI_RSFORM_LIST: return '= список конституент';
+ case HelpTopic.UI_RSFORM_EDITOR: return '= редактор конституенты';
+ case HelpTopic.UI_GRAPH_TERM: return '= граф термов';
+ case HelpTopic.UI_CST_STATUS: return '= статус конституенты';
+ case HelpTopic.UI_CST_CLASS: return '= класс конституенты';
case HelpTopic.CONCEPTUAL: return 'Концептуализация';
case HelpTopic.CC_SYSTEM: return '- система определений';
@@ -399,14 +399,14 @@ export function describeHelpTopic(topic: HelpTopic): string {
case HelpTopic.MAIN: return 'Общая справка по порталу';
case HelpTopic.INTERFACE: return 'Описание интерфейса пользователя';
- case HelpTopic.LIBRARY: return 'Интерфейс Библиотеки схем';
- case HelpTopic.RSFORM_UI: return 'Просмотр и редактирование концептуальной схемы';
- case HelpTopic.RSFORM_CARD: return 'Интерфейс Карточки схемы';
- case HelpTopic.RSFORM_LIST: return 'Интерфейс Списка конституент';
- case HelpTopic.RSFORM_EDITOR: return 'Интерфейс редактирования конституенты';
- case HelpTopic.GRAPH_TERM: return 'Интерфейс графа термов';
- case HelpTopic.CST_STATUS: return 'Нотация отображения статуса конституенты';
- case HelpTopic.CST_CLASS: return 'Нотация отображения класса конституенты';
+ case HelpTopic.UI_LIBRARY: return 'Интерфейс Библиотеки схем';
+ case HelpTopic.UI_RSFORM: return 'Просмотр и редактирование концептуальной схемы';
+ case HelpTopic.UI_RSFORM_CARD: return 'Интерфейс Карточки схемы';
+ case HelpTopic.UI_RSFORM_LIST: return 'Интерфейс Списка конституент';
+ case HelpTopic.UI_RSFORM_EDITOR: return 'Интерфейс редактирования конституенты';
+ case HelpTopic.UI_GRAPH_TERM: return 'Интерфейс графа термов';
+ case HelpTopic.UI_CST_STATUS: return 'Нотация отображения статуса конституенты';
+ case HelpTopic.UI_CST_CLASS: return 'Нотация отображения класса конституенты';
case HelpTopic.CONCEPTUAL: return 'Основы концептуализации и концептуального мышления';
case HelpTopic.CC_SYSTEM: return 'Концептуальная схема как система понятий';