From 5c79884b640dedb56f3d761c6bf5d9222896ef39 Mon Sep 17 00:00:00 2001 From: Simon G Date: Thu, 7 Jan 2021 20:08:17 +0100 Subject: [PATCH] perf: use hooks for chapter content - remove chapter components to reduce the complexity and maintenance - transform chapters into custom hooks - add utils function `innerText` to get inner text from react elements - rename lunr to custom hook `useLunr` - rename `id` to `chapterId` - rename `subId` to `sectionId` --- src/App.tsx | 13 +- src/components/Chapters/01/01.tsx | 75 ------- src/components/Chapters/01/02.tsx | 67 ------- src/components/Chapters/01/03.tsx | 66 ------ src/components/Chapters/01/04.tsx | 75 ------- src/components/Chapters/01/config.ts | 105 ---------- src/components/Chapters/01/index.tsx | 4 - src/components/Chapters/02/01.tsx | 78 -------- src/components/Chapters/02/02.tsx | 68 ------- src/components/Chapters/02/03.tsx | 69 ------- src/components/Chapters/02/04.tsx | 76 ------- src/components/Chapters/02/05.tsx | 68 ------- src/components/Chapters/02/06.tsx | 74 ------- src/components/Chapters/02/config.ts | 144 ------------- src/components/Chapters/02/index.tsx | 6 - src/components/Chapters/ChapterViewPage.tsx | 31 +++ src/components/Chapters/index.tsx | 83 ++++---- src/components/Home/index.tsx | 45 ++--- src/components/Menu/index.tsx | 66 ++---- src/components/SearchResults/index.tsx | 13 +- src/data/chapter/chapter.tsx | 13 ++ src/data/chapter/chapter01.tsx | 122 +++++++++++ src/data/chapter/chapter02.tsx | 200 +++++++++++++++++++ src/pages/Chapter/index.tsx | 11 +- src/pages/Page.tsx | 11 +- src/pages/Search/index.tsx | 8 +- src/utils/chapters.tsx | 39 ++++ src/utils/hooks/useChapterSection.tsx | 53 +++++ src/utils/hooks/useChapterSectionContent.tsx | 66 ++++++ src/utils/hooks/useLunr.tsx | 82 ++++++++ src/utils/hooks/useMenus.tsx | 88 ++++++++ src/utils/innerText.ts | 42 ++++ src/utils/lunr.tsx | 73 ------- 33 files changed, 835 insertions(+), 1199 deletions(-) delete mode 100644 src/components/Chapters/01/01.tsx delete mode 100644 src/components/Chapters/01/02.tsx delete mode 100644 src/components/Chapters/01/03.tsx delete mode 100644 src/components/Chapters/01/04.tsx delete mode 100644 src/components/Chapters/01/config.ts delete mode 100644 src/components/Chapters/01/index.tsx delete mode 100644 src/components/Chapters/02/01.tsx delete mode 100644 src/components/Chapters/02/02.tsx delete mode 100644 src/components/Chapters/02/03.tsx delete mode 100644 src/components/Chapters/02/04.tsx delete mode 100644 src/components/Chapters/02/05.tsx delete mode 100644 src/components/Chapters/02/06.tsx delete mode 100644 src/components/Chapters/02/config.ts delete mode 100644 src/components/Chapters/02/index.tsx create mode 100644 src/components/Chapters/ChapterViewPage.tsx create mode 100644 src/data/chapter/chapter.tsx create mode 100644 src/data/chapter/chapter01.tsx create mode 100644 src/data/chapter/chapter02.tsx create mode 100644 src/utils/chapters.tsx create mode 100644 src/utils/hooks/useChapterSection.tsx create mode 100644 src/utils/hooks/useChapterSectionContent.tsx create mode 100644 src/utils/hooks/useLunr.tsx create mode 100644 src/utils/hooks/useMenus.tsx create mode 100644 src/utils/innerText.ts delete mode 100644 src/utils/lunr.tsx diff --git a/src/App.tsx b/src/App.tsx index ca24281..33a0d9c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,7 @@ import { IonReactRouter } from '@ionic/react-router'; import { Redirect, Route } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { Menu } from './components/Menu'; -import Page from './pages/Page'; +import { HomePage } from './pages/Page'; import { ChapterPage } from './pages/Chapter'; /* Core CSS required for Ionic components to work properly */ import '@ionic/react/css/core.css'; @@ -40,6 +40,7 @@ const App: React.FC = () => { + } /> } @@ -47,13 +48,11 @@ const App: React.FC = () => { /> { - return ; - }} + render={() => } exact={true} /> { return ; }} @@ -61,9 +60,7 @@ const App: React.FC = () => { /> { - return ; - }} + render={() => } exact={true} /> = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.01.01.TITLE`)}

-
- -

{t(`CHAPTER.01.01.TEXT.PARAGRAPH.01`)}

-
    -
  • {t(`CHAPTER.01.01.TEXT.LIST.01.010000`)}
  • -
      -
    • {t(`CHAPTER.01.01.TEXT.LIST.01.010100`)}
    • -
    • {t(`CHAPTER.01.01.TEXT.LIST.01.010200`)}
    • -
    -
  • {t(`CHAPTER.01.01.TEXT.LIST.01.020000`)}
  • -
      -
    • {t(`CHAPTER.01.01.TEXT.LIST.01.020100`)}
    • -
    • {t(`CHAPTER.01.01.TEXT.LIST.01.020200`)}
    • -
    • {t(`CHAPTER.01.01.TEXT.LIST.01.020300`)}
    • -
    -
  • {t(`CHAPTER.01.01.TEXT.LIST.01.030000`)}
  • -
  • {t(`CHAPTER.01.01.TEXT.LIST.01.040000`)}
  • -
  • {t(`CHAPTER.01.01.TEXT.LIST.01.050000`)}
  • -
  • {t(`CHAPTER.01.01.TEXT.LIST.01.060000`)}
  • -
  • {t(`CHAPTER.01.01.TEXT.LIST.01.070000`)}
  • -
  • {t(`CHAPTER.01.01.TEXT.LIST.01.080000`)}
  • -
- - {t(`CHAPTER.01.01.IMAGE.01.TITLE`)} -
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/01/02.tsx b/src/components/Chapters/01/02.tsx deleted file mode 100644 index 01d1ea0..0000000 --- a/src/components/Chapters/01/02.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { IonCol, IonGrid, IonImg, IonRow, IonText } from '@ionic/react'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { ChapterFooter } from '../footer'; -import { ChapterViewList } from '../ChapterViewList'; -import { ChapterViewCard } from '../ChapterViewCard'; -import { ChapterProps } from '../types'; - -export const Chapter0102: React.FC = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.01.02.TITLE`)}

-
- -

{t(`CHAPTER.01.02.TEXT.PARAGRAPH.01`)}

-
    -
  • {t(`CHAPTER.01.02.TEXT.LIST.01.010000`)}
  • -
  • {t(`CHAPTER.01.02.TEXT.LIST.01.020000`)}
  • -
  • {t(`CHAPTER.01.02.TEXT.LIST.01.030000`)}
  • -
  • {t(`CHAPTER.01.02.TEXT.LIST.01.040000`)}
  • -
  • {t(`CHAPTER.01.02.TEXT.LIST.01.050000`)}
  • -
  • {t(`CHAPTER.01.02.TEXT.LIST.01.060000`)}
  • -
