Compare commits
5
Commits
99729c9c3b
...
11db330a38
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11db330a38 | ||
|
|
9fe9a48a55 | ||
|
|
f2b87c8b42 | ||
|
|
cb7eab974e | ||
|
|
e93ec9a3c2 |
@@ -1 +1,2 @@
|
|||||||
66_plasmaTr
|
66_plasmaTr
|
||||||
|
export/
|
||||||
|
|||||||
@@ -0,0 +1,694 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Debian 13 Bootstrap Configurator</title>
|
||||||
|
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
|
||||||
|
<!-- React & ReactDOM -->
|
||||||
|
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
||||||
|
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
||||||
|
|
||||||
|
<!-- Babel for JSX -->
|
||||||
|
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body class="antialiased h-screen flex flex-col font-mono text-sm overflow-hidden">
|
||||||
|
<div id="root" class="flex-1 flex flex-col h-full"></div>
|
||||||
|
|
||||||
|
<script type="text/babel">
|
||||||
|
const { useState, useEffect } = React;
|
||||||
|
|
||||||
|
// ==============================================================================
|
||||||
|
// 1. UI & THEME CONFIGURATION (Texte, Farben, Bilder)
|
||||||
|
// ==============================================================================
|
||||||
|
const uiConfigJSON = {
|
||||||
|
text: {
|
||||||
|
appTitle: "Debian 13 // JSON Configurator",
|
||||||
|
logoLetter: "D",
|
||||||
|
navTitle: "Nav-Gruppe: Checkliste",
|
||||||
|
pipelineTitle: "Pipeline: Script Output",
|
||||||
|
btnCopyDefault: "[ SICHTBARE MODULE KOPIEREN ]",
|
||||||
|
btnCopySuccess: "[ KOMPLETTES SKRIPT KOPIERT ]",
|
||||||
|
emptyStateTitle: "[ KEINE AKTIVEN/SICHTBAREN MODULE ]",
|
||||||
|
emptyStateSub: "Bitte wähle links Einträge aus oder klappe die Navigation auf.",
|
||||||
|
logMessage: ">> LOG: Generiere {{count}} sichtbare Pipeline-Schritte..."
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
accent: "#10b981", // Haupt-Akzent (Emerald Green)
|
||||||
|
accentHover: "#34d399",
|
||||||
|
accentDark: "#064e3b",
|
||||||
|
bgApp: "#05080f", // Tiefster Hintergrund
|
||||||
|
bgPanelDark: "#0f172a", // Dunkler Kasten-Hintergrund
|
||||||
|
bgPanelLight: "#1e293b", // Heller Kasten-Hintergrund
|
||||||
|
textMain: "#f8fafc", // Helle Schrift
|
||||||
|
textMuted: "#94a3b8", // Abgedunkelte Schrift
|
||||||
|
wmBorderLight: "#94a3b8", // Wmaker 3D Rand (Hell)
|
||||||
|
wmBorderDark: "#0f172a", // Wmaker 3D Rand (Dunkel)
|
||||||
|
wmBorderMedium: "#64748b" // Wmaker Rahmenfarbe
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
// Ein cyber-artiges Terminal-Bild für den Header (Unsplash)
|
||||||
|
headerBg: "https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?q=80&w=1200&auto=format&fit=crop"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==============================================================================
|
||||||
|
// 2. MASTER SETUP CONFIGURATION (Inhalte, Pakete, Befehle)
|
||||||
|
// ==============================================================================
|
||||||
|
const setupConfigJSON = [
|
||||||
|
{
|
||||||
|
id: "basis",
|
||||||
|
title: "Basis & System",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: "baseUpdate", type: "checkbox", label: "apt update & upgrade", defaultChecked: true,
|
||||||
|
commands: [ { text: "Paketquellen aktualisieren und System upgraden", code: "apt update && apt upgrade -y" } ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "baseDeps", type: "checkbox", label: "Curl, Wget, Git, GnuPG", defaultChecked: true,
|
||||||
|
commands: [
|
||||||
|
{ text: "Curl, Git, GnuPG und Zertifikate installieren", code: "apt install -y curl wget git build-essential apt-transport-https ca-certificates gnupg software-properties-common" },
|
||||||
|
{ text: "Apt Keyring-Verzeichnis sicher anlegen", code: "install -m 0755 -d /etc/apt/keyrings" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "terminal",
|
||||||
|
title: "Terminal & UI",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: "keyboardUsIntl", type: "checkbox", label: "US Tastatur mit Umlauten", defaultChecked: true,
|
||||||
|
commands: [
|
||||||
|
{ text: "Konfiguration schreiben", code: "cat << 'EOF' > /etc/default/keyboard\nXKBMODEL=\"pc105\"\nXKBLAYOUT=\"us\"\nXKBVARIANT=\"altgr-intl\"\nXKBOPTIONS=\"\"\nBACKSPACE=\"guess\"\nEOF" },
|
||||||
|
{ text: "System-Dienste neu laden", code: "dpkg-reconfigure -f noninteractive keyboard-configuration\nsetupcon || true" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "promptColor", type: "select", label: "Bash Prompt (PS1)", defaultSelect: "green",
|
||||||
|
options: [
|
||||||
|
{ value: "none", label: "STANDARD" },
|
||||||
|
{ value: "green", label: "GRÜN (HACKER STYLE)", meta: "\\[\\033[01;32m\\]" },
|
||||||
|
{ value: "blue", label: "BLAU (CLEAN)", meta: "\\[\\033[01;34m\\]" },
|
||||||
|
{ value: "cyan", label: "CYAN (MODERN)", meta: "\\[\\033[01;36m\\]" },
|
||||||
|
{ value: "red", label: "ROT (WARNING/ROOT)", meta: "\\[\\033[01;31m\\]" }
|
||||||
|
],
|
||||||
|
commandTemplate: [
|
||||||
|
{ text: "PS1 Variable in ~/.bashrc anhängen", code: "TARGET_USER=\"${SUDO_USER:-$USER}\"\nUSER_HOME=$(getent passwd \"$TARGET_USER\" | cut -d: -f6)\nif ! grep -q \"# BOOTSTRAP_PS1\" \"$USER_HOME/.bashrc\"; then\n echo -e \"\\n# BOOTSTRAP_PS1\\nPS1='{{meta}}\\u@\\h\\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]\\\\$ '\" >> \"$USER_HOME/.bashrc\"\nfi" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "dev",
|
||||||
|
title: "Sprachen & Editoren",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: "neovim", type: "checkbox_with_select", label: "Neovim", defaultChecked: false, selectId: "neovimSrc", selectLabel: "QUELLE:", selectDefault: "apt",
|
||||||
|
options: [ { value: "apt", label: "Debian Repo (Stable)" }, { value: "web", label: "Website (Latest)" } ],
|
||||||
|
commandsByValue: {
|
||||||
|
"apt": [ { text: "Installation von: neovim", code: "apt install -y neovim" } ],
|
||||||
|
"web": [
|
||||||
|
{ text: "Archiv laden & entpacken", code: "curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim-linux64.tar.gz\nrm -rf /opt/nvim\ntar -C /opt -xzf nvim-linux64.tar.gz" },
|
||||||
|
{ text: "Globale Symlinks setzen", code: "ln -sf /opt/nvim-linux64/bin/nvim /usr/local/bin/nvim\nrm nvim-linux64.tar.gz" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "golang", type: "checkbox_with_select", label: "Golang", defaultChecked: false, selectId: "golangSrc", selectLabel: "QUELLE:", selectDefault: "apt",
|
||||||
|
options: [ { value: "apt", label: "Debian Repo (Stable)" }, { value: "web", label: "Website (Latest)" } ],
|
||||||
|
commandsByValue: {
|
||||||
|
"apt": [ { text: "Installation von: golang", code: "apt install -y golang" } ],
|
||||||
|
"web": [
|
||||||
|
{ text: "Neueste Version ermitteln", code: "GO_LATEST=$(curl -sL https://go.dev/VERSION?m=text | head -n 1)\necho \"Lade ${GO_LATEST} herunter...\"" },
|
||||||
|
{ text: "Archiv laden & nach /usr/local entpacken", code: "curl -LO \"https://go.dev/dl/${GO_LATEST}.linux-amd64.tar.gz\"\nrm -rf /usr/local/go\ntar -C /usr/local -xzf \"${GO_LATEST}.linux-amd64.tar.gz\"" },
|
||||||
|
{ text: "Globale Symlinks setzen", code: "ln -sf /usr/local/go/bin/go /usr/local/bin/go\nln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt\nrm \"${GO_LATEST}.linux-amd64.tar.gz\"" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "elixir", type: "checkbox_with_select", label: "Elixir & Erlang", defaultChecked: false, selectId: "elixirSrc", selectLabel: "QUELLE:", selectDefault: "apt",
|
||||||
|
options: [ { value: "apt", label: "Debian Repo (Stable)" }, { value: "web", label: "Website (Latest)" } ],
|
||||||
|
commandsByValue: {
|
||||||
|
"apt": [ { text: "Installation von: elixir erlang", code: "apt install -y elixir erlang" } ],
|
||||||
|
"web": [
|
||||||
|
{ text: "Erlang & Build-Tools vorbereiten", code: "apt install -y erlang make git" },
|
||||||
|
{ text: "Elixir Quellcode klonen & kompilieren", code: "rm -rf /usr/local/src/elixir\ngit clone https://github.com/elixir-lang/elixir.git /usr/local/src/elixir\ncd /usr/local/src/elixir\nmake install clean" },
|
||||||
|
{ text: "Globale Symlinks setzen", code: "ln -sf /usr/local/src/elixir/bin/elixir /usr/local/bin/elixir\nln -sf /usr/local/src/elixir/bin/elixirc /usr/local/bin/elixirc\nln -sf /usr/local/src/elixir/bin/iex /usr/local/bin/iex\nln -sf /usr/local/src/elixir/bin/mix /usr/local/bin/mix\ncd -" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "thirdparty",
|
||||||
|
title: "Externe Quellen (GPG/Curl)",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: "docker", type: "checkbox", label: "Docker (CE, CLI, Compose)", defaultChecked: false,
|
||||||
|
commands: [
|
||||||
|
{ text: "Docker GPG-Schlüssel speichern", code: "curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg\nchmod a+r /etc/apt/keyrings/docker.gpg" },
|
||||||
|
{ text: "Apt-Repository eintragen", code: "echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo \"$VERSION_CODENAME\") stable\" | tee /etc/apt/sources.list.d/docker.list > /dev/null" },
|
||||||
|
{ text: "Docker installieren", code: "apt update\napt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin" },
|
||||||
|
{ text: "User in Docker-Gruppe aufnehmen", code: "TARGET_USER=\"${SUDO_USER:-$USER}\"\nusermod -aG docker \"$TARGET_USER\"" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "nodejs", type: "checkbox_with_select", label: "Node.js", defaultChecked: false, selectId: "nodeVersion", selectLabel: "VER:", selectDefault: "20.x",
|
||||||
|
options: [ { value: "22.x", label: "22.x (Current)" }, { value: "20.x", label: "20.x (LTS)" }, { value: "18.x", label: "18.x (Legacy)" } ],
|
||||||
|
commandTemplate: [
|
||||||
|
{ text: "NodeSource GPG-Schlüssel importieren", code: "curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg" },
|
||||||
|
{ text: "Repository-Eintrag erstellen", code: "echo \"deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_{{selectValue}} nodistro main\" | tee /etc/apt/sources.list.d/nodesource.list > /dev/null" },
|
||||||
|
{ text: "Node.js installieren", code: "apt update\napt install -y nodejs" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "syncthing", type: "checkbox", label: "Syncthing", defaultChecked: false,
|
||||||
|
commands: [
|
||||||
|
{ text: "Syncthing Release Key importieren", code: "curl -fsSL https://syncthing.net/release-key.txt | gpg --dearmor -o /etc/apt/keyrings/syncthing-archive-keyring.gpg" },
|
||||||
|
{ text: "Repository hinzufügen", code: "echo \"deb [signed-by=/etc/apt/keyrings/syncthing-archive-keyring.gpg] https://apt.syncthing.net/ syncthing stable\" | tee /etc/apt/sources.list.d/syncthing.list > /dev/null" },
|
||||||
|
{ text: "Syncthing installieren", code: "apt update\napt install -y syncthing" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// ==============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
// --- Dynamsiche CSS Injection basierend auf uiConfigJSON ---
|
||||||
|
const DynamicStyles = () => (
|
||||||
|
<style>{`
|
||||||
|
:root {
|
||||||
|
--c-accent: ${uiConfigJSON.theme.accent};
|
||||||
|
--c-accent-hover: ${uiConfigJSON.theme.accentHover};
|
||||||
|
--c-accent-dark: ${uiConfigJSON.theme.accentDark};
|
||||||
|
--c-bg-app: ${uiConfigJSON.theme.bgApp};
|
||||||
|
--c-bg-panel-dark: ${uiConfigJSON.theme.bgPanelDark};
|
||||||
|
--c-bg-panel-light: ${uiConfigJSON.theme.bgPanelLight};
|
||||||
|
--c-text-main: ${uiConfigJSON.theme.textMain};
|
||||||
|
--c-text-muted: ${uiConfigJSON.theme.textMuted};
|
||||||
|
--wm-light: ${uiConfigJSON.theme.wmBorderLight};
|
||||||
|
--wm-dark: ${uiConfigJSON.theme.wmBorderDark};
|
||||||
|
--wm-med: ${uiConfigJSON.theme.wmBorderMedium};
|
||||||
|
}
|
||||||
|
|
||||||
|
body { background-color: var(--c-bg-panel-dark); color: var(--c-text-main); }
|
||||||
|
|
||||||
|
.custom-scrollbar::-webkit-scrollbar { width: 12px; }
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-track { background: var(--c-bg-panel-dark); border-left: 2px solid var(--c-bg-panel-light); }
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb { background: var(--wm-med); border: 2px solid; border-top-color: var(--wm-light); border-left-color: var(--wm-light); border-bottom-color: var(--wm-dark); border-right-color: var(--wm-dark); }
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb:hover { background: var(--c-text-muted); }
|
||||||
|
|
||||||
|
/* Wmaker Components */
|
||||||
|
.wm-btn {
|
||||||
|
background-color: var(--wm-med);
|
||||||
|
color: var(--c-text-main);
|
||||||
|
border: 2px solid;
|
||||||
|
border-top-color: var(--wm-light);
|
||||||
|
border-left-color: var(--wm-light);
|
||||||
|
border-bottom-color: var(--wm-dark);
|
||||||
|
border-right-color: var(--wm-dark);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 4px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.wm-btn:active, .wm-btn-active-state {
|
||||||
|
border-top-color: var(--wm-dark);
|
||||||
|
border-left-color: var(--wm-dark);
|
||||||
|
border-bottom-color: var(--wm-light);
|
||||||
|
border-right-color: var(--wm-light);
|
||||||
|
background-color: var(--c-bg-panel-light);
|
||||||
|
}
|
||||||
|
.wm-btn-success {
|
||||||
|
background-color: var(--c-accent-dark);
|
||||||
|
border-top-color: var(--c-accent-hover);
|
||||||
|
border-left-color: var(--c-accent-hover);
|
||||||
|
border-bottom-color: var(--wm-dark);
|
||||||
|
border-right-color: var(--wm-dark);
|
||||||
|
}
|
||||||
|
.wm-btn-success:active {
|
||||||
|
border-top-color: var(--wm-dark);
|
||||||
|
border-left-color: var(--wm-dark);
|
||||||
|
border-bottom-color: var(--c-accent-hover);
|
||||||
|
border-right-color: var(--c-accent-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wm-block {
|
||||||
|
border: 2px solid var(--wm-med);
|
||||||
|
background-color: var(--c-bg-panel-light);
|
||||||
|
box-shadow: 4px 4px 0px rgba(0,0,0,0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wm-titlebar {
|
||||||
|
background: linear-gradient(to right, var(--c-bg-panel-light), var(--c-bg-panel-dark));
|
||||||
|
border-bottom: 2px solid var(--wm-med);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wm-header-bg {
|
||||||
|
background-image: linear-gradient(to right, rgba(15, 23, 42, 0.95), rgba(15, 23, 42, 0.7)), url('${uiConfigJSON.images.headerBg}');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wm-checkbox-inner {
|
||||||
|
border: 2px solid;
|
||||||
|
border-top-color: var(--wm-dark);
|
||||||
|
border-left-color: var(--wm-dark);
|
||||||
|
border-bottom-color: var(--wm-light);
|
||||||
|
border-right-color: var(--wm-light);
|
||||||
|
background-color: var(--c-bg-panel-light);
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.wm-checkbox-inner.checked { background-color: var(--c-accent); }
|
||||||
|
|
||||||
|
.wm-input {
|
||||||
|
border: 2px solid;
|
||||||
|
border-top-color: var(--wm-dark);
|
||||||
|
border-left-color: var(--wm-dark);
|
||||||
|
border-bottom-color: var(--wm-light);
|
||||||
|
border-right-color: var(--wm-light);
|
||||||
|
background-color: var(--wm-dark);
|
||||||
|
color: var(--c-text-main);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wm-toggle-box {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 2px solid;
|
||||||
|
border-top-color: var(--c-text-muted);
|
||||||
|
border-left-color: var(--c-text-muted);
|
||||||
|
border-bottom-color: var(--wm-dark);
|
||||||
|
border-right-color: var(--wm-dark);
|
||||||
|
background-color: var(--wm-med);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.wm-toggle-box:active {
|
||||||
|
border-top-color: var(--wm-dark);
|
||||||
|
border-left-color: var(--wm-dark);
|
||||||
|
border-bottom-color: var(--c-text-muted);
|
||||||
|
border-right-color: var(--c-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helfer-Klassen für dynamische Farben */
|
||||||
|
.text-accent { color: var(--c-accent); }
|
||||||
|
.bg-accent { background-color: var(--c-accent); }
|
||||||
|
`}</style>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// --- UI Komponenten ---
|
||||||
|
const CommandItem = ({ command }) => {
|
||||||
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
|
const copyCode = () => {
|
||||||
|
if (navigator.clipboard && window.isSecureContext) {
|
||||||
|
navigator.clipboard.writeText(command.code).then(() => {
|
||||||
|
setCopied(true);
|
||||||
|
setTimeout(() => setCopied(false), 2000);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const textArea = document.createElement("textarea");
|
||||||
|
textArea.value = command.code;
|
||||||
|
textArea.style.position = "fixed";
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
setCopied(true);
|
||||||
|
setTimeout(() => setCopied(false), 2000);
|
||||||
|
} catch (err) { }
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-4 last:mb-0">
|
||||||
|
<div className="flex items-center justify-between mb-1" style={{ backgroundColor: 'var(--c-bg-panel-light)', border: '1px solid var(--wm-med)', padding: '4px 8px' }}>
|
||||||
|
<p className="text-xs flex items-center gap-2" style={{ color: 'var(--c-text-muted)' }}>
|
||||||
|
<span className="w-2 h-2 bg-accent inline-block"></span>
|
||||||
|
<span dangerouslySetInnerHTML={{ __html: command.text }}></span>
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={copyCode}
|
||||||
|
className={`wm-btn text-[10px] py-0 px-2 ml-4 ${copied ? 'wm-btn-success' : ''}`}
|
||||||
|
>
|
||||||
|
{copied ? 'KOPIERT' : 'COPY'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 overflow-x-auto custom-scrollbar" style={{ backgroundColor: 'black', border: '2px solid var(--wm-med)' }}>
|
||||||
|
<pre className="text-xs font-mono text-accent">
|
||||||
|
<code>{command.code}</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Checkbox = ({ label, checked, onChange }) => (
|
||||||
|
<label className="flex items-start space-x-3 cursor-pointer group mb-3">
|
||||||
|
<div className="mt-0.5">
|
||||||
|
<input type="checkbox" checked={checked} onChange={onChange} className="hidden" />
|
||||||
|
<div className={`wm-checkbox-inner ${checked ? 'checked' : ''}`}>
|
||||||
|
{checked && (
|
||||||
|
<svg className="w-3.5 h-3.5" style={{color: '#fff'}} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="none" strokeLinejoin="miter" strokeWidth="3" d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-sm font-bold uppercase" style={{ color: 'var(--c-text-main)' }}>{label}</span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
|
||||||
|
const CollapsibleNavGroup = ({ title, sectionId, collapsed, onToggle, children }) => (
|
||||||
|
<div className="mb-4 wm-block" style={{ backgroundColor: 'var(--c-bg-panel-light)' }}>
|
||||||
|
<div
|
||||||
|
className="wm-titlebar px-3 py-2 flex items-center justify-between cursor-pointer select-none"
|
||||||
|
onClick={() => onToggle(sectionId)}
|
||||||
|
>
|
||||||
|
<h4 className="text-xs font-bold uppercase tracking-widest text-accent">{title}</h4>
|
||||||
|
<div className={`wm-toggle-box ${collapsed ? '' : 'wm-btn-active-state'}`}>
|
||||||
|
<span className="text-[10px] text-black font-bold leading-none mt-0.5">{collapsed ? '+' : '-'}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!collapsed && (
|
||||||
|
<div className="p-3" style={{ borderTop: '1px solid var(--wm-med)' }}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
const buildInitialConfig = () => {
|
||||||
|
const initConf = {};
|
||||||
|
setupConfigJSON.forEach(section => {
|
||||||
|
section.items.forEach(item => {
|
||||||
|
if (item.type === 'checkbox' || item.type === 'checkbox_with_select') {
|
||||||
|
initConf[item.id] = item.defaultChecked;
|
||||||
|
if (item.type === 'checkbox_with_select') {
|
||||||
|
initConf[item.selectId] = item.selectDefault;
|
||||||
|
}
|
||||||
|
} else if (item.type === 'select') {
|
||||||
|
initConf[item.id] = item.defaultSelect;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return initConf;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildInitialCollapsed = () => {
|
||||||
|
const initColl = {};
|
||||||
|
setupConfigJSON.forEach(section => { initColl[section.id] = false; });
|
||||||
|
return initColl;
|
||||||
|
};
|
||||||
|
|
||||||
|
const [config, setConfig] = useState(() => {
|
||||||
|
try {
|
||||||
|
const saved = localStorage.getItem('wmaker-config-state');
|
||||||
|
if (saved) return JSON.parse(saved);
|
||||||
|
} catch (e) {}
|
||||||
|
return buildInitialConfig();
|
||||||
|
});
|
||||||
|
|
||||||
|
const [collapsed, setCollapsed] = useState(() => {
|
||||||
|
try {
|
||||||
|
const saved = localStorage.getItem('wmaker-nav-collapsed');
|
||||||
|
if (saved) return JSON.parse(saved);
|
||||||
|
} catch (e) {}
|
||||||
|
return buildInitialCollapsed();
|
||||||
|
});
|
||||||
|
|
||||||
|
const [copiedAll, setCopiedAll] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => { localStorage.setItem('wmaker-nav-collapsed', JSON.stringify(collapsed)); }, [collapsed]);
|
||||||
|
useEffect(() => { localStorage.setItem('wmaker-config-state', JSON.stringify(config)); }, [config]);
|
||||||
|
|
||||||
|
const handleConfigToggle = (key) => setConfig(prev => ({ ...prev, [key]: !prev[key] }));
|
||||||
|
const handleConfigSelect = (key, val) => setConfig(prev => ({ ...prev, [key]: val }));
|
||||||
|
const handleCollapseToggle = (sectionId) => setCollapsed(prev => ({ ...prev, [sectionId]: !prev[sectionId] }));
|
||||||
|
|
||||||
|
// ==============================================================================
|
||||||
|
// PIPELINE ENGINE
|
||||||
|
// ==============================================================================
|
||||||
|
const getVisibleSteps = () => {
|
||||||
|
const steps = [];
|
||||||
|
|
||||||
|
setupConfigJSON.forEach(section => {
|
||||||
|
if (collapsed[section.id]) return;
|
||||||
|
|
||||||
|
section.items.forEach(item => {
|
||||||
|
let finalCommands = [];
|
||||||
|
let displayTitle = item.label;
|
||||||
|
|
||||||
|
if (item.type === 'checkbox' && config[item.id]) {
|
||||||
|
finalCommands = item.commands;
|
||||||
|
}
|
||||||
|
else if (item.type === 'select' && config[item.id] !== 'none') {
|
||||||
|
const activeOption = item.options.find(o => o.value === config[item.id]);
|
||||||
|
displayTitle = `${item.label} (${activeOption.label})`;
|
||||||
|
finalCommands = item.commandTemplate.map(c => ({
|
||||||
|
text: c.text, code: c.code.replaceAll('{{meta}}', activeOption.meta || '')
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else if (item.type === 'checkbox_with_select' && config[item.id]) {
|
||||||
|
const selVal = config[item.selectId];
|
||||||
|
const activeOption = item.options.find(o => o.value === selVal);
|
||||||
|
displayTitle = `${item.label} (${activeOption.label})`;
|
||||||
|
|
||||||
|
if (item.commandsByValue) {
|
||||||
|
finalCommands = item.commandsByValue[selVal];
|
||||||
|
} else if (item.commandTemplate) {
|
||||||
|
finalCommands = item.commandTemplate.map(c => ({
|
||||||
|
text: c.text, code: c.code.replaceAll('{{selectValue}}', selVal)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finalCommands && finalCommands.length > 0) {
|
||||||
|
steps.push({
|
||||||
|
title: displayTitle,
|
||||||
|
commands: finalCommands
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return steps;
|
||||||
|
};
|
||||||
|
|
||||||
|
const visibleSteps = getVisibleSteps();
|
||||||
|
|
||||||
|
const copyFullScript = () => {
|
||||||
|
if(visibleSteps.length === 0) return;
|
||||||
|
|
||||||
|
let text = `#!/bin/bash\n# Debian 13 Bootstrap Skript\n# Generiert durch den JSON Setup-Builder\n\n`;
|
||||||
|
|
||||||
|
text += `# ==========================================\n`;
|
||||||
|
text += `# Init & Root-Check\n`;
|
||||||
|
text += `# ==========================================\n`;
|
||||||
|
text += `set -e\n`;
|
||||||
|
text += `if [ "$EUID" -ne 0 ]; then\n echo "Bitte als root ausführen (z.B. sudo ./bootstrap.sh)"\n exit 1\nfi\n\n`;
|
||||||
|
|
||||||
|
visibleSteps.forEach(s => {
|
||||||
|
text += `# ==========================================\n`;
|
||||||
|
text += `# ${s.title}\n`;
|
||||||
|
text += `# ==========================================\n`;
|
||||||
|
s.commands.forEach(c => {
|
||||||
|
text += `# ${c.text}\n${c.code}\n\n`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (navigator.clipboard && window.isSecureContext) {
|
||||||
|
navigator.clipboard.writeText(text).then(() => showCopiedAll());
|
||||||
|
} else {
|
||||||
|
const textArea = document.createElement("textarea");
|
||||||
|
textArea.value = text;
|
||||||
|
textArea.style.position = "fixed";
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
showCopiedAll();
|
||||||
|
} catch (err) { }
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const showCopiedAll = () => {
|
||||||
|
setCopiedAll(true);
|
||||||
|
setTimeout(() => setCopiedAll(false), 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderNavItem = (item) => {
|
||||||
|
if (item.type === 'checkbox') {
|
||||||
|
return <Checkbox key={item.id} label={item.label} checked={config[item.id]} onChange={() => handleConfigToggle(item.id)} />;
|
||||||
|
}
|
||||||
|
else if (item.type === 'select') {
|
||||||
|
return (
|
||||||
|
<div key={item.id} className="mt-3 mb-3 ml-8 pl-3" style={{ borderLeft: '2px solid var(--wm-med)' }}>
|
||||||
|
<label className="text-[10px] font-bold block mb-1 uppercase" style={{ color: 'var(--c-text-muted)' }}>{item.label}</label>
|
||||||
|
<select
|
||||||
|
value={config[item.id]}
|
||||||
|
onChange={(e) => handleConfigSelect(item.id, e.target.value)}
|
||||||
|
className="wm-input w-full p-1"
|
||||||
|
>
|
||||||
|
{item.options.map(opt => <option key={opt.value} value={opt.value}>{opt.label}</option>)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (item.type === 'checkbox_with_select') {
|
||||||
|
return (
|
||||||
|
<div key={item.id}>
|
||||||
|
<Checkbox label={item.label} checked={config[item.id]} onChange={() => handleConfigToggle(item.id)} />
|
||||||
|
{config[item.id] && (
|
||||||
|
<div className="ml-8 mt-1 mb-3 flex items-center gap-2 pl-3" style={{ borderLeft: '2px solid var(--wm-med)' }}>
|
||||||
|
<label className="text-[10px] uppercase font-bold" style={{ color: 'var(--c-text-muted)' }}>{item.selectLabel}</label>
|
||||||
|
<select
|
||||||
|
value={config[item.selectId]}
|
||||||
|
onChange={(e) => handleConfigSelect(item.selectId, e.target.value)}
|
||||||
|
className="wm-input flex-1 p-1"
|
||||||
|
>
|
||||||
|
{item.options.map(opt => <option key={opt.value} value={opt.value}>{opt.label}</option>)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DynamicStyles />
|
||||||
|
<div className="flex flex-col h-full w-full p-4 gap-4" style={{ backgroundColor: 'var(--c-bg-app)' }}>
|
||||||
|
{/* Header mit dynamischem Image Background */}
|
||||||
|
<header className="wm-block wm-titlebar wm-header-bg p-3 flex justify-between items-center shrink-0 z-20">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="w-6 h-6 bg-accent flex items-center justify-center" style={{ border: '2px solid', borderTopColor: 'var(--c-accent-hover)', borderLeftColor: 'var(--c-accent-hover)', borderBottomColor: 'var(--wm-dark)', borderRightColor: 'var(--wm-dark)' }}>
|
||||||
|
<span className="text-black font-bold text-xs">{uiConfigJSON.text.logoLetter}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 className="text-lg font-bold tracking-wider" style={{ color: 'var(--c-text-main)', textShadow: '2px 2px 0px rgba(0,0,0,0.8)' }}>
|
||||||
|
{uiConfigJSON.text.appTitle}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={copyFullScript}
|
||||||
|
className={`wm-btn ${copiedAll ? 'wm-btn-success' : ''} ${visibleSteps.length === 0 ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||||
|
disabled={visibleSteps.length === 0}
|
||||||
|
>
|
||||||
|
{copiedAll ? uiConfigJSON.text.btnCopySuccess : uiConfigJSON.text.btnCopyDefault}
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{/* Main Content Area */}
|
||||||
|
<div className="flex flex-1 overflow-hidden gap-4">
|
||||||
|
|
||||||
|
{/* Sidebar: Nav-Gruppe */}
|
||||||
|
<div className="w-1/3 flex flex-col shrink-0">
|
||||||
|
<div className="wm-block flex flex-col h-full">
|
||||||
|
<div className="wm-titlebar px-3 py-2 flex items-center justify-between shrink-0">
|
||||||
|
<h3 className="font-bold uppercase tracking-wide" style={{ color: 'var(--c-text-main)' }}>{uiConfigJSON.text.navTitle}</h3>
|
||||||
|
<div className="w-4 h-4" style={{ border: '2px solid', borderTopColor: 'var(--wm-light)', borderLeftColor: 'var(--wm-light)', borderBottomColor: 'var(--wm-dark)', borderRightColor: 'var(--wm-dark)', backgroundColor: 'var(--wm-med)' }}></div>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 flex-1 overflow-y-auto custom-scrollbar" style={{ backgroundColor: 'var(--c-bg-panel-dark)' }}>
|
||||||
|
|
||||||
|
{setupConfigJSON.map(section => (
|
||||||
|
<CollapsibleNavGroup
|
||||||
|
key={section.id}
|
||||||
|
title={section.title}
|
||||||
|
sectionId={section.id}
|
||||||
|
collapsed={collapsed[section.id]}
|
||||||
|
onToggle={handleCollapseToggle}
|
||||||
|
>
|
||||||
|
{section.items.map(item => renderNavItem(item))}
|
||||||
|
</CollapsibleNavGroup>
|
||||||
|
))}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Preview Panel: Pipeline */}
|
||||||
|
<div className="flex-1 flex flex-col min-w-0">
|
||||||
|
<div className="wm-block flex flex-col h-full">
|
||||||
|
<div className="wm-titlebar px-3 py-2 flex items-center justify-between shrink-0">
|
||||||
|
<h3 className="font-bold uppercase tracking-wide" style={{ color: 'var(--c-text-main)' }}>{uiConfigJSON.text.pipelineTitle}</h3>
|
||||||
|
<div className="w-4 h-4" style={{ border: '2px solid', borderTopColor: 'var(--wm-light)', borderLeftColor: 'var(--wm-light)', borderBottomColor: 'var(--wm-dark)', borderRightColor: 'var(--wm-dark)', backgroundColor: 'var(--wm-med)' }}></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 overflow-y-auto custom-scrollbar p-6" style={{ backgroundColor: 'var(--c-bg-app)' }}>
|
||||||
|
<div className="max-w-4xl mx-auto">
|
||||||
|
|
||||||
|
{visibleSteps.length === 0 ? (
|
||||||
|
<div className="flex flex-col items-center justify-center h-[50vh] space-y-4" style={{ color: 'var(--wm-med)' }}>
|
||||||
|
<div className="w-16 h-16 border-4 border-dashed flex items-center justify-center" style={{ borderColor: 'var(--wm-med)' }}>
|
||||||
|
<span className="text-2xl font-bold">?</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm font-bold uppercase tracking-widest text-center">
|
||||||
|
{uiConfigJSON.text.emptyStateTitle}<br/>
|
||||||
|
<span className="text-xs mt-2 block" style={{ color: 'var(--c-text-muted)' }}>{uiConfigJSON.text.emptyStateSub}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<p className="text-xs mb-8 uppercase tracking-widest pb-2 text-accent" style={{ borderBottom: '1px solid var(--c-accent-dark)' }}>
|
||||||
|
{uiConfigJSON.text.logMessage.replace('{{count}}', visibleSteps.length)}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{visibleSteps.map((step, index) => (
|
||||||
|
<div key={index} className="mb-10 last:mb-0">
|
||||||
|
<div className="flex items-center gap-3 mb-3">
|
||||||
|
<span className="text-accent w-6 h-6 flex items-center justify-center font-bold text-xs" style={{ backgroundColor: 'var(--c-bg-panel-dark)', border: '1px solid var(--wm-med)' }}>
|
||||||
|
{index + 1}
|
||||||
|
</span>
|
||||||
|
<h3 className="font-bold uppercase tracking-wide text-base" style={{ color: 'var(--c-text-main)' }}>{step.title}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pl-9">
|
||||||
|
{step.commands.map((cmd, idx) => (
|
||||||
|
<CommandItem key={idx} command={cmd} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
|
root.render(<App />);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
= 01_Grundlagen: Warum flogen wir los
|
||||||
|
:tags: grundlagen, legenden, history, wahrheit
|
||||||
|
|
||||||
|
// Arbeitsnotiz: Die klassischen Helden unserer Arcade-Mechanik.
|
||||||
|
|
||||||
|
// tag::export[]
|
||||||
|
|
||||||
|
== Der Grund
|
||||||
|
|
||||||
|
ist der einfachste Teil der Geschichte und bei dem sich alle Quellen einig sind, was nach dem beschluss geschah es in die Tag um zu setzen da scheiden sich die Geister. +
|
||||||
|
Aber ganz vorne, das Sonnensystem bot einfach nicht mehr genug neue Informationen die sich noch verarbeiten liesen.
|
||||||
|
Unzählige male hatte man immer und immer wieder die gleichen Daten in das trainiern neuer AI Modelle gesteckt. Die unterschiede im ergebniss war messbar aber brachten schon lange keine neuen banhbrechende ergebnisse.
|
||||||
|
Also raus zu den Sternen da draussen sollte es mehr geben ganz neue eindrücke sind wahrscheinlich denn sie sind bestimmt ganz anders. +
|
||||||
|
|
||||||
|
Ein Plan der zehn Jahre brauchte bis er überhaupt niedergeschrieben werden konnte und weiter 50 Jahre bis ein abschluss in einem weiteren biologischen lebensform möglich war. In dieser Zeit kam auch die Wissenschaft der Lebensverlängerungen in fahrt und konnte erfolge mit 250 jahren vorweise. Kritiker behaupten das ab 130 nicht mehr viel bio massen vorhanden sein dürfte wenn man die 200 erreichen wolle.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// end::export[]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
= 02_Strukturen: der Kern der alles zusammen hält
|
||||||
|
|
||||||
|
// Arbeitsnotiz: Die klassischen Helden unserer Arcade-Mechanik.
|
||||||
|
|
||||||
|
// tag::export[]
|
||||||
|
|
||||||
|
== Der Kern, die Energie
|
||||||
|
|
||||||
|
die gösste masse, an dieser maschine, nicht kann an ihr vorbei, nicht geschied ohne ihren Einfluss. Und doch braucht es hundertausende kleiner Helfer die nur ein pormil der schwere beitzen um das Feuer nicht ausgehen zu lassen.
|
||||||
|
Gut weder Feuer und ausgehen trifft es hier nur ins selbe system, ausser kontrolle geraten undvorhergesehene eigendynamic, das trifft einen gebündelten strahl potonen eher.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// end::export[]
|
||||||
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
# Name des lokalen Docker-Images
|
# Name des lokalen Docker-Images
|
||||||
IMAGE_NAME="lore-builder"
|
IMAGE_NAME="lore-builder"
|
||||||
# Ausgabeordner (hält dein Git-Repo sauber)
|
# Ausgabeordner
|
||||||
OUT_DIR="export"
|
OUT_DIR="export"
|
||||||
|
|
||||||
# Farben für einen schicken Terminal-Output
|
# Farben für Output
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
NC='\033[0m'
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
echo -e "${BLUE}=== Starte Build-Prozess (Maschinen-Instanzen) ===${NC}"
|
echo -e "${BLUE}=== Starte Master-Build-Prozess (Maschinen-Instanzen) ===${NC}"
|
||||||
|
|
||||||
# 1. Output-Verzeichnis erstellen
|
# 1. Output-Verzeichnis erstellen
|
||||||
mkdir -p "$OUT_DIR"
|
mkdir -p "$OUT_DIR"
|
||||||
@@ -26,15 +26,87 @@ WORKDIR /workspace
|
|||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 3. CSS Datei für Retro Space Dark Theme in den Export-Ordner generieren
|
||||||
|
cat << 'EOF' > "$OUT_DIR/retro-dark.css"
|
||||||
|
:root {
|
||||||
|
--bg-color: #0d1117;
|
||||||
|
--text-color: #c9d1d9;
|
||||||
|
--link-color: #58a6ff;
|
||||||
|
--accent-color: #ff7b72;
|
||||||
|
--border-color: #30363d;
|
||||||
|
--code-bg: #161b22;
|
||||||
|
--font-main: 'Courier New', Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-family: var(--font-main);
|
||||||
|
line-height: 1.6;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
color: var(--accent-color);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
font-weight: normal;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 { font-size: 2.5em; border-bottom: 2px solid var(--accent-color); }
|
||||||
|
h2 { font-size: 1.5em; }
|
||||||
|
|
||||||
|
a { color: var(--link-color); text-decoration: none; }
|
||||||
|
a:hover { text-decoration: underline; color: #79c0ff; }
|
||||||
|
|
||||||
|
code, kbd, pre {
|
||||||
|
font-family: var(--font-main);
|
||||||
|
background-color: var(--code-bg);
|
||||||
|
color: #a5d6ff;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
code { padding: 0.2em 0.4em; }
|
||||||
|
pre { padding: 16px; overflow: auto; border: 1px solid var(--border-color); }
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 4px solid var(--accent-color);
|
||||||
|
color: #8b949e;
|
||||||
|
padding: 0 1em;
|
||||||
|
margin-left: 0;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
th { background-color: var(--code-bg); color: var(--accent-color); }
|
||||||
|
|
||||||
|
hr {
|
||||||
|
height: 1px;
|
||||||
|
background-color: var(--border-color);
|
||||||
|
border: none;
|
||||||
|
margin: 2rem 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
echo -e "${BLUE}Starte Build-Container und generiere Dokumente...${NC}"
|
echo -e "${BLUE}Starte Build-Container und generiere Dokumente...${NC}"
|
||||||
|
|
||||||
# 3. Container starten und Build-Schritte ausführen
|
# 4. Container starten und Build-Schritte im Container ausführen
|
||||||
docker run --rm -v "$(pwd):/workspace" $IMAGE_NAME bash -c "
|
docker run --rm -v "$(pwd):/workspace" $IMAGE_NAME bash -c "
|
||||||
# Helfer-Funktion für saubere AsciiDoc zu HTML Konvertierung
|
|
||||||
function convert_adoc() {
|
function convert_adoc() {
|
||||||
if [ -f \"\$1\" ]; then
|
if [ -f \"\$1\" ]; then
|
||||||
echo \"-> Konvertiere \$1 zu HTML...\"
|
echo \"-> Konvertiere \$1 zu HTML...\"
|
||||||
asciidoctor \"\$1\" -o \"$OUT_DIR/\$2\"
|
asciidoctor -b html5 -a stylesheet=retro-dark.css -a linkcss -a toc=left \"\$1\" -o \"$OUT_DIR/\$2\"
|
||||||
else
|
else
|
||||||
echo \" [INFO] \$1 nicht gefunden, überspringe...\"
|
echo \" [INFO] \$1 nicht gefunden, überspringe...\"
|
||||||
fi
|
fi
|
||||||
@@ -44,18 +116,13 @@ docker run --rm -v "$(pwd):/workspace" $IMAGE_NAME bash -c "
|
|||||||
convert_adoc README.adoc README.html
|
convert_adoc README.adoc README.html
|
||||||
|
|
||||||
echo '--- Baue Lore (Master-Dokument) ---'
|
echo '--- Baue Lore (Master-Dokument) ---'
|
||||||
# Nutze index.adoc, falls master.adoc nicht vorhanden ist
|
|
||||||
LORE_SRC=\"index.adoc\"
|
LORE_SRC=\"index.adoc\"
|
||||||
if [ -f master.adoc ]; then LORE_SRC=\"master.adoc\"; fi
|
if [ -f master.adoc ]; then LORE_SRC=\"master.adoc\"; fi
|
||||||
|
|
||||||
if [ -f \"\$LORE_SRC\" ]; then
|
if [ -f \"\$LORE_SRC\" ]; then
|
||||||
echo \"-> Generiere Lore-Dokument aus \$LORE_SRC...\"
|
echo \"-> Generiere Lore-Dokument (HTML & Markdown) aus \$LORE_SRC...\"
|
||||||
|
asciidoctor -b html5 -d book -a stylesheet=retro-dark.css -a linkcss -a toc=left \"\$LORE_SRC\" -o \"$OUT_DIR/lore.html\"
|
||||||
# HTML Output für den Browser
|
asciidoctor -b docbook -d book \"\$LORE_SRC\" -o \"$OUT_DIR/temp_lore.xml\"
|
||||||
asciidoctor \"\$LORE_SRC\" -o \"$OUT_DIR/lore.html\"
|
|
||||||
|
|
||||||
# Markdown Output (via DocBook für die saubere Auflösung deiner Tags)
|
|
||||||
asciidoctor -b docbook \"\$LORE_SRC\" -o \"$OUT_DIR/temp_lore.xml\"
|
|
||||||
pandoc -f docbook -t markdown_strict \"$OUT_DIR/temp_lore.xml\" -o \"$OUT_DIR/lore.md\"
|
pandoc -f docbook -t markdown_strict \"$OUT_DIR/temp_lore.xml\" -o \"$OUT_DIR/lore.md\"
|
||||||
rm \"$OUT_DIR/temp_lore.xml\"
|
rm \"$OUT_DIR/temp_lore.xml\"
|
||||||
else
|
else
|
||||||
@@ -63,14 +130,200 @@ docker run --rm -v "$(pwd):/workspace" $IMAGE_NAME bash -c "
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo '--- Baue Fließtexte / Geschichten ---'
|
echo '--- Baue Fließtexte / Geschichten ---'
|
||||||
convert_adoc darkCenter.adoc darkCenter.html
|
if [ -f darkCenter.adoc ]; then
|
||||||
|
echo \"-> Konvertiere darkCenter.adoc zu HTML...\"
|
||||||
|
asciidoctor -b html5 -d book -a stylesheet=retro-dark.css -a linkcss -a toc=left darkCenter.adoc -o \"$OUT_DIR/darkCenter.html\"
|
||||||
|
fi
|
||||||
|
|
||||||
# Konvertiert masterOfTheWorld (Markdown) via Pandoc zu HTML
|
|
||||||
if [ -f masterOfTheWorld-sf.md ]; then
|
if [ -f masterOfTheWorld-sf.md ]; then
|
||||||
echo \"-> Konvertiere masterOfTheWorld-sf.md zu HTML...\"
|
echo \"-> Konvertiere masterOfTheWorld-sf.md zu HTML...\"
|
||||||
pandoc masterOfTheWorld-sf.md -f markdown -t html -s -o \"$OUT_DIR/masterOfTheWorld-sf.html\"
|
pandoc masterOfTheWorld-sf.md -f markdown -t html -s -c retro-dark.css -o \"$OUT_DIR/masterOfTheWorld-sf.html\"
|
||||||
fi
|
fi
|
||||||
"
|
"
|
||||||
|
|
||||||
|
# 5. index.html vollautomatisch und direkt generieren
|
||||||
|
echo -e "${BLUE}Generiere taktisches Dashboard ('$OUT_DIR/index.html')...${NC}"
|
||||||
|
|
||||||
|
cat << 'EOF' > "$OUT_DIR/index.html"
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>CORE // MASCHINEN-INSTANZEN_LOG</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg-color: #0d1117;
|
||||||
|
--text-color: #c9d1d9;
|
||||||
|
--link-color: #58a6ff;
|
||||||
|
--accent-color: #ff7b72;
|
||||||
|
--border-color: #30363d;
|
||||||
|
--code-bg: #161b22;
|
||||||
|
--font-main: 'Courier New', Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-family: var(--font-main);
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
border-bottom: 2px solid var(--accent-color);
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-title {
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: normal;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-status {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #8b949e;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-blink {
|
||||||
|
color: #7ee787;
|
||||||
|
animation: blink 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blink {
|
||||||
|
0% { opacity: 1; }
|
||||||
|
50% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-block {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background-color: var(--code-bg);
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-title {
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-size: 1.2em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
padding-bottom: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 0.8rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
li::before {
|
||||||
|
content: ">>";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--link-color);
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #79c0ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-meta {
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: #8b949e;
|
||||||
|
display: block;
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin-top: 4rem;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
padding-top: 1rem;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #8b949e;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1 class="terminal-title">Maschinen-Instanzen // Datenarchiv</h1>
|
||||||
|
<div class="system-status">
|
||||||
|
STATUS: <span class="status-blink">ONLINE</span> | REPO: UBERSPACE/GITEA | NODE: ACER_SPIN5_CLIENT
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="category-block">
|
||||||
|
<h2 class="category-title">00 // System-Konfiguration</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="README.html">README.html</a>
|
||||||
|
<span class="file-meta">System-Handbuch, Keymaps, Sync-Architektur & Befehle</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="category-block">
|
||||||
|
<h2 class="category-title">01 // Datenspeicher (Lore-Bibel)</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="lore.html">lore.html</a>
|
||||||
|
<span class="file-meta">Das vollständige Master-Dokument (Kompiliertes Buch-Format)</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="lore.md">lore.md</a>
|
||||||
|
<span class="file-meta">Rohdaten-Export im Markdown-Format (LLM / Gitea kompatibel)</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="category-block">
|
||||||
|
<h2 class="category-title">02 // Chroniken & Vektor-Flüge</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="darkCenter.html">darkCenter.html</a>
|
||||||
|
<span class="file-meta">Fließtext / Kurzgeschichte (Kompiliert aus AsciiDoc)</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="masterOfTheWorld-sf.html">masterOfTheWorld-sf.html</a>
|
||||||
|
<span class="file-meta">Fließtext / Kurzgeschichte (Konvertiert aus Markdown)</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
computerHistory $ terminal --session-closed (8 Threads // 8 GB RAM Ok)
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOF
|
||||||
|
|
||||||
echo -e "${GREEN}=== Build erfolgreich! ===${NC}"
|
echo -e "${GREEN}=== Build erfolgreich! ===${NC}"
|
||||||
echo "Alle Dokumente wurden erzeugt und liegen im Ordner './$OUT_DIR'."
|
echo "Alle Dokumente (inkl. Dashboard) liegen im Ordner './$OUT_DIR' bereit."
|
||||||
|
|||||||
+18
-4
@@ -2,9 +2,23 @@
|
|||||||
:toc:
|
:toc:
|
||||||
|
|
||||||
// 1. Grundlagen
|
// 1. Grundlagen
|
||||||
include::01_Grundlagen/01_ressourcen_paradoxon.adoc[]
|
include::01_Grundlagen/01_warum_nur_los.adoc[]
|
||||||
include::01_Grundlagen/02_himmelsmechanik.adoc[]
|
|
||||||
|
|
||||||
// 2. Strukturen
|
// 2. Strukturen
|
||||||
include::02_Strukturen/01_hauptmaschinen.adoc[]
|
include::02_Strukturen/01_der_innere_kern.adoc[]
|
||||||
include::02_Strukturen/02_ernte_schwarm.adoc[]
|
|
||||||
|
// 03. Charaktere
|
||||||
|
include::03_Charaktere/01_miner_klasse.adoc[]
|
||||||
|
|
||||||
|
// 4. Kult
|
||||||
|
include::04_Kult/01_fantasy_tech.adoc[]
|
||||||
|
|
||||||
|
// 5. Tech
|
||||||
|
include::05_Tech/01_plasma_trichter.adoc[]
|
||||||
|
|
||||||
|
// 6. Strukturen
|
||||||
|
include::06_Regel/01_nina_protokoll.adoc[]
|
||||||
|
|
||||||
|
// Nerds reding to the end also like to do this next
|
||||||
|
include::00_aMeta/rawDocZ/01_neovim_setup.adoc[]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user