Skip to content

Commit

Permalink
Merge branch 'refactor/generic-cms-text' into feature/cms-upload-form…
Browse files Browse the repository at this point in the history
…-xlsx
  • Loading branch information
lebalz committed Dec 1, 2024
2 parents 49955e5 + 41ea8f0 commit 4a208af
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 17 deletions.
114 changes: 107 additions & 7 deletions docs/Komponentengalerie/cms-text.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ page_id: 9440f367-3529-4e8d-8477-492bd94482dc
---

import CmsText from '@tdev-components/documents/CmsText';
import CmsCode from '@tdev-components/documents/CmsText/Code';
import WithCmsText from '@tdev-components/documents/CmsText/WithCmsText';
import DefinitionList from '@tdev-components/DefinitionList';
import BrowserWindow from '@tdev-components/BrowserWindow';
Expand All @@ -13,12 +14,13 @@ import FromXlsxClipboard from '@tdev-components/shared/FromXlsxClipboard'

# CMS Text
export const DocumentCreator = observer(() => {

useFirstMainDocument('21535ea1-47d9-4521-a7fa-392f06d08f0a', new CmsTextMeta({
default: 'CMS-Text aus der Datenbank 📚'
}));

return <></>;
useFirstMainDocument('5b72150a-947b-4cf2-b616-727ff77c5119', new CmsTextMeta({
default: `print('Hello CMS Code!')`
}));
return null;
});