- - {t(`CHAPTER.01.02.IMAGE.01.TITLE`)} -
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/01/03.tsx b/src/components/Chapters/01/03.tsx deleted file mode 100644 index 4c98984..0000000 --- a/src/components/Chapters/01/03.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { IonCol, IonGrid, IonImg, IonRow, IonText } from '@ionic/react'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { ChapterFooter } from '../footer'; -import { ChapterViewList } from '../ChapterViewList'; -import { ChapterViewCard } from '../ChapterViewCard'; -import { ChapterProps } from '../types'; - -export const Chapter0103: React.FC = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.01.03.TITLE`)}

-
- -
    -
  • {t(`CHAPTER.01.03.TEXT.LIST.01.010000`)}
  • -
  • {t(`CHAPTER.01.03.TEXT.LIST.01.020000`)}
  • -
  • {t(`CHAPTER.01.03.TEXT.LIST.01.030000`)}
  • -
  • {t(`CHAPTER.01.03.TEXT.LIST.01.040000`)}
  • -
  • {t(`CHAPTER.01.03.TEXT.LIST.01.050000`)}
  • -
  • {t(`CHAPTER.01.03.TEXT.LIST.01.060000`)}
  • -
- - {t(`CHAPTER.01.03.IMAGE.01.TITLE`)} -
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/01/04.tsx b/src/components/Chapters/01/04.tsx deleted file mode 100644 index 0a68f50..0000000 --- a/src/components/Chapters/01/04.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; -import { IonCol, IonGrid, IonImg, IonRow, IonText } from '@ionic/react'; -import { useTranslation } from 'react-i18next'; -import { ChapterFooter } from '../footer'; -import { ChapterViewList } from '../ChapterViewList'; -import { ChapterViewCard } from '../ChapterViewCard'; -import { ChapterProps } from '../types'; - -export const Chapter0104: React.FC = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.01.04.TITLE`)}

-
- -

{t(`CHAPTER.01.04.TEXT.PARAGRAPH.01`)}

-
    -
  • {t(`CHAPTER.01.04.TEXT.LIST.01.010000`)}
  • -
  • {t(`CHAPTER.01.04.TEXT.LIST.01.020000`)}
  • -
      -
    • {t(`CHAPTER.01.04.TEXT.LIST.01.020100`)}
    • -
    • {t(`CHAPTER.01.04.TEXT.LIST.01.020200`)}
    • -
    • {t(`CHAPTER.01.04.TEXT.LIST.01.020300`)}
    • -
    -
  • {t(`CHAPTER.01.04.TEXT.LIST.01.030000`)}
  • -
      -
    • {t(`CHAPTER.01.04.TEXT.LIST.01.030100`)}
    • -
    • {t(`CHAPTER.01.04.TEXT.LIST.01.030200`)}
    • -
    • {t(`CHAPTER.01.04.TEXT.LIST.01.030300`)}
    • -
    -
  • {t(`CHAPTER.01.04.TEXT.LIST.01.040000`)}
  • -
- - {t(`CHAPTER.01.04.IMAGE.01.TITLE`)} -
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/01/config.ts b/src/components/Chapters/01/config.ts deleted file mode 100644 index 73b278b..0000000 --- a/src/components/Chapters/01/config.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { book, bookmark } from 'ionicons/icons'; -import { Chapter } from '../types'; - -export const CHAPTER_01_00: Chapter = { - color: 'accent-step-0100', - icon: book, - image: '', - isHeader: true, - title: 'CHAPTER.01.00.TITLE', - url: '', -}; - -export const CHAPTER_01_01: Chapter = { - body: [ - 'CHAPTER.01.01.TEXT.PARAGRAPH.01', - 'CHAPTER.01.01.TEXT.LIST.01.010000', - 'CHAPTER.01.01.TEXT.LIST.01.010100', - 'CHAPTER.01.01.TEXT.LIST.01.010200', - 'CHAPTER.01.01.TEXT.LIST.01.020000', - 'CHAPTER.01.01.TEXT.LIST.01.020100', - 'CHAPTER.01.01.TEXT.LIST.01.020200', - 'CHAPTER.01.01.TEXT.LIST.01.020300', - 'CHAPTER.01.01.TEXT.LIST.01.030000', - 'CHAPTER.01.01.TEXT.LIST.01.040000', - 'CHAPTER.01.01.TEXT.LIST.01.050000', - 'CHAPTER.01.01.TEXT.LIST.01.060000', - 'CHAPTER.01.01.TEXT.LIST.01.070000', - 'CHAPTER.01.01.TEXT.LIST.01.080000', - 'CHAPTER.01.01.IMAGE.01.TITLE', - ], - color: 'accent-step-0100', - icon: bookmark, - image: 'CHAPTER.01.01.IMAGE.01.FILENAME', - isHeader: false, - title: 'CHAPTER.01.01.TITLE', - url: '/chapter/01/01', -}; - -export const CHAPTER_01_02: Chapter = { - body: [ - 'CHAPTER.01.02.TEXT.PARAGRAPH.01', - 'CHAPTER.01.02.TEXT.LIST.01.010000', - 'CHAPTER.01.02.TEXT.LIST.01.020000', - 'CHAPTER.01.02.TEXT.LIST.01.030000', - 'CHAPTER.01.02.TEXT.LIST.01.040000', - 'CHAPTER.01.02.TEXT.LIST.01.050000', - 'CHAPTER.01.02.TEXT.LIST.01.060000', - 'CHAPTER.01.02.IMAGE.01.TITLE', - ], - color: 'accent-step-0100', - icon: bookmark, - image: 'CHAPTER.01.02.IMAGE.01.FILENAME', - isHeader: false, - title: 'CHAPTER.01.02.TITLE', - url: '/chapter/01/02', -}; - -export const CHAPTER_01_03: Chapter = { - body: [ - 'CHAPTER.01.03.TEXT.LIST.01.010000', - 'CHAPTER.01.03.TEXT.LIST.01.020000', - 'CHAPTER.01.03.TEXT.LIST.01.030000', - 'CHAPTER.01.03.TEXT.LIST.01.040000', - 'CHAPTER.01.03.TEXT.LIST.01.050000', - 'CHAPTER.01.03.TEXT.LIST.01.060000', - 'CHAPTER.01.03.IMAGE.01.TITLE', - ], - title: 'CHAPTER.01.03.TITLE', - image: 'CHAPTER.01.03.IMAGE.01.FILENAME', - isHeader: false, - url: '/chapter/01/03', - icon: bookmark, - color: 'accent-step-0100', -}; - -export const CHAPTER_01_04: Chapter = { - body: [ - 'CHAPTER.01.04.TEXT.PARAGRAPH.01', - 'CHAPTER.01.04.TEXT.LIST.01.010000', - 'CHAPTER.01.04.TEXT.LIST.01.020000', - 'CHAPTER.01.04.TEXT.LIST.01.020100', - 'CHAPTER.01.04.TEXT.LIST.01.020200', - 'CHAPTER.01.04.TEXT.LIST.01.020300', - 'CHAPTER.01.04.TEXT.LIST.01.030000', - 'CHAPTER.01.04.TEXT.LIST.01.030100', - 'CHAPTER.01.04.TEXT.LIST.01.030200', - 'CHAPTER.01.04.TEXT.LIST.01.030300', - 'CHAPTER.01.04.TEXT.LIST.01.040000', - 'CHAPTER.01.04.IMAGE.01.TITLE', - ], - title: 'CHAPTER.01.04.TITLE', - image: 'CHAPTER.01.04.IMAGE.01.FILENAME', - isHeader: false, - url: '/chapter/01/04', - icon: bookmark, - color: 'accent-step-0100', -}; - -export const CHAPTER_01: Chapter[] = [ - CHAPTER_01_00, - CHAPTER_01_01, - CHAPTER_01_02, - CHAPTER_01_03, - CHAPTER_01_04, -]; diff --git a/src/components/Chapters/01/index.tsx b/src/components/Chapters/01/index.tsx deleted file mode 100644 index 747b585..0000000 --- a/src/components/Chapters/01/index.tsx +++ /dev/null @@ -1,4 +0,0 @@ -export { Chapter0101 } from './01'; -export { Chapter0102 } from './02'; -export { Chapter0103 } from './03'; -export { Chapter0104 } from './04'; diff --git a/src/components/Chapters/02/01.tsx b/src/components/Chapters/02/01.tsx deleted file mode 100644 index b5f145c..0000000 --- a/src/components/Chapters/02/01.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { IonCol, IonGrid, IonImg, IonRow, IonText } from '@ionic/react'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { ChapterFooter } from '../footer'; -import { ChapterViewList } from '../ChapterViewList'; -import { ChapterViewCard } from '../ChapterViewCard'; -import { ChapterProps } from '../types'; - -export const Chapter0201: React.FC = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.02.01.TITLE`)}

-
- -

{t(`CHAPTER.02.01.TEXT.PARAGRAPH.01`)}

-
    -
  • {t(`CHAPTER.02.01.TEXT.LIST.01.010000`)}
  • -
  • {t(`CHAPTER.02.01.TEXT.LIST.01.020000`)}
  • -
  • {t(`CHAPTER.02.01.TEXT.LIST.01.030000`)}
  • -
  • {t(`CHAPTER.02.01.TEXT.LIST.01.040000`)}
  • -
    - - {t(`CHAPTER.02.01.IMAGE.01.TITLE`)} -
    -
  • {t(`CHAPTER.02.01.TEXT.LIST.01.050000`)}
  • -
      -
    • {t(`CHAPTER.02.01.TEXT.LIST.01.050100`)}
    • -
    -
  • {t(`CHAPTER.02.01.TEXT.LIST.01.060000`)}
  • -
  • {t(`CHAPTER.02.01.TEXT.LIST.01.070000`)}
  • -
  • {t(`CHAPTER.02.01.TEXT.LIST.01.080000`)}
  • -
  • {t(`CHAPTER.02.01.TEXT.LIST.01.090000`)}
  • -
    - - {t(`CHAPTER.02.01.IMAGE.02.TITLE`)} -
    -
-
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/02/02.tsx b/src/components/Chapters/02/02.tsx deleted file mode 100644 index b166560..0000000 --- a/src/components/Chapters/02/02.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { IonCol, IonGrid, IonImg, IonRow, IonText } from '@ionic/react'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { ChapterFooter } from '../footer'; -import { ChapterViewList } from '../ChapterViewList'; -import { ChapterViewCard } from '../ChapterViewCard'; -import { ChapterProps } from '../types'; - -export const Chapter0202: React.FC = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.02.02.TITLE`)}

