generated from cms/tibi-docs
header & menu
This commit is contained in:
parent
f290e9d039
commit
7ce16346e0
@ -1,21 +0,0 @@
|
|||||||
# TibiCMS Dokumentation
|
|
||||||
|
|
||||||
![TibiCMS Aufbau](./md/tibi-aufbau.svg)
|
|
||||||
|
|
||||||
## Einleitung
|
|
||||||
|
|
||||||
_TibiCMS_ ist der Sammelbegriff für die Komponenten _tibi-server_ und _tibi-admin_, welche einen Rest-API Server und eine Administrationsoberfläche zur Verfügung stellen. Auf Basis dieser beiden Komponenten und der _MongoDB_ als Abhängigkeit lassen sich WebCMS Anwendungen abbilden.
|
|
||||||
|
|
||||||
Das CMS ist multi-mandanten-fähig, d.h. es kann mehrer Projekte mit unterschiedlichen Zugriffsbeschränkungen verwalten.
|
|
||||||
|
|
||||||
### tibi-server
|
|
||||||
|
|
||||||
Der Server selbst kommt ohne grafische Oberfläche oder WebUI. Er ist ausschließlich nach außen über eine Rest-API erreichbar.
|
|
||||||
|
|
||||||
Als einzige Abhängigkeit ist eine _MongoDB_ zu erwähnen. Da der Server in Go geschrieben ist, sind keine externen Bibliotheken notwendig. Er lässt sich daher prima via Docker-Container verteilen.
|
|
||||||
|
|
||||||
### tibi-admin
|
|
||||||
|
|
||||||
Die Administrationsoberfläche ist wie jeder andere Service, der die Rest-API des Servers nutzt, nur ein Frontend. _tibi-admin_ läuft vollständig im Browser und benötigt nur einen Webserver, der statischen Content ausliefert.
|
|
||||||
|
|
||||||
Die Version des _tibi-admin_ sollte synchron zur _tibi-server_ Version gehalten werden, damit alle Datentypen bedient werden können.
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"docs": "md",
|
|
||||||
"markdown": {
|
|
||||||
"plugins": {
|
|
||||||
"code-include": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"css": ["md/docpress.css", "md/github-dark-dimmed.css"]
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const INCLUDE_RE = /!{3}\s*include(.+?)!{3}/i;
|
|
||||||
const BRACES_RE = /\((.+?)\)/i;
|
|
||||||
|
|
||||||
const include_plugin = (md, options) => {
|
|
||||||
const defaultOptions = {
|
|
||||||
root: '.',
|
|
||||||
getRootDir: (pluginOptions/*, state, startLine, endLine*/) => pluginOptions.root,
|
|
||||||
includeRe: INCLUDE_RE,
|
|
||||||
throwError: false,
|
|
||||||
bracesAreOptional: false,
|
|
||||||
notFoundMessage: 'File \'{{FILE}}\' not found.',
|
|
||||||
circularMessage: 'Circular reference between \'{{FILE}}\' and \'{{PARENT}}\'.'
|
|
||||||
};
|
|
||||||
|
|
||||||
if (typeof options === 'string') {
|
|
||||||
options = {
|
|
||||||
...defaultOptions,
|
|
||||||
root: options
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
options = {
|
|
||||||
...defaultOptions,
|
|
||||||
...options
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const _replaceIncludeByContent = (src, rootdir, parentFilePath, filesProcessed) => {
|
|
||||||
filesProcessed = filesProcessed ? filesProcessed.slice() : []; // making a copy
|
|
||||||
let cap, filePath, mdSrc, errorMessage;
|
|
||||||
|
|
||||||
// store parent file path to check circular references
|
|
||||||
if (parentFilePath) {
|
|
||||||
filesProcessed.push(parentFilePath);
|
|
||||||
}
|
|
||||||
while ((cap = options.includeRe.exec(src))) {
|
|
||||||
let includePath = cap[1].trim();
|
|
||||||
const sansBracesMatch = BRACES_RE.exec(includePath);
|
|
||||||
|
|
||||||
if (!sansBracesMatch && !options.bracesAreOptional) {
|
|
||||||
errorMessage = `INCLUDE statement '${src.trim()}' MUST have '()' braces around the include path ('${includePath}')`;
|
|
||||||
} else if (sansBracesMatch) {
|
|
||||||
includePath = sansBracesMatch[1].trim();
|
|
||||||
} else if (!/^\s/.test(cap[1])) {
|
|
||||||
// path SHOULD have been preceeded by at least ONE whitespace character!
|
|
||||||
/* eslint max-len: "off" */
|
|
||||||
errorMessage = `INCLUDE statement '${src.trim()}': when not using braces around the path ('${includePath}'), it MUST be preceeded by at least one whitespace character to separate the include keyword and the include path.`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!errorMessage) {
|
|
||||||
filePath = path.resolve(rootdir, includePath);
|
|
||||||
|
|
||||||
// check if child file exists or if there is a circular reference
|
|
||||||
if (!fs.existsSync(filePath)) {
|
|
||||||
// child file does not exist
|
|
||||||
errorMessage = options.notFoundMessage.replace('{{FILE}}', filePath);
|
|
||||||
} else if (filesProcessed.indexOf(filePath) !== -1) {
|
|
||||||
// reference would be circular
|
|
||||||
errorMessage = options.circularMessage.replace('{{FILE}}', filePath).replace('{{PARENT}}', parentFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if there were any errors
|
|
||||||
if (errorMessage) {
|
|
||||||
if (options.throwError) {
|
|
||||||
throw new Error(errorMessage);
|
|
||||||
}
|
|
||||||
mdSrc = `\n\n# INCLUDE ERROR: ${errorMessage}\n\n`;
|
|
||||||
} else {
|
|
||||||
// get content of child file
|
|
||||||
mdSrc = fs.readFileSync(filePath, 'utf8');
|
|
||||||
// check if child file also has includes
|
|
||||||
mdSrc = _replaceIncludeByContent(mdSrc, path.dirname(filePath), filePath, filesProcessed);
|
|
||||||
// remove one trailing newline, if it exists: that way, the included content does NOT
|
|
||||||
// automatically terminate the paragraph it is in due to the writer of the included
|
|
||||||
// part having terminated the content with a newline.
|
|
||||||
// However, when that snippet writer terminated with TWO (or more) newlines, these, minus one,
|
|
||||||
// will be merged with the newline after the #include statement, resulting in a 2-NL paragraph
|
|
||||||
// termination.
|
|
||||||
const len = mdSrc.length;
|
|
||||||
if (mdSrc[len - 1] === '\n') {
|
|
||||||
mdSrc = mdSrc.substring(0, len - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const labelStyle = `padding: 0 4px; font-size: 12px; font-weight: bold; color: #ffffff; background: #444444; opacity: .6;`
|
|
||||||
|
|
||||||
const fileLabel = `<div style="position:relative; height: 0px;"><div class="code-file-label" style="position:absolute; top: -10px;${labelStyle}">${includePath}</div></div>\n\n`
|
|
||||||
const fileExt = includePath.replace(/^.+\./, "")
|
|
||||||
|
|
||||||
// replace include by file content
|
|
||||||
src = src.slice(0, cap.index) + fileLabel + "```" + fileExt + "\n" + mdSrc + "\n```" + src.slice(cap.index + cap[0].length, src.length);
|
|
||||||
}
|
|
||||||
return src;
|
|
||||||
};
|
|
||||||
|
|
||||||
const _includeFileParts = (state, startLine, endLine/*, silent*/) => {
|
|
||||||
state.src = _replaceIncludeByContent(state.src, options.getRootDir(options, state, startLine, endLine));
|
|
||||||
};
|
|
||||||
|
|
||||||
md.core.ruler.before('normalize', 'include', _includeFileParts);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = include_plugin;
|
|
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "markdown-it-code-include",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"description": "A markdown-it plugin to include code blocks.",
|
|
||||||
"main": "./index.js",
|
|
||||||
"scripts": {
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"markdown",
|
|
||||||
"markdown-it",
|
|
||||||
"markdown-it-plugin",
|
|
||||||
"code-blocks",
|
|
||||||
"fence"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"node-html-parser": "^1.3.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"markdown-it": "^12.0.0",
|
|
||||||
"markdown-it-testgen": "^0.1.6",
|
|
||||||
"path": "^0.12.7"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
- [TibiCMS](../README.md)
|
|
||||||
- [Begriffe](begriffe.md)
|
|
||||||
- Servergrundlagen
|
|
||||||
- [Konfiguration](servergrundlagen/konfiguration.md)
|
|
||||||
- [Entitäten](servergrundlagen/entitaeten.md)
|
|
||||||
- RestAPI Endpunkte
|
|
||||||
- [/login](restapi/login.md)
|
|
||||||
- [/user](restapi/user.md)
|
|
||||||
- [/project](restapi/project.md)
|
|
||||||
- [/_/NS/COLLECTION](restapi/collection.md)
|
|
||||||
- [/_/NS/_/assets/ASSETSNAME](restapi/assets.md)
|
|
||||||
- Projekt Konfiguration
|
|
||||||
- [Ordnerstruktur](projektkonfig/ordnerstruktur.md)
|
|
||||||
- [config.yml](projektkonfig/config.yml.md)
|
|
||||||
- [collections](projektkonfig/collections.md)
|
|
||||||
- [fields](projektkonfig/collections/fields.md)
|
|
||||||
- [Datentypen](projektkonfig/collections/fields/datentypen.md)
|
|
||||||
- [Admin Widgets](projektkonfig/collections/fields/widgets.md)
|
|
||||||
- [· ContentBuilder](projektkonfig/collections/fields/widgets/contentbuilder.md)
|
|
||||||
- [indexes](projektkonfig/collections/indexes.md)
|
|
||||||
- [hooks](projektkonfig/collections/hooks.md)
|
|
||||||
- [imageFilter](projektkonfig/collections/imageFilter.md)
|
|
||||||
- [meta](projektkonfig/collections/meta.md)
|
|
||||||
- [jobs](projektkonfig/jobs.md)
|
|
||||||
- [assets](projektkonfig/assets.md)
|
|
||||||
- Admin Javascript Kontext
|
|
||||||
- [Allgemeines](admin-javascript-kontext/allgemeines.md)
|
|
||||||
- [collection.meta..eval](admin-javascript-kontext/collection.meta..eval.md)
|
|
||||||
- [field.meta..eval](admin-javascript-kontext/field.meta..eval.md)
|
|
||||||
- Server Javascript Kontext
|
|
||||||
- [Allgmeines](server-javascript-kontext/allgemeines.md)
|
|
||||||
- [hook](server-javascript-kontext/hook.md)
|
|
||||||
- [job](server-javascript-kontext/job.md)
|
|
||||||
- [validator](server-javascript-kontext/validator.md)
|
|
||||||
- Packages
|
|
||||||
- [user](server-javascript-kontext/packages/user.md)
|
|
||||||
- [response](server-javascript-kontext/packages/response.md)
|
|
||||||
- [cookie](server-javascript-kontext/packages/cookie.md)
|
|
||||||
- [db](server-javascript-kontext/packages/db.md)
|
|
||||||
- [http](server-javascript-kontext/packages/http.md)
|
|
||||||
- [smtp](server-javascript-kontext/packages/smtp.md)
|
|
||||||
- [fs](server-javascript-kontext/packages/fs.md)
|
|
||||||
- [tpl](server-javascript-kontext/packages/tpl.md)
|
|
||||||
- [jwt](server-javascript-kontext/packages/jwt.md)
|
|
||||||
- [image](server-javascript-kontext/packages/image.md)
|
|
||||||
- [bcrypt](server-javascript-kontext/packages/bcrypt.md)
|
|
||||||
- [xml](server-javascript-kontext/packages/xml.md)
|
|
||||||
- [charset](server-javascript-kontext/packages/charset.md)
|
|
||||||
- [pdf](server-javascript-kontext/packages/pdf.md)
|
|
||||||
- [debug](server-javascript-kontext/packages/debug.md)
|
|
@ -1,47 +0,0 @@
|
|||||||
# Javascript-Kontext im tibi-admin
|
|
||||||
|
|
||||||
Diverse `meta`-Angaben ermöglichen neben der eigentliche Angabe eines festen Wertes wie z.B:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
defaultValue: "Hallo Welt"
|
|
||||||
```
|
|
||||||
|
|
||||||
auch die Angabe eines Javascript-Ausdrucks, der zur Laufzeit ausgewertet wird. Dieser Ausdruck wird in einem Javascript-Kontext clientseitig ausgeführt und ist mit diversen Variablen vorbelegt.
|
|
||||||
Die Angabe des Javascript-Codes erfolgt dabei meist mit dem `eval`-Attribut dessen Wert der String des Codes ist:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
defaultValue:
|
|
||||||
eval: "new Date().toISOString().substr(0, 10)"
|
|
||||||
```
|
|
||||||
|
|
||||||
In den Fällen in denen ein Oneliner nicht ausreiched ist, bieten sich "selbst ausführende Funktionen" an, wie z.B.:
|
|
||||||
|
|
||||||
```js
|
|
||||||
(function() {
|
|
||||||
return new Date().toISOString().substr(0, 10)
|
|
||||||
})()
|
|
||||||
```
|
|
||||||
|
|
||||||
Um diese im YAML unterzubringen nutzt man YAML-Multiline-Modifizierer:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
defaultValue:
|
|
||||||
eval: |
|
|
||||||
(function() {
|
|
||||||
return new Date().toISOString().substr(0, 10)
|
|
||||||
})()
|
|
||||||
```
|
|
||||||
|
|
||||||
## Kontext-Variablen
|
|
||||||
|
|
||||||
Der Javascript-Kontext ist mit folgenden Variablen standardmäßig angereichert:
|
|
||||||
|
|
||||||
| Variable | Datentyp | Bedeutung |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| `$namespace` | string | Der Namespacebezeichner des aktuellen Projekts |
|
|
||||||
| `$apiBase` | string | Basis-URL des API-Endpunkts |
|
|
||||||
| `$projectBase` | string | Basis-URL des Projekts-API-Endpunkts (`$apiBase`_/`$namespace`/) |
|
|
||||||
| `$auth` TODO | object | Das aktuelle Auth-Objetc des eingeloggten Benutzers |
|
|
||||||
| `$project` | object | Das aktuelle Projekt-Objekt, siehe [API /project](./../restapi/project.md) |
|
|
||||||
|
|
||||||
Die `meta`-Daten der Collections und Fields bekommen in den Javascript-Kontext der `eval`-Eigenschaften noch jeweils zusätzliche Variablen.
|
|
@ -1,9 +0,0 @@
|
|||||||
# collection.meta..eval Javascript-Kontext
|
|
||||||
|
|
||||||
Die `eval`-Properties der Eigenschaften (wo möglich) bekommen unterhalb des `collection.meta`-Objektes zusätzlich zu den bereits bekannten Variablen (siehe [Allgemeines zum Kontext](./allgemeines.md)) folgende Variable zur Verfügung:
|
|
||||||
|
|
||||||
|
|
||||||
| Variable | Datentyp | Bedeutung |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| `$object` | object | Das aktuelle Kollektion-Objekt, siehe [API /collection](./../restapi/collection.md) |
|
|
||||||
| `$navigation` | object | Das aktuelle Navigation-Objekt, also den entsprechenden aktiven Eintrag aus `meta.subNavigation` |
|
|
@ -1,104 +0,0 @@
|
|||||||
# field.meta..eval Javascript-Kontext
|
|
||||||
|
|
||||||
Zuätzlich zu den allgemeinen und Kollektions-spezifischen Variablen, die im Javascript-Kontext der `eval`-Eigenschaften unterhalb des zur Verfügung stehen, gibt es noch folgende Variablen unterhalb des `field.meta`-Objektes für die Evaluierung:
|
|
||||||
|
|
||||||
| Variable | Datentyp | Bedeutung |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| `$field` TODO | object | Das aktuelle Feld-Objekt |
|
|
||||||
| `$method` | `"post"`/`"put"` | `"put"` bedeuted, dass der Datensatz gerade in Bearbeitung ist, `"post"` = Datensatz soll angelegt werden |
|
|
||||||
| `$this` | any | Der aktuelle Wert des Feldes |
|
|
||||||
| `$` | object | Das gesamte Objekt des Dokuments |
|
|
||||||
| `$parent` | object oder array | Der Wert des Elternknotens zum aktuellen Feld |
|
|
||||||
| `$stack` | array | Der Stack bis zum Ursprung des gesamten Objekts |
|
|
||||||
|
|
||||||
## Der Stack
|
|
||||||
|
|
||||||
Um die Abhängigkeiten zu bestimmten Werten ausdrücken zu können (z.B. in `meta.dependsOn.eval`), sind die Variablen `$this`, `$`, `$parent` und `$stack` verfügbar.
|
|
||||||
|
|
||||||
Folgendes Beispiel eines Datensatzes verdeutlicht die Belegung, während die Maske zum Editieren im *tibi-admin* geöffnet ist:
|
|
||||||
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "Mein Datensatz",
|
|
||||||
"meta": {
|
|
||||||
"keywords": [
|
|
||||||
{
|
|
||||||
"key": "pla",
|
|
||||||
"description": "Ah Plah"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "blup",
|
|
||||||
"description": "Buh Blup"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
wobei wir den `"key": "pla"` betrachten, wären die Inhalte der Variablen folgende:
|
|
||||||
|
|
||||||
`$this`:
|
|
||||||
|
|
||||||
plah
|
|
||||||
|
|
||||||
`$parent` und `$stack[0]`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"key": "pla",
|
|
||||||
"description": "Ah Plah"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`$stack[1]`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"key": "pla",
|
|
||||||
"description": "Ah Plah"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "blup",
|
|
||||||
"description": "Buh Blup"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
`$stack[2]`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"keywords": [
|
|
||||||
{
|
|
||||||
"key": "pla",
|
|
||||||
"description": "Ah Plah"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "blup",
|
|
||||||
"description": "Buh Blup"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`$stack[3]`, `entry` und `$`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "Mein Datensatz",
|
|
||||||
"meta": {
|
|
||||||
"keywords": [
|
|
||||||
{
|
|
||||||
"key": "pla",
|
|
||||||
"description": "Ah Plah"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "blup",
|
|
||||||
"description": "Buh Blup"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,53 +0,0 @@
|
|||||||
# Begriffe
|
|
||||||
|
|
||||||
## TibiCMS
|
|
||||||
|
|
||||||
Oberbegriff der den gesamten Stack, bestehend aus *tibi-server* mit *MongoDB** und *tibi-admin* beschreibt.
|
|
||||||
|
|
||||||
## tibi-server
|
|
||||||
|
|
||||||
Rest-API Server des *TibiCMS* Stack
|
|
||||||
|
|
||||||
## tibi-admin
|
|
||||||
|
|
||||||
Admin-UI/Backend zur Verwaltung der Inhalte im *tibi-server*
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
Schnittstelle (hier Rest-API) des *tibi-server* (im Projektkontext ebenso für Projektspezifische Schnittstelle vrwendet)
|
|
||||||
|
|
||||||
## project / Projekt
|
|
||||||
|
|
||||||
Projekt innerhalb des *TibiCMS* welches üblicherweise die Datengrundlage für eine Website im *TibiCMS* ist
|
|
||||||
|
|
||||||
## collection / Kollektion
|
|
||||||
|
|
||||||
Datensammlung innerhalb eines Projekte (z.B. Newsartikel), in relationalen Datenbanken oft eine Tabelle
|
|
||||||
|
|
||||||
## field / Feld
|
|
||||||
|
|
||||||
Ein Datenfeld innerhalb einer Kollektion mit einem bestimmten Datentyp (z.B. string, number, ...)
|
|
||||||
|
|
||||||
## validator / Validator
|
|
||||||
|
|
||||||
Code oder Anweisung zur Überprüfung der Gültigkeit von Feld-Daten
|
|
||||||
|
|
||||||
## filter / Filter
|
|
||||||
|
|
||||||
Bildfilter zum Verkleinern oder Bearbeiten von Bildern beim Abruf von der API
|
|
||||||
|
|
||||||
## projection / Projektion
|
|
||||||
|
|
||||||
Abbildung der Daten auf ein Subset der Originaldaten
|
|
||||||
|
|
||||||
## hook
|
|
||||||
|
|
||||||
Vorerst nur in Javascript geschriebene Algorithmen, die die sich in die API einklinken um Daten oder Abläufe zu manipulieren
|
|
||||||
|
|
||||||
## user / Benutzer
|
|
||||||
|
|
||||||
Ein Benutzer mit Login innerhalb des *TibiCMS*
|
|
||||||
|
|
||||||
## permission / Berechtigung
|
|
||||||
|
|
||||||
Berechtigung innerhalb eines Projektes, welche einem Benutzer zugeordnet werden kann
|
|
@ -1,34 +0,0 @@
|
|||||||
.title, h1, h2, h3, h4, h5, .link.title.link-index {
|
|
||||||
color: #531414!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link.title {
|
|
||||||
color: black!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toc-menu .link.-active, .toc-menu .hlink.-active {
|
|
||||||
box-shadow: inset -2px 0 #7c2828!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.heading-list .hlink, ul.heading-list .hlink:visited {
|
|
||||||
color: #414141!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-toggle:hover, .footer-nav a:hover, .footer-nav a:hover:after, .footer-nav a:hover:before {
|
|
||||||
color: #7c2828!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code-file-label {
|
|
||||||
background: #dcd9d9!important;
|
|
||||||
color: #3a0909!important;
|
|
||||||
right: 0px;
|
|
||||||
opacity: 1!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #7c2828!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
color:#3a0909!important;
|
|
||||||
}
|
|
@ -1,130 +0,0 @@
|
|||||||
/*!
|
|
||||||
Theme: GitHub Dark Dimmed
|
|
||||||
Description: Dark dimmed theme as seen on github.com
|
|
||||||
Author: github.com
|
|
||||||
Maintainer: @Hirse
|
|
||||||
Updated: 2021-05-15
|
|
||||||
|
|
||||||
Colors taken from GitHub's CSS
|
|
||||||
*/
|
|
||||||
|
|
||||||
.hljs, pre, pre code {
|
|
||||||
color: #adbac7!important;
|
|
||||||
background: #22272e!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-doctag,
|
|
||||||
.hljs-keyword,
|
|
||||||
.hljs-meta .hljs-keyword,
|
|
||||||
.hljs-template-tag,
|
|
||||||
.hljs-template-variable,
|
|
||||||
.hljs-type,
|
|
||||||
.hljs-variable.language_,
|
|
||||||
.pl-k {
|
|
||||||
/* prettylights-syntax-keyword */
|
|
||||||
color: #f47067!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-title,
|
|
||||||
.hljs-title.class_,
|
|
||||||
.hljs-title.class_.inherited__,
|
|
||||||
.hljs-title.function_i,
|
|
||||||
.pl-s {
|
|
||||||
/* prettylights-syntax-entity */
|
|
||||||
color: #dcbdfb!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-attr,
|
|
||||||
.hljs-attribute,
|
|
||||||
.hljs-literal,
|
|
||||||
.hljs-meta,
|
|
||||||
.hljs-number,
|
|
||||||
.hljs-operator,
|
|
||||||
.hljs-variable,
|
|
||||||
.hljs-selector-attr,
|
|
||||||
.hljs-selector-class,
|
|
||||||
.hljs-selector-id,
|
|
||||||
.pl-e {
|
|
||||||
/* prettylights-syntax-constant */
|
|
||||||
color: #6cb6ff!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-regexp,
|
|
||||||
.hljs-string,
|
|
||||||
.hljs-meta .hljs-string,
|
|
||||||
.pl-s {
|
|
||||||
/* prettylights-syntax-string */
|
|
||||||
color: #96d0ff!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-built_in,
|
|
||||||
.hljs-symbol,
|
|
||||||
.pl-c1 {
|
|
||||||
/* prettylights-syntax-variable */
|
|
||||||
color: #f69d50!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-comment,
|
|
||||||
.hljs-code,
|
|
||||||
.hljs-formula,
|
|
||||||
.pl-c {
|
|
||||||
/* prettylights-syntax-comment */
|
|
||||||
color: #768390!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-name,
|
|
||||||
.hljs-quote,
|
|
||||||
.hljs-selector-tag,
|
|
||||||
.hljs-selector-pseudo {
|
|
||||||
/* prettylights-syntax-entity-tag */
|
|
||||||
color: #8ddb8c!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-subst {
|
|
||||||
/* prettylights-syntax-storage-modifier-import */
|
|
||||||
color: #adbac7!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-section {
|
|
||||||
/* prettylights-syntax-markup-heading */
|
|
||||||
color: #316dca!important;
|
|
||||||
font-weight: bold!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-bullet {
|
|
||||||
/* prettylights-syntax-markup-list */
|
|
||||||
color: #eac55f!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-emphasis {
|
|
||||||
/* prettylights-syntax-markup-italic */
|
|
||||||
color: #adbac7!important;
|
|
||||||
font-style: italic!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-strong {
|
|
||||||
/* prettylights-syntax-markup-bold */
|
|
||||||
color: #adbac7!important;
|
|
||||||
font-weight: bold!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-addition {
|
|
||||||
/* prettylights-syntax-markup-inserted */
|
|
||||||
color: #b4f1b4!important;
|
|
||||||
background-color: #1b4721!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-deletion {
|
|
||||||
/* prettylights-syntax-markup-deleted */
|
|
||||||
color: #ffd8d3!important;
|
|
||||||
background-color: #78191b!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-char.escape_,
|
|
||||||
.hljs-link,
|
|
||||||
.hljs-params,
|
|
||||||
.hljs-property,
|
|
||||||
.hljs-punctuation,
|
|
||||||
.hljs-tag {
|
|
||||||
/* purposely ignored */
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 47 KiB |
@ -1,6 +0,0 @@
|
|||||||
# assets
|
|
||||||
|
|
||||||
Folgende Angaben sind in der `assets`-Sektion der [config.yml](./config.yml.md) geführt als Liste möglich:
|
|
||||||
|
|
||||||
|
|
||||||
!!!include(../api/assets/demoassets.yml)!!!
|
|
@ -1,17 +0,0 @@
|
|||||||
# collections
|
|
||||||
|
|
||||||
Die Konfiguration einer Kollektion sollte zur besseren Übersicht innerhalb einer gesonderten Datei im Unterorder **api/collections/** erfolgen und via `!include` in die [config.yml](./config.yml.md) eingebunden werden.
|
|
||||||
|
|
||||||
## Grundlegender Aufbau
|
|
||||||
|
|
||||||
Eine solche Datei hat folgenden Aufbau:
|
|
||||||
|
|
||||||
!!!include(../api/collections/democol.yml)!!!
|
|
||||||
|
|
||||||
### siehe
|
|
||||||
|
|
||||||
- [fields](./collections/fields.md)
|
|
||||||
- [indexes](./collections/indexes.md)
|
|
||||||
- [hooks](./collections/hooks.md)
|
|
||||||
- [imageFilter](./collections/imageFilter.md)
|
|
||||||
- [meta](./collections/meta.md)
|
|
Binary file not shown.
@ -1,120 +0,0 @@
|
|||||||
# fields
|
|
||||||
|
|
||||||
Felder im _tibi-server_ müssen einen bestimmten Datentyp haben. Über den _tibi-admin_ können die Felder über Widgets in unterschiedlichen Ausprägungen dargestellt werden (view-Widgets), bzw. dem Benutzer eine Eingabe abverlangen (input-Widgets).
|
|
||||||
|
|
||||||
Es gibt grundlegende Angaben, die jedes Feld haben muss um vom _tibi-server_ akzeptiert zu werden. Darüber hinaus kann auch jedes Feld ein `meta` Objekt haben, was dem _tibi-admin_ mitteilt, wie er dieses Feld für Ausgabe und Eingabe behandel soll.
|
|
||||||
|
|
||||||
Zunächst folgt der grundlegende Aufbau des Feld-Objektes:
|
|
||||||
|
|
||||||
!!!include(../api/collections/fields/date.yml)!!!
|
|
||||||
|
|
||||||
## validator Objekt
|
|
||||||
|
|
||||||
<video width="100%" controls muted autoplay loop>
|
|
||||||
<source src="validator.webm" type="video/webm">
|
|
||||||
</video>
|
|
||||||
|
|
||||||
Wie im Beispiel von **fields/date.yml** unter `validator` zu sehen ist, wird dort ein Datum nach dem aktuellen erwartet. Wie der Validator sich auf die UI auswirkt, ist im obigen Video zu sehen.
|
|
||||||
|
|
||||||
Das `validator` Objekt wird _tibi-server_ seitig genutzt um die Daten zu validieren. Da das `validator` Objekt dem _tibi-admin_ ebenso zur Verfügung steht, kann vorab eine client-seitige Validierung zusätzlich durchgeführt werden.
|
|
||||||
|
|
||||||
Attribute des Objektes:
|
|
||||||
|
|
||||||
| Attribut | Datentyp | Beschreibung |
|
|
||||||
| ----------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| `required` | boolean | wenn `true`, dann ist zwingend eine Eingabe zu diesem Feld nötig |
|
|
||||||
| `allowZero` | boolean | in Kombination mit `required: true`, wenn `true`, dann ist der jeweilige "Null"-Wert des Datentyps erlaubt<br><br>z.B. `type: string` erlaubt den leeren String und `type: number` erlaubt `0` |
|
|
||||||
| `eval` | string | Javascript-Code der zu true evaluieren muss um den Wert des Feldes als gültig zu definieren |
|
|
||||||
|
|
||||||
### eval-Attribut
|
|
||||||
|
|
||||||
Der Javascript-Code in diesem Attribut kann folgende Rückgabe-Werte haben:
|
|
||||||
|
|
||||||
| Wert | Bedeutung |
|
|
||||||
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| `true` | Der Wert des Feldes ist gültig |
|
|
||||||
| `false` | Der Wert des Feldes ist ungültig |
|
|
||||||
| `"Text"` | Wird ein String zurückgegeben ist, wird der Wert es Feldes ebenso als ungültig erachtet und der String selbst ist eine benutzerdefinierte Fehlermeldung, die in der Serverantwort gelesen werden kann. |
|
|
||||||
|
|
||||||
Da der `eval` Code serverseitig immer ausgeführt wird und ein Fehlschlag zwangsläufig zum Abbruch der Serveraktion führt, ist es wichtig, dass der [serverseitige Javascript-Kontext](./../../server-javascript-kontext/validator.md) berücksichtigt wird.
|
|
||||||
|
|
||||||
Optional kann der Code auch zusätzlich über eine Lauffähigkeit ohne Fehler (z.B. keine Verwendung nicht vorhandender Kontext-Variablen oder Verwendung von `try ... catch`) im _tibi-admin_ verfügen. Das hat den Vorteil, dass eine Vorab-Validierung stattfindet, bevor der Datensatz an der Server gesendet wird.
|
|
||||||
|
|
||||||
Sollte der `eval` Code im _tibi-admin_ nicht lauffähig sein (nicht abgefangene Exception), wird der Validator clientseitig ingoriert und nur die serverseitige Prüfung beeinflusst die Aktion.
|
|
||||||
|
|
||||||
#### siehe
|
|
||||||
|
|
||||||
- [Server Javascript Kontext](./../../server-javascript-kontext/allgemeines.md)
|
|
||||||
- [Validator Javascript Kontext](./../../server-javascript-kontext/validator.md)
|
|
||||||
|
|
||||||
## dependsOn
|
|
||||||
|
|
||||||
<video width="100%" controls muted autoplay loop>
|
|
||||||
<source src="dependsOn.webm" type="video/webm">
|
|
||||||
</video>
|
|
||||||
|
|
||||||
Obige Darstellung wie im Video wird beispielsweise durch folgende Feld-Konfiguration erreicht:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# in einer Kollektions-Konfiguration
|
|
||||||
fields:
|
|
||||||
- name: type
|
|
||||||
type: string
|
|
||||||
meta:
|
|
||||||
label:
|
|
||||||
de: Typ
|
|
||||||
en: Type
|
|
||||||
widget: select
|
|
||||||
choices:
|
|
||||||
- name:
|
|
||||||
de: Standardseite
|
|
||||||
en: Standard page
|
|
||||||
id: page
|
|
||||||
- name:
|
|
||||||
de: News
|
|
||||||
en: News
|
|
||||||
id: news
|
|
||||||
|
|
||||||
- name: title
|
|
||||||
type: string
|
|
||||||
meta:
|
|
||||||
label:
|
|
||||||
de: Titel
|
|
||||||
en: Title
|
|
||||||
|
|
||||||
- name: date
|
|
||||||
type: date
|
|
||||||
meta:
|
|
||||||
label:
|
|
||||||
de: Titel
|
|
||||||
en: title
|
|
||||||
widget: date
|
|
||||||
defaultValue:
|
|
||||||
eval: new Date()
|
|
||||||
dependsOn:
|
|
||||||
eval: $parent?.type == "news"
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
`meta.dependsOn` kann als Objekt mit `eval`-Attribut für Javascript oder als `string` mit dem Feldnamen (Punktschreibweise, z.B. `"additionalData.author"`) angegeben werden.
|
|
||||||
|
|
||||||
Wird der Feldname verwendet wird nur geprüft, ob das Feld belegt ist. TODO
|
|
||||||
|
|
||||||
Die `eval` Variante verwendet als Javascript-Kontext Variablen die auf folgenden Seite beschrieben werden:
|
|
||||||
|
|
||||||
- [Admin Javascript Kontext](./../../admin-javascript-kontext/allgemeines.md)
|
|
||||||
- [collection.meta..eval](./../../admin-javascript-kontext/collection.meta..eval.md)
|
|
||||||
- [field.meta..eval](./../../admin-javascript-kontext/field.meta..eval.md)
|
|
||||||
|
|
||||||
Die Rückgabe des Javascript-Codes beeinflusst die Einblendung des betroffenen Feldes in folgender Weise:
|
|
||||||
|
|
||||||
| Rückgabe | Bedeutung |
|
|
||||||
| -------- | -------------------------- |
|
|
||||||
| `true` | Das Feld wird angezeigt |
|
|
||||||
| `false` | Das Feld wird ausgeblendet |
|
|
||||||
|
|
||||||
## defaultValue
|
|
||||||
|
|
||||||
Für die Vorlegung neu anzulegender Datensätze kann in `field.meta.defaultValue` direkt der Standardwert hinterlegt werden, oder über `field.meta.defaultValue.eval` ein Javascript-Code angegeben werden, der den Wert ermittelt. Die Rückgabe des Javascript-Codes, sowie auch die direkte Vergabe des Wertes muss dem Datentyp des Feldes entsprechen.
|
|
||||||
|
|
||||||
Der Javascript-Kontext ist der gleiche wie bei `field.meta.dependsOn.eval`.
|
|
@ -1,44 +0,0 @@
|
|||||||
# Datentypen
|
|
||||||
|
|
||||||
Via `type` wird der Datentyp des Feldes definiert. Folgende Datentypen sind möglich:
|
|
||||||
|
|
||||||
## string
|
|
||||||
|
|
||||||
String wird für Zeichenketten verwendet. Das Standardwidget ohne weitere Angabe ist bei der Ausgabe die direkte Textausgabe und bei der Eingabe ein HTML `<input ...>` Element mit dem Attribut `type="text"`.
|
|
||||||
|
|
||||||
## number
|
|
||||||
|
|
||||||
Number wird sowohl für ganze Zahlen, wie auch für Gleitkommawerte definiert. Auch hier ist das Standard-Widget für die Eingabe ein HTML `<input ...>` Element, allerdings mit dem Attribut `type="number"`.
|
|
||||||
|
|
||||||
## boolean
|
|
||||||
|
|
||||||
Ein boolcher Wert, also `true` oder `false`, wird über den Typ `"boolean"` definiert und standardmäßig als Checkbox dargestellt.
|
|
||||||
|
|
||||||
## date
|
|
||||||
|
|
||||||
`"date"` als Datentyp kann sowohl Datumsangabe mit, als auch ohne Uhrzeit aufnehmen. Das Standardwidget ist die einfache Datumseingabe ohne Uhrzeit.
|
|
||||||
|
|
||||||
## file
|
|
||||||
|
|
||||||
Der Datentyp `"file"` ist für Dateiuploads vorgesehen. Es daher standardmäßig ein Datei-Auswahl-Dialog als Widget für die Eingabe angeboten.
|
|
||||||
|
|
||||||
## string[]
|
|
||||||
|
|
||||||
Für `"string[]` Arrays ist die Angabe des Widgets zwingend notwendig.
|
|
||||||
|
|
||||||
## number[]
|
|
||||||
|
|
||||||
Auch für `"number[]"` Arrays wird die Widget-Angabe erwartet.
|
|
||||||
|
|
||||||
## object
|
|
||||||
|
|
||||||
`"object"` ist ein spezieller Datentyp der zur Strukturierung der API und der Eingabe dient. Dieser Datentyp fasst `subFields` zusammen.
|
|
||||||
|
|
||||||
## object[]
|
|
||||||
|
|
||||||
Wie `"object"` fasst auch das `"object[]"` Array `subFields` zusammen. Diese allerdings als Liste von Objekten, anstatt als Einzelobjekt.
|
|
||||||
|
|
||||||
## any
|
|
||||||
|
|
||||||
Felder vom Typ `"any"` können beliebige Daten aufnehmen. Die Validierung schlägt auf Basis der Typ-Validierung hier nie fehl.
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
# Widgets
|
|
||||||
|
|
||||||
Das im *tibi-admin* für die Ein- und Ausgabe von Daten zu verwendente Widget wird über die Feldkonfiguration `meta.widget` festgelegt. Die Angabe erfolgt als String mit dem Widget-Namen.
|
|
||||||
|
|
||||||
Nicht jedes Widget kann mit jedem Datentyp umgehen, die möglichen Datentypen werden aber nachfolgend bei jedem Widget erwähnt. Außerdem wird auf individuelle Konfigurationsmöglichkeiten eingegangen.
|
|
||||||
|
|
||||||
## text
|
|
||||||
|
|
||||||
## number
|
|
||||||
|
|
||||||
## checkbox
|
|
||||||
|
|
||||||
## select
|
|
||||||
|
|
||||||
## date
|
|
||||||
|
|
||||||
## datetime
|
|
||||||
|
|
||||||
## richtext
|
|
||||||
|
|
||||||
## file
|
|
||||||
|
|
||||||
## image
|
|
||||||
|
|
||||||
## selectArray
|
|
||||||
|
|
||||||
## checkboxArray
|
|
||||||
|
|
||||||
## chipArray
|
|
||||||
|
|
||||||
## object
|
|
||||||
|
|
||||||
## objectArray
|
|
||||||
|
|
||||||
## tabs
|
|
||||||
|
|
||||||
## contentbuilder
|
|
||||||
|
|
||||||
siehe: [ContentBuilder](./widgets/contentbuilder.md)
|
|
Binary file not shown.
Binary file not shown.
@ -1,35 +0,0 @@
|
|||||||
# contentbuilder
|
|
||||||
|
|
||||||
> Der ContentBuilder ist ein Drittanbieter-Produkt und steht nicht in jeder Lizenz zur Verfügung. Bitte kontaktieren Sie uns, wenn Sie Interesse an diesem Widget haben.
|
|
||||||
|
|
||||||
Für die Gestaltung von HTML-Inhalten ist der ContentBuilder eine einfache und intuitive Lösung. Es sind Layout-Hilfmittel wie Spalten und Zeilen ebenso verfügbar, wie die Möglichkeit Dateien (Bilder, Video, Downloads) direkt in den HTML-Code einzubinden.
|
|
||||||
|
|
||||||
Wie der ContentBuilder an einem Feld konfiguriert wird verdeutlicht folgendes Beispiel:
|
|
||||||
|
|
||||||
!!!include(../api/collections/fields/content.yml)!!!
|
|
||||||
|
|
||||||
## Mediathek Kollektion
|
|
||||||
|
|
||||||
<video width="100%" controls autoplay muted loop>
|
|
||||||
<source src="contentbuilder-medialib.webm" type="video/webm">
|
|
||||||
</video>
|
|
||||||
|
|
||||||
Wie aus der obigen Definition unterhalb von z.B. "imageSelect" zu lesen, bedarf es einer eigenen Kollektion für Bilder und andere Dateien. Diese Kollektion könnte wie folgt aussehen:
|
|
||||||
|
|
||||||
> Die Bedeutung der hier nicht beschriebenen Eigenschaften ist unter [collections](./../../../collections.md) zu finden.
|
|
||||||
|
|
||||||
!!!include(../api/collections/medialib.yml)!!!
|
|
||||||
|
|
||||||
## Module (customTags)
|
|
||||||
|
|
||||||
Die Einbindung des konfigurierten Beispiel-Moduls aus obiger Definition erfolgt im ContentBuilder wie im folgenden Video zu sehen ist:
|
|
||||||
|
|
||||||
<video width="100%" controls autoplay muted loop>
|
|
||||||
<source src="contentbuilder-module.webm" type="video/webm">
|
|
||||||
</video>
|
|
||||||
|
|
||||||
Wie oben schon erwähnt, sind die `placeholder` frei wählbar. Eine HTML5-Schreibweise bietet sich aber sowohl für das Styling, als auch für die spätere Einbindung in ein Frontend an.
|
|
||||||
|
|
||||||
In unserem Beispiel hier wurden zusättzlich zum eigentlichen Modul-Tag noch Attribute (`title` und `description`) definiert. Diese können dann im Frontend das eigentliche Modul beeinflussen.
|
|
||||||
|
|
||||||
Im Frontend könnte ein Modul dann später als "Custom Element" implementiert werden oder es wird ein HTML-Parser verwendet, der die Tags durch eigene Komponenten ersetzt, wie er im Anhang [TODO] zu finden ist.
|
|
@ -1 +0,0 @@
|
|||||||
# hooks
|
|
@ -1,30 +0,0 @@
|
|||||||
# imageFilter Objekt
|
|
||||||
|
|
||||||
Die Bildmanipulation von hochgeladen Bildern zu einer Kollektion kann über das `imageFilter` Objekt definiert werden.
|
|
||||||
Der Filter wird angewandt, wenn an die Bild-URL der Parameter `filter=...` angehangen wird.
|
|
||||||
|
|
||||||
Der Prozess selbst erfolgt beim ersten Abruf des Bildes und wird zwischengespeichert.
|
|
||||||
|
|
||||||
Eine beispielhafte Konfiguration, die die Bilder nur verkleinert sieht so aus:
|
|
||||||
|
|
||||||
!!!include(../api/collections/democol/imageFilter.yml)!!!
|
|
||||||
|
|
||||||
Folgende Attribute können Filter-Eintrage haben, wobei `fit` und `fill` exklusiv sind:
|
|
||||||
|
|
||||||
| Attribut | Typ | Beschreibung |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `fit` | boolean | passt das Bild in ein Rechteck ein |
|
|
||||||
| `fill` | boolean | streckt/staucht das Bild, so dass es das Rechteck komplett ausfüllt |
|
|
||||||
| `height` | number | Höhe des Rechtecks |
|
|
||||||
| `width` | number | Breite des Rechtecks |
|
|
||||||
| `blur` | number | Verwischungsgrad |
|
|
||||||
| `brightness` | number | Helligkeit |
|
|
||||||
| `contrast` | number | Konrast |
|
|
||||||
| `gamma` | number | Gamma-Wert |
|
|
||||||
| `saturation` | number | Sättigung |
|
|
||||||
| `sharpen` | number | Schärfe |
|
|
||||||
| `invert` | boolean | Farben invertieren |
|
|
||||||
| `grayscale` | boolean | Schwarz-Weiß |
|
|
||||||
| `resampling` | "lanczos"<br>"nearestNeighbor"<br>"linear"<br>"catmullRom" | Resampling-Algorithmus |
|
|
||||||
| `quality` | number | Ausgabequalität 0..100 |
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
# indexes Liste
|
|
||||||
|
|
||||||
TODO
|
|
@ -1,29 +0,0 @@
|
|||||||
# meta Objekt
|
|
||||||
|
|
||||||
Wie bereits an anderer Stelle beschrieben, dient das `meta` Objekt zur Definition von Merkmalen, die im *tibi-admin* finden. Zum Anlegen der Struktur in der Datenbank und Definition der API haben diese Angaben keine Relevanz.
|
|
||||||
|
|
||||||
Folgende Angaben sind möglich:
|
|
||||||
|
|
||||||
!!!include(../api/collections/democol/meta.yml)!!!
|
|
||||||
|
|
||||||
## views Liste
|
|
||||||
|
|
||||||
`views` werden für die Darstellung der Kollektion-Daten im *tibi-admin* benötigt. Die Auswahl des passenden View erfolgt über CSS Media-Queries.
|
|
||||||
|
|
||||||
Optionale Unternavigationen können eigene `views` haben.
|
|
||||||
|
|
||||||
Folgende möglche Einträge für `views` gibt es derzeit:
|
|
||||||
|
|
||||||
### simpleList
|
|
||||||
|
|
||||||
!!!include(../api/collections/democol/simpleList.yml)!!!
|
|
||||||
|
|
||||||
### table
|
|
||||||
|
|
||||||
!!!include(../api/collections/democol/table.yml)!!!
|
|
||||||
|
|
||||||
## tablist
|
|
||||||
|
|
||||||
Wird die `tablist` verwendet, ist sicher zu stellen, dass alle Felder in der Definition aufgenommen werden. Werden Felder nicht in die `tablist` aufgenommen, sind diese weiterhin in einer Gesamtliste unterhalb der Tabs und bringen das Layout durcheinander.
|
|
||||||
|
|
||||||
!!!include(../api/collections/democol/tablist.yml)!!!
|
|
Binary file not shown.
@ -1,15 +0,0 @@
|
|||||||
# config.yml
|
|
||||||
|
|
||||||
Die Datei **config.yml** ist der Einstieg in die API-Konfiguration eines Projekts. Die Datei kann sich an einem beliebigen Ort befinden. Die einzige Bedingung ist, dass sie durch den tibi-server lesbar ist.
|
|
||||||
|
|
||||||
Es hat sich jedoch als günstig erwiesen bei Webprojekten die Datei und alle anderen Datein, die zur API-Konfiguration gehören, im ordner [api/](./ordnerstruktur.md) unterhalb des eigentlichen Webprojektes anzuordnen. Die Quellen des Frontends und der API können somit in ein Mono-Repo eingecheckt werden.
|
|
||||||
|
|
||||||
## Aufbau
|
|
||||||
|
|
||||||
!!!include(../api/config.yml)!!!
|
|
||||||
|
|
||||||
### siehe
|
|
||||||
|
|
||||||
- [collections](./collections.md)
|
|
||||||
- [jobs](./jobs.md)
|
|
||||||
- [assets](./assets.md)
|
|
@ -1,11 +0,0 @@
|
|||||||
# jobs
|
|
||||||
|
|
||||||
In dem ein oder anderen Projekt werden sicherlich Jobs im Hintergrund benötigt, die zu bestimmten Zeiten oder Intervallweise ausgeführt werden müssen (z.B. Datenbereinigung). Diese Jobs können innerhalb der [config.yml](./config.yml.md) definiert werden.
|
|
||||||
|
|
||||||
Wie in allen YAML-Definitionen können auch die Jobs via `!include` ausgelagert werden.
|
|
||||||
|
|
||||||
Der Aufbau eines Jobs ausgelagert in einer Datei sieht beispielsweise folgendermaßen aus:
|
|
||||||
|
|
||||||
!!!include(../api/jobs/demojob.yml)!!!
|
|
||||||
|
|
||||||
Die Möglichkeiten innerhalb der Javascript-Datei werden im Kapitel [Javascript Kontext](./../server-javascript-kontext/job.md) beschrieben.
|
|
@ -1,65 +0,0 @@
|
|||||||
# Ordnerstruktur
|
|
||||||
|
|
||||||
Als Konvention für neue Projekte hat sich folgende Ordnerstruktur etabliert:
|
|
||||||
|
|
||||||
![Ordnerstruktur](api-ordner.png)
|
|
||||||
|
|
||||||
Die Aufteilung der YAML-Konfiguration ist durch den YAML-Tag `!include` möglich. Genaueres dazu wird auf den nachfolgenden Seiten beschrieben.
|
|
||||||
|
|
||||||
## /api
|
|
||||||
|
|
||||||
Der Einstiegsordner in die Konfiguration ist frei wählbar. "/api" innerhalb des Projektrepositories hat sich jedoch bewährt.
|
|
||||||
|
|
||||||
Die Einstiegsdatei in die Gesamt-Konfiguration liegt hier und heißt [config.yml](./config.yml.md). In dieser können Umgebungsvariablen erstetzt werden, welche in [config.yml.env](./config.yml.md) definiert sind.
|
|
||||||
|
|
||||||
Ebenso sind alle nachfolgenden Unterordner beliebig zu benennen. Da aber ein JSON-Schema und VSCode-Konfiguration zur Validierung der YAML Dateien existiert, ist folgende Struktur hilfreich.
|
|
||||||
|
|
||||||
### JSON-Schema
|
|
||||||
|
|
||||||
Das JSON-Schema ist in die package.json einzubinden via:
|
|
||||||
|
|
||||||
```json
|
|
||||||
...
|
|
||||||
"devDependencies": {
|
|
||||||
...,
|
|
||||||
"tibi-types": "https://gitbase.de/cms/tibi-types.git"
|
|
||||||
},
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
Die im Projekt liegende VSCode-Konfig sollte dementsprechend ergänzt werden:
|
|
||||||
|
|
||||||
```json
|
|
||||||
...
|
|
||||||
"yaml.schemas": {
|
|
||||||
"node_modules/tibi-types/schemas/api-config/config.json": "api/config.y*ml",
|
|
||||||
"node_modules/tibi-types/schemas/api-config/collection.json": "api/collections/*.y*ml",
|
|
||||||
"node_modules/tibi-types/schemas/api-config/field.json": "api/collections/fields/*.y*ml",
|
|
||||||
"node_modules/tibi-types/schemas/api-config/fieldArray.json": "api/collections/fieldLists/*.y*ml"
|
|
||||||
},
|
|
||||||
"yaml.customTags": ["!include scalar"],
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
Sollte Yarn2 verwendet werden ist die Verlinkung von **node_modules** nötig. Dazu ist folgendes in der **.yarnrc.yml** einzutragen:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
...
|
|
||||||
nodeLinker: node-modules
|
|
||||||
```
|
|
||||||
|
|
||||||
## /api/collections
|
|
||||||
|
|
||||||
Bei Aufteilung der Kollektionskonfigurationen in einzelne Dateien, sollten diese in diesem Ordner gespeichert werden. Für jede Kollektion sollte eine eigene Datei verwendet werden, hier im Beispiel [api/collections/democol.yml](./collections.md).
|
|
||||||
|
|
||||||
### /api/collections/fields
|
|
||||||
|
|
||||||
Sollten Feldkonfigurationen wieder verwendet werden, können diese im [api/collections/fields/](./collections/fields.md) Unterordner gepeichert werden. Diese sind pro Feldkonfiguration als einzelne Datei aufzuführen.
|
|
||||||
|
|
||||||
### /api/hooks
|
|
||||||
|
|
||||||
Jede Javascript-Datei, die einen Hook bedient sollte im Unterordner benannt nach der Kollektion im Ordner [api/hooks/](./collections/hooks.md) sein. Der Name der Datei sollte sich nach den Hook richten. Z.B. **get_return.js** ist zustängig für den GET-Hook nach dem Lesen der Daten, bevor diese zurück gegeben werden. Mehr dazu unter [Hooks](./collections/hooks.md).
|
|
||||||
|
|
||||||
### /api/templates
|
|
||||||
|
|
||||||
Ist es nötig im Projekt Templates zu rendern (z.B. für den Email-Versand), sind diese im Ordner **templates** gut aufgehoben.
|
|
@ -1,3 +0,0 @@
|
|||||||
# `/_/NAMESPACE/_/assets/ASSETSNAME`
|
|
||||||
|
|
||||||
TODO
|
|
@ -1,3 +0,0 @@
|
|||||||
# `/_/NAMESPACE/COLLECTION`
|
|
||||||
|
|
||||||
TODO
|
|
@ -1,3 +0,0 @@
|
|||||||
# `/login`
|
|
||||||
|
|
||||||
TODO
|
|
@ -1,3 +0,0 @@
|
|||||||
# `/project`
|
|
||||||
|
|
||||||
TODO
|
|
@ -1,3 +0,0 @@
|
|||||||
# `/user`
|
|
||||||
|
|
||||||
TODO
|
|
@ -1,13 +0,0 @@
|
|||||||
# Entitäten
|
|
||||||
|
|
||||||
## Projekt
|
|
||||||
|
|
||||||
Jedes Projekt hat eine eigene Konfig-Datei im YAML-Format [config.yml](../projektkonfig/config.yml.md) deren Aufbau später beschrieben wird.
|
|
||||||
|
|
||||||
Wird der Server als "root" ausgeführt, so werden die individuellen Projekt-Threads mit der Benutzer- und Gruppenberechtigung der [config.yml](../projektkonfig/config.yml.md) Datei ausgeführt. Somit ist ein Multi-Mandanten-Server mit getrennten Dateisystem-Berechtigungen möglich.
|
|
||||||
|
|
||||||
Die Projektkonfiguration ist zwingend notwendig und wird beim Anlegen oder Bearbeiten von Projekten über die Rest-API neu eingelesen.
|
|
||||||
|
|
||||||
## Benutzer
|
|
||||||
|
|
||||||
TODO
|
|
@ -1,3 +0,0 @@
|
|||||||
# Serverkonfiguration
|
|
||||||
|
|
||||||
TODO
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 291 KiB |
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "tibi-docs",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"main": "README.md",
|
|
||||||
"repository": "https://gitbase.de/cms/tibi-docs",
|
|
||||||
"author": "Sebastian Frank <sebastian@webmakers.de>",
|
|
||||||
"license": "MIT",
|
|
||||||
"packageManager": "yarn@3.2.4",
|
|
||||||
"scripts": {
|
|
||||||
"docpress:serve": "docpress serve",
|
|
||||||
"docpress:build": "docpress build"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"docpress": "^0.8.2"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"markdown-it-code-include": "./markdown-it-code-include"
|
|
||||||
}
|
|
||||||
}
|
|
7181
docs/yarn.lock
7181
docs/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import Header from "./lib/components/Menu/Header.svelte"
|
||||||
|
import Menu from "./lib/components/Menu/Menu.svelte"
|
||||||
import { location } from "./store"
|
import { location } from "./store"
|
||||||
|
|
||||||
export let url = ""
|
export let url = ""
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
// ssr
|
|
||||||
let l = url.split("?")
|
let l = url.split("?")
|
||||||
$location = {
|
$location = {
|
||||||
path: l[0],
|
path: l[0],
|
||||||
@ -17,11 +18,28 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof window !== "undefined") console.log("App initialized")
|
if (typeof window !== "undefined") console.log("App initialized")
|
||||||
|
let activeMenu = true
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1>Hello Worlddg g</h1>
|
<main class="">
|
||||||
|
<Header bind:active="{activeMenu}" />
|
||||||
|
<Menu bind:active="{activeMenu}" />
|
||||||
|
</main>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less" global>
|
||||||
|
@import "./lib/assets/css/main.less";
|
||||||
|
@import "./lib/assets/css/base.less";
|
||||||
|
main {
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
@media @mobile {
|
||||||
|
font-size: @bodyfontsize;
|
||||||
|
}
|
||||||
|
@media @tablet {
|
||||||
|
font-size: @bodyfontsize_desktop;
|
||||||
|
}
|
||||||
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-family: "Libre Franklin";
|
font-family: "Libre Franklin";
|
||||||
|
64
frontend/src/lib/assets/css/base.less
Normal file
64
frontend/src/lib/assets/css/base.less
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: #333 !important;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links */
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tabellen */
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
transition: background-color 0.5s ease, border-color 0.5s ease, color 0.5s ease, max-height 0.5s, height 0.5s ease,
|
||||||
|
width 0.5s ease, flex 0.5s ease, opacity 0.5s ease, top 0.5s ease, bottom 0.5s ease, left 0.5s ease,
|
||||||
|
right 0.5s ease, transform 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: left;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background-color: inherit;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: inherit;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
input,
|
||||||
|
select {
|
||||||
|
color: #333;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-container {
|
||||||
|
}
|
@ -2,3 +2,11 @@
|
|||||||
@bg-color-secondary: #000;
|
@bg-color-secondary: #000;
|
||||||
@font-color: #000;
|
@font-color: #000;
|
||||||
@font-color-secondary: #fff;
|
@font-color-secondary: #fff;
|
||||||
|
|
||||||
|
@desktop_large:~ "only screen and (min-width: 1200px)";
|
||||||
|
@desktop:~ "only screen and (min-width: 1024px)";
|
||||||
|
@tablet:~ "only screen and (min-width: 768px)";
|
||||||
|
@mobile: ~"only screen and (min-width: 0px)";
|
||||||
|
|
||||||
|
@bodyfontsize: 16px;
|
||||||
|
@bodyfontsize_desktop: 20px;
|
||||||
|
54
frontend/src/lib/components/Menu/Header.svelte
Normal file
54
frontend/src/lib/components/Menu/Header.svelte
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let active = false
|
||||||
|
export let opened = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="header">
|
||||||
|
<div class="logo">
|
||||||
|
<img src="/media/Logo Quer.svg" alt="Logo Quer" />
|
||||||
|
</div>
|
||||||
|
<button class="menu" on:click="{() => (active = !active)}">
|
||||||
|
<div>MENÜ</div>
|
||||||
|
{#if opened}
|
||||||
|
<img src="/media/ei close.svg" alt="Logo" />
|
||||||
|
{:else}
|
||||||
|
<img src="/media/BurgerMenu.svg" alt="Menu" />
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@import "../../assets/css/main.less";
|
||||||
|
.header {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10.4px 5px;
|
||||||
|
@media @tablet {
|
||||||
|
padding: 25.4px 60px;
|
||||||
|
}
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 25px;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-weight: bold;
|
||||||
|
@media @tablet {
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
86
frontend/src/lib/components/Menu/Menu.svelte
Normal file
86
frontend/src/lib/components/Menu/Menu.svelte
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Header from "./Header.svelte"
|
||||||
|
export let active = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="menu" class:active="{active}">
|
||||||
|
<div class="menu-container">
|
||||||
|
<Header bind:active="{active}" opened="{true}" />
|
||||||
|
<div class="menu-content">
|
||||||
|
<div class="container">
|
||||||
|
<div class="pages">
|
||||||
|
{#each ["Ihre Bedürfnisse", "Unsere Lösungen", "Über uns", "Kontakt"] as page}
|
||||||
|
<button class="page">
|
||||||
|
{page}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="footer-infos"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@import "../../assets/css/main.less";
|
||||||
|
.menu {
|
||||||
|
position: absolute;
|
||||||
|
background-color: @bg-color;
|
||||||
|
z-index: 1000;
|
||||||
|
top: 110vh;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
height: 100vh;
|
||||||
|
&.active {
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.menu-content {
|
||||||
|
background-color: @bg-color-secondary;
|
||||||
|
color: @font-color-secondary;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
width: 80%;
|
||||||
|
margin: 10vw 0px;
|
||||||
|
.footer-infos {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.pages {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
.page {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
color: @font-color-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media @tablet {
|
||||||
|
flex-direction: row;
|
||||||
|
.footer-infos {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.pages {
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user