<DocumentCreator />
Expand All @@ -28,7 +30,17 @@ export const DocumentCreator = observer(() => {
::::info[Erstellung von Documents]
Im Gegensatz zu vielen anderen Komponenten erstellen die Komponenten rund um CMS-Text bewusst **nicht** automatisch ein Document, wenn keins vorhanden ist.

Diese Gallery-Page ist so aufgesetzt, dass für die DocumentRoot-ID `21535ea1-47d9-4521-a7fa-392f06d08f0a` automatisch ein CmsText-Document erzeugt wird. Für die ID `2c0c085d-388a-48cd-9871-975bab0ffda3` wird kein Document erstellt.
Diese Gallery-Page ist so aufgesetzt, dass für einige DocumentRoot-IDs automatisch ein CmsText-Document erzeugt wird:

`21535ea1`
: Inhalt: "CMS-Text aus der Datenbank 📚"
: UUID: `21535ea1-47d9-4521-a7fa-392f06d08f0a`
`5b72150a`
: Inhalt: `print('Hello CMS Code!')`
: UUID: `5b72150a-947b-4cf2-b616-727ff77c5119`


Für die ID `2c0c085d-388a-48cd-9871-975bab0ffda3` wird kein Document erstellt.

:::details[Implementierung]
Das Dokument wird hier im `.mdx` wie folgt erzeugt:
Expand All @@ -37,7 +49,10 @@ export const DocumentCreator = observer(() => {
useFirstMainDocument('21535ea1-47d9-4521-a7fa-392f06d08f0a', new CmsTextMeta({
default: 'CMS-Text aus der Datenbank 📚'
}));
return <></>;
useFirstMainDocument('5b72150a-947b-4cf2-b616-727ff77c5119', new CmsTextMeta({
default: `print('Hello CMS Code!')`
}));
return null;
});
<DocumentCreator />
```
Expand All @@ -50,6 +65,8 @@ Ein möglicher Anwendungsfall ist die Bereitstellung individualisierter Informat

## Inline-Text aus dem CMS
```md
import CmsText from '@tdev-components/documents/CmsText';

Der Text "<CmsText id="21535ea1-47d9-4521-a7fa-392f06d08f0a"/>" wurde aus der Datenbank geladen.
```

Expand All @@ -67,6 +84,82 @@ Der Text "<CmsText id="2c0c085d-388a-48cd-9871-975bab0ffda3"/>" wurde aus der Da
Der Text "<CmsText id="2c0c085d-388a-48cd-9871-975bab0ffda3"/>" wurde aus der Datenbank geladen.
</BrowserWindow>

## CMS-Text mit Permissions Panel
CMS Text kann auch nützlich sein, um bspw. Prüfungsinhalte erst zur gegebenen Zeit mit einer __Shared Permission__ anzuzeigen. Das Permissions Panel kann deshalb optional angezeigt werden:

```md
<BrowserWindow>
Diskutieren Sie das nachfolgende Zitat:
> <CmsText id="21535ea1-47d9-4521-a7fa-392f06d08f0a" showPermissionsPanel/>

</BrowserWindow>
```

<BrowserWindow>
Diskutieren Sie das nachfolgende Zitat:

> <CmsText id="21535ea1-47d9-4521-a7fa-392f06d08f0a" showPermissionsPanel/>
</BrowserWindow>


## CMS Code
Es können auch Code-Blöcke aus dem CMS geladen werden:

```md
import CmsCode from '@tdev-components/documents/CmsText/Code';

<CmsCode
id="5b72150a-947b-4cf2-b616-727ff77c5119"
codeBlockProps={{
language: 'python'
}}
/>
<CmsCode
id="5b72150a-947b-4cf2-b616-727ff77c5119"
codeBlockProps={{
language: 'python'
}}
showPermissionsPanel
/>
`codeBlockProps` entspricht den Props der Komponente `@theme/CodeBlock`.
<CmsCode
id="5b72150a-947b-4cf2-b616-727ff77c5119"
codeBlockProps={{
language: 'python',
showLineNumbers: true,
title: 'Hello World'
}}
showPermissionsPanel
/>
```

<BrowserWindow>
<CmsCode
id="5b72150a-947b-4cf2-b616-727ff77c5119"
codeBlockProps={{
language: 'python'
}}
/>
<CmsCode
id="5b72150a-947b-4cf2-b616-727ff77c5119"
codeBlockProps={{
language: 'python'
}}
showPermissionsPanel
/>
`codeBlockProps` entspricht den Props der Komponente `@theme/CodeBlock`.
<CmsCode
id="5b72150a-947b-4cf2-b616-727ff77c5119"
codeBlockProps={{
language: 'python',
showLineNumbers: true,
title: 'Hello World'
}}
showPermissionsPanel
/>
</BrowserWindow>

## Einfluss auf umliegende Elemente
In vielen Fällen kann es nützlich sein, auch umliegende Elemente nur dann anzuzeigen, wenn ein bestimmter CMS-Text verfügbar ist. Dazu kann die Komponente `<WithCmsText>` verwendet werden.

Expand Down Expand Up @@ -101,29 +194,36 @@ Im folgenden Beispiel wird die gesamte `<DefinitionList>` nur dann angezeigt, we
Zusätzlich wird ein weiterer CMS-Text mit der ID `2c0c085d-388a-48cd-9871-975bab0ffda3` verwendet. Wenn dort das entsprechende Dokument fehlt, bleibt der Eintrag einfach leer.

```md
<WithCmsText entries={{demo: "21535ea1-47d9-4521-a7fa-392f06d08f0a"}}>
<WithCmsText entries={{
demo: "21535ea1-47d9-4521-a7fa-392f06d08f0a",
code: "5b72150a-947b-4cf2-b616-727ff77c5119"
}}>
<DefinitionList>
<dt>Hallo</dt>
<dd>Das ist der erste Eintrag.</dd>
<dt>Welt</dt>
<dd>Das ist der zweite Eintrag.</dd>
<dt>CMS-Eintrag</dt>
<dd><CmsText name="demo" /></dd>
<dt>CMS-Code</dt>
<dd><CmsCode name="code" codeBlockProps={{language: 'py'}} /></dd>
<dt>Anderer CMS-Eintrag</dt>
<dt><CmsText id="2c0c085d-388a-48cd-9871-975bab0ffda3" /></dt>
</DefinitionList>
</WithCmsText>
```

<BrowserWindow>
<WithCmsText entries={{demo: "21535ea1-47d9-4521-a7fa-392f06d08f0a"}}>
<WithCmsText entries={{demo: "21535ea1-47d9-4521-a7fa-392f06d08f0a", code: "5b72150a-947b-4cf2-b616-727ff77c5119"}}>
<DefinitionList>
<dt>Hallo</dt>
<dd>Das ist der erste Eintrag.</dd>
<dt>Welt</dt>
<dd>Das ist der zweite Eintrag.</dd>
<dt>CMS-Eintrag</dt>
<dd><CmsText name="demo" /></dd>
<dt>CMS-Code</dt>
<dd><CmsCode name="code" codeBlockProps={{language: 'py'}} /></dd>
<dt>Anderer CMS-Eintrag</dt>
<dt><CmsText id="2c0c085d-388a-48cd-9871-975bab0ffda3" /></dt>
</DefinitionList>
Expand Down
11 changes: 8 additions & 3 deletions src/components/PermissionsPanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import useIsMobileView from '@tdev-hooks/useIsMobileView';
interface Props {
documentRootId: string;
position?: PopupPosition | PopupPosition[];
className?: string;
}

const PermissionsPanel = observer(({ documentRootId, position }: Props) => {
const PermissionsPanel = observer((props: Props) => {
const { documentRootId, position } = props;
const [isOpen, setIsOpen] = React.useState(false);
const userStore = useStore('userStore');
const documentRootStore = useStore('documentRootStore');
Expand All @@ -39,7 +41,10 @@ const PermissionsPanel = observer(({ documentRootId, position }: Props) => {
.userPermissionsByDocumentRoot(documentRoot.id)
.find((permission) => permission.userId === viewedUser.id);
return (
<div className={styles.viewedUserPermissionPanel} onClick={(e) => e.stopPropagation()}>
<div
className={clsx(styles.viewedUserPermissionPanel, props.className)}
onClick={(e) => e.stopPropagation()}
>
{userPermission ? (
<UserPermission permission={userPermission} />
) : (
Expand All @@ -57,7 +62,7 @@ const PermissionsPanel = observer(({ documentRootId, position }: Props) => {
return (
<Popup
trigger={
<span>
<span className={clsx(props.className)}>
<Button
onClick={(e) => {
e.preventDefault();
Expand Down
34 changes: 34 additions & 0 deletions src/components/documents/CmsText/Code/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { observer } from 'mobx-react-lite';
import { CmsTextContext, useFirstCmsTextDocumentIfExists } from '@tdev-components/documents/CmsText/shared';
import React from 'react';
import CodeBlock, { Props as CodeBlockProps } from '@theme/CodeBlock';
import PermissionsPanel from '@tdev-components/PermissionsPanel';
import { Props as DefaultCmsProps } from '..';
import styles from './styles.module.scss';
import clsx from 'clsx';

interface Props extends DefaultCmsProps {
codeBlockProps?: CodeBlockProps;
}

const CmsCode = observer((props: Props) => {
const { id, name, showPermissionsPanel } = props;
const contextId = name ? React.useContext(CmsTextContext)?.entries[name] : undefined;
const rootId = id || contextId;
const cmsText = useFirstCmsTextDocumentIfExists(rootId);
if (!cmsText || !cmsText.canDisplay) {
return showPermissionsPanel && rootId ? <PermissionsPanel documentRootId={rootId} /> : null;
}
if (showPermissionsPanel && rootId) {
return (
<div className={clsx(styles.container, props.codeBlockProps?.title && styles.withTitle)}>
<PermissionsPanel documentRootId={rootId} className={clsx(styles.codeBlock)} />
<CodeBlock {...(props.codeBlockProps || {})}>{cmsText.text}</CodeBlock>
</div>
);
}

return <CodeBlock {...(props.codeBlockProps || {})}>{cmsText.text}</CodeBlock>;
});

export default CmsCode;
18 changes: 18 additions & 0 deletions src/components/documents/CmsText/Code/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.container {
.codeBlock {
align-self: flex-end;
}
&:not(.withTitle) {
display: flex;
flex-direction: column;
}
&.withTitle {
position: relative;
.codeBlock {
z-index: var(--ifm-z-index-dropdown);
position: absolute;
right: 0;
top: 0;
}
}
}
19 changes: 12 additions & 7 deletions src/components/documents/CmsText/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import { observer } from 'mobx-react-lite';
import { CmsTextContext, useFirstCmsTextDocumentIfExists } from '@tdev-components/documents/CmsText/shared';
import React from 'react';
import PermissionsPanel from '@tdev-components/PermissionsPanel';

interface Props {
export interface Props {
id?: string;
showPermissionsPanel?: boolean;
name?: string;
}

const CmsText = observer(({ id, name }: Props) => {
const CmsText = observer(({ id, name, showPermissionsPanel }: Props) => {
const contextId = name ? React.useContext(CmsTextContext)?.entries[name] : undefined;
const cmsText = useFirstCmsTextDocumentIfExists(id || contextId)?.text;
const rootId = id || contextId;
const cmsText = useFirstCmsTextDocumentIfExists(rootId);
if (!cmsText || !cmsText.canDisplay) {
return showPermissionsPanel && rootId ? <PermissionsPanel documentRootId={rootId} /> : null;
}

return cmsText ? (
return (
<>
<span>{cmsText}</span>
{showPermissionsPanel && rootId && <PermissionsPanel documentRootId={rootId} />}
{cmsText.text}
</>
) : (
<></>
);
});

Expand Down
3 changes: 3 additions & 0 deletions src/components/documents/CmsText/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ interface CmsTextContextType {

export const CmsTextContext = React.createContext<CmsTextContextType | undefined>(undefined);

/**
* @returns an existing, real CmsText document or undefined. (no dummy document is returned)
*/
export function useFirstCmsTextDocumentIfExists(id?: string): CmsText | undefined {
if (!id) {
return undefined;
Expand Down

0 comments on commit 4a208af

Please sign in to comment.