-
- -

{t(`CHAPTER.02.02.TEXT.PARAGRAPH.01`)}

-
    -
  • {t(`CHAPTER.02.02.TEXT.LIST.01.010000`)}
  • -
  • {t(`CHAPTER.02.02.TEXT.LIST.01.020000`)}
  • -
  • {t(`CHAPTER.02.02.TEXT.LIST.01.030000`)}
  • -
  • {t(`CHAPTER.02.02.TEXT.LIST.01.040000`)}
  • -
  • {t(`CHAPTER.02.02.TEXT.LIST.01.050000`)}
  • -
  • {t(`CHAPTER.02.02.TEXT.LIST.01.060000`)}
  • -
  • {t(`CHAPTER.02.02.TEXT.LIST.01.070000`)}
  • -
- - {t(`CHAPTER.02.02.IMAGE.01.TITLE`)} -
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/02/03.tsx b/src/components/Chapters/02/03.tsx deleted file mode 100644 index e4d3d75..0000000 --- a/src/components/Chapters/02/03.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { IonCol, IonGrid, IonImg, IonRow, IonText } from '@ionic/react'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { ChapterFooter } from '../footer'; -import { ChapterViewList } from '../ChapterViewList'; -import { ChapterViewCard } from '../ChapterViewCard'; -import { ChapterProps } from '../types'; - -export const Chapter0203: React.FC = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.02.03.TITLE`)}

-
- -
    -
  • {t(`CHAPTER.02.03.TEXT.LIST.01.010000`)}
  • -
  • {t(`CHAPTER.02.03.TEXT.LIST.01.020000`)}
  • -
  • {t(`CHAPTER.02.03.TEXT.LIST.01.030000`)}
  • -
  • {t(`CHAPTER.02.03.TEXT.LIST.01.040000`)}
  • -
  • {t(`CHAPTER.02.03.TEXT.LIST.01.050000`)}
  • -
  • {t(`CHAPTER.02.03.TEXT.LIST.01.060000`)}
  • -
  • {t(`CHAPTER.02.03.TEXT.LIST.01.070000`)}
  • -
  • {t(`CHAPTER.02.03.TEXT.LIST.01.080000`)}
  • -
  • {t(`CHAPTER.02.03.TEXT.LIST.01.090000`)}
  • -
- - {t(`CHAPTER.02.03.IMAGE.01.TITLE`)} -
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/02/04.tsx b/src/components/Chapters/02/04.tsx deleted file mode 100644 index 846a356..0000000 --- a/src/components/Chapters/02/04.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { IonCol, IonGrid, IonImg, IonRow, IonText } from '@ionic/react'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { ChapterFooter } from '../footer'; -import { ChapterViewList } from '../ChapterViewList'; -import { ChapterViewCard } from '../ChapterViewCard'; -import { ChapterProps } from '../types'; - -export const Chapter0204: React.FC = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.02.04.TITLE`)}

-
- -

{t(`CHAPTER.02.04.TEXT.PARAGRAPH.01`)}

-
    -
  • {t(`CHAPTER.02.04.TEXT.LIST.01.010000`)}
  • -
  • {t(`CHAPTER.02.04.TEXT.LIST.01.020000`)}
  • -
    - - {t(`CHAPTER.02.04.IMAGE.01.TITLE`)} -
    -
-

{t(`CHAPTER.02.04.TEXT.PARAGRAPH.02`)}

-
    -
  • {t(`CHAPTER.02.04.TEXT.LIST.02.010000`)}
  • -
  • {t(`CHAPTER.02.04.TEXT.LIST.02.020000`)}
  • -
  • {t(`CHAPTER.02.04.TEXT.LIST.02.030000`)}
  • -
-

{t(`CHAPTER.02.04.TEXT.PARAGRAPH.03`)}

