Initial
190
README.md
@@ -4,10 +4,10 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h1 align="center">Name des Projekts</h1>
|
||||
<h1 align="center">Trilium Notes Branding</h1>
|
||||
|
||||
<h4 align="center">
|
||||
Kurzbeschreibung des Projekts/Anwendung, um die es geht
|
||||
Updatefeste Branding- und Theme-Anpassungen fuer TriliumNext Shared Notes
|
||||
</h4>
|
||||
|
||||
<h6 align="center">
|
||||
@@ -22,7 +22,189 @@
|
||||
<br><br>
|
||||
|
||||
|
||||
CONTENT BEREICH
|
||||
## Ueber dieses Projekt
|
||||
|
||||
Dieses Repository enthaelt updatefeste Anpassungen fuer eine TriliumNext-Installation. Ziel ist, eigene Branding-Dateien, ein angepasstes Dark-Theme fuer Shared Notes, ein Hintergrundbild und kleine Komfortfunktionen per Docker-Volume einzubinden, ohne Dateien im Container-Image dauerhaft zu veraendern.
|
||||
|
||||
Die Dateien liegen bewusst unter `./data/custom`, damit alle persistenten Konfigurationen und Assets an einem Ort liegen.
|
||||
|
||||
## Funktionen
|
||||
|
||||
- eigenes Logo fuer Shared Notes
|
||||
- eigenes Favicon fuer Shared Notes und die Hauptanwendung
|
||||
- eigenes Login-Logo
|
||||
- eigenes PWA/App-Icon
|
||||
- Dark-only Theme fuer Shared Notes
|
||||
- Hintergrundbild fuer Shared Notes
|
||||
- Kopierbutton fuer Codebloecke
|
||||
- Seitenleiste in Shared Notes standardmaessig eingeklappt
|
||||
- Burger-Menue bleibt erhalten, damit freigegebene Verzeichnisse weiter navigierbar sind
|
||||
- alle Anpassungen als read-only Docker-Bind-Mounts
|
||||
|
||||
## Ordnerstruktur
|
||||
|
||||
```text
|
||||
.
|
||||
├── data/
|
||||
│ └── custom/
|
||||
│ ├── branding/
|
||||
│ │ ├── techniverse-favicon.ico
|
||||
│ │ ├── techniverse-icon-180.png
|
||||
│ │ ├── techniverse-icon-32.png
|
||||
│ │ ├── techniverse-icon-512.png
|
||||
│ │ ├── techniverse-icon-64.png
|
||||
│ │ ├── techniverse-logo-256.png
|
||||
│ │ ├── techniverse-logo-original.png
|
||||
│ │ └── techniverse-logo.svg
|
||||
│ └── share-theme/
|
||||
│ ├── custom-share-copy.js
|
||||
│ ├── custom-share-dark.css
|
||||
│ ├── page.ejs
|
||||
│ ├── share-background.jpg
|
||||
│ └── share-background.jpg.old
|
||||
└── docker-compose.yaml
|
||||
```
|
||||
|
||||
## Docker-Mounts
|
||||
|
||||
Die relevanten Dateien werden in `docker-compose.yaml` read-only in den Container gemountet:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./data/trilium-data:/home/node/trilium-data
|
||||
- ./data/custom/share-theme/page.ejs:/usr/src/app/share-theme/templates/page.ejs:ro
|
||||
- ./data/custom/share-theme/custom-share-dark.css:/usr/src/app/share-theme/assets/custom-share-dark.css:ro
|
||||
- ./data/custom/share-theme/custom-share-copy.js:/usr/src/app/share-theme/assets/custom-share-copy.js:ro
|
||||
- ./data/custom/share-theme/share-background.jpg:/usr/src/app/share-theme/assets/share-background.jpg:ro
|
||||
- ./data/custom/branding/techniverse-logo-256.png:/usr/src/app/share-theme/assets/techniverse-logo-256.png:ro
|
||||
- ./data/custom/branding/techniverse-icon-64.png:/usr/src/app/share-theme/assets/techniverse-icon-64.png:ro
|
||||
- ./data/custom/branding/techniverse-logo.svg:/usr/src/app/assets/images/icon-color.svg:ro
|
||||
- ./data/custom/branding/techniverse-icon-180.png:/usr/src/app/assets/images/app-icons/ios/apple-touch-icon.png:ro
|
||||
- ./data/custom/branding/techniverse-icon-512.png:/usr/src/app/public/assets/icon.png:ro
|
||||
- ./data/custom/branding/techniverse-favicon.ico:/usr/src/app/public/favicon.ico:ro
|
||||
- ./data/custom/branding/techniverse-favicon.ico:/usr/src/app/assets/icon.ico:ro
|
||||
```
|
||||
|
||||
## Shared Notes Theme
|
||||
|
||||
Die Datei `data/custom/share-theme/custom-share-dark.css` ueberschreibt das Standard-Theme der TriliumNext Shared Notes. Der Lightmode wird dabei absichtlich nicht separat gepflegt:
|
||||
|
||||
- `html.theme-light` und `html.theme-dark` verwenden dieselben dunklen Variablen
|
||||
- `color-scheme: dark` ist gesetzt
|
||||
- die Theme-Auswahl wird per CSS ausgeblendet
|
||||
|
||||
Dadurch muss nur ein konsistenter Darkmode gepflegt werden.
|
||||
|
||||
## Hintergrundbild
|
||||
|
||||
Das Hintergrundbild liegt unter:
|
||||
|
||||
```text
|
||||
data/custom/share-theme/share-background.jpg
|
||||
```
|
||||
|
||||
Es wird in `custom-share-dark.css` referenziert:
|
||||
|
||||
```css
|
||||
--mtp-share-background: url("share-background.jpg?v=20260605");
|
||||
```
|
||||
|
||||
Wenn das Bild ausgetauscht wird, kann der Browser die alte Version noch im Cache haben. In dem Fall entweder hart neu laden oder den Cache-Buster in der CSS-Datei erhoehen, zum Beispiel:
|
||||
|
||||
```css
|
||||
--mtp-share-background: url("share-background.jpg?v=20260605-2");
|
||||
```
|
||||
|
||||
Ein Container-Neustart ist nur noetig, wenn der Dateiname oder der Docker-Mount geaendert wird.
|
||||
|
||||
## Kopierbutton fuer Codebloecke
|
||||
|
||||
Die Datei `data/custom/share-theme/custom-share-copy.js` fuegt in Shared Notes an alle echten Codebloecke einen Button hinzu.
|
||||
|
||||
Der Button:
|
||||
|
||||
- erscheint bei `<pre><code>`-Bloecken
|
||||
- kopiert den Code in die Zwischenablage
|
||||
- zeigt nach dem Klick kurz `Kopiert`
|
||||
- nutzt die Clipboard API mit Fallback fuer aeltere Browser
|
||||
|
||||
## Seitenleiste und Burger-Menue
|
||||
|
||||
Die Seitenleiste startet fuer neue Besucher standardmaessig eingeklappt. Das Burger-Menue bleibt sichtbar und kann die Navigation weiterhin oeffnen.
|
||||
|
||||
Das ist wichtig fuer freigegebene Verzeichnisse, weil dort die Unterseiten ueber die Seitenleiste erreichbar sind.
|
||||
|
||||
Technisch wird beim ersten Aufruf gesetzt:
|
||||
|
||||
```js
|
||||
localStorage.setItem("left-pane-collapsed", "true");
|
||||
```
|
||||
|
||||
Wenn ein Besucher die Seitenleiste oeffnet, speichert Trilium diese Entscheidung wie gewohnt im Browser.
|
||||
|
||||
## Branding
|
||||
|
||||
Die Branding-Dateien liegen unter:
|
||||
|
||||
```text
|
||||
data/custom/branding/
|
||||
```
|
||||
|
||||
Verwendete Dateien:
|
||||
|
||||
- `techniverse-logo-256.png`: Logo in Shared Notes
|
||||
- `techniverse-icon-64.png`: Favicon fuer Shared Notes
|
||||
- `techniverse-logo.svg`: Ersatz fuer Triliums Login-Logo `icon-color.svg`
|
||||
- `techniverse-icon-180.png`: Apple-Touch-Icon
|
||||
- `techniverse-icon-512.png`: PWA/App-Icon
|
||||
- `techniverse-icon-32.png`: kleine Icon-Variante, aktuell Reserve/Quelle fuer weitere Mounts
|
||||
- `techniverse-favicon.ico`: Favicon der Hauptanwendung
|
||||
- `techniverse-logo-original.png`: Originaldatei als Quelle
|
||||
|
||||
Die Datei `share-background.jpg.old` ist nur eine lokale Sicherung des vorherigen Hintergrundbildes und wird nicht in den Container gemountet.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Repository auf den Docker-Host kopieren.
|
||||
2. Trilium-Daten unter `data/trilium-data` bereitstellen oder vorhandene Daten dort belassen.
|
||||
3. `docker-compose.yaml` bei Bedarf an Port, Netzwerk oder Containername anpassen.
|
||||
4. Compose-Konfiguration pruefen:
|
||||
|
||||
```bash
|
||||
docker compose config
|
||||
```
|
||||
|
||||
5. Container starten oder neu erstellen:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Update-Hinweise
|
||||
|
||||
Die Anpassungen sind updatefest, weil sie als read-only Volumes eingebunden werden. Beim Update des TriliumNext-Images bleiben die Dateien unter `data/custom` erhalten.
|
||||
|
||||
Wichtig ist nur `data/custom/share-theme/page.ejs`: Diese Datei basiert auf dem TriliumNext Share-Template und enthaelt zusaetzliche Includes fuer CSS, JavaScript, Logo und Favicon. Wenn TriliumNext das Share-Template groesser veraendert, sollte die neue Upstream-Version mit dieser Datei verglichen werden.
|
||||
|
||||
Beibehalten werden sollten:
|
||||
|
||||
- Include fuer `custom-share-dark.css`
|
||||
- Include fuer `custom-share-copy.js`
|
||||
- Branding-Variablen fuer Logo und Favicon
|
||||
- Default-Collapse-Logik fuer die Seitenleiste
|
||||
|
||||
## Cache-Hinweise
|
||||
|
||||
Browser cachen CSS, Bilder und Favicons oft aggressiv. Wenn eine Aenderung nicht sichtbar ist:
|
||||
|
||||
- Seite hart neu laden
|
||||
- Inkognito-Fenster testen
|
||||
- Cache-Buster in CSS oder Template erhoehen
|
||||
- bei geaenderten Mounts den Container neu erstellen
|
||||
|
||||
## Dokumentation
|
||||
|
||||
Die Projektdokumentation liegt bewusst zentral in dieser `README.md`. Zusaetzliche README-Dateien in Unterordnern wurden entfernt, damit spaeter beim Veroeffentlichen des Repositories keine widerspruechlichen oder veralteten Hinweise entstehen.
|
||||
|
||||
|
||||
<br><br>
|
||||
@@ -34,4 +216,4 @@ CONTENT BEREICH
|
||||
<sub>
|
||||
© Patrick Asmus · Techniverse Network · <a href="./LICENSE">Lizenz</a>
|
||||
</sub>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
BIN
data/custom/branding/techniverse-favicon.ico
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
data/custom/branding/techniverse-icon-180.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
data/custom/branding/techniverse-icon-32.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
data/custom/branding/techniverse-icon-512.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
data/custom/branding/techniverse-icon-64.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
data/custom/branding/techniverse-logo-256.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
data/custom/branding/techniverse-logo-original.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
3
data/custom/branding/techniverse-logo.svg
Normal file
|
After Width: | Height: | Size: 26 KiB |
89
data/custom/share-theme/custom-share-copy.js
Normal file
@@ -0,0 +1,89 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
const copiedLabel = "Kopiert";
|
||||
const copyLabel = "Kopieren";
|
||||
const resetDelayMs = 1600;
|
||||
|
||||
function getCodeText(codeElement) {
|
||||
return codeElement.textContent.replace(/\n$/, "");
|
||||
}
|
||||
|
||||
async function copyText(text) {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return;
|
||||
}
|
||||
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.value = text;
|
||||
textArea.setAttribute("readonly", "");
|
||||
textArea.style.position = "fixed";
|
||||
textArea.style.top = "-1000px";
|
||||
textArea.style.opacity = "0";
|
||||
document.body.appendChild(textArea);
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
document.execCommand("copy");
|
||||
} finally {
|
||||
textArea.remove();
|
||||
}
|
||||
}
|
||||
|
||||
function setButtonState(button, label, copied) {
|
||||
button.textContent = label;
|
||||
button.setAttribute("aria-label", label);
|
||||
button.classList.toggle("is-copied", copied);
|
||||
}
|
||||
|
||||
function enhanceCodeBlock(preElement) {
|
||||
if (preElement.closest(".mtp-code-block")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const codeElement = preElement.querySelector("code");
|
||||
if (!codeElement || !getCodeText(codeElement).trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.className = "mtp-code-block";
|
||||
preElement.parentNode.insertBefore(wrapper, preElement);
|
||||
wrapper.appendChild(preElement);
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "mtp-copy-code-button";
|
||||
setButtonState(button, copyLabel, false);
|
||||
|
||||
button.addEventListener("click", async () => {
|
||||
const originalLabel = button.textContent;
|
||||
button.disabled = true;
|
||||
|
||||
try {
|
||||
await copyText(getCodeText(codeElement));
|
||||
setButtonState(button, copiedLabel, true);
|
||||
window.setTimeout(() => {
|
||||
button.disabled = false;
|
||||
setButtonState(button, copyLabel, false);
|
||||
}, resetDelayMs);
|
||||
} catch (error) {
|
||||
button.disabled = false;
|
||||
setButtonState(button, originalLabel || copyLabel, false);
|
||||
}
|
||||
});
|
||||
|
||||
wrapper.appendChild(button);
|
||||
}
|
||||
|
||||
function initCopyButtons() {
|
||||
document.querySelectorAll("#content pre").forEach(enhanceCodeBlock);
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", initCopyButtons, { once: true });
|
||||
} else {
|
||||
initCopyButtons();
|
||||
}
|
||||
})();
|
||||
333
data/custom/share-theme/custom-share-dark.css
Normal file
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Media-Techport TriliumNext share theme overrides.
|
||||
* Mounted as a read-only Docker volume so image updates do not overwrite it.
|
||||
*/
|
||||
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
--mtp-radius: 8px;
|
||||
--mtp-radius-sm: 6px;
|
||||
--mtp-shadow: 0 18px 48px rgb(0 0 0 / 18%);
|
||||
--mtp-content-width: 980px;
|
||||
--mtp-font-sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
--mtp-font-mono: "JetBrains Mono", "Cascadia Code", Consolas, monospace;
|
||||
--mtp-share-background: url("share-background.jpg?v=20260605");
|
||||
}
|
||||
|
||||
html.theme-light,
|
||||
html.theme-dark {
|
||||
--background-primary: #11110f;
|
||||
--background-secondary: #191816;
|
||||
--background-highlight: #2b2924;
|
||||
--background-active: #d2a84a;
|
||||
--text-primary: #e8e2d6;
|
||||
--text-heading: #fff6e5;
|
||||
--text-menu: #cfc6b8;
|
||||
--text-link: #69d5c3;
|
||||
--text-menu-active: #171411;
|
||||
}
|
||||
|
||||
html.theme-light .light-icon,
|
||||
html.theme-light .dark-icon,
|
||||
html.theme-dark .light-icon,
|
||||
html.theme-dark .dark-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--mtp-font-sans);
|
||||
letter-spacing: 0;
|
||||
text-rendering: optimizeLegibility;
|
||||
background: var(--background-primary);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--text-link);
|
||||
text-underline-offset: 0.18em;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#header {
|
||||
min-height: 56px;
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 1px 0 rgb(255 255 255 / 6%);
|
||||
}
|
||||
|
||||
#header-logo {
|
||||
gap: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
#header-logo img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
object-fit: contain;
|
||||
border-radius: var(--mtp-radius-sm);
|
||||
}
|
||||
|
||||
#left-pane {
|
||||
border-right-width: 1px;
|
||||
box-shadow: 12px 0 40px rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
#navigation {
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.theme-selection {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
min-height: 36px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
border-color: var(--text-link);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--text-link) 22%, transparent);
|
||||
}
|
||||
|
||||
#menu a {
|
||||
min-height: 30px;
|
||||
padding: 4px 8px;
|
||||
border-radius: var(--mtp-radius-sm);
|
||||
}
|
||||
|
||||
#menu a:hover {
|
||||
background: color-mix(in srgb, var(--background-highlight) 72%, var(--text-link));
|
||||
border-color: transparent;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#menu a.active {
|
||||
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--background-active) 65%, white);
|
||||
}
|
||||
|
||||
#right-pane {
|
||||
background:
|
||||
linear-gradient(90deg, rgb(17 17 15 / 72%), rgb(17 17 15 / 52%) 42%, rgb(17 17 15 / 78%)),
|
||||
linear-gradient(180deg, rgb(17 17 15 / 28%), rgb(17 17 15 / 86%) 78%),
|
||||
var(--mtp-share-background) center / cover fixed,
|
||||
var(--background-primary);
|
||||
}
|
||||
|
||||
#main {
|
||||
max-width: var(--mtp-content-width);
|
||||
padding: 34px clamp(18px, 4vw, 56px) 42px;
|
||||
}
|
||||
|
||||
#content {
|
||||
font-size: 1rem;
|
||||
line-height: 1.72;
|
||||
}
|
||||
|
||||
#title {
|
||||
margin-bottom: 0.85em;
|
||||
padding-top: 0;
|
||||
font-size: clamp(2rem, 4vw, 3.4rem);
|
||||
line-height: 1.08;
|
||||
}
|
||||
|
||||
#content h1,
|
||||
#content h2,
|
||||
#content h3,
|
||||
#content h4,
|
||||
#content h5,
|
||||
#content h6 {
|
||||
margin-top: 1.45em;
|
||||
margin-bottom: 0.55em;
|
||||
padding-bottom: 0.25em;
|
||||
line-height: 1.22;
|
||||
border-bottom-color: color-mix(in srgb, var(--background-highlight) 76%, transparent);
|
||||
}
|
||||
|
||||
#content p,
|
||||
#content ul,
|
||||
#content ol {
|
||||
margin-block: 0.75em;
|
||||
}
|
||||
|
||||
#content li + li {
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
#content blockquote {
|
||||
margin: 1.1em 0;
|
||||
padding: 0.8em 1em;
|
||||
color: color-mix(in srgb, var(--text-primary) 84%, var(--text-link));
|
||||
background: color-mix(in srgb, var(--background-secondary) 82%, var(--text-link));
|
||||
border-left: 4px solid var(--text-link);
|
||||
border-radius: var(--mtp-radius-sm);
|
||||
}
|
||||
|
||||
.ck-content code,
|
||||
.ck-content pre {
|
||||
font-family: var(--mtp-font-mono);
|
||||
background: color-mix(in srgb, var(--background-secondary) 88%, black);
|
||||
border-color: color-mix(in srgb, var(--background-highlight) 70%, var(--text-link));
|
||||
}
|
||||
|
||||
.ck-content code {
|
||||
font-size: 0.92em;
|
||||
}
|
||||
|
||||
.ck-content pre {
|
||||
padding: 14px 16px;
|
||||
box-shadow: inset 0 1px 0 rgb(255 255 255 / 4%);
|
||||
}
|
||||
|
||||
.mtp-code-block {
|
||||
position: relative;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.mtp-code-block > pre {
|
||||
margin: 0;
|
||||
padding-top: 42px;
|
||||
}
|
||||
|
||||
.mtp-copy-code-button {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
z-index: 2;
|
||||
min-height: 28px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid color-mix(in srgb, var(--background-highlight) 78%, var(--text-link));
|
||||
border-radius: var(--mtp-radius-sm);
|
||||
color: var(--text-menu);
|
||||
background: color-mix(in srgb, var(--background-secondary) 88%, black);
|
||||
font: 600 0.78rem/1 var(--mtp-font-sans);
|
||||
cursor: pointer;
|
||||
opacity: 0.86;
|
||||
transition:
|
||||
opacity 160ms ease,
|
||||
color 160ms ease,
|
||||
background-color 160ms ease,
|
||||
border-color 160ms ease;
|
||||
}
|
||||
|
||||
.mtp-copy-code-button:hover,
|
||||
.mtp-copy-code-button:focus-visible {
|
||||
opacity: 1;
|
||||
color: var(--text-heading);
|
||||
background: color-mix(in srgb, var(--background-highlight) 72%, var(--text-link));
|
||||
border-color: var(--text-link);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.mtp-copy-code-button.is-copied {
|
||||
color: var(--text-menu-active);
|
||||
background: var(--background-active);
|
||||
border-color: var(--background-active);
|
||||
}
|
||||
|
||||
.ck-content table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
overflow: hidden;
|
||||
border-radius: var(--mtp-radius-sm);
|
||||
}
|
||||
|
||||
.ck-content table td,
|
||||
.ck-content table th {
|
||||
border-color: var(--background-highlight);
|
||||
padding: 0.55em 0.7em;
|
||||
}
|
||||
|
||||
.ck-content table th {
|
||||
color: var(--text-heading);
|
||||
background: var(--background-secondary);
|
||||
}
|
||||
|
||||
#content img {
|
||||
border-radius: var(--mtp-radius);
|
||||
box-shadow: var(--mtp-shadow);
|
||||
}
|
||||
|
||||
#childLinks {
|
||||
margin-top: 2rem;
|
||||
padding-top: 1.2rem;
|
||||
}
|
||||
|
||||
#childLinks li,
|
||||
#childLinks li a {
|
||||
border-radius: var(--mtp-radius-sm);
|
||||
}
|
||||
|
||||
#toc-pane {
|
||||
border-left: 1px solid var(--background-highlight);
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
#toc-pane h3 {
|
||||
letter-spacing: 0.08em;
|
||||
color: color-mix(in srgb, var(--text-menu) 82%, var(--text-link));
|
||||
}
|
||||
|
||||
#content-footer {
|
||||
margin-top: 2.5rem;
|
||||
border-top: 1px solid var(--background-highlight);
|
||||
}
|
||||
|
||||
#content-footer .navigation a {
|
||||
border-radius: var(--mtp-radius-sm);
|
||||
}
|
||||
|
||||
html.theme-light #header,
|
||||
html.theme-light #left-pane,
|
||||
html.theme-dark #header,
|
||||
html.theme-dark #left-pane {
|
||||
background: rgb(25 24 22 / 94%);
|
||||
}
|
||||
|
||||
html.theme-light .search-results,
|
||||
html.theme-dark .search-results {
|
||||
box-shadow: var(--mtp-shadow);
|
||||
}
|
||||
|
||||
html.theme-light ::selection,
|
||||
html.theme-dark ::selection {
|
||||
color: #11110f;
|
||||
background: #69d5c3;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
#main {
|
||||
padding: 22px 18px 34px;
|
||||
}
|
||||
|
||||
#title {
|
||||
font-size: clamp(1.8rem, 8vw, 2.6rem);
|
||||
}
|
||||
|
||||
#content {
|
||||
font-size: 0.98rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
#header,
|
||||
#left-pane,
|
||||
#toc-pane {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#split-pane,
|
||||
#right-pane {
|
||||
overflow: visible !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
#main {
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
263
data/custom/share-theme/page.ejs
Normal file
@@ -0,0 +1,263 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<%
|
||||
const hasTree = subRoot.note.hasVisibleChildren();
|
||||
|
||||
// Collect HTML snippets by location
|
||||
const htmlSnippetsByLocation = {};
|
||||
for (const htmlRelation of note.getRelations("shareHtml")) {
|
||||
const htmlNote = htmlRelation.targetNote;
|
||||
if (htmlNote) {
|
||||
let location = htmlNote.getLabelValue("shareHtmlLocation") || "content:end";
|
||||
// Default to :end if no position specified
|
||||
if (!location.includes(":")) {
|
||||
location = location + ":end";
|
||||
}
|
||||
if (!htmlSnippetsByLocation[location]) {
|
||||
htmlSnippetsByLocation[location] = [];
|
||||
}
|
||||
htmlSnippetsByLocation[location].push(htmlNote.getContent());
|
||||
}
|
||||
}
|
||||
const renderSnippets = (location) => {
|
||||
const snippets = htmlSnippetsByLocation[location];
|
||||
return snippets ? snippets.join("\n") : "";
|
||||
};
|
||||
%>
|
||||
<%- renderSnippets("head:start") %>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<%
|
||||
const customShareAssetBase = (cssToLoad.find(url => url.endsWith("assets/styles.css")) || "assets/styles.css")
|
||||
.replace(/styles\.css$/, "");
|
||||
const customShareCssUrl = `${customShareAssetBase}custom-share-dark.css?v=20260605`;
|
||||
const customShareCopyJsUrl = `${customShareAssetBase}custom-share-copy.js?v=20260605`;
|
||||
const customShareFaviconUrl = faviconUrl.includes("favicon.ico")
|
||||
? `${customShareAssetBase}techniverse-icon-64.png?v=20260605`
|
||||
: faviconUrl;
|
||||
%>
|
||||
<link rel="shortcut icon" href="<%= customShareFaviconUrl %>">
|
||||
<% for (const url of cssToLoad) { %>
|
||||
<link href="<%= url %>" rel="stylesheet">
|
||||
<% } %>
|
||||
<link href="<%= customShareCssUrl %>" rel="stylesheet">
|
||||
<% for (const url of jsToLoad) { %>
|
||||
<script type="module" src="<%= url %>"></script>
|
||||
<% } %>
|
||||
<script defer src="<%= customShareCopyJsUrl %>"></script>
|
||||
<% if (note.hasLabel("shareDisallowRobotIndexing")) { %>
|
||||
<meta name="robots" content="noindex,follow" />
|
||||
<% } %>
|
||||
|
||||
<%
|
||||
const pageTitle = `${note.title}${note.noteId !== subRoot.note.noteId ? ` - ${subRoot.note.title}` : ""}`;
|
||||
|
||||
// Setup some key OpenGraph variables
|
||||
const openGraphColor = subRoot.note.getLabelValue("shareOpenGraphColor");
|
||||
const openGraphURL = subRoot.note.getLabelValue("shareOpenGraphURL");
|
||||
const openGraphDomain = subRoot.note.getLabelValue("shareOpenGraphDomain");
|
||||
let openGraphImage = subRoot.note.getLabelValue("shareOpenGraphImage");
|
||||
// Relation takes priority and requires some altering
|
||||
if (subRoot.note.hasRelation("shareOpenGraphImage")) {
|
||||
openGraphImage = `api/images/${subRoot.note.getRelation("shareOpenGraphImage").value}/image.png`;
|
||||
}
|
||||
%>
|
||||
<title><%= pageTitle %></title>
|
||||
<script>
|
||||
// Load dark/light theme as soon as possible to avoid color flashes.
|
||||
let theme = localStorage.getItem("theme");
|
||||
if (!theme) {
|
||||
theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? "dark" : "light";
|
||||
}
|
||||
document.documentElement.classList.add(`theme-${theme}`);
|
||||
|
||||
window.glob = {
|
||||
isStatic: <%= !!isStatic %>,
|
||||
theme
|
||||
};
|
||||
|
||||
(function() {
|
||||
const leftPaneState = localStorage.getItem("left-pane-collapsed");
|
||||
const leftCollapsed = leftPaneState === null ? true : leftPaneState === "true";
|
||||
const tocCollapsed = localStorage.getItem("toc-pane-collapsed") === "true";
|
||||
if (leftPaneState === null) localStorage.setItem("left-pane-collapsed", "true");
|
||||
if (leftCollapsed) document.documentElement.classList.add("left-pane-collapsed");
|
||||
if (tocCollapsed) document.documentElement.classList.add("toc-pane-collapsed");
|
||||
})();
|
||||
</script>
|
||||
<!-- HTML Meta Tags -->
|
||||
<meta name="description" content="<%= note.getLabelValue("shareDescription") %>">
|
||||
<!-- Facebook Meta Tags -->
|
||||
<meta property="og:url" content="<%= openGraphURL %>">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="<%= pageTitle %>">
|
||||
<meta property="og:description" content="<%= note.getLabelValue("shareDescription") %>">
|
||||
<meta property="og:image" content="<%= openGraphImage %>">
|
||||
<!-- Twitter Meta Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:domain" content="<%= openGraphDomain %>">
|
||||
<meta property="twitter:url" content="<%= openGraphURL %>">
|
||||
<meta name="twitter:title" content="<%= pageTitle %>">
|
||||
<meta name="twitter:description" content="<%= note.getLabelValue("shareDescription") %>">
|
||||
<meta name="twitter:image" content="<%= openGraphImage %>">
|
||||
<!-- Meta Tags Generated via https://opengraph.dev -->
|
||||
<meta name="theme-color" content="<%= openGraphColor %>">
|
||||
<style id="trilium-icon-packs">
|
||||
<%- iconPackCss %>
|
||||
</style>
|
||||
<%- renderSnippets("head:end") %>
|
||||
</head>
|
||||
<%
|
||||
const logoWidth = subRoot.note.getLabelValue("shareLogoWidth") ?? 53;
|
||||
const logoHeight = subRoot.note.getLabelValue("shareLogoHeight") ?? 40;
|
||||
const mobileLogoHeight = logoHeight && logoWidth ? 32 / (logoWidth / logoHeight) : "";
|
||||
const customShareLogoUrl = logoUrl.includes("icon-color.svg")
|
||||
? `${customShareAssetBase}techniverse-logo-256.png?v=20260605`
|
||||
: logoUrl;
|
||||
const customShareLogoHeight = customShareLogoUrl === logoUrl ? mobileLogoHeight : 32;
|
||||
const shareRootLink = subRoot.note.hasLabel("shareRootLink") ? subRoot.note.getLabelValue("shareRootLink") : `./${subRoot.note.noteId}`;
|
||||
const headingRe = /(<h[1-6]>)(.+?)(<\/h[1-6]>)/g;
|
||||
const headingMatches = [...content.matchAll(headingRe)];
|
||||
content = content.replaceAll(headingRe, (...match) => {
|
||||
const slug = utils.slugify(utils.stripTags(match[2]));
|
||||
match[0] = match[0].replace(match[3], `<a id="${slug}" class="toc-anchor" name="${slug}" href="#${slug}">#</a>${match[3]}`);
|
||||
return match[0];
|
||||
});
|
||||
%>
|
||||
<body data-note-id="<%= note.noteId %>" class="type-<%= note.type %>" data-ancestor-note-id="<%= subRoot.note.noteId %>">
|
||||
<%- renderSnippets("body:start") %>
|
||||
<div id="header">
|
||||
<button aria-label="Toggle Navigation" id="left-pane-toggle-button" class="header-button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"></path></svg></button>
|
||||
<a href="<%= shareRootLink %>" id="header-logo">
|
||||
<img src="<%= customShareLogoUrl %>" width="32" height="<%= customShareLogoHeight %>" alt="Logo" />
|
||||
<%= subRoot.note.title %>
|
||||
</a>
|
||||
<% if (headingMatches.length > 1) { %>
|
||||
<button aria-label="Toggle Table of Contents" id="toc-pane-toggle-button" class="header-button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10V7h2v2h-2zm0 6h2v-2h-2v2z"></path></svg></button>
|
||||
<% } else { %>
|
||||
<div class="header-button-placeholder"></div>
|
||||
<% } %>
|
||||
</div>
|
||||
<div id="split-pane">
|
||||
<div id="left-pane">
|
||||
<div id="navigation">
|
||||
<div id="site-header">
|
||||
<div class="theme-selection">
|
||||
<span id="sitetheme"><%= t("share_theme.site-theme") %></span>
|
||||
<label class="switch">
|
||||
<input type="checkbox" aria-labelledby="sitetheme">
|
||||
<span class="slider"></span>
|
||||
<svg class="dark-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M20.742 13.045a8.088 8.088 0 0 1-2.077.271c-2.135 0-4.14-.83-5.646-2.336a8.025 8.025 0 0 1-2.064-7.723A1 1 0 0 0 9.73 2.034a10.014 10.014 0 0 0-4.489 2.582c-3.898 3.898-3.898 10.243 0 14.143a9.937 9.937 0 0 0 7.072 2.93 9.93 9.93 0 0 0 7.07-2.929 10.007 10.007 0 0 0 2.583-4.491 1.001 1.001 0 0 0-1.224-1.224zm-2.772 4.301a7.947 7.947 0 0 1-5.656 2.343 7.953 7.953 0 0 1-5.658-2.344c-3.118-3.119-3.118-8.195 0-11.314a7.923 7.923 0 0 1 2.06-1.483 10.027 10.027 0 0 0 2.89 7.848 9.972 9.972 0 0 0 7.848 2.891 8.036 8.036 0 0 1-1.484 2.059z"></path></svg>
|
||||
<svg class="light-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M6.993 12c0 2.761 2.246 5.007 5.007 5.007s5.007-2.246 5.007-5.007S14.761 6.993 12 6.993 6.993 9.239 6.993 12zM12 8.993c1.658 0 3.007 1.349 3.007 3.007S13.658 15.007 12 15.007 8.993 13.658 8.993 12 10.342 8.993 12 8.993zM10.998 19h2v3h-2zm0-17h2v3h-2zm-9 9h3v2h-3zm17 0h3v2h-3zM4.219 18.363l2.12-2.122 1.415 1.414-2.12 2.122zM16.24 6.344l2.122-2.122 1.414 1.414-2.122 2.122zM6.342 7.759 4.22 5.637l1.415-1.414 2.12 2.122zm13.434 10.605-1.414 1.414-2.122-2.122 1.414-1.414z"></path></svg>
|
||||
</label>
|
||||
<script>
|
||||
const el = document.querySelector(".theme-selection input");
|
||||
el.checked = (glob.theme === "dark");
|
||||
</script>
|
||||
</div>
|
||||
<% if (hasTree) { %>
|
||||
<div class="search-item">
|
||||
<svg class="search-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M10 18a7.952 7.952 0 0 0 4.897-1.688l4.396 4.396 1.414-1.414-4.396-4.396A7.952 7.952 0 0 0 18 10c0-4.411-3.589-8-8-8s-8 3.589-8 8 3.589 8 8 8zm0-14c3.309 0 6 2.691 6 6s-2.691 6-6 6-6-2.691-6-6 2.691-6 6-6z"></path></svg>
|
||||
<input type="text" class="search-input" placeholder="<%= t("share_theme.search_placeholder") %>">
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<% if (hasTree) { %>
|
||||
<nav id="menu">
|
||||
<%- include("tree_item", {note: subRoot.note, activeNote: note, subRoot: subRoot, ancestors}) %>
|
||||
</nav>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
<div id="right-pane">
|
||||
<div id="main">
|
||||
<div id="content" class="type-<%= note.type %><% if (note.type === "text") { %> ck-content<% } %><% if (isEmpty) { %> no-content<% } %>">
|
||||
<%- renderSnippets("content:start") %>
|
||||
<h1 id="title"><%= note.title %></h1>
|
||||
<% if (isEmpty && (!note.hasVisibleChildren() && note.type !== "book")) { %>
|
||||
<p>This note has no content.</p>
|
||||
<% } else { %>
|
||||
<%
|
||||
content = content.replace(/<img /g, `<img alt="${t("share_theme.image_alt")}" loading="lazy" `);
|
||||
%>
|
||||
<%- content %>
|
||||
<% } %>
|
||||
<%- renderSnippets("content:end") %>
|
||||
</div>
|
||||
|
||||
<% if (note.hasVisibleChildren() || note.type === "book") { %>
|
||||
<nav id="childLinks" class="<% if (isEmpty) { %>grid<% } else { %>list<% } %>">
|
||||
<% if (!isEmpty) { %>
|
||||
<span><%= t("share_theme.subpages") %></span>
|
||||
<% } %>
|
||||
|
||||
<ul>
|
||||
<%
|
||||
const action = note.type === "book" ? "getChildNotes" : "getVisibleChildNotes";
|
||||
for (const childNote of note[action]()) {
|
||||
const isExternalLink = childNote.hasLabel("shareExternal") || childNote.hasLabel("shareExternalLink");
|
||||
const linkHref = isExternalLink ? childNote.getLabelValue("shareExternal") ?? childNote.getLabelValue("shareExternalLink") : `./${childNote.shareId}`;
|
||||
const target = isExternalLink ? ` target="_blank" rel="noopener noreferrer"` : "";
|
||||
%>
|
||||
<li>
|
||||
<a class="type-<%= childNote.type %>" href="<%= linkHref %>"<%= target %>><%= childNote.title %></a>
|
||||
</li>
|
||||
<% } %>
|
||||
</ul>
|
||||
</nav>
|
||||
<% } %>
|
||||
|
||||
<footer id="content-footer">
|
||||
<% if (!isEmpty && !isStatic) { %>
|
||||
<div class="updated">
|
||||
<% const lastUpdated = new Date(note.utcDateModified); %>
|
||||
<%- t("share_theme.last-updated", { date: `<time datetime="${lastUpdated.toISOString()}">${lastUpdated.toLocaleDateString()}</time>`}) %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<% if (hasTree) { %>
|
||||
<%- include("prev_next", { note: note, subRoot: subRoot }) %>
|
||||
<% } %>
|
||||
</footer>
|
||||
</div>
|
||||
<%
|
||||
if (headingMatches.length > 1) {
|
||||
const level = (m) => parseInt(m[1].replace(/[<h>]+/g, ""));
|
||||
|
||||
const toc = [
|
||||
{
|
||||
level: level(headingMatches[0]),
|
||||
name: headingMatches[0][2],
|
||||
children: []
|
||||
}
|
||||
];
|
||||
const last = (arr = toc) => arr[arr.length - 1];
|
||||
const makeEntry = (m) => ({level: level(m), name: m[2], children: []});
|
||||
const getLevelArr = (lvl, arr = toc) => {
|
||||
if (arr[0].level === lvl) return arr;
|
||||
const top = last(arr);
|
||||
return top.children.length ? getLevelArr(lvl, top.children) : top.children;
|
||||
};
|
||||
|
||||
|
||||
for (let m = 1; m < headingMatches.length; m++) {
|
||||
const target = getLevelArr(level(headingMatches[m]));
|
||||
target.push(makeEntry(headingMatches[m]));
|
||||
}
|
||||
%>
|
||||
<div id="toc-pane">
|
||||
<h3><%= t("share_theme.on-this-page") %></h3>
|
||||
<ul id="toc">
|
||||
<% for (const entry of toc) { %>
|
||||
<%- include("toc_item", {entry}) %>
|
||||
<% } %>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
<%- renderSnippets("body:end") %>
|
||||
</body>
|
||||
</html>
|
||||
BIN
data/custom/share-theme/share-background.jpg
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
data/custom/share-theme/share-background.jpg.old
Normal file
|
After Width: | Height: | Size: 93 KiB |
46
docker-compose.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
services:
|
||||
trilium:
|
||||
image: triliumnext/trilium:latest
|
||||
container_name: trilium
|
||||
hostname: trilium
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TRILIUM_DATA_DIR: /home/node/trilium-data
|
||||
|
||||
ports:
|
||||
- "16001:8080"
|
||||
|
||||
volumes:
|
||||
- ./data/trilium-data:/home/node/trilium-data
|
||||
- ./data/custom/share-theme/page.ejs:/usr/src/app/share-theme/templates/page.ejs:ro
|
||||
- ./data/custom/share-theme/custom-share-dark.css:/usr/src/app/share-theme/assets/custom-share-dark.css:ro
|
||||
- ./data/custom/share-theme/custom-share-copy.js:/usr/src/app/share-theme/assets/custom-share-copy.js:ro
|
||||
- ./data/custom/share-theme/share-background.jpg:/usr/src/app/share-theme/assets/share-background.jpg:ro
|
||||
- ./data/custom/branding/techniverse-logo-256.png:/usr/src/app/share-theme/assets/techniverse-logo-256.png:ro
|
||||
- ./data/custom/branding/techniverse-icon-64.png:/usr/src/app/share-theme/assets/techniverse-icon-64.png:ro
|
||||
- ./data/custom/branding/techniverse-logo.svg:/usr/src/app/assets/images/icon-color.svg:ro
|
||||
- ./data/custom/branding/techniverse-icon-180.png:/usr/src/app/assets/images/app-icons/ios/apple-touch-icon.png:ro
|
||||
- ./data/custom/branding/techniverse-icon-512.png:/usr/src/app/public/assets/icon.png:ro
|
||||
- ./data/custom/branding/techniverse-favicon.ico:/usr/src/app/public/favicon.ico:ro
|
||||
- ./data/custom/branding/techniverse-favicon.ico:/usr/src/app/assets/icon.ico:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
|
||||
networks:
|
||||
trilium_net:
|
||||
ipv4_address: 172.29.37.10
|
||||
|
||||
networks:
|
||||
trilium_net:
|
||||
name: trilium.dockernetwork.local
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.29.37.0/24
|
||||
gateway: 172.29.37.1
|
||||
ip_range: 172.29.37.128/25
|
||||
36
docker-compose.yaml.orig
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
services:
|
||||
trilium:
|
||||
image: triliumnext/trilium:latest
|
||||
container_name: trilium
|
||||
hostname: trilium
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TRILIUM_DATA_DIR: /home/node/trilium-data
|
||||
|
||||
ports:
|
||||
- "16001:8080"
|
||||
|
||||
volumes:
|
||||
- ./data/trilium-data:/home/node/trilium-data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
|
||||
networks:
|
||||
trilium_net:
|
||||
ipv4_address: 172.29.37.10
|
||||
|
||||
networks:
|
||||
trilium_net:
|
||||
name: trilium.dockernetwork.local
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.29.37.0/24
|
||||
gateway: 172.29.37.1
|
||||
ip_range: 172.29.37.128/25
|
||||
|
||||
36
docker-compose.yaml.remote-current
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
services:
|
||||
trilium:
|
||||
image: triliumnext/trilium:latest
|
||||
container_name: trilium
|
||||
hostname: trilium
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TRILIUM_DATA_DIR: /home/node/trilium-data
|
||||
|
||||
ports:
|
||||
- "16001:8080"
|
||||
|
||||
volumes:
|
||||
- ./data/trilium-data:/home/node/trilium-data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
|
||||
networks:
|
||||
trilium_net:
|
||||
ipv4_address: 172.29.37.10
|
||||
|
||||
networks:
|
||||
trilium_net:
|
||||
name: trilium.dockernetwork.local
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.29.37.0/24
|
||||
gateway: 172.29.37.1
|
||||
ip_range: 172.29.37.128/25
|
||||
|
||||
36
noop-compose-check.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
services:
|
||||
trilium:
|
||||
image: triliumnext/trilium:latest
|
||||
container_name: trilium
|
||||
hostname: trilium
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TRILIUM_DATA_DIR: /home/node/trilium-data
|
||||
|
||||
ports:
|
||||
- "16001:8080"
|
||||
|
||||
volumes:
|
||||
- ./data/trilium-data:/home/node/trilium-data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
|
||||
networks:
|
||||
trilium_net:
|
||||
ipv4_address: 172.29.37.10
|
||||
|
||||
networks:
|
||||
trilium_net:
|
||||
name: trilium.dockernetwork.local
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.29.37.0/24
|
||||
gateway: 172.29.37.1
|
||||
ip_range: 172.29.37.128/25
|
||||
|
||||