Skip to content

Commit

Permalink
Fetch upstream changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
SilasBerger committed Oct 30, 2024
1 parent a343bd9 commit 66fc635
Show file tree
Hide file tree
Showing 10 changed files with 359 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .upstreamSync
Original file line number Diff line number Diff line change
@@ -1 +1 @@
CURRENT_COMMIT=c632ee60ec4f8512e03dea51c5cef3cdcc92954a
CURRENT_COMMIT=37f5128850d0e1240af4e23dd5c2c8afa2f8bf55
202 changes: 202 additions & 0 deletions docs/material/Components-Gallery/99-Shared-Components/cms-text.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
---
page_id: 9440f367-3529-4e8d-8477-492bd94482dc
---

import CmsText from '@tdev-components/documents/CmsText';
import WithCmsText from '@tdev-components/documents/CmsText/WithCmsText';
import DefinitionList from '@tdev-components/DefinitionList';
import BrowserWindow from '@tdev-components/BrowserWindow';
import { observer } from 'mobx-react-lite';
import { useFirstMainDocument } from '@tdev-hooks/useFirstMainDocument';
import { CmsTextMeta } from '@tdev-models/documents/CmsText';

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

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

return <></>;
});

<DocumentCreator />
::::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.

:::details[Implementierung]
Das Dokument wird hier im `.mdx` wie folgt erzeugt:
```tsx
export const DocumentCreator = observer(() => {
useFirstMainDocument('21535ea1-47d9-4521-a7fa-392f06d08f0a', new CmsTextMeta({
default: 'CMS-Text aus der Datenbank 📚'
}));
return <></>;
});
<DocumentCreator />
```
:::
::::

Soll ein bestimmter Wert nicht fix im Markdown hinterlegt, sondern aus der Datenbank geladen werden, eignet sich die Komponente `<CmsText>`.

Ein möglicher Anwendungsfall ist die Bereitstellung individualisierter Informationen (z.B. Noten).

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

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

Besitzt der aktuelle User kein Document für die angegebene DocumentRoot-ID, dann bleibt der Text leer:

```md
Der Text "<CmsText id="2c0c085d-388a-48cd-9871-975bab0ffda3"/>" wurde aus der Datenbank geladen.
```

<BrowserWindow>
Der Text "<CmsText id="2c0c085d-388a-48cd-9871-975bab0ffda3"/>" wurde aus der Datenbank geladen.
</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.

```md
<WithCmsText entries={{demo: "21535ea1-47d9-4521-a7fa-392f06d08f0a"}}>
Der Text "<CmsText name="demo" />" wurde aus der Datenbank geladen.
</WithCmsText>
```

<BrowserWindow>
<WithCmsText entries={{demo: "21535ea1-47d9-4521-a7fa-392f06d08f0a"}}>
Der Text "<CmsText name="demo" />" wurde aus der Datenbank geladen.
</WithCmsText>
</BrowserWindow>

Ist einer der in `entries` aufgeführten CMS-Texte nicht verfügbar, wird der gesamte Inhalt dieser Klammer ausgeblendet:
```md
<WithCmsText entries={{demo: "2c0c085d-388a-48cd-9871-975bab0ffda3"}}>
Der Text "<CmsText name="demo" />" wurde aus der Datenbank geladen.
</WithCmsText>
```

<BrowserWindow>
<WithCmsText entries={{text: "2c0c085d-388a-48cd-9871-975bab0ffda3"}}>
Der Text "<CmsText name="demo" />" wurde aus der Datenbank geladen.
</WithCmsText>
</BrowserWindow>