-
- - {t(`CHAPTER.02.04.IMAGE.02.TITLE`)} -
-
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/02/05.tsx b/src/components/Chapters/02/05.tsx deleted file mode 100644 index f744711..0000000 --- a/src/components/Chapters/02/05.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { IonCol, IonGrid, IonImg, IonRow, IonText } from '@ionic/react'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { ChapterFooter } from '../footer'; -import { ChapterViewList } from '../ChapterViewList'; -import { ChapterViewCard } from '../ChapterViewCard'; -import { ChapterProps } from '../types'; - -export const Chapter0205: React.FC = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.02.05.TITLE`)}

-
- -

{t(`CHAPTER.02.05.TEXT.PARAGRAPH.01`)}

-
    -
  • {t(`CHAPTER.02.05.TEXT.LIST.01.010000`)}
  • -
  • {t(`CHAPTER.02.05.TEXT.LIST.01.020000`)}
  • -
  • {t(`CHAPTER.02.05.TEXT.LIST.01.030000`)}
  • -
  • {t(`CHAPTER.02.05.TEXT.LIST.01.040000`)}
  • -
  • {t(`CHAPTER.02.05.TEXT.LIST.01.050000`)}
  • -
-
- - {t(`CHAPTER.02.05.IMAGE.01.TITLE`)} -
-
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/02/06.tsx b/src/components/Chapters/02/06.tsx deleted file mode 100644 index 061837b..0000000 --- a/src/components/Chapters/02/06.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { IonCol, IonGrid, IonImg, IonRow, IonText } from '@ionic/react'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { ChapterFooter } from '../footer'; -import { ChapterViewList } from '../ChapterViewList'; -import { ChapterViewCard } from '../ChapterViewCard'; -import { ChapterProps } from '../types'; - -export const Chapter0206: React.FC = (props) => { - const { view } = props; - const { t } = useTranslation(); - - if (view === 'card') { - return ( - - ); - } - - if (view === 'list') { - return ( - - ); - } - - return ( - <> - - - - -

{t(`CHAPTER.02.06.TITLE`)}

-
- -

{t(`CHAPTER.02.06.TEXT.PARAGRAPH.01`)}

-
    -
  • {t(`CHAPTER.02.06.TEXT.LIST.01.010000`)}
  • -
      -
    • {t(`CHAPTER.02.06.TEXT.LIST.01.010100`)}
    • -
    • {t(`CHAPTER.02.06.TEXT.LIST.01.010200`)}
    • -
    -
  • {t(`CHAPTER.02.06.TEXT.LIST.01.020000`)}
  • -
      -
    • {t(`CHAPTER.02.06.TEXT.LIST.01.020100`)}
    • -
    • {t(`CHAPTER.02.06.TEXT.LIST.01.020200`)}
    • -
    • {t(`CHAPTER.02.06.TEXT.LIST.01.020300`)}
    • -
    -
-
- - {t(`CHAPTER.02.06.IMAGE.01.TITLE`)} -
-
-
-
-
- - - ); -}; diff --git a/src/components/Chapters/02/config.ts b/src/components/Chapters/02/config.ts deleted file mode 100644 index 8dabe28..0000000 --- a/src/components/Chapters/02/config.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { book, bookmark } from 'ionicons/icons'; -import { Chapter } from '../types'; - -export const CHAPTER_02_00: Chapter = { - color: 'accent-step-0200', - icon: book, - image: '', - isHeader: true, - title: 'CHAPTER.02.00.TITLE', - url: '', -}; - -export const CHAPTER_02_01: Chapter = { - body: [ - 'CHAPTER.02.01.TEXT.PARAGRAPH.01', - 'CHAPTER.02.01.TEXT.LIST.01.010000', - 'CHAPTER.02.01.TEXT.LIST.01.020000', - 'CHAPTER.02.01.TEXT.LIST.01.030000', - 'CHAPTER.02.01.TEXT.LIST.01.040000', - 'CHAPTER.02.01.IMAGE.01.TITLE', - 'CHAPTER.02.01.TEXT.LIST.01.050000', - 'CHAPTER.02.01.TEXT.LIST.01.050100', - 'CHAPTER.02.01.TEXT.LIST.01.060000', - 'CHAPTER.02.01.TEXT.LIST.01.070000', - 'CHAPTER.02.01.TEXT.LIST.01.080000', - 'CHAPTER.02.01.TEXT.LIST.01.090000', - ], - color: 'accent-step-0200', - icon: bookmark, - image: 'CHAPTER.02.01.IMAGE.01.FILENAME', - isHeader: false, - title: 'CHAPTER.02.01.TITLE', - url: '/chapter/02/01', -}; - -export const CHAPTER_02_02: Chapter = { - body: [ - 'CHAPTER.02.02.TEXT.PARAGRAPH.01', - 'CHAPTER.02.02.TEXT.LIST.01.010000', - 'CHAPTER.02.02.TEXT.LIST.01.020000', - 'CHAPTER.02.02.TEXT.LIST.01.030000', - 'CHAPTER.02.02.TEXT.LIST.01.040000', - 'CHAPTER.02.02.TEXT.LIST.01.050000', - 'CHAPTER.02.02.TEXT.LIST.01.060000', - 'CHAPTER.02.02.TEXT.LIST.01.070000', - 'CHAPTER.02.02.IMAGE.01.TITLE', - ], - color: 'accent-step-0200', - icon: bookmark, - image: 'CHAPTER.02.02.IMAGE.01.FILENAME', - isHeader: false, - title: 'CHAPTER.02.02.TITLE', - url: '/chapter/02/02', -}; - -export const CHAPTER_02_03: Chapter = { - body: [ - 'CHAPTER.02.03.TEXT.LIST.01.010000', - 'CHAPTER.02.03.TEXT.LIST.01.020000', - 'CHAPTER.02.03.TEXT.LIST.01.030000', - 'CHAPTER.02.03.TEXT.LIST.01.040000', - 'CHAPTER.02.03.TEXT.LIST.01.050000', - 'CHAPTER.02.03.TEXT.LIST.01.060000', - 'CHAPTER.02.03.TEXT.LIST.01.070000', - 'CHAPTER.02.03.TEXT.LIST.01.080000', - 'CHAPTER.02.03.TEXT.LIST.01.090000', - 'CHAPTER.02.03.IMAGE.01.TITLE', - ], - color: 'accent-step-0200', - icon: bookmark, - image: 'CHAPTER.02.03.IMAGE.01.FILENAME', - isHeader: false, - title: 'CHAPTER.02.03.TITLE', - url: '/chapter/02/03', -}; - -export const CHAPTER_02_04: Chapter = { - body: [ - 'CHAPTER.02.04.TEXT.PARAGRAPH.01', - 'CHAPTER.02.04.TEXT.LIST.01.010000', - 'CHAPTER.02.04.TEXT.LIST.01.020000', - 'CHAPTER.02.04.IMAGE.01.TITLE', - 'CHAPTER.02.04.TEXT.PARAGRAPH.02', - 'CHAPTER.02.04.TEXT.LIST.02.010000', - 'CHAPTER.02.04.TEXT.LIST.02.020000', - 'CHAPTER.02.04.TEXT.LIST.02.030000', - 'CHAPTER.02.04.TEXT.PARAGRAPH.03', - 'CHAPTER.02.04.IMAGE.02.TITLE', - ], - color: 'accent-step-0200', - icon: bookmark, - image: 'CHAPTER.02.04.IMAGE.01.FILENAME', - isHeader: false, - title: 'CHAPTER.02.04.TITLE', - url: '/chapter/02/04', -}; - -export const CHAPTER_02_05: Chapter = { - body: [ - 'CHAPTER.02.05.TEXT.PARAGRAPH.01', - 'CHAPTER.02.05.TEXT.LIST.01.010000', - 'CHAPTER.02.05.TEXT.LIST.01.020000', - 'CHAPTER.02.05.TEXT.LIST.01.030000', - 'CHAPTER.02.05.TEXT.LIST.01.040000', - 'CHAPTER.02.05.TEXT.LIST.01.050000', - 'CHAPTER.02.05.IMAGE.01.TITLE', - ], - color: 'accent-step-0200', - icon: bookmark, - image: 'CHAPTER.02.05.IMAGE.01.FILENAME', - isHeader: false, - title: 'CHAPTER.02.05.TITLE', - url: '/chapter/02/05', -}; - -export const CHAPTER_02_06: Chapter = { - body: [ - 'CHAPTER.02.06.TEXT.PARAGRAPH.01', - 'CHAPTER.02.06.TEXT.LIST.01.010000', - 'CHAPTER.02.06.TEXT.LIST.01.010100', - 'CHAPTER.02.06.TEXT.LIST.01.010200', - 'CHAPTER.02.06.TEXT.LIST.01.020000', - 'CHAPTER.02.06.TEXT.LIST.01.020100', - 'CHAPTER.02.06.TEXT.LIST.01.020200', - 'CHAPTER.02.06.TEXT.LIST.01.020300', - 'CHAPTER.02.06.IMAGE.01.TITLE', - ], - color: 'accent-step-0200', - icon: bookmark, - image: 'CHAPTER.02.06.IMAGE.01.FILENAME', - isHeader: false, - title: 'CHAPTER.02.06.TITLE', - url: '/chapter/02/06', -}; - -export const CHAPTER_02 = [ - CHAPTER_02_00, - CHAPTER_02_01, - CHAPTER_02_02, - CHAPTER_02_03, - CHAPTER_02_04, - CHAPTER_02_05, - CHAPTER_02_06, -]; diff --git a/src/components/Chapters/02/index.tsx b/src/components/Chapters/02/index.tsx deleted file mode 100644 index 4b1edbc..0000000 --- a/src/components/Chapters/02/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -export { Chapter0201 } from './01'; -export { Chapter0202 } from './02'; -export { Chapter0203 } from './03'; -export { Chapter0204 } from './04'; -export { Chapter0205 } from './05'; -export { Chapter0206 } from './06'; diff --git a/src/components/Chapters/ChapterViewPage.tsx b/src/components/Chapters/ChapterViewPage.tsx new file mode 100644 index 0000000..06fedc2 --- /dev/null +++ b/src/components/Chapters/ChapterViewPage.tsx @@ -0,0 +1,31 @@ +import { IonCol, IonGrid, IonRow, IonText } from '@ionic/react'; +import React, { ReactNode } from 'react'; +import { ChapterFooter } from './footer'; + +interface ComponentProps { + content: ReactNode | string; + color?: string; + link: { next: string; previous: string; self: string }; + subTitle?: string; + title: string; +} + +export const ChapterViewPage: React.FC = (props) => { + const { content, link, title } = props; + + return ( + <> + + + + +

{title}

+
+ {content} +
+
+
+ + + ); +}; diff --git a/src/components/Chapters/index.tsx b/src/components/Chapters/index.tsx index 259fa67..0fa0956 100644 --- a/src/components/Chapters/index.tsx +++ b/src/components/Chapters/index.tsx @@ -1,51 +1,56 @@ import React from 'react'; -import * as Chapter01 from './01'; -import * as Chapter02 from './02'; +import { useChapterSection } from '../../utils/hooks/useChapterSection'; +import { ChapterViewCard } from './ChapterViewCard'; +import { ChapterViewList } from './ChapterViewList'; +import { ChapterViewPage } from './ChapterViewPage'; import './index.css'; interface ContainerProps { - id: string; - routerLink?: string; - subId: string; + chapterId: string; + sectionId: string; view?: 'card' | 'list' | 'page'; } -export const getChapterIdsByUrl = (url: string) => { - // url syntax: '/chapter/01/01' - if (url.startsWith('/chapter/')) { - const [id, subId] = url.split('/').slice(2); - return { id, subId }; - } - return { id: '', subId: '' }; -}; - export const Chapter: React.FC = (props) => { - const { id, subId, view = 'page' } = props; - const chapterId = `${id}${subId}`; + const { chapterId, sectionId, view = 'page' } = props; + + const { color, image, link, title, view: chapterView } = useChapterSection( + chapterId, + sectionId, + ); - switch (chapterId) { - case '0101': - return ; - case '0102': - return ; - case '0103': - return ; - case '0104': - return ; - case '0201': - return ; - case '0202': - return ; - case '0203': - return ; - case '0204': - return ; - case '0205': - return ; - case '0206': - return ; - default: - return
Not Implemented Chapter {chapterId}
; + if (view === 'card') { + return ( + + ); } + + if (view === 'list') { + return ( + + ); + } + + return ( + + ); }; diff --git a/src/components/Home/index.tsx b/src/components/Home/index.tsx index 35f7682..505de3a 100644 --- a/src/components/Home/index.tsx +++ b/src/components/Home/index.tsx @@ -1,42 +1,33 @@ -import { IonRouterLink, IonText } from '@ionic/react'; +import { IonText } from '@ionic/react'; import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { Chapter, getChapterIdsByUrl } from '../Chapters'; -import { CHAPTER_01 } from '../Chapters/01/config'; -import { CHAPTER_02 } from '../Chapters/02/config'; +import { useMenuChapters } from '../../utils/hooks/useMenus'; +import { Chapter } from '../Chapters'; import './index.css'; -interface ContainerProps { - name: string; -} - -export const HomeContainer: React.FC = (props) => { - const { t } = useTranslation(); - const MENUS = [CHAPTER_01, CHAPTER_02]; +export const HomeContainer: React.FC = () => { + const chapterMenus = useMenuChapters(); return ( <> - {MENUS.map((chapters, chaptersIndex) => { - const chapterHeader = chapters[0]; - const chapterContent = chapters.slice(1); + {chapterMenus.map((chapterSections, chapterSectionsIndex) => { + const sectionHeader = chapterSections[0]; + const sections = chapterSections.slice(1); return ( - + -

{t(chapterHeader.title)}

+

{sectionHeader.title}

- {chapterContent.map((chapter, chapterIndex) => { - const chapterUrl = chapter.url; - const { id, subId } = getChapterIdsByUrl(chapterUrl); + {sections.map((section, sectionIndex) => { + const { chapterId = '', sectionId = '' } = section; return ( - - - + ); })}
diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx index 7fe03f5..ef618c9 100644 --- a/src/components/Menu/index.tsx +++ b/src/components/Menu/index.tsx @@ -10,54 +10,16 @@ import { IonFooter, IonHeader, } from '@ionic/react'; +import { push } from 'connected-react-router'; +import { settingsOutline } from 'ionicons/icons'; import React from 'react'; -import { - settingsOutline, - information, - homeOutline, - searchOutline, -} from 'ionicons/icons'; import { useDispatch } from 'react-redux'; -import { push } from 'connected-react-router'; - +import { useMenus } from '../../utils/hooks/useMenus'; import './index.css'; -import { useTranslation } from 'react-i18next'; -import { CHAPTER_01 } from '../Chapters/01/config'; -import { CHAPTER_02 } from '../Chapters/02/config'; - -interface AppPage { - color?: string; - isHeader?: boolean; - icon: string; - title: string; - url: string; -} - -const appPages: AppPage[] = [ - { - title: 'Home', - url: '/page/home', - icon: homeOutline, - }, - { - title: 'About', - url: '/page/about', - icon: information, - }, - { - title: 'SEARCH.TITLE', - url: '/page/search', - icon: searchOutline, - }, - ...CHAPTER_01, - ...CHAPTER_02, -]; - -interface MenuProps {} -export const Menu: React.FunctionComponent = (props) => { - const { t } = useTranslation(); +export const Menu: React.FC = () => { const dispatch = useDispatch(); + const menus = useMenus(); return ( @@ -68,28 +30,28 @@ export const Menu: React.FunctionComponent = (props) => { - {appPages.map((appPage, appPageIndex) => { - const { color, icon, title } = appPage; + {menus.map((menu, menuIndex) => { + const { color, icon, title } = menu; - if (appPage.isHeader) { + if (menu.isHeader) { return ( - - {t(title)} + + {title} ); } return ( - + dispatch(push(appPage.url))} + onClick={() => dispatch(push(menu.url))} > - {t(title)} + {title} ); diff --git a/src/components/SearchResults/index.tsx b/src/components/SearchResults/index.tsx index a49111b..46d0f71 100644 --- a/src/components/SearchResults/index.tsx +++ b/src/components/SearchResults/index.tsx @@ -2,8 +2,8 @@ import { IonGrid, IonNote, IonRow } from '@ionic/react'; import React from 'react'; import { useSelector } from 'react-redux'; import { selectCurrentSearchView } from '../../data/user/user.selector'; -import { LunrResult } from '../../utils/lunr'; -import { Chapter, getChapterIdsByUrl } from '../Chapters'; +import { LunrResult } from '../../utils/hooks/useLunr'; +import { Chapter } from '../Chapters'; interface ContainerProps { results: LunrResult[]; @@ -32,11 +32,14 @@ export const SearchResults: React.FC = (props) => { {results.map((result, resultIndex) => { - const { id: chapterUrl } = result; - const { id, subId } = getChapterIdsByUrl(chapterUrl); + const { chapterId, sectionId } = result; return ( - + ); })} diff --git a/src/data/chapter/chapter.tsx b/src/data/chapter/chapter.tsx new file mode 100644 index 0000000..51cfd42 --- /dev/null +++ b/src/data/chapter/chapter.tsx @@ -0,0 +1,13 @@ +export const CHAPTER_COLOR = new Map([ + ['01', 'accent-step-0100'], + ['02', 'accent-step-0200'], + ['03', 'accent-step-0300'], + ['04', 'accent-step-0400'], + ['05', 'accent-step-0500'], + ['06', 'accent-step-0600'], + ['07', 'accent-step-0700'], + ['08', 'accent-step-0800'], + ['09', 'accent-step-0900'], + ['10', 'accent-step-1000'], + ['11', 'accent-step-1100'], +]); diff --git a/src/data/chapter/chapter01.tsx b/src/data/chapter/chapter01.tsx new file mode 100644 index 0000000..6f0a269 --- /dev/null +++ b/src/data/chapter/chapter01.tsx @@ -0,0 +1,122 @@ +import { IonImg, IonText } from '@ionic/react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +const CHAPTER_ID = '01'; + +export const Section01 = () => { + const sectionId = '01'; + const { t } = useTranslation(); + + return ( + +

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.01`)}

