Skip to content

Commit

Permalink
Merge branch 'master' into feat/cms
Browse files Browse the repository at this point in the history
  • Loading branch information
yusuke-sak committed Oct 12, 2023
2 parents c81bd77 + 8949729 commit cf8e6cf
Show file tree
Hide file tree
Showing 23 changed files with 370 additions and 89 deletions.
3 changes: 3 additions & 0 deletions apps/app/src/client/services/renderer/renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ export const generateSimpleViewOptions = (
attachment.sanitizeOption,
lsxGrowiDirective.sanitizeOption,
refsGrowiDirective.sanitizeOption,
{
tagNames: ['cource-end'],
},
)]
: () => {};

Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/components/Layout/BasicLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const PageCreateModal = dynamic(() => import('../PageCreateModal'), { ssr: false
const PageDuplicateModal = dynamic(() => import('../PageDuplicateModal'), { ssr: false });
const PageDeleteModal = dynamic(() => import('../PageDeleteModal'), { ssr: false });
const PageRenameModal = dynamic(() => import('../PageRenameModal'), { ssr: false });
const PagePresentationModal = dynamic(() => import('../PagePresentationModal'), { ssr: false });
const PagePresentationModal = dynamic(() => import('../PagePresentationModal').then(mod => mod.PagePresentationModal), { ssr: false });
const PageAccessoriesModal = dynamic(() => import('../PageAccessoriesModal').then(mod => mod.PageAccessoriesModal), { ssr: false });
const DeleteBookmarkFolderModal = dynamic(() => import('../DeleteBookmarkFolderModal').then(mod => mod.DeleteBookmarkFolderModal), { ssr: false });
// Fab
Expand Down
28 changes: 16 additions & 12 deletions apps/app/src/components/PagePresentationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {

import { useIsEnabledMarp } from '~/stores/context';
import { usePagePresentationModal } from '~/stores/modal';
import { useSWRxCurrentPage } from '~/stores/page';
import { useSWRxCurrentPage, useSWRxPageRevision } from '~/stores/page';
import { usePresentationViewOptions } from '~/stores/renderer';
import { useNextThemes } from '~/stores/use-next-themes';

Expand All @@ -26,15 +26,22 @@ const Presentation = dynamic<PresentationProps>(() => import('./Presentation/Pre
});


const PagePresentationModal = (): JSX.Element => {
export const PagePresentationModal = (): JSX.Element => {

const { data: currentPage } = useSWRxCurrentPage();
const { data: presentationModalData, close: closePresentationModal } = usePagePresentationModal();

const { isOpened = false, page: specifiedPage, rendererOptions: specifiedRendererOptions } = presentationModalData ?? {};

const { data: specifiedRevision } = useSWRxPageRevision(
isOpened ? specifiedPage?.pageId : undefined,
isOpened ? specifiedPage?.revisionId : undefined,
);

const { isDarkMode } = useNextThemes();
const fullscreen = useFullScreen();

const { data: currentPage } = useSWRxCurrentPage();
const { data: rendererOptions } = usePresentationViewOptions();
const { data: presentationViewOptions } = usePresentationViewOptions();

const { data: isEnabledMarp } = useIsEnabledMarp();

Expand All @@ -54,17 +61,16 @@ const PagePresentationModal = (): JSX.Element => {
closePresentationModal();
}, [fullscreen, closePresentationModal]);

const isOpen = presentationModalData?.isOpened ?? false;

if (!isOpen) {
if (!isOpened) {
return <></>;
}

const markdown = currentPage?.revision.body;
const markdown = (specifiedRevision ?? currentPage?.revision)?.body;
const rendererOptions = (specifiedRendererOptions ?? presentationViewOptions) as ReactMarkdownOptions;

return (
<Modal
isOpen={isOpen}
isOpen={isOpened}
toggle={closeHandler}
data-testid="page-presentation-modal"
className={`grw-presentation-modal ${styles['grw-presentation-modal']}`}
Expand All @@ -81,7 +87,7 @@ const PagePresentationModal = (): JSX.Element => {
{ rendererOptions != null && isEnabledMarp != null && (
<Presentation
options={{
rendererOptions: rendererOptions as ReactMarkdownOptions,
rendererOptions,
revealOptions: {
embedded: true,
hash: true,
Expand All @@ -97,5 +103,3 @@ const PagePresentationModal = (): JSX.Element => {
</Modal>
);
};

export default PagePresentationModal;
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import type { IPageHasId } from '@growi/core';
import { DevidedPagePath } from '@growi/core/dist/models';
import { format } from 'date-fns';

import PagePathHierarchicalLink from '~/components/PagePathHierarchicalLink';
import LinkedPagePath from '~/models/linked-page-path';


const formatDate = (date: Date | null) => {
if (date == null) {
return '';
}
return format(new Date(date), 'yyyy-MM-dd HH:mm');
};

export const ArticleListHead = (): JSX.Element => {
return (
<tr>
<th>Article name</th>
<th>Author</th>
<th>Published at</th>
<th style={{ width: '200px' }}>Last update</th>
</tr>
);
};
Expand All @@ -21,7 +30,7 @@ type Props = {

export const ArticleListRow = (props: Props): JSX.Element => {
const { page } = props;
const author = page.creator.name;
const { creator, updatedAt } = page;

const dPagePath: DevidedPagePath = new DevidedPagePath(page.path, false);
const linkedPagePath = new LinkedPagePath(dPagePath.latter);
Expand All @@ -31,8 +40,8 @@ export const ArticleListRow = (props: Props): JSX.Element => {
<td>
<PagePathHierarchicalLink linkedPagePath={linkedPagePath} basePath={dPagePath.isRoot ? undefined : dPagePath.former} />
</td>
<td>{author}</td>
<td>(TBD)</td>
<td className="align-middle">{creator.name}</td>
<td className="align-middle">{formatDate(updatedAt)}</td>
</tr>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.lms-cource-end :global {
.btn {
width: 400px;
height: 150px;
pointer-events: auto;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useCallback } from 'react';

import { usePagePresentationModal } from '~/stores/modal';

import styles from './CourceEnd.module.scss';

export const CourceEnd = (): JSX.Element => {

const { close } = usePagePresentationModal();

const clickHandler = useCallback(() => {
close();
}, [close]);

return (
<div className={`${styles['lms-cource-end']} d-flex justify-content-center`}>
<button type="button" className="btn btn-lg btn-outline-success" onClick={clickHandler}>
<div className="display-4">Save and exit</div>
</button>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './CourceEnd';

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const CourceDashboard = (): JSX.Element => {
return <>(TBD) Dashboard</>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './CourceDashboard';
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import React from 'react';
import React, { useCallback, useMemo } from 'react';

import type {
IPageHasId,
} from '@growi/core';

import { IPagingResult } from '~/interfaces/paging-result';
import { useIsSharedUser } from '~/stores/context';
import { useIsSharedUser, useRendererConfig } from '~/stores/context';
import { usePagePresentationModal } from '~/stores/modal';
import { useCurrentPagePath } from '~/stores/page';
import {
useSWRxPageList,
} from '~/stores/page-listing';

import { generatePresentationCourceUnitOptions } from '../../../services/renderer/renderer';

import { CourceUnitHead, CourceUnitRow } from './CourceUnitRow';


Expand All @@ -21,6 +25,28 @@ const CourceUnitListSubstance = (props: SubstanceProps): JSX.Element => {

const { pagingResult } = props;

const { data: currentPagePath } = useCurrentPagePath();
const { open: openPresentationModal } = usePagePresentationModal();

const { data: rendererConfig } = useRendererConfig();

const rendererOptions = useMemo(() => {
if (rendererConfig == null || currentPagePath == null) {
return null;
}
return generatePresentationCourceUnitOptions(rendererConfig, currentPagePath);
}, [currentPagePath, rendererConfig]);

const playHandler = useCallback((page: IPageHasId) => {
openPresentationModal({
page: {
pageId: page._id,
revisionId: page.revision.toString(),
},
rendererOptions,
});
}, [openPresentationModal, rendererOptions]);

// const pageDeletedHandler: OnDeletedFunction = useCallback((...args) => {
// const path = args[0];
// const isCompletely = args[2];
Expand All @@ -39,7 +65,7 @@ const CourceUnitListSubstance = (props: SubstanceProps): JSX.Element => {

if (pagingResult == null) {
return (
<div className="wiki">
<div>
<div className="text-muted text-center">
<i className="fa fa-2x fa-spinner fa-pulse mr-1"></i>
</div>
Expand All @@ -48,7 +74,7 @@ const CourceUnitListSubstance = (props: SubstanceProps): JSX.Element => {
}

const rowList = pagingResult.items.map(page => (
<CourceUnitRow page={page} />
<CourceUnitRow key={page._id} page={page} onPlayButtonClicked={playHandler} />
));

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { IPageHasId } from '@growi/core';
import { DevidedPagePath } from '@growi/core/dist/models';
import { format } from 'date-fns';

import PagePathHierarchicalLink from '~/components/PagePathHierarchicalLink';
import LinkedPagePath from '~/models/linked-page-path';


const formatDate = (date: Date | null) => {
if (date == null) {
return '';
}
return format(new Date(date), 'yyyy-MM-dd HH:mm');
};


export const CourceUnitHead = (): JSX.Element => {
return (
<tr>
<th style={{ width: '1px' }}></th>
<th>Cource unit name</th>
<th>Author</th>
<th style={{ width: '200px' }}>Last update</th>
</tr>
);
};


type Props = {
page: IPageHasId,
onPlayButtonClicked?: (page: IPageHasId) => void,
}

export const CourceUnitRow = (props: Props): JSX.Element => {
const { page, onPlayButtonClicked } = props;
const { creator, updatedAt } = page;

const dPagePath: DevidedPagePath = new DevidedPagePath(page.path, false);
const linkedPagePath = new LinkedPagePath(dPagePath.latter);

return (
<tr>
<td>
<button type="button" className="btn btn-lg btn-light d-flex align-items-center" onClick={() => onPlayButtonClicked?.(page)}>
<span className="material-icons">play_arrow</span>
</button>
</td>
<td className="align-middle">
<PagePathHierarchicalLink linkedPagePath={linkedPagePath} basePath={dPagePath.isRoot ? undefined : dPagePath.former} />
</td>
<td className="align-middle">{creator.name}</td>
<td className="align-middle">{formatDate(updatedAt)}</td>
</tr>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useState } from 'react';

import dynamic from 'next/dynamic';
import { TabContent, TabPane } from 'reactstrap';

import { useCurrentPathname } from '~/stores/context';

import { CourceUnitList } from './CourceUnitList';


const CourceDashboard = dynamic(() => import('./CourceDashboard').then(mod => mod.CourceDashboard), {
ssr: false,
});

export const CourceView = (): JSX.Element => {

const { data: currentPagePath } = useCurrentPathname();

const [isDashboardMode, setDashboardMode] = useState(false);

if (currentPagePath == null) {
return <></>;
}

const Toggler = () => (
<div className="btn-group btn-group-toggle" data-toggle="buttons">
<label className={`btn btn-outline-secondary ${isDashboardMode ? 'active' : ''}`} onClick={() => setDashboardMode(true)}>
<input type="radio" name="options" id="option1" checked={isDashboardMode} onChange={() => setDashboardMode(true)} />
<span className="icon icon-graph"></span>
</label>
<label className={`btn btn-outline-secondary ${isDashboardMode ? '' : 'active'}`} onClick={() => setDashboardMode(false)}>
<input type="radio" name="options" id="option2" checked={!isDashboardMode} onChange={() => setDashboardMode(true)} />
<span className="icon icon-list"></span>
</label>
</div>
);

return (
<>
<div className="d-flex flex-column align-items-end">
<Toggler />
</div>
<div className="mt-3">
<TabContent activeTab={isDashboardMode ? 'dashboard' : 'list'}>
<TabPane tabId="dashboard">
<CourceDashboard />
</TabPane>
<TabPane tabId="list">
<CourceUnitList path={currentPagePath} />
</TabPane>
</TabContent>
</div>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './CourceView';
2 changes: 2 additions & 0 deletions apps/app/src/features/lms/client/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './CourceList';
export * from './CourceView';
Loading

0 comments on commit cf8e6cf

Please sign in to comment.