### Anwendungsbeispiele
Im folgenden Beispiel wird die gesamte `<DefinitionList>` nur dann angezeigt, wenn der Eintrag für die DocumentRoot-ID `21535ea1-47d9-4521-a7fa-392f06d08f0a` vorhanden ist. In dem Fall steht der entsprechende CMS-Text innerhalb der `<WithCmsText>`-Klammer unter dem Namen `demo` zur Verfügung.

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"}}>
<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>Anderer CMS-Eintrag</dt>
<dt><CmsText id="2c0c085d-388a-48cd-9871-975bab0ffda3" /></dt>
</DefinitionList>
</WithCmsText>
```

<BrowserWindow>
<WithCmsText entries={{demo: "21535ea1-47d9-4521-a7fa-392f06d08f0a"}}>
<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>Anderer CMS-Eintrag</dt>
<dt><CmsText id="2c0c085d-388a-48cd-9871-975bab0ffda3" /></dt>
</DefinitionList>
</WithCmsText>
</BrowserWindow>

Bei mehreren Einträgen zeigt die `<WithCmsText>`-Klammer ihren Inhalt nur dann an, wenn alle entsprechenden Documents vorhanden sind:

```md
<WithCmsText entries={{
a: "21535ea1-47d9-4521-a7fa-392f06d08f0a",
b: "2c0c085d-388a-48cd-9871-975bab0ffda3"}}>
<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="a" /></dd>
<dt>Anderer CMS-Eintrag</dt>
<dt><CmsText name="b" /></dt>
</DefinitionList>
</WithCmsText>
```

<BrowserWindow>
<WithCmsText
entries={{
a: '21535ea1-47d9-4521-a7fa-392f06d08f0a',
b: '2c0c085d-388a-48cd-9871-975bab0ffda3'
}}
>
<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="a" /></dd>
<dt>Anderer CMS-Eintrag</dt>
<dt><CmsText name="b" /></dt>
</DefinitionList>
</WithCmsText>
</BrowserWindow>

`<WithCmsText>`-Klammern können auch verschachtelt genutzt werden:

```md
<WithCmsText entries={{demo: "21535ea1-47d9-4521-a7fa-392f06d08f0a"}}>
<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>
<WithCmsText entries={{demo: "2c0c085d-388a-48cd-9871-975bab0ffda3"}}>
<dt>Anderer CMS-Eintrag</dt>
<dt><CmsText id="demo" /></dt>
</WithCmsText>
</DefinitionList>
</WithCmsText>
```

<BrowserWindow>
<WithCmsText entries={{demo: "21535ea1-47d9-4521-a7fa-392f06d08f0a"}}>
<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>
<WithCmsText entries={{demo: "2c0c085d-388a-48cd-9871-975bab0ffda3"}}>
<dt>Anderer CMS-Eintrag</dt>
<dt><CmsText id="demo" /></dt>
</WithCmsText>
</DefinitionList>
</WithCmsText>
</BrowserWindow>
13 changes: 11 additions & 2 deletions src/api/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import File from '../models/documents/FileSystem/File';
import Restricted from '@tdev-models/documents/Restricted';
import MdxComment from '@tdev-models/documents/MdxComment';
import { Color } from '@tdev-components/shared/Colors';
import CmsText from '@tdev-models/documents/CmsText';

export enum Access {
RO_DocumentRoot = 'RO_DocumentRoot',
Expand All @@ -35,7 +36,8 @@ export enum DocumentType {
Dir = 'dir',
File = 'file',
MdxComment = 'mdx_comment',
Restricted = 'restricted'
Restricted = 'restricted',
CmsText = 'cms_text'
}
export interface ScriptData {
code: string;
Expand Down Expand Up @@ -63,6 +65,10 @@ export interface RestrictedData {
/** no content needed */
}

export interface CmsTextData {
text: string;
}

export interface DirData {
name: string;
isOpen: boolean;
Expand Down Expand Up @@ -105,6 +111,7 @@ export interface TypeDataMapping {
[DocumentType.File]: FileData;
[DocumentType.MdxComment]: MdxCommentData;
[DocumentType.Restricted]: RestrictedData;
[DocumentType.CmsText]: CmsTextData;
// Add more mappings as needed
}

Expand All @@ -119,6 +126,7 @@ export interface TypeModelMapping {
[DocumentType.File]: File;
[DocumentType.MdxComment]: MdxComment;
[DocumentType.Restricted]: Restricted;
[DocumentType.CmsText]: CmsText;
/**
* Add more mappings as needed
* TODO: implement the mapping in DocumentRoot.ts
Expand All @@ -137,7 +145,8 @@ export type DocumentTypes =
| Directory
| File
| MdxComment
| Restricted;
| Restricted
| CmsText;

export interface Document<Type extends DocumentType> {
id: string;
Expand Down
60 changes: 60 additions & 0 deletions src/models/documents/CmsText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { action, computed, observable } from 'mobx';
import iDocument, { Source } from '@tdev-models/iDocument';
import { DocumentType, Document as DocumentProps, TypeDataMapping, Access } from '@tdev-api/document';
import DocumentStore from '@tdev-stores/DocumentStore';
import { TypeMeta } from '@tdev-models/DocumentRoot';

export interface MetaInit {
default?: string;
}

export class CmsTextMeta extends TypeMeta<DocumentType.CmsText> {
readonly type = DocumentType.CmsText;
readonly default: string;

constructor(props: Partial<MetaInit>) {
super(DocumentType.CmsText, undefined);
this.default = props.default ?? '';
}

get defaultData(): TypeDataMapping[DocumentType.CmsText] {
return {
text: this.default
};
}
}

class CmsText extends iDocument<DocumentType.CmsText> {
@observable accessor text: string;
constructor(props: DocumentProps<DocumentType.CmsText>, store: DocumentStore) {
super(props, store);
this.text = props.data?.text || '';
}

@action
setData(data: TypeDataMapping[DocumentType.CmsText], from: Source, updatedAt?: Date): void {
this.text = data.text;
if (from === Source.LOCAL) {
this.save();
}
if (updatedAt) {
this.updatedAt = new Date(updatedAt);
}
}

get data(): TypeDataMapping[DocumentType.CmsText] {
return {
text: this.text
};
}

@computed
get meta(): CmsTextMeta {
if (this.root?.type === DocumentType.CmsText) {
return this.root.meta as CmsTextMeta;
}
return new CmsTextMeta({});
}
}

export default CmsText;
21 changes: 21 additions & 0 deletions src/sharedComponents/documents/CmsText/WithCmsText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { CmsTextContext, useFirstCmsTextDocumentIfExists } from '@tdev-components/documents/CmsText/shared';
import { observer } from 'mobx-react-lite';

interface Props {
entries: { [key: string]: string };
children?: React.ReactNode;
}

const WithCmsText = observer(({ entries, children }: Props) => {
const allDocumentsAvailable = Object.values(entries)
.map((documentRootId) => !!useFirstCmsTextDocumentIfExists(documentRootId))
.every(Boolean);

return allDocumentsAvailable ? (
<CmsTextContext.Provider value={{ entries }}>{children}</CmsTextContext.Provider>
) : (
<></>
);
});

export default WithCmsText;
23 changes: 23 additions & 0 deletions src/sharedComponents/documents/CmsText/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { observer } from 'mobx-react-lite';
import { CmsTextContext, useFirstCmsTextDocumentIfExists } from '@tdev-components/documents/CmsText/shared';
import React from 'react';

interface Props {
id?: string;
name?: string;
}

const CmsText = observer(({ id, name }: Props) => {
const contextId = name ? React.useContext(CmsTextContext)?.entries[name] : undefined;
const cmsText = useFirstCmsTextDocumentIfExists(id || contextId)?.text;

return cmsText ? (
<>
<span>{cmsText}</span>
</>
) : (
<></>
);
});

export default CmsText;
19 changes: 19 additions & 0 deletions src/sharedComponents/documents/CmsText/shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { useDocumentRoot } from '@tdev-hooks/useDocumentRoot';
import CmsText, { CmsTextMeta } from '@tdev-models/documents/CmsText';

interface CmsTextContextType {
entries: { [key: string]: string };
}

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

export function useFirstCmsTextDocumentIfExists(id?: string): CmsText | undefined {
if (!id) {
return undefined;
}

// Not using useFirstMainDocument() here because that would always supply a (dummy) document.
const docRoot = useDocumentRoot(id, new CmsTextMeta({}), false);
return docRoot?.firstMainDocument;
}
Loading

0 comments on commit 66fc635

Please sign in to comment.