+
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
      +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010100`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010200`)}
    • +
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
      +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020100`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020200`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020300`)}
    • +
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.040000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.050000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.060000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.070000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.080000`)}
  • +
+ + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
+ ); +}; + +export const Section02 = () => { + const sectionId = '02'; + const { t } = useTranslation(); + + return ( + +

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.01`)}

+
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.040000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.050000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.060000`)}
  • +
+ + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
+ ); +}; + +export const Section03 = () => { + const sectionId = '03'; + const { t } = useTranslation(); + + return ( + +
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.040000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.050000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.060000`)}
  • +
+ + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
+ ); +}; + +export const Section04 = () => { + const sectionId = '04'; + const { t } = useTranslation(); + + return ( + +

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.01`)}

+
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
      +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020100`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020200`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020300`)}
    • +
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030000`)}
  • +
      +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030100`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030200`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030300`)}
    • +
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.040000`)}
  • +
+ + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
+ ); +}; + +export const Chapter01 = { + Section01, + Section02, + Section03, + Section04, +}; diff --git a/src/data/chapter/chapter02.tsx b/src/data/chapter/chapter02.tsx new file mode 100644 index 0000000..089c1e2 --- /dev/null +++ b/src/data/chapter/chapter02.tsx @@ -0,0 +1,200 @@ +import { IonImg, IonText } from '@ionic/react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +const CHAPTER_ID = '02'; + +export const Section01 = () => { + const sectionId = '01'; + const { t } = useTranslation(); + + return ( + +

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.01`)}

+
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.040000`)}
  • +
    + + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.050000`)}
  • +
      +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.050100`)}
    • +
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.060000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.070000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.080000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.090000`)}
  • +
    + + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.02.TITLE`)} + +
    +
+
+ ); +}; + +export const Section02 = () => { + const sectionId = '02'; + const { t } = useTranslation(); + + return ( + +

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.01`)}

+
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.040000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.050000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.060000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.070000`)}
  • +
+ + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
+ ); +}; + +export const Section03 = () => { + const sectionId = '03'; + const { t } = useTranslation(); + + return ( + +
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.040000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.050000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.060000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.070000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.080000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.090000`)}
  • +
+ + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
+ ); +}; + +export const Section04 = () => { + const sectionId = '04'; + const { t } = useTranslation(); + + return ( + +

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.01`)}

+
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
    + + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
    +
+

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.02`)}

+
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.02.010000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.02.020000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.02.030000`)}
  • +
+

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.03`)}

+
+ + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.02.TITLE`)} + +
+
+ ); +}; + +export const Section05 = () => { + const sectionId = '05'; + const { t } = useTranslation(); + + return ( + +

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.01`)}

+
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.030000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.040000`)}
  • +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.050000`)}
  • +
+
+ + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
+
+ ); +}; + +export const Section06 = () => { + const sectionId = '06'; + const { t } = useTranslation(); + + return ( + +

{t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.PARAGRAPH.01`)}

+
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010000`)}
  • +
      +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010100`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.010200`)}
    • +
    +
  • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020000`)}
  • +
      +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020100`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020200`)}
    • +
    • {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.TEXT.LIST.01.020300`)}
    • +
    +
+
+ + + {t(`CHAPTER.${CHAPTER_ID}.${sectionId}.IMAGE.01.TITLE`)} + +
+
+ ); +}; + +export const Chapter = { + Section01, + Section02, + Section03, + Section04, + Section05, + Section06, +}; diff --git a/src/pages/Chapter/index.tsx b/src/pages/Chapter/index.tsx index e6e9716..5f8142f 100644 --- a/src/pages/Chapter/index.tsx +++ b/src/pages/Chapter/index.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { IonButtons, IonContent, @@ -8,21 +7,21 @@ import { IonTitle, IonToolbar, } from '@ionic/react'; +import React from 'react'; import { useTranslation } from 'react-i18next'; import { RouteComponentProps } from 'react-router'; import { Chapter } from '../../components/Chapters'; interface MatchParams { - id: string; - subId: string; + chapterId: string; + sectionId: string; } interface ContainerProps extends RouteComponentProps {} export const ChapterPage: React.FC = (props) => { const { match } = props; - const { params } = match; - const { id, subId } = params; + const { chapterId, sectionId } = match.params; const { t } = useTranslation(); @@ -37,7 +36,7 @@ export const ChapterPage: React.FC = (props) => { - + ); diff --git a/src/pages/Page.tsx b/src/pages/Page.tsx index a4dda79..6b36e13 100644 --- a/src/pages/Page.tsx +++ b/src/pages/Page.tsx @@ -9,15 +9,10 @@ import { } from '@ionic/react'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import { RouteComponentProps } from 'react-router'; import { HomeContainer } from '../components/Home'; import './Page.css'; -interface ContainerProps { - selectedPage: string; -} - -const Page: React.FC> = ({ match }) => { +export const HomePage: React.FC = () => { const { t } = useTranslation(); return ( @@ -31,10 +26,8 @@ const Page: React.FC> = ({ match }) => { - + ); }; - -export default Page; diff --git a/src/pages/Search/index.tsx b/src/pages/Search/index.tsx index db5ec44..444ba1b 100644 --- a/src/pages/Search/index.tsx +++ b/src/pages/Search/index.tsx @@ -1,4 +1,3 @@ -import React, { useState } from 'react'; import { IonButtons, IonContent, @@ -9,14 +8,13 @@ import { IonTitle, IonToolbar, } from '@ionic/react'; +import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { SearchPopover } from '../../components/SearchPopover'; import { SearchResults } from '../../components/SearchResults'; -import { useLunr } from '../../utils/lunr'; - -interface ContainerProps {} +import { useLunr } from '../../utils/hooks/useLunr'; -export const SearchPage: React.FC = (props) => { +export const SearchPage: React.FC = () => { const { t } = useTranslation(); const [searchValue, setSearchValue] = useState(''); diff --git a/src/utils/chapters.tsx b/src/utils/chapters.tsx new file mode 100644 index 0000000..48147a4 --- /dev/null +++ b/src/utils/chapters.tsx @@ -0,0 +1,39 @@ +import { CHAPTER_COLOR } from '../data/chapter/chapter'; +import * as translations from '../translations/en.json'; + +export type ChapterId = keyof typeof translations.CHAPTER; + +export const getChapterColor = (id: string) => { + const chapterColor = CHAPTER_COLOR.get(id); + return chapterColor; +}; + +export const getChapterStructures = () => { + const chapterIds = getChapterIds(); + const structure = chapterIds.map((chapterId) => { + const sectionIds = getSectionIds(chapterId); + return sectionIds.map((sectionId) => { + return { chapterId, sectionId }; + }); + }); + return structure; +}; + +export const getChapterIds = (): ChapterId[] => { + const chapterIds = Object.keys(translations.CHAPTER).sort(); + return chapterIds as ChapterId[]; +}; + +export const getSectionIds = (chapterId: ChapterId) => { + const sectionIds = Object.keys(translations.CHAPTER[chapterId]).sort(); + return sectionIds; +}; + +export const getChapterIdsByUrl = (url: string) => { + // url syntax: '/chapter/01/01' + if (url.startsWith('/chapter/')) { + const [id, subId] = url.split('/').slice(2); + return { id, subId }; + } + return { id: '', subId: '' }; +}; diff --git a/src/utils/hooks/useChapterSection.tsx b/src/utils/hooks/useChapterSection.tsx new file mode 100644 index 0000000..9e909b8 --- /dev/null +++ b/src/utils/hooks/useChapterSection.tsx @@ -0,0 +1,53 @@ +import { book, bookmark } from 'ionicons/icons'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { getChapterColor } from '../chapters'; +import { innerText } from '../innerText'; +import { getChapterSectionContent } from './useChapterSectionContent'; + +const increaseValue = (value: string, count: number = 1): string => { + const result = Number(value) + count; + return result.toString().padStart(2, '0'); +}; + +const decreaseValue = (value: string, count: number = 1): string => { + const result = Number(value) - count; + return result.toString().padStart(2, '0'); +}; + +export const useChapterSection = (chapterId: string, sectionId: string) => { + const { t } = useTranslation(); + const content = getChapterSectionContent(chapterId, sectionId); + const text = innerText(content); + + const color = getChapterColor(chapterId); + + const isHeader = sectionId === '00'; + + return { + color, + icon: isHeader ? book : bookmark, + id: `chapter${chapterId}${sectionId}`, + image: t(`CHAPTER.${chapterId}.${sectionId}.IMAGE.01.FILENAME`), + isHeader, + link: { + next: `/chapter/${chapterId}/${increaseValue(sectionId)}`, + previous: `/chapter/${chapterId}/${decreaseValue(sectionId)}`, + self: `/chapter/${chapterId}/${sectionId}`, + }, + title: { + chapter: t(`CHAPTER.${chapterId}.00.TITLE`) || '', + section: t(`CHAPTER.${chapterId}.${sectionId}.TITLE`) || '', + }, + url: `/chapter/${chapterId}/${sectionId}`, + view: { + list: { + content: <>{text[0] || ''}, + }, + page: { + content, + text, + }, + }, + }; +}; diff --git a/src/utils/hooks/useChapterSectionContent.tsx b/src/utils/hooks/useChapterSectionContent.tsx new file mode 100644 index 0000000..add6e73 --- /dev/null +++ b/src/utils/hooks/useChapterSectionContent.tsx @@ -0,0 +1,66 @@ +import { IonIcon, IonItem, IonLabel } from '@ionic/react'; +import { warning } from 'ionicons/icons'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Chapter01 } from '../../data/chapter/chapter01'; +import { Chapter as Chapter02 } from '../../data/chapter/chapter02'; + +const ChapterSectionNotAvailable = () => { + const { t } = useTranslation(); + return ( + + + + {t(`APP.ERROR.NOT_AVAILABLE_CHAPTER_SECTION_CONTENT`)} + + + ); +}; + +export const getChapterSectionContent = ( + chapterId: string, + sectionId: string, +) => { + if (chapterId === '01') { + if (sectionId === '01') { + return Chapter01.Section01(); + } + if (sectionId === '02') { + return Chapter01.Section02(); + } + if (sectionId === '03') { + return Chapter01.Section03(); + } + if (sectionId === '04') { + return Chapter01.Section04(); + } + } + + if (chapterId === '02') { + if (sectionId === '01') { + return Chapter02.Section01(); + } + if (sectionId === '02') { + return Chapter02.Section02(); + } + if (sectionId === '03') { + return Chapter02.Section03(); + } + if (sectionId === '04') { + return Chapter02.Section04(); + } + if (sectionId === '05') { + return Chapter02.Section05(); + } + if (sectionId === '06') { + return Chapter02.Section06(); + } + } + + return ChapterSectionNotAvailable(); +}; diff --git a/src/utils/hooks/useLunr.tsx b/src/utils/hooks/useLunr.tsx new file mode 100644 index 0000000..7a89325 --- /dev/null +++ b/src/utils/hooks/useLunr.tsx @@ -0,0 +1,82 @@ +import lunr from 'lunr'; +import { useMemo } from 'react'; +import { getChapterStructures } from '../chapters'; +import { useChapterSection } from './useChapterSection'; + +type LunrDocs = { + [key: string]: { + body: string; + chapterId: string; + id: string; + sectionId: string; + title: string; + }; +}; + +export type LunrResult = { + chapterId: string; + body: string; + id: string; + sectionId: string; + title: string; +}; + +const createLunrDocs = (): LunrDocs => { + const chapters = getChapterStructures(); + const lunrDocs = chapters.reduce((docs, sections) => { + const chapterDocs = sections.reduce((sectionDocs, section) => { + const { chapterId, sectionId } = section; + if (sectionId === '00') { + return sectionDocs; + } + + const { title, url, view } = useChapterSection(chapterId, sectionId); + + return { + ...sectionDocs, + [url]: { + body: view.page.text.join(' '), + chapterId, + id: url, + sectionId, + title: title.section, + }, + }; + }, {}); + + return { ...docs, ...chapterDocs }; + }, {}); + + return lunrDocs; +}; + +export const useLunr = (query: string) => { + const docs = createLunrDocs(); + + const idx = useMemo(() => { + return lunr((builder) => { + builder.field('body'); + builder.field('title'); + + Object.values(docs).forEach((doc) => { + builder.add(doc); + }); + }); + }, [docs]); + + const rankings = useMemo(() => { + if (!query || !idx) { + return []; + } + return idx.search(query); + }, [query, idx]); + + const results = useMemo(() => { + if (!rankings) { + return []; + } + return rankings.map(({ ref }) => docs[ref]); + }, [rankings, docs]); + + return { rankings, results }; +}; diff --git a/src/utils/hooks/useMenus.tsx b/src/utils/hooks/useMenus.tsx new file mode 100644 index 0000000..4416b8e --- /dev/null +++ b/src/utils/hooks/useMenus.tsx @@ -0,0 +1,88 @@ +import { + book, + bookmark, + homeOutline, + information, + searchOutline, +} from 'ionicons/icons'; +import { useTranslation } from 'react-i18next'; +import { getChapterColor, getChapterIds, getSectionIds } from '../chapters'; + +export interface Menu { + chapterId?: string; + color: string | undefined; + icon: string; + isHeader: boolean; + sectionId?: string; + title: string; + url: string; +} + +export const useMenus = (): Menu[] => { + const about = useMenuAbout(); + const home = useMenuHome(); + const search = useMenuSearch(); + const chapters = useMenuChapters(); + + return [home, about, search, ...chapters.flat()]; +}; + +const useMenuAbout = (): Menu => { + const { t } = useTranslation(); + + return { + color: '', + icon: information, + isHeader: false, + title: t('ABOUT.TITLE'), + url: '/page/about', + }; +}; + +export const useMenuChapters = (): Menu[][] => { + const { t } = useTranslation(); + + const chapterIds = getChapterIds(); + const chapterMenus = chapterIds.map((chapterId) => { + const sectionIds = getSectionIds(chapterId); + const sectionMenus = sectionIds.flatMap((sectionId) => { + const color = getChapterColor(chapterId); + const isHeader = sectionId === '00'; + return { + chapterId, + color, + icon: isHeader ? book : bookmark, + isHeader, + sectionId, + title: t(`CHAPTER.${chapterId}.${sectionId}.TITLE`), + url: `/chapter/${chapterId}/${sectionId}`, + }; + }); + return sectionMenus; + }); + return chapterMenus; +}; + +const useMenuHome = (): Menu => { + const { t } = useTranslation(); + + return { + color: '', + icon: homeOutline, + isHeader: false, + title: t('HOME.TITLE'), + url: '/page/home', + }; +}; + +const useMenuSearch = (): Menu => { + const { t } = useTranslation(); + + return { + color: '', + icon: searchOutline, + isHeader: false, + title: t('SEARCH.TITLE'), + url: '/page/search', + }; +}; diff --git a/src/utils/innerText.ts b/src/utils/innerText.ts new file mode 100644 index 0000000..77c46d5 --- /dev/null +++ b/src/utils/innerText.ts @@ -0,0 +1,42 @@ +import { ReactElement, ReactNode } from 'react'; + +const hasProps = (jsx: ReactNode): jsx is ReactElement => + Object.prototype.hasOwnProperty.call(jsx, 'props'); + +export const innerText = (jsx: ReactNode): string[] => { + // Empty + if (jsx === null || typeof jsx === 'boolean' || typeof jsx === 'undefined') { + return []; + } + + // Numeric children. + if (typeof jsx === 'number') { + return [jsx.toString()]; + } + + // String literals. + if (typeof jsx === 'string') { + return [jsx]; + } + + // Array of JSX. + if (Array.isArray(jsx)) { + return jsx.reduce( + (previous: string[], current: ReactNode): string[] => [ + ...previous, + ...innerText(current), + ], + [], + ); + } + + // Children prop. + if ( + hasProps(jsx) && + Object.prototype.hasOwnProperty.call(jsx.props, 'children') + ) { + return innerText(jsx.props.children); + } + + return []; +}; diff --git a/src/utils/lunr.tsx b/src/utils/lunr.tsx deleted file mode 100644 index 58fa148..0000000 --- a/src/utils/lunr.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { useTranslation } from 'react-i18next'; -import { CHAPTER_01 } from '../components/Chapters/01/config'; -import { useMemo } from 'react'; -import lunr from 'lunr'; -import { CHAPTER_02 } from '../components/Chapters/02/config'; - -type LunrDocs = { - [key: string]: { - id: string; - title: string; - body: string; - }; -}; - -export type LunrResult = { - id: string; - title: string; - body: string; -}; - -const createLunrDocs = () => { - // eslint-disable-next-line react-hooks/rules-of-hooks - const { t } = useTranslation(); - - const chapters = [...CHAPTER_01, ...CHAPTER_02]; - - return chapters.reduce((docs, chapter) => { - if (chapter.isHeader) { - return docs; - } - - const doc = { - [chapter.url]: { - id: chapter.url, - title: t(chapter.title), - body: chapter.body?.map((text) => t(text)).join(' ') || '', - }, - }; - - return { ...docs, ...doc }; - }, {}); -}; - -export const useLunr = (query: string) => { - const docs = createLunrDocs(); - - const idx = useMemo(() => { - return lunr((builder) => { - builder.field('body'); - builder.field('title'); - - Object.values(docs).forEach((doc) => { - builder.add(doc); - }); - }); - }, [docs]); - - const rankings = useMemo(() => { - if (!query || !idx) { - return []; - } - return idx.search(query); - }, [query, idx]); - - const results = useMemo(() => { - if (!rankings) { - return []; - } - return rankings.map(({ ref }) => docs[ref]); - }, [rankings, docs]); - - return { rankings, results }; -};