Updating from WIkiJS
This commit is contained in:
parent
e90e9bce56
commit
7846130a4a
70 changed files with 18448 additions and 930 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/.quarto/
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,8 +1,27 @@
|
|||
{
|
||||
"index.qmd": {
|
||||
"index.html": "d99f7c3a"
|
||||
"index.html": "d99f7c3a",
|
||||
"index.tex": "2767060a"
|
||||
},
|
||||
"about.qmd": {
|
||||
"about.html": "67271bd5"
|
||||
"about.html": "67271bd5",
|
||||
"about.tex": "213452bd"
|
||||
},
|
||||
"sites/introduction.qmd": {
|
||||
"introduction.html": "7be58818"
|
||||
},
|
||||
"sites/styleguide.qmd": {
|
||||
"styleguide.html": "09b1328c",
|
||||
"styleguide.tex": "772a8301"
|
||||
},
|
||||
"sites/webservices.qmd": {
|
||||
"webservices.html": "2bb00f73",
|
||||
"webservices.tex": "db01438b"
|
||||
},
|
||||
"sites/getstarted.qmd": {
|
||||
"getstarted.html": "58d9f35c"
|
||||
},
|
||||
"sites/overview.qmd": {
|
||||
"overview.html": "a690ee7d"
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"entries":[],"headings":[]}
|
||||
{"entries":[],"headings":["welcome-to-the-documentation","features"]}
|
57
_quarto.yml
57
_quarto.yml
|
@ -2,20 +2,53 @@ project:
|
|||
type: website
|
||||
|
||||
website:
|
||||
title: "VIRTUOS WORLD Documentation"
|
||||
title: "DOCS"
|
||||
navbar:
|
||||
left:
|
||||
- href: index.qmd
|
||||
text: Home
|
||||
- about.qmd
|
||||
- text: "Homepage"
|
||||
href: https://virtuos.world
|
||||
sidebar:
|
||||
style: "docked"
|
||||
search: true
|
||||
contents:
|
||||
- section: "Overview"
|
||||
href: sites/overview.qmd
|
||||
- section: "Styleguide"
|
||||
href: sites/styleguide.qmd
|
||||
contents:
|
||||
- layout.qmd
|
||||
- layout-knitr.qmd
|
||||
- layout-jupyter.qmd
|
||||
- section: "Webservices"
|
||||
href: sites/webservices.qmd
|
||||
contents:
|
||||
- layout.qmd
|
||||
- layout-knitr.qmd
|
||||
- layout-jupyter.qmd
|
||||
- section: "Getting Started"
|
||||
href: sites/getstarted.qmd
|
||||
|
||||
format:
|
||||
page-footer:
|
||||
left: "Copyright 2025, Simeon Wallrath"
|
||||
right:
|
||||
- icon: github
|
||||
href: https://github.com/
|
||||
- icon: mastodon
|
||||
href: https://twitter.com/
|
||||
reader-mode: true
|
||||
|
||||
|
||||
theme:
|
||||
- Zephyr
|
||||
- theme.scss
|
||||
|
||||
# Set the logo for the header
|
||||
logo: "logo.png"
|
||||
|
||||
output-dir: "_site"
|
||||
|
||||
format:
|
||||
html:
|
||||
theme:
|
||||
- cosmo
|
||||
- brand
|
||||
css: styles.css
|
||||
toc: true
|
||||
|
||||
|
||||
|
||||
grid:
|
||||
margin-width: 350px
|
879
_site/about.html
879
_site/about.html
|
@ -2,12 +2,12 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="quarto-1.7.21">
|
||||
<meta name="generator" content="quarto-1.6.43">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
|
||||
|
||||
<title>About – VIRTUOS WORLD Documentation</title>
|
||||
<title>About – DOCS</title>
|
||||
<style>
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
|
@ -30,16 +30,15 @@ ul.task-list li input[type="checkbox"] {
|
|||
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
||||
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
||||
<meta name="quarto:offset" content="./">
|
||||
<script src="site_libs/quarto-html/quarto.js" type="module"></script>
|
||||
<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
|
||||
<script src="site_libs/quarto-html/quarto.js"></script>
|
||||
<script src="site_libs/quarto-html/popper.min.js"></script>
|
||||
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
||||
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
||||
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
||||
<link href="site_libs/quarto-html/quarto-syntax-highlighting-b2bd955b7378b94aa8c2ba4fafa553c9.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||
<link href="site_libs/quarto-html/quarto-syntax-highlighting-d4d76bf8491c20bad77d141916dc28e1.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
||||
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="site_libs/bootstrap/bootstrap-0813dcf0c0fbb2745f2010876f3afe2b.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||
<link href="site_libs/bootstrap/bootstrap-96f0ff77f429b54fb9fb81a812e140da.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||
<script id="quarto-search-options" type="application/json">{
|
||||
"location": "navbar",
|
||||
"copy-button": false,
|
||||
|
@ -72,7 +71,7 @@ ul.task-list li input[type="checkbox"] {
|
|||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
|
||||
<body class="nav-fixed quarto-light">
|
||||
<body class="nav-sidebar docked nav-fixed">
|
||||
|
||||
<div id="quarto-search-results"></div>
|
||||
<header id="quarto-header" class="headroom fixed-top">
|
||||
|
@ -80,7 +79,7 @@ ul.task-list li input[type="checkbox"] {
|
|||
<div class="navbar-container container-fluid">
|
||||
<div class="navbar-brand-container mx-auto">
|
||||
<a class="navbar-brand" href="./index.html">
|
||||
<span class="navbar-title">VIRTUOS WORLD Documentation</span>
|
||||
<span class="navbar-title">DOCS</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
|
@ -90,27 +89,101 @@ ul.task-list li input[type="checkbox"] {
|
|||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav navbar-nav-scroll me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./index.html">
|
||||
<span class="menu-text">Home</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="./about.html" aria-current="page">
|
||||
<span class="menu-text">About</span></a>
|
||||
<a class="nav-link" href="https://virtuos.world">
|
||||
<span class="menu-text">Homepage</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div> <!-- /navcollapse -->
|
||||
<div class="quarto-navbar-tools">
|
||||
<a href="" class="quarto-reader-toggle quarto-navigation-tool px-1" onclick="window.quartoToggleReader(); return false;" title="Toggle reader mode">
|
||||
<div class="quarto-reader-toggle-btn">
|
||||
<i class="bi"></i>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div> <!-- /container-fluid -->
|
||||
</nav>
|
||||
<nav class="quarto-secondary-nav">
|
||||
<div class="container-fluid d-flex">
|
||||
<button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" role="button" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
<i class="bi bi-layout-text-sidebar-reverse"></i>
|
||||
</button>
|
||||
<nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">About</li></ol></nav>
|
||||
<a class="flex-grow-1" role="navigation" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
</a>
|
||||
<button type="button" class="btn quarto-search-button" aria-label="Search" onclick="window.quartoOpenSearch();">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<!-- content -->
|
||||
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
|
||||
<!-- sidebar -->
|
||||
<!-- margin-sidebar -->
|
||||
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar zindex-bottom">
|
||||
|
||||
<nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal quarto-sidebar-collapse-item sidebar-navigation docked overflow-auto">
|
||||
<div class="mt-2 flex-shrink-0 align-items-center">
|
||||
<div class="sidebar-search">
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-menu-container">
|
||||
<ul class="list-unstyled mt-1">
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<span class="sidebar-item-text sidebar-link text-start">
|
||||
<span class="menu-text">Overview</span></span>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<div class="sidebar-item-container">
|
||||
<a href="./sites/styleguide.html" class="sidebar-item-text sidebar-link">
|
||||
<span class="menu-text">Styleguide</span></a>
|
||||
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" role="navigation" aria-expanded="true" aria-label="Toggle section">
|
||||
<i class="bi bi-chevron-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show">
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-knitr.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-jupyter.qmd</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<div class="sidebar-item-container">
|
||||
<a href="./sites/webservices.html" class="sidebar-item-text sidebar-link">
|
||||
<span class="menu-text">Webservices</span></a>
|
||||
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" role="navigation" aria-expanded="true" aria-label="Toggle section">
|
||||
<i class="bi bi-chevron-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth1 show">
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-knitr.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-jupyter.qmd</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<span class="sidebar-item-text sidebar-link text-start">
|
||||
<span class="menu-text">Getting Started</span></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="quarto-sidebar-glass" class="quarto-sidebar-collapse-item" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item"></div>
|
||||
<!-- margin-sidebar -->
|
||||
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
|
||||
|
||||
<div class="quarto-alternate-formats"><h2>Other Formats</h2><ul><li><a href="about.pdf"><i class="bi bi-file-pdf"></i>PDF</a></li></ul></div></div>
|
||||
<!-- main -->
|
||||
<main class="content" id="quarto-document-content">
|
||||
|
||||
|
@ -139,242 +212,236 @@ ul.task-list li input[type="checkbox"] {
|
|||
|
||||
</main> <!-- /main -->
|
||||
<script id="quarto-html-after-body" type="application/javascript">
|
||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||
const icon = "";
|
||||
const anchorJS = new window.AnchorJS();
|
||||
anchorJS.options = {
|
||||
placement: 'right',
|
||||
icon: icon
|
||||
};
|
||||
anchorJS.add('.anchored');
|
||||
const isCodeAnnotation = (el) => {
|
||||
for (const clz of el.classList) {
|
||||
if (clz.startsWith('code-annotation-')) {
|
||||
return true;
|
||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||
const toggleBodyColorMode = (bsSheetEl) => {
|
||||
const mode = bsSheetEl.getAttribute("data-mode");
|
||||
const bodyEl = window.document.querySelector("body");
|
||||
if (mode === "dark") {
|
||||
bodyEl.classList.add("quarto-dark");
|
||||
bodyEl.classList.remove("quarto-light");
|
||||
} else {
|
||||
bodyEl.classList.add("quarto-light");
|
||||
bodyEl.classList.remove("quarto-dark");
|
||||
}
|
||||
}
|
||||
const toggleBodyColorPrimary = () => {
|
||||
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
|
||||
if (bsSheetEl) {
|
||||
toggleBodyColorMode(bsSheetEl);
|
||||
}
|
||||
}
|
||||
toggleBodyColorPrimary();
|
||||
const icon = "";
|
||||
const anchorJS = new window.AnchorJS();
|
||||
anchorJS.options = {
|
||||
placement: 'right',
|
||||
icon: icon
|
||||
};
|
||||
anchorJS.add('.anchored');
|
||||
const isCodeAnnotation = (el) => {
|
||||
for (const clz of el.classList) {
|
||||
if (clz.startsWith('code-annotation-')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const onCopySuccess = function(e) {
|
||||
// button target
|
||||
const button = e.trigger;
|
||||
// don't keep focus
|
||||
button.blur();
|
||||
// flash "checked"
|
||||
button.classList.add('code-copy-button-checked');
|
||||
var currentTitle = button.getAttribute("title");
|
||||
button.setAttribute("title", "Copied!");
|
||||
let tooltip;
|
||||
if (window.bootstrap) {
|
||||
button.setAttribute("data-bs-toggle", "tooltip");
|
||||
button.setAttribute("data-bs-placement", "left");
|
||||
button.setAttribute("data-bs-title", "Copied!");
|
||||
tooltip = new bootstrap.Tooltip(button,
|
||||
{ trigger: "manual",
|
||||
customClass: "code-copy-button-tooltip",
|
||||
offset: [0, -8]});
|
||||
tooltip.show();
|
||||
}
|
||||
setTimeout(function() {
|
||||
if (tooltip) {
|
||||
tooltip.hide();
|
||||
button.removeAttribute("data-bs-title");
|
||||
button.removeAttribute("data-bs-toggle");
|
||||
button.removeAttribute("data-bs-placement");
|
||||
}
|
||||
button.setAttribute("title", currentTitle);
|
||||
button.classList.remove('code-copy-button-checked');
|
||||
}, 1000);
|
||||
// clear code selection
|
||||
e.clearSelection();
|
||||
}
|
||||
const getTextToCopy = function(trigger) {
|
||||
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
||||
for (const childEl of codeEl.children) {
|
||||
if (isCodeAnnotation(childEl)) {
|
||||
childEl.remove();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const onCopySuccess = function(e) {
|
||||
// button target
|
||||
const button = e.trigger;
|
||||
// don't keep focus
|
||||
button.blur();
|
||||
// flash "checked"
|
||||
button.classList.add('code-copy-button-checked');
|
||||
var currentTitle = button.getAttribute("title");
|
||||
button.setAttribute("title", "Copied!");
|
||||
let tooltip;
|
||||
if (window.bootstrap) {
|
||||
button.setAttribute("data-bs-toggle", "tooltip");
|
||||
button.setAttribute("data-bs-placement", "left");
|
||||
button.setAttribute("data-bs-title", "Copied!");
|
||||
tooltip = new bootstrap.Tooltip(button,
|
||||
{ trigger: "manual",
|
||||
customClass: "code-copy-button-tooltip",
|
||||
offset: [0, -8]});
|
||||
tooltip.show();
|
||||
}
|
||||
setTimeout(function() {
|
||||
if (tooltip) {
|
||||
tooltip.hide();
|
||||
button.removeAttribute("data-bs-title");
|
||||
button.removeAttribute("data-bs-toggle");
|
||||
button.removeAttribute("data-bs-placement");
|
||||
}
|
||||
button.setAttribute("title", currentTitle);
|
||||
button.classList.remove('code-copy-button-checked');
|
||||
}, 1000);
|
||||
// clear code selection
|
||||
e.clearSelection();
|
||||
}
|
||||
const getTextToCopy = function(trigger) {
|
||||
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
||||
for (const childEl of codeEl.children) {
|
||||
if (isCodeAnnotation(childEl)) {
|
||||
childEl.remove();
|
||||
}
|
||||
}
|
||||
return codeEl.innerText;
|
||||
}
|
||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||
text: getTextToCopy
|
||||
return codeEl.innerText;
|
||||
}
|
||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||
text: getTextToCopy
|
||||
});
|
||||
clipboard.on('success', onCopySuccess);
|
||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||
text: getTextToCopy,
|
||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||
});
|
||||
clipboard.on('success', onCopySuccess);
|
||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||
text: getTextToCopy,
|
||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||
});
|
||||
clipboardModal.on('success', onCopySuccess);
|
||||
clipboardModal.on('success', onCopySuccess);
|
||||
}
|
||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||
var mailtoRegex = new RegExp(/^mailto:/);
|
||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||
var isInternal = (href) => {
|
||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||
}
|
||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||
var mailtoRegex = new RegExp(/^mailto:/);
|
||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||
var isInternal = (href) => {
|
||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||
}
|
||||
// Inspect non-navigation links and adorn them if external
|
||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||
for (var i=0; i<links.length; i++) {
|
||||
const link = links[i];
|
||||
if (!isInternal(link.href)) {
|
||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||
// links that we want to consider external
|
||||
if (link.dataset.originalHref !== undefined) {
|
||||
link.href = link.dataset.originalHref;
|
||||
}
|
||||
// Inspect non-navigation links and adorn them if external
|
||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||
for (var i=0; i<links.length; i++) {
|
||||
const link = links[i];
|
||||
if (!isInternal(link.href)) {
|
||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||
// links that we want to consider external
|
||||
if (link.dataset.originalHref !== undefined) {
|
||||
link.href = link.dataset.originalHref;
|
||||
}
|
||||
}
|
||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||
const config = {
|
||||
allowHTML: true,
|
||||
maxWidth: 500,
|
||||
delay: 100,
|
||||
arrow: false,
|
||||
appendTo: function(el) {
|
||||
return el.parentElement;
|
||||
},
|
||||
interactive: true,
|
||||
interactiveBorder: 10,
|
||||
theme: 'quarto',
|
||||
placement: 'bottom-start',
|
||||
};
|
||||
if (contentFn) {
|
||||
config.content = contentFn;
|
||||
}
|
||||
if (onTriggerFn) {
|
||||
config.onTrigger = onTriggerFn;
|
||||
}
|
||||
if (onUntriggerFn) {
|
||||
config.onUntrigger = onUntriggerFn;
|
||||
}
|
||||
window.tippy(el, config);
|
||||
}
|
||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||
for (var i=0; i<noterefs.length; i++) {
|
||||
const ref = noterefs[i];
|
||||
tippyHover(ref, function() {
|
||||
// use id or data attribute instead here
|
||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||
try { href = new URL(href).hash; } catch {}
|
||||
const id = href.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note) {
|
||||
return note.innerHTML;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||
const config = {
|
||||
allowHTML: true,
|
||||
maxWidth: 500,
|
||||
delay: 100,
|
||||
arrow: false,
|
||||
appendTo: function(el) {
|
||||
return el.parentElement;
|
||||
},
|
||||
interactive: true,
|
||||
interactiveBorder: 10,
|
||||
theme: 'quarto',
|
||||
placement: 'bottom-start',
|
||||
};
|
||||
if (contentFn) {
|
||||
config.content = contentFn;
|
||||
}
|
||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||
const processXRef = (id, note) => {
|
||||
// Strip column container classes
|
||||
const stripColumnClz = (el) => {
|
||||
el.classList.remove("page-full", "page-columns");
|
||||
if (el.children) {
|
||||
for (const child of el.children) {
|
||||
stripColumnClz(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
stripColumnClz(note)
|
||||
if (id === null || id.startsWith('sec-')) {
|
||||
// Special case sections, only their first couple elements
|
||||
const container = document.createElement("div");
|
||||
if (note.children && note.children.length > 2) {
|
||||
container.appendChild(note.children[0].cloneNode(true));
|
||||
for (let i = 1; i < note.children.length; i++) {
|
||||
const child = note.children[i];
|
||||
if (child.tagName === "P" && child.innerText === "") {
|
||||
continue;
|
||||
} else {
|
||||
container.appendChild(child.cloneNode(true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(container);
|
||||
}
|
||||
return container.innerHTML
|
||||
} else {
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
return note.innerHTML;
|
||||
}
|
||||
if (onTriggerFn) {
|
||||
config.onTrigger = onTriggerFn;
|
||||
}
|
||||
if (onUntriggerFn) {
|
||||
config.onUntrigger = onUntriggerFn;
|
||||
}
|
||||
window.tippy(el, config);
|
||||
}
|
||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||
for (var i=0; i<noterefs.length; i++) {
|
||||
const ref = noterefs[i];
|
||||
tippyHover(ref, function() {
|
||||
// use id or data attribute instead here
|
||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||
try { href = new URL(href).hash; } catch {}
|
||||
const id = href.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note) {
|
||||
return note.innerHTML;
|
||||
} else {
|
||||
// Remove any anchor links if they are present
|
||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||
if (anchorLink) {
|
||||
anchorLink.remove();
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||
const processXRef = (id, note) => {
|
||||
// Strip column container classes
|
||||
const stripColumnClz = (el) => {
|
||||
el.classList.remove("page-full", "page-columns");
|
||||
if (el.children) {
|
||||
for (const child of el.children) {
|
||||
stripColumnClz(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
stripColumnClz(note)
|
||||
if (id === null || id.startsWith('sec-')) {
|
||||
// Special case sections, only their first couple elements
|
||||
const container = document.createElement("div");
|
||||
if (note.children && note.children.length > 2) {
|
||||
container.appendChild(note.children[0].cloneNode(true));
|
||||
for (let i = 1; i < note.children.length; i++) {
|
||||
const child = note.children[i];
|
||||
if (child.tagName === "P" && child.innerText === "") {
|
||||
continue;
|
||||
} else {
|
||||
container.appendChild(child.cloneNode(true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(container);
|
||||
}
|
||||
return container.innerHTML
|
||||
} else {
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
if (note.classList.contains("callout")) {
|
||||
return note.outerHTML;
|
||||
} else {
|
||||
return note.innerHTML;
|
||||
}
|
||||
return note.innerHTML;
|
||||
}
|
||||
} else {
|
||||
// Remove any anchor links if they are present
|
||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||
if (anchorLink) {
|
||||
anchorLink.remove();
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
if (note.classList.contains("callout")) {
|
||||
return note.outerHTML;
|
||||
} else {
|
||||
return note.innerHTML;
|
||||
}
|
||||
}
|
||||
for (var i=0; i<xrefs.length; i++) {
|
||||
const xref = xrefs[i];
|
||||
tippyHover(xref, undefined, function(instance) {
|
||||
instance.disable();
|
||||
let url = xref.getAttribute('href');
|
||||
let hash = undefined;
|
||||
if (url.startsWith('#')) {
|
||||
hash = url;
|
||||
} else {
|
||||
try { hash = new URL(url).hash; } catch {}
|
||||
}
|
||||
if (hash) {
|
||||
const id = hash.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note !== null) {
|
||||
try {
|
||||
const html = processXRef(id, note.cloneNode(true));
|
||||
instance.setContent(html);
|
||||
} finally {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch this
|
||||
fetch(url.split('#')[0])
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.getElementById(id);
|
||||
if (note !== null) {
|
||||
const html = processXRef(id, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
for (var i=0; i<xrefs.length; i++) {
|
||||
const xref = xrefs[i];
|
||||
tippyHover(xref, undefined, function(instance) {
|
||||
instance.disable();
|
||||
let url = xref.getAttribute('href');
|
||||
let hash = undefined;
|
||||
if (url.startsWith('#')) {
|
||||
hash = url;
|
||||
} else {
|
||||
try { hash = new URL(url).hash; } catch {}
|
||||
}
|
||||
if (hash) {
|
||||
const id = hash.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note !== null) {
|
||||
try {
|
||||
const html = processXRef(id, note.cloneNode(true));
|
||||
instance.setContent(html);
|
||||
} finally {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch a full url (with no hash to target)
|
||||
// This is a special case and we should probably do some content thinning / targeting
|
||||
fetch(url)
|
||||
// See if we can fetch this
|
||||
fetch(url.split('#')[0])
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.querySelector('main.content');
|
||||
const note = htmlDoc.getElementById(id);
|
||||
if (note !== null) {
|
||||
// This should only happen for chapter cross references
|
||||
// (since there is no id in the URL)
|
||||
// remove the first header
|
||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||
note.children[0].remove();
|
||||
}
|
||||
const html = processXRef(null, note);
|
||||
const html = processXRef(id, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
|
@ -382,162 +449,212 @@ ul.task-list li input[type="checkbox"] {
|
|||
instance.show();
|
||||
});
|
||||
}
|
||||
}, function(instance) {
|
||||
});
|
||||
}
|
||||
let selectedAnnoteEl;
|
||||
const selectorForAnnotation = ( cell, annotation) => {
|
||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||
return selector;
|
||||
}
|
||||
const selectCodeLines = (annoteEl) => {
|
||||
const doc = window.document;
|
||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||
const lineIds = lines.map((line) => {
|
||||
return targetCell + "-" + line;
|
||||
})
|
||||
let top = null;
|
||||
let height = null;
|
||||
let parent = null;
|
||||
if (lineIds.length > 0) {
|
||||
//compute the position of the single el (top and bottom and make a div)
|
||||
const el = window.document.getElementById(lineIds[0]);
|
||||
top = el.offsetTop;
|
||||
height = el.offsetHeight;
|
||||
parent = el.parentElement.parentElement;
|
||||
if (lineIds.length > 1) {
|
||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||
height = bottom - top;
|
||||
}
|
||||
if (top !== null && height !== null && parent !== null) {
|
||||
// cook up a div (if necessary) and position it
|
||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||
if (div === null) {
|
||||
div = window.document.createElement("div");
|
||||
div.setAttribute("id", "code-annotation-line-highlight");
|
||||
div.style.position = 'absolute';
|
||||
parent.appendChild(div);
|
||||
}
|
||||
div.style.top = top - 2 + "px";
|
||||
div.style.height = height + 4 + "px";
|
||||
div.style.left = 0;
|
||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||
if (gutterDiv === null) {
|
||||
gutterDiv = window.document.createElement("div");
|
||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||
gutterDiv.style.position = 'absolute';
|
||||
const codeCell = window.document.getElementById(targetCell);
|
||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||
gutter.appendChild(gutterDiv);
|
||||
}
|
||||
gutterDiv.style.top = top - 2 + "px";
|
||||
gutterDiv.style.height = height + 4 + "px";
|
||||
}
|
||||
selectedAnnoteEl = annoteEl;
|
||||
}
|
||||
};
|
||||
const unselectCodeLines = () => {
|
||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||
elementsIds.forEach((elId) => {
|
||||
const div = window.document.getElementById(elId);
|
||||
if (div) {
|
||||
div.remove();
|
||||
}
|
||||
});
|
||||
selectedAnnoteEl = undefined;
|
||||
};
|
||||
// Handle positioning of the toggle
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
elRect = undefined;
|
||||
if (selectedAnnoteEl) {
|
||||
selectCodeLines(selectedAnnoteEl);
|
||||
}
|
||||
}, 10)
|
||||
);
|
||||
function throttle(fn, ms) {
|
||||
let throttle = false;
|
||||
let timer;
|
||||
return (...args) => {
|
||||
if(!throttle) { // first call gets through
|
||||
fn.apply(this, args);
|
||||
throttle = true;
|
||||
} else { // all the others get throttled
|
||||
if(timer) clearTimeout(timer); // cancel #2
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
timer = throttle = false;
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
}
|
||||
// Attach click handler to the DT
|
||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||
for (const annoteDlNode of annoteDls) {
|
||||
annoteDlNode.addEventListener('click', (event) => {
|
||||
const clickedEl = event.target;
|
||||
if (clickedEl !== selectedAnnoteEl) {
|
||||
unselectCodeLines();
|
||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||
if (activeEl) {
|
||||
activeEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
selectCodeLines(clickedEl);
|
||||
clickedEl.classList.add('code-annotation-active');
|
||||
} else {
|
||||
// Unselect the line
|
||||
unselectCodeLines();
|
||||
clickedEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
const findCites = (el) => {
|
||||
const parentEl = el.parentElement;
|
||||
if (parentEl) {
|
||||
const cites = parentEl.dataset.cites;
|
||||
if (cites) {
|
||||
return {
|
||||
el,
|
||||
cites: cites.split(' ')
|
||||
};
|
||||
} else {
|
||||
return findCites(el.parentElement)
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||
for (var i=0; i<bibliorefs.length; i++) {
|
||||
const ref = bibliorefs[i];
|
||||
const citeInfo = findCites(ref);
|
||||
if (citeInfo) {
|
||||
tippyHover(citeInfo.el, function() {
|
||||
var popup = window.document.createElement('div');
|
||||
citeInfo.cites.forEach(function(cite) {
|
||||
var citeDiv = window.document.createElement('div');
|
||||
citeDiv.classList.add('hanging-indent');
|
||||
citeDiv.classList.add('csl-entry');
|
||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||
if (biblioDiv) {
|
||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||
// See if we can fetch a full url (with no hash to target)
|
||||
// This is a special case and we should probably do some content thinning / targeting
|
||||
fetch(url)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.querySelector('main.content');
|
||||
if (note !== null) {
|
||||
// This should only happen for chapter cross references
|
||||
// (since there is no id in the URL)
|
||||
// remove the first header
|
||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||
note.children[0].remove();
|
||||
}
|
||||
popup.appendChild(citeDiv);
|
||||
});
|
||||
return popup.innerHTML;
|
||||
const html = processXRef(null, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
}, function(instance) {
|
||||
});
|
||||
}
|
||||
let selectedAnnoteEl;
|
||||
const selectorForAnnotation = ( cell, annotation) => {
|
||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||
return selector;
|
||||
}
|
||||
const selectCodeLines = (annoteEl) => {
|
||||
const doc = window.document;
|
||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||
const lineIds = lines.map((line) => {
|
||||
return targetCell + "-" + line;
|
||||
})
|
||||
let top = null;
|
||||
let height = null;
|
||||
let parent = null;
|
||||
if (lineIds.length > 0) {
|
||||
//compute the position of the single el (top and bottom and make a div)
|
||||
const el = window.document.getElementById(lineIds[0]);
|
||||
top = el.offsetTop;
|
||||
height = el.offsetHeight;
|
||||
parent = el.parentElement.parentElement;
|
||||
if (lineIds.length > 1) {
|
||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||
height = bottom - top;
|
||||
}
|
||||
if (top !== null && height !== null && parent !== null) {
|
||||
// cook up a div (if necessary) and position it
|
||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||
if (div === null) {
|
||||
div = window.document.createElement("div");
|
||||
div.setAttribute("id", "code-annotation-line-highlight");
|
||||
div.style.position = 'absolute';
|
||||
parent.appendChild(div);
|
||||
}
|
||||
div.style.top = top - 2 + "px";
|
||||
div.style.height = height + 4 + "px";
|
||||
div.style.left = 0;
|
||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||
if (gutterDiv === null) {
|
||||
gutterDiv = window.document.createElement("div");
|
||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||
gutterDiv.style.position = 'absolute';
|
||||
const codeCell = window.document.getElementById(targetCell);
|
||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||
gutter.appendChild(gutterDiv);
|
||||
}
|
||||
gutterDiv.style.top = top - 2 + "px";
|
||||
gutterDiv.style.height = height + 4 + "px";
|
||||
}
|
||||
selectedAnnoteEl = annoteEl;
|
||||
}
|
||||
};
|
||||
const unselectCodeLines = () => {
|
||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||
elementsIds.forEach((elId) => {
|
||||
const div = window.document.getElementById(elId);
|
||||
if (div) {
|
||||
div.remove();
|
||||
}
|
||||
});
|
||||
selectedAnnoteEl = undefined;
|
||||
};
|
||||
// Handle positioning of the toggle
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
elRect = undefined;
|
||||
if (selectedAnnoteEl) {
|
||||
selectCodeLines(selectedAnnoteEl);
|
||||
}
|
||||
}, 10)
|
||||
);
|
||||
function throttle(fn, ms) {
|
||||
let throttle = false;
|
||||
let timer;
|
||||
return (...args) => {
|
||||
if(!throttle) { // first call gets through
|
||||
fn.apply(this, args);
|
||||
throttle = true;
|
||||
} else { // all the others get throttled
|
||||
if(timer) clearTimeout(timer); // cancel #2
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
timer = throttle = false;
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
// Attach click handler to the DT
|
||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||
for (const annoteDlNode of annoteDls) {
|
||||
annoteDlNode.addEventListener('click', (event) => {
|
||||
const clickedEl = event.target;
|
||||
if (clickedEl !== selectedAnnoteEl) {
|
||||
unselectCodeLines();
|
||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||
if (activeEl) {
|
||||
activeEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
selectCodeLines(clickedEl);
|
||||
clickedEl.classList.add('code-annotation-active');
|
||||
} else {
|
||||
// Unselect the line
|
||||
unselectCodeLines();
|
||||
clickedEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
const findCites = (el) => {
|
||||
const parentEl = el.parentElement;
|
||||
if (parentEl) {
|
||||
const cites = parentEl.dataset.cites;
|
||||
if (cites) {
|
||||
return {
|
||||
el,
|
||||
cites: cites.split(' ')
|
||||
};
|
||||
} else {
|
||||
return findCites(el.parentElement)
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||
for (var i=0; i<bibliorefs.length; i++) {
|
||||
const ref = bibliorefs[i];
|
||||
const citeInfo = findCites(ref);
|
||||
if (citeInfo) {
|
||||
tippyHover(citeInfo.el, function() {
|
||||
var popup = window.document.createElement('div');
|
||||
citeInfo.cites.forEach(function(cite) {
|
||||
var citeDiv = window.document.createElement('div');
|
||||
citeDiv.classList.add('hanging-indent');
|
||||
citeDiv.classList.add('csl-entry');
|
||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||
if (biblioDiv) {
|
||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||
}
|
||||
popup.appendChild(citeDiv);
|
||||
});
|
||||
return popup.innerHTML;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div> <!-- /content -->
|
||||
<footer class="footer">
|
||||
<div class="nav-footer">
|
||||
<div class="nav-footer-left">
|
||||
<p>Copyright 2025, Simeon Wallrath</p>
|
||||
</div>
|
||||
<div class="nav-footer-center">
|
||||
|
||||
</div>
|
||||
<div class="nav-footer-right">
|
||||
<ul class="footer-items list-unstyled">
|
||||
<li class="nav-item compact">
|
||||
<a class="nav-link" href="https://github.com/">
|
||||
<i class="bi bi-github" role="img">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item compact">
|
||||
<a class="nav-link" href="https://twitter.com/">
|
||||
<i class="bi bi-mastodon" role="img">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
|
||||
|
|
BIN
_site/about.pdf
Normal file
BIN
_site/about.pdf
Normal file
Binary file not shown.
BIN
_site/img/Logo.png
Normal file
BIN
_site/img/Logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 212 KiB |
904
_site/index.html
904
_site/index.html
File diff suppressed because it is too large
Load diff
BIN
_site/index.pdf
Normal file
BIN
_site/index.pdf
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-00e317c04aea4af52dd5195a48104e8a.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-00e317c04aea4af52dd5195a48104e8a.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-040fcd844c9d9710447b707c0ff8ce03.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-040fcd844c9d9710447b707c0ff8ce03.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-086dd5c92b40c4eff013a097b829feaf.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-086dd5c92b40c4eff013a097b829feaf.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-0c71289b08d25ab41a08e9df125cbaf5.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-0c71289b08d25ab41a08e9df125cbaf5.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-16df56eaa6a782f86d1a8bf4f6901577.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-16df56eaa6a782f86d1a8bf4f6901577.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-2410d78af41c0c52b9548e6bfc7f7541.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-2410d78af41c0c52b9548e6bfc7f7541.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-2a37986a1d96212c1a83532f96985942.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-2a37986a1d96212c1a83532f96985942.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-307fd4256ae263362b06ecc72bba574e.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-307fd4256ae263362b06ecc72bba574e.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-3ae9948aeee0d3e926123330955d58f5.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-3ae9948aeee0d3e926123330955d58f5.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-3c90a6c791b666540c630c37e4ff2bb8.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-3c90a6c791b666540c630c37e4ff2bb8.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-445e32e47ef9296697e194cfbc967925.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-445e32e47ef9296697e194cfbc967925.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-5a2435c51800bbb0cb26d4bcf48c131e.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-5a2435c51800bbb0cb26d4bcf48c131e.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-5bde865b8b86d8c72d3158cdd886eed7.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-5bde865b8b86d8c72d3158cdd886eed7.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-69a822137359fc5af24ad56c433e27e8.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-69a822137359fc5af24ad56c433e27e8.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-6c4311b41ee52381acf90d6d3514cbe7.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-6c4311b41ee52381acf90d6d3514cbe7.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-86a27437206f565b6f6363daa2a05c59.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-86a27437206f565b6f6363daa2a05c59.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-88433f23eba7cb867322b20b025b24da.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-88433f23eba7cb867322b20b025b24da.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-8ea241a1766a3129914e7a59ac5729ec.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-8ea241a1766a3129914e7a59ac5729ec.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-96f0ff77f429b54fb9fb81a812e140da.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-96f0ff77f429b54fb9fb81a812e140da.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-9d22bb36268c99d87eb70ac19e66ae27.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-9d22bb36268c99d87eb70ac19e66ae27.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-a6121a9be4c5d06673cf87a00dc8d95e.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-a6121a9be4c5d06673cf87a00dc8d95e.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-a8af56dc2111db2feac5102a5b225cc2.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-a8af56dc2111db2feac5102a5b225cc2.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-ab2165296c2394069beed34e014f8abd.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-ab2165296c2394069beed34e014f8abd.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-ac04a87afecc004bd6a6520b7e186556.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-ac04a87afecc004bd6a6520b7e186556.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-add8453ca41efac0195e2667f1159653.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-add8453ca41efac0195e2667f1159653.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-c7471dbc465b381eec74c3a941558e8c.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-c7471dbc465b381eec74c3a941558e8c.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-caad5a33608f20b489c873d59bbc3f5f.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-caad5a33608f20b489c873d59bbc3f5f.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-d4be639c637f3db3c684c66cefad7e0c.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-d4be639c637f3db3c684c66cefad7e0c.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-ddd961a2510921635943dfbbd19534c4.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-ddd961a2510921635943dfbbd19534c4.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-e04861dee4cf4c3b0e8824036b47c80d.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-e04861dee4cf4c3b0e8824036b47c80d.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-e8723066ee47ed1f1f1e9b8a743ac125.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-e8723066ee47ed1f1f1e9b8a743ac125.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-eb14dc340b39297571542011def00b57.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-eb14dc340b39297571542011def00b57.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-f51c8039368b03061c673365a1412cc9.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-f51c8039368b03061c673365a1412cc9.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-f91f8b38e0178e1030cbb628ceb8e0de.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-f91f8b38e0178e1030cbb628ceb8e0de.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
_site/site_libs/bootstrap/bootstrap-fcb5aaac23d555c39d33b41c4ae819e0.min.css
vendored
Normal file
12
_site/site_libs/bootstrap/bootstrap-fcb5aaac23d555c39d33b41c4ae819e0.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -202,4 +202,4 @@ code span.kw {
|
|||
content: "</";
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bd9315517b35d1ca99281302af408dd3.css.map */
|
||||
/*# sourceMappingURL=c9c5d451c23b744f9cb2c98992a0aef2.css.map */
|
|
@ -0,0 +1,189 @@
|
|||
/* quarto syntax highlight colors */
|
||||
:root {
|
||||
--quarto-hl-al-color: #f07178;
|
||||
--quarto-hl-an-color: #d4d0ab;
|
||||
--quarto-hl-at-color: #00e0e0;
|
||||
--quarto-hl-bn-color: #d4d0ab;
|
||||
--quarto-hl-bu-color: #abe338;
|
||||
--quarto-hl-ch-color: #abe338;
|
||||
--quarto-hl-co-color: #f8f8f2;
|
||||
--quarto-hl-cv-color: #ffd700;
|
||||
--quarto-hl-cn-color: #ffd700;
|
||||
--quarto-hl-cf-color: #ffa07a;
|
||||
--quarto-hl-dt-color: #ffa07a;
|
||||
--quarto-hl-dv-color: #d4d0ab;
|
||||
--quarto-hl-do-color: #f8f8f2;
|
||||
--quarto-hl-er-color: #f07178;
|
||||
--quarto-hl-ex-color: #00e0e0;
|
||||
--quarto-hl-fl-color: #d4d0ab;
|
||||
--quarto-hl-fu-color: #ffa07a;
|
||||
--quarto-hl-im-color: #abe338;
|
||||
--quarto-hl-in-color: #d4d0ab;
|
||||
--quarto-hl-kw-color: #ffa07a;
|
||||
--quarto-hl-op-color: #ffa07a;
|
||||
--quarto-hl-ot-color: #00e0e0;
|
||||
--quarto-hl-pp-color: #dcc6e0;
|
||||
--quarto-hl-re-color: #00e0e0;
|
||||
--quarto-hl-sc-color: #abe338;
|
||||
--quarto-hl-ss-color: #abe338;
|
||||
--quarto-hl-st-color: #abe338;
|
||||
--quarto-hl-va-color: #00e0e0;
|
||||
--quarto-hl-vs-color: #abe338;
|
||||
--quarto-hl-wa-color: #dcc6e0;
|
||||
}
|
||||
|
||||
/* other quarto variables */
|
||||
:root {
|
||||
--quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
}
|
||||
|
||||
code span.al {
|
||||
background-color: #2a0f15;
|
||||
font-weight: bold;
|
||||
color: #f07178;
|
||||
}
|
||||
|
||||
code span.an {
|
||||
color: #d4d0ab;
|
||||
}
|
||||
|
||||
code span.at {
|
||||
color: #00e0e0;
|
||||
}
|
||||
|
||||
code span.bn {
|
||||
color: #d4d0ab;
|
||||
}
|
||||
|
||||
code span.bu {
|
||||
color: #abe338;
|
||||
}
|
||||
|
||||
code span.ch {
|
||||
color: #abe338;
|
||||
}
|
||||
|
||||
code span.co {
|
||||
font-style: italic;
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
code span.cv {
|
||||
color: #ffd700;
|
||||
}
|
||||
|
||||
code span.cn {
|
||||
color: #ffd700;
|
||||
}
|
||||
|
||||
code span.cf {
|
||||
font-weight: bold;
|
||||
color: #ffa07a;
|
||||
}
|
||||
|
||||
code span.dt {
|
||||
color: #ffa07a;
|
||||
}
|
||||
|
||||
code span.dv {
|
||||
color: #d4d0ab;
|
||||
}
|
||||
|
||||
code span.do {
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
code span.er {
|
||||
color: #f07178;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
code span.ex {
|
||||
font-weight: bold;
|
||||
color: #00e0e0;
|
||||
}
|
||||
|
||||
code span.fl {
|
||||
color: #d4d0ab;
|
||||
}
|
||||
|
||||
code span.fu {
|
||||
color: #ffa07a;
|
||||
}
|
||||
|
||||
code span.im {
|
||||
color: #abe338;
|
||||
}
|
||||
|
||||
code span.in {
|
||||
color: #d4d0ab;
|
||||
}
|
||||
|
||||
code span.kw {
|
||||
font-weight: bold;
|
||||
color: #ffa07a;
|
||||
}
|
||||
|
||||
pre > code.sourceCode > span {
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
code span {
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
code.sourceCode > span {
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
div.sourceCode,
|
||||
div.sourceCode pre.sourceCode {
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
code span.op {
|
||||
color: #ffa07a;
|
||||
}
|
||||
|
||||
code span.ot {
|
||||
color: #00e0e0;
|
||||
}
|
||||
|
||||
code span.pp {
|
||||
color: #dcc6e0;
|
||||
}
|
||||
|
||||
code span.re {
|
||||
background-color: #f8f8f2;
|
||||
color: #00e0e0;
|
||||
}
|
||||
|
||||
code span.sc {
|
||||
color: #abe338;
|
||||
}
|
||||
|
||||
code span.ss {
|
||||
color: #abe338;
|
||||
}
|
||||
|
||||
code span.st {
|
||||
color: #abe338;
|
||||
}
|
||||
|
||||
code span.va {
|
||||
color: #00e0e0;
|
||||
}
|
||||
|
||||
code span.vs {
|
||||
color: #abe338;
|
||||
}
|
||||
|
||||
code span.wa {
|
||||
color: #dcc6e0;
|
||||
}
|
||||
|
||||
.prevent-inlining {
|
||||
content: "</";
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=358cf41e74b1efa21c8e6dcd38cd2fd6.css.map */
|
|
@ -1,5 +1,3 @@
|
|||
import * as tabsets from "./tabsets/tabsets.js";
|
||||
|
||||
const sectionChanged = new CustomEvent("quarto-sectionChanged", {
|
||||
detail: {},
|
||||
bubbles: true,
|
||||
|
@ -66,41 +64,19 @@ window.document.addEventListener("DOMContentLoaded", function (_event) {
|
|||
}
|
||||
};
|
||||
|
||||
// dispatch for htmlwidgets
|
||||
// they use slideenter event to trigger resize
|
||||
function fireSlideEnter() {
|
||||
// fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior)
|
||||
function fireSlideEnter(e) {
|
||||
const event = window.document.createEvent("Event");
|
||||
event.initEvent("slideenter", true, true);
|
||||
window.document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]');
|
||||
tabs.forEach((tab) => {
|
||||
tab.addEventListener("shown.bs.tab", fireSlideEnter);
|
||||
});
|
||||
|
||||
// dispatch for shiny
|
||||
// they use BS shown and hidden events to trigger rendering
|
||||
function distpatchShinyEvents(previous, current) {
|
||||
if (window.jQuery) {
|
||||
if (previous) {
|
||||
window.jQuery(previous).trigger("hidden");
|
||||
}
|
||||
if (current) {
|
||||
window.jQuery(current).trigger("shown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tabby.js listener: Trigger event for htmlwidget and shiny
|
||||
document.addEventListener(
|
||||
"tabby",
|
||||
function (event) {
|
||||
fireSlideEnter();
|
||||
distpatchShinyEvents(event.detail.previousTab, event.detail.tab);
|
||||
},
|
||||
false
|
||||
);
|
||||
// fire slideEnter for tabby tab activations (for htmlwidget resize behavior)
|
||||
document.addEventListener("tabby", fireSlideEnter, false);
|
||||
|
||||
// Track scrolling and mark TOC links as active
|
||||
// get table of contents and sidebar (bail if we don't have at least one)
|
||||
|
@ -260,10 +236,9 @@ window.document.addEventListener("DOMContentLoaded", function (_event) {
|
|||
for (const listingPath of listingPaths) {
|
||||
const pathWithoutLeadingSlash = listingPath.listing.substring(1);
|
||||
for (const item of listingPath.items) {
|
||||
const encodedItem = encodeURI(item);
|
||||
if (
|
||||
encodedItem === currentPagePath ||
|
||||
encodedItem === currentPagePath + "index.html"
|
||||
item === currentPagePath ||
|
||||
item === currentPagePath + "index.html"
|
||||
) {
|
||||
// Resolve this path against the offset to be sure
|
||||
// we already are using the correct path to the listing
|
||||
|
@ -765,7 +740,7 @@ window.document.addEventListener("DOMContentLoaded", function (_event) {
|
|||
|
||||
// See if there is an active child to this element
|
||||
let hasActiveChild = false;
|
||||
for (const child of el.children) {
|
||||
for (child of el.children) {
|
||||
hasActiveChild = walk(child, depth) || hasActiveChild;
|
||||
}
|
||||
|
||||
|
@ -825,7 +800,98 @@ window.document.addEventListener("DOMContentLoaded", function (_event) {
|
|||
highlightReaderToggle(isReaderMode());
|
||||
});
|
||||
|
||||
tabsets.init();
|
||||
// grouped tabsets
|
||||
window.addEventListener("pageshow", (_event) => {
|
||||
function getTabSettings() {
|
||||
const data = localStorage.getItem("quarto-persistent-tabsets-data");
|
||||
if (!data) {
|
||||
localStorage.setItem("quarto-persistent-tabsets-data", "{}");
|
||||
return {};
|
||||
}
|
||||
if (data) {
|
||||
return JSON.parse(data);
|
||||
}
|
||||
}
|
||||
|
||||
function setTabSettings(data) {
|
||||
localStorage.setItem(
|
||||
"quarto-persistent-tabsets-data",
|
||||
JSON.stringify(data)
|
||||
);
|
||||
}
|
||||
|
||||
function setTabState(groupName, groupValue) {
|
||||
const data = getTabSettings();
|
||||
data[groupName] = groupValue;
|
||||
setTabSettings(data);
|
||||
}
|
||||
|
||||
function toggleTab(tab, active) {
|
||||
const tabPanelId = tab.getAttribute("aria-controls");
|
||||
const tabPanel = document.getElementById(tabPanelId);
|
||||
if (active) {
|
||||
tab.classList.add("active");
|
||||
tabPanel.classList.add("active");
|
||||
} else {
|
||||
tab.classList.remove("active");
|
||||
tabPanel.classList.remove("active");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleAll(selectedGroup, selectorsToSync) {
|
||||
for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) {
|
||||
const active = selectedGroup === thisGroup;
|
||||
for (const tab of tabs) {
|
||||
toggleTab(tab, active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findSelectorsToSyncByLanguage() {
|
||||
const result = {};
|
||||
const tabs = Array.from(
|
||||
document.querySelectorAll(`div[data-group] a[id^='tabset-']`)
|
||||
);
|
||||
for (const item of tabs) {
|
||||
const div = item.parentElement.parentElement.parentElement;
|
||||
const group = div.getAttribute("data-group");
|
||||
if (!result[group]) {
|
||||
result[group] = {};
|
||||
}
|
||||
const selectorsToSync = result[group];
|
||||
const value = item.innerHTML;
|
||||
if (!selectorsToSync[value]) {
|
||||
selectorsToSync[value] = [];
|
||||
}
|
||||
selectorsToSync[value].push(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function setupSelectorSync() {
|
||||
const selectorsToSync = findSelectorsToSyncByLanguage();
|
||||
Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => {
|
||||
Object.entries(tabSetsByValue).forEach(([value, items]) => {
|
||||
items.forEach((item) => {
|
||||
item.addEventListener("click", (_event) => {
|
||||
setTabState(group, value);
|
||||
toggleAll(value, selectorsToSync[group]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return selectorsToSync;
|
||||
}
|
||||
|
||||
const selectorsToSync = setupSelectorSync();
|
||||
for (const [group, selectedName] of Object.entries(getTabSettings())) {
|
||||
const selectors = selectorsToSync[group];
|
||||
// it's possible that stale state gives us empty selections, so we explicitly check here.
|
||||
if (selectors) {
|
||||
toggleAll(selectedName, selectors);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function throttle(func, wait) {
|
||||
let waiting = false;
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
// grouped tabsets
|
||||
|
||||
export function init() {
|
||||
window.addEventListener("pageshow", (_event) => {
|
||||
function getTabSettings() {
|
||||
const data = localStorage.getItem("quarto-persistent-tabsets-data");
|
||||
if (!data) {
|
||||
localStorage.setItem("quarto-persistent-tabsets-data", "{}");
|
||||
return {};
|
||||
}
|
||||
if (data) {
|
||||
return JSON.parse(data);
|
||||
}
|
||||
}
|
||||
|
||||
function setTabSettings(data) {
|
||||
localStorage.setItem(
|
||||
"quarto-persistent-tabsets-data",
|
||||
JSON.stringify(data)
|
||||
);
|
||||
}
|
||||
|
||||
function setTabState(groupName, groupValue) {
|
||||
const data = getTabSettings();
|
||||
data[groupName] = groupValue;
|
||||
setTabSettings(data);
|
||||
}
|
||||
|
||||
function toggleTab(tab, active) {
|
||||
const tabPanelId = tab.getAttribute("aria-controls");
|
||||
const tabPanel = document.getElementById(tabPanelId);
|
||||
if (active) {
|
||||
tab.classList.add("active");
|
||||
tabPanel.classList.add("active");
|
||||
} else {
|
||||
tab.classList.remove("active");
|
||||
tabPanel.classList.remove("active");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleAll(selectedGroup, selectorsToSync) {
|
||||
for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) {
|
||||
const active = selectedGroup === thisGroup;
|
||||
for (const tab of tabs) {
|
||||
toggleTab(tab, active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findSelectorsToSyncByLanguage() {
|
||||
const result = {};
|
||||
const tabs = Array.from(
|
||||
document.querySelectorAll(`div[data-group] a[id^='tabset-']`)
|
||||
);
|
||||
for (const item of tabs) {
|
||||
const div = item.parentElement.parentElement.parentElement;
|
||||
const group = div.getAttribute("data-group");
|
||||
if (!result[group]) {
|
||||
result[group] = {};
|
||||
}
|
||||
const selectorsToSync = result[group];
|
||||
const value = item.innerHTML;
|
||||
if (!selectorsToSync[value]) {
|
||||
selectorsToSync[value] = [];
|
||||
}
|
||||
selectorsToSync[value].push(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function setupSelectorSync() {
|
||||
const selectorsToSync = findSelectorsToSyncByLanguage();
|
||||
Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => {
|
||||
Object.entries(tabSetsByValue).forEach(([value, items]) => {
|
||||
items.forEach((item) => {
|
||||
item.addEventListener("click", (_event) => {
|
||||
setTabState(group, value);
|
||||
toggleAll(value, selectorsToSync[group]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return selectorsToSync;
|
||||
}
|
||||
|
||||
const selectorsToSync = setupSelectorSync();
|
||||
for (const [group, selectedName] of Object.entries(getTabSettings())) {
|
||||
const selectors = selectorsToSync[group];
|
||||
// it's possible that stale state gives us empty selections, so we explicitly check here.
|
||||
if (selectors) {
|
||||
toggleAll(selectedName, selectors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
714
_site/sites/getstarted.html
Normal file
714
_site/sites/getstarted.html
Normal file
|
@ -0,0 +1,714 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="quarto-1.6.43">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
|
||||
|
||||
<title>Getting Started – DOCS</title>
|
||||
<style>
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
||||
div.column{flex: auto; overflow-x: auto;}
|
||||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||||
ul.task-list{list-style: none;}
|
||||
ul.task-list li input[type="checkbox"] {
|
||||
width: 0.8em;
|
||||
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* CSS for syntax highlighting */
|
||||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||||
pre > code.sourceCode > span { line-height: 1.25; }
|
||||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||||
.sourceCode { overflow: visible; }
|
||||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||||
div.sourceCode { margin: 1em 0; }
|
||||
pre.sourceCode { margin: 0; }
|
||||
@media screen {
|
||||
div.sourceCode { overflow: auto; }
|
||||
}
|
||||
@media print {
|
||||
pre > code.sourceCode { white-space: pre-wrap; }
|
||||
pre > code.sourceCode > span { display: inline-block; text-indent: -5em; padding-left: 5em; }
|
||||
}
|
||||
pre.numberSource code
|
||||
{ counter-reset: source-line 0; }
|
||||
pre.numberSource code > span
|
||||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||||
pre.numberSource code > span > a:first-child::before
|
||||
{ content: counter(source-line);
|
||||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||||
border: none; display: inline-block;
|
||||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||||
-khtml-user-select: none; -moz-user-select: none;
|
||||
-ms-user-select: none; user-select: none;
|
||||
padding: 0 4px; width: 4em;
|
||||
}
|
||||
pre.numberSource { margin-left: 3em; padding-left: 4px; }
|
||||
div.sourceCode
|
||||
{ }
|
||||
@media screen {
|
||||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script src="../site_libs/quarto-nav/quarto-nav.js"></script>
|
||||
<script src="../site_libs/quarto-nav/headroom.min.js"></script>
|
||||
<script src="../site_libs/clipboard/clipboard.min.js"></script>
|
||||
<script src="../site_libs/quarto-search/autocomplete.umd.js"></script>
|
||||
<script src="../site_libs/quarto-search/fuse.min.js"></script>
|
||||
<script src="../site_libs/quarto-search/quarto-search.js"></script>
|
||||
<meta name="quarto:offset" content="../">
|
||||
<script src="../site_libs/quarto-html/quarto.js"></script>
|
||||
<script src="../site_libs/quarto-html/popper.min.js"></script>
|
||||
<script src="../site_libs/quarto-html/tippy.umd.min.js"></script>
|
||||
<script src="../site_libs/quarto-html/anchor.min.js"></script>
|
||||
<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet">
|
||||
<link href="../site_libs/quarto-html/quarto-syntax-highlighting-d4d76bf8491c20bad77d141916dc28e1.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||
<script src="../site_libs/bootstrap/bootstrap.min.js"></script>
|
||||
<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="../site_libs/bootstrap/bootstrap-040fcd844c9d9710447b707c0ff8ce03.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||
<script id="quarto-search-options" type="application/json">{
|
||||
"location": "navbar",
|
||||
"copy-button": false,
|
||||
"collapse-after": 3,
|
||||
"panel-placement": "end",
|
||||
"type": "overlay",
|
||||
"limit": 50,
|
||||
"keyboard-shortcut": [
|
||||
"f",
|
||||
"/",
|
||||
"s"
|
||||
],
|
||||
"show-item-context": false,
|
||||
"language": {
|
||||
"search-no-results-text": "No results",
|
||||
"search-matching-documents-text": "matching documents",
|
||||
"search-copy-link-title": "Copy link to search",
|
||||
"search-hide-matches-text": "Hide additional matches",
|
||||
"search-more-match-text": "more match in this document",
|
||||
"search-more-matches-text": "more matches in this document",
|
||||
"search-clear-button-title": "Clear",
|
||||
"search-text-placeholder": "",
|
||||
"search-detached-cancel-button-title": "Cancel",
|
||||
"search-submit-button-title": "Submit",
|
||||
"search-label": "Search"
|
||||
}
|
||||
}</script>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
</head>
|
||||
|
||||
<body class="nav-sidebar docked nav-fixed">
|
||||
|
||||
<div id="quarto-search-results"></div>
|
||||
<header id="quarto-header" class="headroom fixed-top">
|
||||
<nav class="navbar navbar-expand-lg " data-bs-theme="dark">
|
||||
<div class="navbar-container container-fluid">
|
||||
<div class="navbar-brand-container mx-auto">
|
||||
<a class="navbar-brand" href="../index.html">
|
||||
<span class="navbar-title">DOCS</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav navbar-nav-scroll me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://virtuos.world">
|
||||
<span class="menu-text">Homepage</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div> <!-- /navcollapse -->
|
||||
<div class="quarto-navbar-tools">
|
||||
<a href="" class="quarto-reader-toggle quarto-navigation-tool px-1" onclick="window.quartoToggleReader(); return false;" title="Toggle reader mode">
|
||||
<div class="quarto-reader-toggle-btn">
|
||||
<i class="bi"></i>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div> <!-- /container-fluid -->
|
||||
</nav>
|
||||
<nav class="quarto-secondary-nav">
|
||||
<div class="container-fluid d-flex">
|
||||
<button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" role="button" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
<i class="bi bi-layout-text-sidebar-reverse"></i>
|
||||
</button>
|
||||
<nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="../sites/getstarted.html">Getting Started</a></li></ol></nav>
|
||||
<a class="flex-grow-1" role="navigation" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
</a>
|
||||
<button type="button" class="btn quarto-search-button" aria-label="Search" onclick="window.quartoOpenSearch();">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<!-- content -->
|
||||
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
|
||||
<!-- sidebar -->
|
||||
<nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal quarto-sidebar-collapse-item sidebar-navigation docked overflow-auto">
|
||||
<div class="mt-2 flex-shrink-0 align-items-center">
|
||||
<div class="sidebar-search">
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-menu-container">
|
||||
<ul class="list-unstyled mt-1">
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<span class="sidebar-item-text sidebar-link text-start">
|
||||
<span class="menu-text">Overview</span></span>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<div class="sidebar-item-container">
|
||||
<a href="../sites/styleguide.html" class="sidebar-item-text sidebar-link">
|
||||
<span class="menu-text">Styleguide</span></a>
|
||||
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" role="navigation" aria-expanded="true" aria-label="Toggle section">
|
||||
<i class="bi bi-chevron-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show">
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-knitr.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-jupyter.qmd</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<div class="sidebar-item-container">
|
||||
<a href="../sites/webservices.html" class="sidebar-item-text sidebar-link">
|
||||
<span class="menu-text">Webservices</span></a>
|
||||
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" role="navigation" aria-expanded="true" aria-label="Toggle section">
|
||||
<i class="bi bi-chevron-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth1 show">
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-knitr.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-jupyter.qmd</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<span class="sidebar-item-text sidebar-link text-start">
|
||||
<span class="menu-text">Getting Started</span></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="quarto-sidebar-glass" class="quarto-sidebar-collapse-item" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item"></div>
|
||||
<!-- margin-sidebar -->
|
||||
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
|
||||
<nav id="TOC" role="doc-toc" class="toc-active">
|
||||
<h2 id="toc-title">On this page</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="#setting-up-the-project-with-ue5" id="toc-setting-up-the-project-with-ue5" class="nav-link active" data-scroll-target="#setting-up-the-project-with-ue5">Setting up the project with UE5</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- main -->
|
||||
<main class="content" id="quarto-document-content">
|
||||
|
||||
<header id="title-block-header" class="quarto-title-block default">
|
||||
<div class="quarto-title">
|
||||
<h1 class="title">Getting Started</h1>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="quarto-title-meta">
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
|
||||
<p>If you want to take a look inside a project, there are currently three important repositories:</p>
|
||||
<ul>
|
||||
<li>VIRTUOS_Playground: The repository contains the Unreal Engine Project</li>
|
||||
<li>VIRTUOS_Assets: Contains all Project related assets like 3D-Models, Graphics etc.</li>
|
||||
<li>VIRTUOS_Documents: Contains all written Documents</li>
|
||||
</ul>
|
||||
<section id="setting-up-the-project-with-ue5" class="level1">
|
||||
<h1>Setting up the project with UE5</h1>
|
||||
<p>If you’re familiar with Git, you’ll likely already know how to get the files.</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> pull https://code.virtuos.world/VIRTUOS_WORLD/VIRTUOS_Docs.git</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<p>If you’re not comforatable with the command line, you can install a Git GUI like Github Desktop.</p>
|
||||
<iframe width="100%" height="500" src="https://blueprintue.com/render/-azlwrm2/" scrolling="no" allowfullscreen=""></iframe>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
</main> <!-- /main -->
|
||||
<script id="quarto-html-after-body" type="application/javascript">
|
||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||
const toggleBodyColorMode = (bsSheetEl) => {
|
||||
const mode = bsSheetEl.getAttribute("data-mode");
|
||||
const bodyEl = window.document.querySelector("body");
|
||||
if (mode === "dark") {
|
||||
bodyEl.classList.add("quarto-dark");
|
||||
bodyEl.classList.remove("quarto-light");
|
||||
} else {
|
||||
bodyEl.classList.add("quarto-light");
|
||||
bodyEl.classList.remove("quarto-dark");
|
||||
}
|
||||
}
|
||||
const toggleBodyColorPrimary = () => {
|
||||
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
|
||||
if (bsSheetEl) {
|
||||
toggleBodyColorMode(bsSheetEl);
|
||||
}
|
||||
}
|
||||
toggleBodyColorPrimary();
|
||||
const icon = "";
|
||||
const anchorJS = new window.AnchorJS();
|
||||
anchorJS.options = {
|
||||
placement: 'right',
|
||||
icon: icon
|
||||
};
|
||||
anchorJS.add('.anchored');
|
||||
const isCodeAnnotation = (el) => {
|
||||
for (const clz of el.classList) {
|
||||
if (clz.startsWith('code-annotation-')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const onCopySuccess = function(e) {
|
||||
// button target
|
||||
const button = e.trigger;
|
||||
// don't keep focus
|
||||
button.blur();
|
||||
// flash "checked"
|
||||
button.classList.add('code-copy-button-checked');
|
||||
var currentTitle = button.getAttribute("title");
|
||||
button.setAttribute("title", "Copied!");
|
||||
let tooltip;
|
||||
if (window.bootstrap) {
|
||||
button.setAttribute("data-bs-toggle", "tooltip");
|
||||
button.setAttribute("data-bs-placement", "left");
|
||||
button.setAttribute("data-bs-title", "Copied!");
|
||||
tooltip = new bootstrap.Tooltip(button,
|
||||
{ trigger: "manual",
|
||||
customClass: "code-copy-button-tooltip",
|
||||
offset: [0, -8]});
|
||||
tooltip.show();
|
||||
}
|
||||
setTimeout(function() {
|
||||
if (tooltip) {
|
||||
tooltip.hide();
|
||||
button.removeAttribute("data-bs-title");
|
||||
button.removeAttribute("data-bs-toggle");
|
||||
button.removeAttribute("data-bs-placement");
|
||||
}
|
||||
button.setAttribute("title", currentTitle);
|
||||
button.classList.remove('code-copy-button-checked');
|
||||
}, 1000);
|
||||
// clear code selection
|
||||
e.clearSelection();
|
||||
}
|
||||
const getTextToCopy = function(trigger) {
|
||||
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
||||
for (const childEl of codeEl.children) {
|
||||
if (isCodeAnnotation(childEl)) {
|
||||
childEl.remove();
|
||||
}
|
||||
}
|
||||
return codeEl.innerText;
|
||||
}
|
||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||
text: getTextToCopy
|
||||
});
|
||||
clipboard.on('success', onCopySuccess);
|
||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||
text: getTextToCopy,
|
||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||
});
|
||||
clipboardModal.on('success', onCopySuccess);
|
||||
}
|
||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||
var mailtoRegex = new RegExp(/^mailto:/);
|
||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||
var isInternal = (href) => {
|
||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||
}
|
||||
// Inspect non-navigation links and adorn them if external
|
||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||
for (var i=0; i<links.length; i++) {
|
||||
const link = links[i];
|
||||
if (!isInternal(link.href)) {
|
||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||
// links that we want to consider external
|
||||
if (link.dataset.originalHref !== undefined) {
|
||||
link.href = link.dataset.originalHref;
|
||||
}
|
||||
}
|
||||
}
|
||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||
const config = {
|
||||
allowHTML: true,
|
||||
maxWidth: 500,
|
||||
delay: 100,
|
||||
arrow: false,
|
||||
appendTo: function(el) {
|
||||
return el.parentElement;
|
||||
},
|
||||
interactive: true,
|
||||
interactiveBorder: 10,
|
||||
theme: 'quarto',
|
||||
placement: 'bottom-start',
|
||||
};
|
||||
if (contentFn) {
|
||||
config.content = contentFn;
|
||||
}
|
||||
if (onTriggerFn) {
|
||||
config.onTrigger = onTriggerFn;
|
||||
}
|
||||
if (onUntriggerFn) {
|
||||
config.onUntrigger = onUntriggerFn;
|
||||
}
|
||||
window.tippy(el, config);
|
||||
}
|
||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||
for (var i=0; i<noterefs.length; i++) {
|
||||
const ref = noterefs[i];
|
||||
tippyHover(ref, function() {
|
||||
// use id or data attribute instead here
|
||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||
try { href = new URL(href).hash; } catch {}
|
||||
const id = href.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note) {
|
||||
return note.innerHTML;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||
const processXRef = (id, note) => {
|
||||
// Strip column container classes
|
||||
const stripColumnClz = (el) => {
|
||||
el.classList.remove("page-full", "page-columns");
|
||||
if (el.children) {
|
||||
for (const child of el.children) {
|
||||
stripColumnClz(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
stripColumnClz(note)
|
||||
if (id === null || id.startsWith('sec-')) {
|
||||
// Special case sections, only their first couple elements
|
||||
const container = document.createElement("div");
|
||||
if (note.children && note.children.length > 2) {
|
||||
container.appendChild(note.children[0].cloneNode(true));
|
||||
for (let i = 1; i < note.children.length; i++) {
|
||||
const child = note.children[i];
|
||||
if (child.tagName === "P" && child.innerText === "") {
|
||||
continue;
|
||||
} else {
|
||||
container.appendChild(child.cloneNode(true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(container);
|
||||
}
|
||||
return container.innerHTML
|
||||
} else {
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
return note.innerHTML;
|
||||
}
|
||||
} else {
|
||||
// Remove any anchor links if they are present
|
||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||
if (anchorLink) {
|
||||
anchorLink.remove();
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
if (note.classList.contains("callout")) {
|
||||
return note.outerHTML;
|
||||
} else {
|
||||
return note.innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i=0; i<xrefs.length; i++) {
|
||||
const xref = xrefs[i];
|
||||
tippyHover(xref, undefined, function(instance) {
|
||||
instance.disable();
|
||||
let url = xref.getAttribute('href');
|
||||
let hash = undefined;
|
||||
if (url.startsWith('#')) {
|
||||
hash = url;
|
||||
} else {
|
||||
try { hash = new URL(url).hash; } catch {}
|
||||
}
|
||||
if (hash) {
|
||||
const id = hash.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note !== null) {
|
||||
try {
|
||||
const html = processXRef(id, note.cloneNode(true));
|
||||
instance.setContent(html);
|
||||
} finally {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch this
|
||||
fetch(url.split('#')[0])
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.getElementById(id);
|
||||
if (note !== null) {
|
||||
const html = processXRef(id, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch a full url (with no hash to target)
|
||||
// This is a special case and we should probably do some content thinning / targeting
|
||||
fetch(url)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.querySelector('main.content');
|
||||
if (note !== null) {
|
||||
// This should only happen for chapter cross references
|
||||
// (since there is no id in the URL)
|
||||
// remove the first header
|
||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||
note.children[0].remove();
|
||||
}
|
||||
const html = processXRef(null, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
}, function(instance) {
|
||||
});
|
||||
}
|
||||
let selectedAnnoteEl;
|
||||
const selectorForAnnotation = ( cell, annotation) => {
|
||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||
return selector;
|
||||
}
|
||||
const selectCodeLines = (annoteEl) => {
|
||||
const doc = window.document;
|
||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||
const lineIds = lines.map((line) => {
|
||||
return targetCell + "-" + line;
|
||||
})
|
||||
let top = null;
|
||||
let height = null;
|
||||
let parent = null;
|
||||
if (lineIds.length > 0) {
|
||||
//compute the position of the single el (top and bottom and make a div)
|
||||
const el = window.document.getElementById(lineIds[0]);
|
||||
top = el.offsetTop;
|
||||
height = el.offsetHeight;
|
||||
parent = el.parentElement.parentElement;
|
||||
if (lineIds.length > 1) {
|
||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||
height = bottom - top;
|
||||
}
|
||||
if (top !== null && height !== null && parent !== null) {
|
||||
// cook up a div (if necessary) and position it
|
||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||
if (div === null) {
|
||||
div = window.document.createElement("div");
|
||||
div.setAttribute("id", "code-annotation-line-highlight");
|
||||
div.style.position = 'absolute';
|
||||
parent.appendChild(div);
|
||||
}
|
||||
div.style.top = top - 2 + "px";
|
||||
div.style.height = height + 4 + "px";
|
||||
div.style.left = 0;
|
||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||
if (gutterDiv === null) {
|
||||
gutterDiv = window.document.createElement("div");
|
||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||
gutterDiv.style.position = 'absolute';
|
||||
const codeCell = window.document.getElementById(targetCell);
|
||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||
gutter.appendChild(gutterDiv);
|
||||
}
|
||||
gutterDiv.style.top = top - 2 + "px";
|
||||
gutterDiv.style.height = height + 4 + "px";
|
||||
}
|
||||
selectedAnnoteEl = annoteEl;
|
||||
}
|
||||
};
|
||||
const unselectCodeLines = () => {
|
||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||
elementsIds.forEach((elId) => {
|
||||
const div = window.document.getElementById(elId);
|
||||
if (div) {
|
||||
div.remove();
|
||||
}
|
||||
});
|
||||
selectedAnnoteEl = undefined;
|
||||
};
|
||||
// Handle positioning of the toggle
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
elRect = undefined;
|
||||
if (selectedAnnoteEl) {
|
||||
selectCodeLines(selectedAnnoteEl);
|
||||
}
|
||||
}, 10)
|
||||
);
|
||||
function throttle(fn, ms) {
|
||||
let throttle = false;
|
||||
let timer;
|
||||
return (...args) => {
|
||||
if(!throttle) { // first call gets through
|
||||
fn.apply(this, args);
|
||||
throttle = true;
|
||||
} else { // all the others get throttled
|
||||
if(timer) clearTimeout(timer); // cancel #2
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
timer = throttle = false;
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
}
|
||||
// Attach click handler to the DT
|
||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||
for (const annoteDlNode of annoteDls) {
|
||||
annoteDlNode.addEventListener('click', (event) => {
|
||||
const clickedEl = event.target;
|
||||
if (clickedEl !== selectedAnnoteEl) {
|
||||
unselectCodeLines();
|
||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||
if (activeEl) {
|
||||
activeEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
selectCodeLines(clickedEl);
|
||||
clickedEl.classList.add('code-annotation-active');
|
||||
} else {
|
||||
// Unselect the line
|
||||
unselectCodeLines();
|
||||
clickedEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
const findCites = (el) => {
|
||||
const parentEl = el.parentElement;
|
||||
if (parentEl) {
|
||||
const cites = parentEl.dataset.cites;
|
||||
if (cites) {
|
||||
return {
|
||||
el,
|
||||
cites: cites.split(' ')
|
||||
};
|
||||
} else {
|
||||
return findCites(el.parentElement)
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||
for (var i=0; i<bibliorefs.length; i++) {
|
||||
const ref = bibliorefs[i];
|
||||
const citeInfo = findCites(ref);
|
||||
if (citeInfo) {
|
||||
tippyHover(citeInfo.el, function() {
|
||||
var popup = window.document.createElement('div');
|
||||
citeInfo.cites.forEach(function(cite) {
|
||||
var citeDiv = window.document.createElement('div');
|
||||
citeDiv.classList.add('hanging-indent');
|
||||
citeDiv.classList.add('csl-entry');
|
||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||
if (biblioDiv) {
|
||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||
}
|
||||
popup.appendChild(citeDiv);
|
||||
});
|
||||
return popup.innerHTML;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div> <!-- /content -->
|
||||
<footer class="footer">
|
||||
<div class="nav-footer">
|
||||
<div class="nav-footer-left">
|
||||
<p>Copyright 2025, Simeon Wallrath</p>
|
||||
</div>
|
||||
<div class="nav-footer-center">
|
||||
|
||||
</div>
|
||||
<div class="nav-footer-right">
|
||||
<ul class="footer-items list-unstyled">
|
||||
<li class="nav-item compact">
|
||||
<a class="nav-link" href="https://github.com/">
|
||||
<i class="bi bi-github" role="img">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item compact">
|
||||
<a class="nav-link" href="https://twitter.com/">
|
||||
<i class="bi bi-mastodon" role="img">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
|
||||
|
||||
</body></html>
|
649
_site/sites/overview.html
Normal file
649
_site/sites/overview.html
Normal file
|
@ -0,0 +1,649 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="quarto-1.6.43">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
|
||||
|
||||
<title>About – DOCS</title>
|
||||
<style>
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
||||
div.column{flex: auto; overflow-x: auto;}
|
||||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||||
ul.task-list{list-style: none;}
|
||||
ul.task-list li input[type="checkbox"] {
|
||||
width: 0.8em;
|
||||
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script src="../site_libs/quarto-nav/quarto-nav.js"></script>
|
||||
<script src="../site_libs/quarto-nav/headroom.min.js"></script>
|
||||
<script src="../site_libs/clipboard/clipboard.min.js"></script>
|
||||
<script src="../site_libs/quarto-search/autocomplete.umd.js"></script>
|
||||
<script src="../site_libs/quarto-search/fuse.min.js"></script>
|
||||
<script src="../site_libs/quarto-search/quarto-search.js"></script>
|
||||
<meta name="quarto:offset" content="../">
|
||||
<script src="../site_libs/quarto-html/quarto.js"></script>
|
||||
<script src="../site_libs/quarto-html/popper.min.js"></script>
|
||||
<script src="../site_libs/quarto-html/tippy.umd.min.js"></script>
|
||||
<script src="../site_libs/quarto-html/anchor.min.js"></script>
|
||||
<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet">
|
||||
<link href="../site_libs/quarto-html/quarto-syntax-highlighting-d4d76bf8491c20bad77d141916dc28e1.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||
<script src="../site_libs/bootstrap/bootstrap.min.js"></script>
|
||||
<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="../site_libs/bootstrap/bootstrap-ab2165296c2394069beed34e014f8abd.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||
<script id="quarto-search-options" type="application/json">{
|
||||
"location": "navbar",
|
||||
"copy-button": false,
|
||||
"collapse-after": 3,
|
||||
"panel-placement": "end",
|
||||
"type": "overlay",
|
||||
"limit": 50,
|
||||
"keyboard-shortcut": [
|
||||
"f",
|
||||
"/",
|
||||
"s"
|
||||
],
|
||||
"show-item-context": false,
|
||||
"language": {
|
||||
"search-no-results-text": "No results",
|
||||
"search-matching-documents-text": "matching documents",
|
||||
"search-copy-link-title": "Copy link to search",
|
||||
"search-hide-matches-text": "Hide additional matches",
|
||||
"search-more-match-text": "more match in this document",
|
||||
"search-more-matches-text": "more matches in this document",
|
||||
"search-clear-button-title": "Clear",
|
||||
"search-text-placeholder": "",
|
||||
"search-detached-cancel-button-title": "Cancel",
|
||||
"search-submit-button-title": "Submit",
|
||||
"search-label": "Search"
|
||||
}
|
||||
}</script>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
</head>
|
||||
|
||||
<body class="nav-sidebar docked nav-fixed">
|
||||
|
||||
<div id="quarto-search-results"></div>
|
||||
<header id="quarto-header" class="headroom fixed-top">
|
||||
<nav class="navbar navbar-expand-lg " data-bs-theme="dark">
|
||||
<div class="navbar-container container-fluid">
|
||||
<div class="navbar-brand-container mx-auto">
|
||||
<a class="navbar-brand" href="../index.html">
|
||||
<span class="navbar-title">DOCS</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav navbar-nav-scroll me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://virtuos.world">
|
||||
<span class="menu-text">Homepage</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div> <!-- /navcollapse -->
|
||||
<div class="quarto-navbar-tools">
|
||||
<a href="" class="quarto-reader-toggle quarto-navigation-tool px-1" onclick="window.quartoToggleReader(); return false;" title="Toggle reader mode">
|
||||
<div class="quarto-reader-toggle-btn">
|
||||
<i class="bi"></i>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div> <!-- /container-fluid -->
|
||||
</nav>
|
||||
<nav class="quarto-secondary-nav">
|
||||
<div class="container-fluid d-flex">
|
||||
<button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" role="button" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
<i class="bi bi-layout-text-sidebar-reverse"></i>
|
||||
</button>
|
||||
<nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="../sites/overview.html">Overview</a></li></ol></nav>
|
||||
<a class="flex-grow-1" role="navigation" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
</a>
|
||||
<button type="button" class="btn quarto-search-button" aria-label="Search" onclick="window.quartoOpenSearch();">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<!-- content -->
|
||||
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
|
||||
<!-- sidebar -->
|
||||
<nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal quarto-sidebar-collapse-item sidebar-navigation docked overflow-auto">
|
||||
<div class="mt-2 flex-shrink-0 align-items-center">
|
||||
<div class="sidebar-search">
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-menu-container">
|
||||
<ul class="list-unstyled mt-1">
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<span class="sidebar-item-text sidebar-link text-start">
|
||||
<span class="menu-text">Overview</span></span>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<div class="sidebar-item-container">
|
||||
<a href="../sites/styleguide.html" class="sidebar-item-text sidebar-link">
|
||||
<span class="menu-text">Styleguide</span></a>
|
||||
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" role="navigation" aria-expanded="true" aria-label="Toggle section">
|
||||
<i class="bi bi-chevron-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show">
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-knitr.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-jupyter.qmd</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<div class="sidebar-item-container">
|
||||
<a href="../sites/webservices.html" class="sidebar-item-text sidebar-link">
|
||||
<span class="menu-text">Webservices</span></a>
|
||||
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" role="navigation" aria-expanded="true" aria-label="Toggle section">
|
||||
<i class="bi bi-chevron-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth1 show">
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-knitr.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-jupyter.qmd</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<div class="sidebar-item-container">
|
||||
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" role="navigation" aria-expanded="true">
|
||||
<span class="menu-text">advanced.qmd</span></a>
|
||||
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" role="navigation" aria-expanded="true" aria-label="Toggle section">
|
||||
<i class="bi bi-chevron-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth1 show">
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">raw-code.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">custom-theme.qmd</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="quarto-sidebar-glass" class="quarto-sidebar-collapse-item" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item"></div>
|
||||
<!-- margin-sidebar -->
|
||||
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar zindex-bottom">
|
||||
|
||||
</div>
|
||||
<!-- main -->
|
||||
<main class="content" id="quarto-document-content">
|
||||
|
||||
<header id="title-block-header" class="quarto-title-block default">
|
||||
<div class="quarto-title">
|
||||
<h1 class="title">About</h1>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="quarto-title-meta">
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
|
||||
<p>About this site</p>
|
||||
|
||||
|
||||
|
||||
</main> <!-- /main -->
|
||||
<script id="quarto-html-after-body" type="application/javascript">
|
||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||
const toggleBodyColorMode = (bsSheetEl) => {
|
||||
const mode = bsSheetEl.getAttribute("data-mode");
|
||||
const bodyEl = window.document.querySelector("body");
|
||||
if (mode === "dark") {
|
||||
bodyEl.classList.add("quarto-dark");
|
||||
bodyEl.classList.remove("quarto-light");
|
||||
} else {
|
||||
bodyEl.classList.add("quarto-light");
|
||||
bodyEl.classList.remove("quarto-dark");
|
||||
}
|
||||
}
|
||||
const toggleBodyColorPrimary = () => {
|
||||
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
|
||||
if (bsSheetEl) {
|
||||
toggleBodyColorMode(bsSheetEl);
|
||||
}
|
||||
}
|
||||
toggleBodyColorPrimary();
|
||||
const icon = "";
|
||||
const anchorJS = new window.AnchorJS();
|
||||
anchorJS.options = {
|
||||
placement: 'right',
|
||||
icon: icon
|
||||
};
|
||||
anchorJS.add('.anchored');
|
||||
const isCodeAnnotation = (el) => {
|
||||
for (const clz of el.classList) {
|
||||
if (clz.startsWith('code-annotation-')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const onCopySuccess = function(e) {
|
||||
// button target
|
||||
const button = e.trigger;
|
||||
// don't keep focus
|
||||
button.blur();
|
||||
// flash "checked"
|
||||
button.classList.add('code-copy-button-checked');
|
||||
var currentTitle = button.getAttribute("title");
|
||||
button.setAttribute("title", "Copied!");
|
||||
let tooltip;
|
||||
if (window.bootstrap) {
|
||||
button.setAttribute("data-bs-toggle", "tooltip");
|
||||
button.setAttribute("data-bs-placement", "left");
|
||||
button.setAttribute("data-bs-title", "Copied!");
|
||||
tooltip = new bootstrap.Tooltip(button,
|
||||
{ trigger: "manual",
|
||||
customClass: "code-copy-button-tooltip",
|
||||
offset: [0, -8]});
|
||||
tooltip.show();
|
||||
}
|
||||
setTimeout(function() {
|
||||
if (tooltip) {
|
||||
tooltip.hide();
|
||||
button.removeAttribute("data-bs-title");
|
||||
button.removeAttribute("data-bs-toggle");
|
||||
button.removeAttribute("data-bs-placement");
|
||||
}
|
||||
button.setAttribute("title", currentTitle);
|
||||
button.classList.remove('code-copy-button-checked');
|
||||
}, 1000);
|
||||
// clear code selection
|
||||
e.clearSelection();
|
||||
}
|
||||
const getTextToCopy = function(trigger) {
|
||||
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
||||
for (const childEl of codeEl.children) {
|
||||
if (isCodeAnnotation(childEl)) {
|
||||
childEl.remove();
|
||||
}
|
||||
}
|
||||
return codeEl.innerText;
|
||||
}
|
||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||
text: getTextToCopy
|
||||
});
|
||||
clipboard.on('success', onCopySuccess);
|
||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||
text: getTextToCopy,
|
||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||
});
|
||||
clipboardModal.on('success', onCopySuccess);
|
||||
}
|
||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||
var mailtoRegex = new RegExp(/^mailto:/);
|
||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||
var isInternal = (href) => {
|
||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||
}
|
||||
// Inspect non-navigation links and adorn them if external
|
||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||
for (var i=0; i<links.length; i++) {
|
||||
const link = links[i];
|
||||
if (!isInternal(link.href)) {
|
||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||
// links that we want to consider external
|
||||
if (link.dataset.originalHref !== undefined) {
|
||||
link.href = link.dataset.originalHref;
|
||||
}
|
||||
}
|
||||
}
|
||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||
const config = {
|
||||
allowHTML: true,
|
||||
maxWidth: 500,
|
||||
delay: 100,
|
||||
arrow: false,
|
||||
appendTo: function(el) {
|
||||
return el.parentElement;
|
||||
},
|
||||
interactive: true,
|
||||
interactiveBorder: 10,
|
||||
theme: 'quarto',
|
||||
placement: 'bottom-start',
|
||||
};
|
||||
if (contentFn) {
|
||||
config.content = contentFn;
|
||||
}
|
||||
if (onTriggerFn) {
|
||||
config.onTrigger = onTriggerFn;
|
||||
}
|
||||
if (onUntriggerFn) {
|
||||
config.onUntrigger = onUntriggerFn;
|
||||
}
|
||||
window.tippy(el, config);
|
||||
}
|
||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||
for (var i=0; i<noterefs.length; i++) {
|
||||
const ref = noterefs[i];
|
||||
tippyHover(ref, function() {
|
||||
// use id or data attribute instead here
|
||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||
try { href = new URL(href).hash; } catch {}
|
||||
const id = href.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note) {
|
||||
return note.innerHTML;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||
const processXRef = (id, note) => {
|
||||
// Strip column container classes
|
||||
const stripColumnClz = (el) => {
|
||||
el.classList.remove("page-full", "page-columns");
|
||||
if (el.children) {
|
||||
for (const child of el.children) {
|
||||
stripColumnClz(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
stripColumnClz(note)
|
||||
if (id === null || id.startsWith('sec-')) {
|
||||
// Special case sections, only their first couple elements
|
||||
const container = document.createElement("div");
|
||||
if (note.children && note.children.length > 2) {
|
||||
container.appendChild(note.children[0].cloneNode(true));
|
||||
for (let i = 1; i < note.children.length; i++) {
|
||||
const child = note.children[i];
|
||||
if (child.tagName === "P" && child.innerText === "") {
|
||||
continue;
|
||||
} else {
|
||||
container.appendChild(child.cloneNode(true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(container);
|
||||
}
|
||||
return container.innerHTML
|
||||
} else {
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
return note.innerHTML;
|
||||
}
|
||||
} else {
|
||||
// Remove any anchor links if they are present
|
||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||
if (anchorLink) {
|
||||
anchorLink.remove();
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
if (note.classList.contains("callout")) {
|
||||
return note.outerHTML;
|
||||
} else {
|
||||
return note.innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i=0; i<xrefs.length; i++) {
|
||||
const xref = xrefs[i];
|
||||
tippyHover(xref, undefined, function(instance) {
|
||||
instance.disable();
|
||||
let url = xref.getAttribute('href');
|
||||
let hash = undefined;
|
||||
if (url.startsWith('#')) {
|
||||
hash = url;
|
||||
} else {
|
||||
try { hash = new URL(url).hash; } catch {}
|
||||
}
|
||||
if (hash) {
|
||||
const id = hash.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note !== null) {
|
||||
try {
|
||||
const html = processXRef(id, note.cloneNode(true));
|
||||
instance.setContent(html);
|
||||
} finally {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch this
|
||||
fetch(url.split('#')[0])
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.getElementById(id);
|
||||
if (note !== null) {
|
||||
const html = processXRef(id, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch a full url (with no hash to target)
|
||||
// This is a special case and we should probably do some content thinning / targeting
|
||||
fetch(url)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.querySelector('main.content');
|
||||
if (note !== null) {
|
||||
// This should only happen for chapter cross references
|
||||
// (since there is no id in the URL)
|
||||
// remove the first header
|
||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||
note.children[0].remove();
|
||||
}
|
||||
const html = processXRef(null, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
}, function(instance) {
|
||||
});
|
||||
}
|
||||
let selectedAnnoteEl;
|
||||
const selectorForAnnotation = ( cell, annotation) => {
|
||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||
return selector;
|
||||
}
|
||||
const selectCodeLines = (annoteEl) => {
|
||||
const doc = window.document;
|
||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||
const lineIds = lines.map((line) => {
|
||||
return targetCell + "-" + line;
|
||||
})
|
||||
let top = null;
|
||||
let height = null;
|
||||
let parent = null;
|
||||
if (lineIds.length > 0) {
|
||||
//compute the position of the single el (top and bottom and make a div)
|
||||
const el = window.document.getElementById(lineIds[0]);
|
||||
top = el.offsetTop;
|
||||
height = el.offsetHeight;
|
||||
parent = el.parentElement.parentElement;
|
||||
if (lineIds.length > 1) {
|
||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||
height = bottom - top;
|
||||
}
|
||||
if (top !== null && height !== null && parent !== null) {
|
||||
// cook up a div (if necessary) and position it
|
||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||
if (div === null) {
|
||||
div = window.document.createElement("div");
|
||||
div.setAttribute("id", "code-annotation-line-highlight");
|
||||
div.style.position = 'absolute';
|
||||
parent.appendChild(div);
|
||||
}
|
||||
div.style.top = top - 2 + "px";
|
||||
div.style.height = height + 4 + "px";
|
||||
div.style.left = 0;
|
||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||
if (gutterDiv === null) {
|
||||
gutterDiv = window.document.createElement("div");
|
||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||
gutterDiv.style.position = 'absolute';
|
||||
const codeCell = window.document.getElementById(targetCell);
|
||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||
gutter.appendChild(gutterDiv);
|
||||
}
|
||||
gutterDiv.style.top = top - 2 + "px";
|
||||
gutterDiv.style.height = height + 4 + "px";
|
||||
}
|
||||
selectedAnnoteEl = annoteEl;
|
||||
}
|
||||
};
|
||||
const unselectCodeLines = () => {
|
||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||
elementsIds.forEach((elId) => {
|
||||
const div = window.document.getElementById(elId);
|
||||
if (div) {
|
||||
div.remove();
|
||||
}
|
||||
});
|
||||
selectedAnnoteEl = undefined;
|
||||
};
|
||||
// Handle positioning of the toggle
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
elRect = undefined;
|
||||
if (selectedAnnoteEl) {
|
||||
selectCodeLines(selectedAnnoteEl);
|
||||
}
|
||||
}, 10)
|
||||
);
|
||||
function throttle(fn, ms) {
|
||||
let throttle = false;
|
||||
let timer;
|
||||
return (...args) => {
|
||||
if(!throttle) { // first call gets through
|
||||
fn.apply(this, args);
|
||||
throttle = true;
|
||||
} else { // all the others get throttled
|
||||
if(timer) clearTimeout(timer); // cancel #2
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
timer = throttle = false;
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
}
|
||||
// Attach click handler to the DT
|
||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||
for (const annoteDlNode of annoteDls) {
|
||||
annoteDlNode.addEventListener('click', (event) => {
|
||||
const clickedEl = event.target;
|
||||
if (clickedEl !== selectedAnnoteEl) {
|
||||
unselectCodeLines();
|
||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||
if (activeEl) {
|
||||
activeEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
selectCodeLines(clickedEl);
|
||||
clickedEl.classList.add('code-annotation-active');
|
||||
} else {
|
||||
// Unselect the line
|
||||
unselectCodeLines();
|
||||
clickedEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
const findCites = (el) => {
|
||||
const parentEl = el.parentElement;
|
||||
if (parentEl) {
|
||||
const cites = parentEl.dataset.cites;
|
||||
if (cites) {
|
||||
return {
|
||||
el,
|
||||
cites: cites.split(' ')
|
||||
};
|
||||
} else {
|
||||
return findCites(el.parentElement)
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||
for (var i=0; i<bibliorefs.length; i++) {
|
||||
const ref = bibliorefs[i];
|
||||
const citeInfo = findCites(ref);
|
||||
if (citeInfo) {
|
||||
tippyHover(citeInfo.el, function() {
|
||||
var popup = window.document.createElement('div');
|
||||
citeInfo.cites.forEach(function(cite) {
|
||||
var citeDiv = window.document.createElement('div');
|
||||
citeDiv.classList.add('hanging-indent');
|
||||
citeDiv.classList.add('csl-entry');
|
||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||
if (biblioDiv) {
|
||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||
}
|
||||
popup.appendChild(citeDiv);
|
||||
});
|
||||
return popup.innerHTML;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div> <!-- /content -->
|
||||
|
||||
|
||||
|
||||
|
||||
</body></html>
|
2892
_site/sites/styleguide.html
Normal file
2892
_site/sites/styleguide.html
Normal file
File diff suppressed because it is too large
Load diff
996
_site/sites/webservices.html
Normal file
996
_site/sites/webservices.html
Normal file
|
@ -0,0 +1,996 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="quarto-1.6.43">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
|
||||
|
||||
<title>Websevices – DOCS</title>
|
||||
<style>
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
||||
div.column{flex: auto; overflow-x: auto;}
|
||||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||||
ul.task-list{list-style: none;}
|
||||
ul.task-list li input[type="checkbox"] {
|
||||
width: 0.8em;
|
||||
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* CSS for syntax highlighting */
|
||||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||||
pre > code.sourceCode > span { line-height: 1.25; }
|
||||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||||
.sourceCode { overflow: visible; }
|
||||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||||
div.sourceCode { margin: 1em 0; }
|
||||
pre.sourceCode { margin: 0; }
|
||||
@media screen {
|
||||
div.sourceCode { overflow: auto; }
|
||||
}
|
||||
@media print {
|
||||
pre > code.sourceCode { white-space: pre-wrap; }
|
||||
pre > code.sourceCode > span { display: inline-block; text-indent: -5em; padding-left: 5em; }
|
||||
}
|
||||
pre.numberSource code
|
||||
{ counter-reset: source-line 0; }
|
||||
pre.numberSource code > span
|
||||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||||
pre.numberSource code > span > a:first-child::before
|
||||
{ content: counter(source-line);
|
||||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||||
border: none; display: inline-block;
|
||||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||||
-khtml-user-select: none; -moz-user-select: none;
|
||||
-ms-user-select: none; user-select: none;
|
||||
padding: 0 4px; width: 4em;
|
||||
}
|
||||
pre.numberSource { margin-left: 3em; padding-left: 4px; }
|
||||
div.sourceCode
|
||||
{ }
|
||||
@media screen {
|
||||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script src="../site_libs/quarto-nav/quarto-nav.js"></script>
|
||||
<script src="../site_libs/quarto-nav/headroom.min.js"></script>
|
||||
<script src="../site_libs/clipboard/clipboard.min.js"></script>
|
||||
<script src="../site_libs/quarto-search/autocomplete.umd.js"></script>
|
||||
<script src="../site_libs/quarto-search/fuse.min.js"></script>
|
||||
<script src="../site_libs/quarto-search/quarto-search.js"></script>
|
||||
<meta name="quarto:offset" content="../">
|
||||
<script src="../site_libs/quarto-html/quarto.js"></script>
|
||||
<script src="../site_libs/quarto-html/popper.min.js"></script>
|
||||
<script src="../site_libs/quarto-html/tippy.umd.min.js"></script>
|
||||
<script src="../site_libs/quarto-html/anchor.min.js"></script>
|
||||
<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet">
|
||||
<link href="../site_libs/quarto-html/quarto-syntax-highlighting-d4d76bf8491c20bad77d141916dc28e1.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||
<script src="../site_libs/bootstrap/bootstrap.min.js"></script>
|
||||
<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="../site_libs/bootstrap/bootstrap-96f0ff77f429b54fb9fb81a812e140da.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||
<script id="quarto-search-options" type="application/json">{
|
||||
"location": "navbar",
|
||||
"copy-button": false,
|
||||
"collapse-after": 3,
|
||||
"panel-placement": "end",
|
||||
"type": "overlay",
|
||||
"limit": 50,
|
||||
"keyboard-shortcut": [
|
||||
"f",
|
||||
"/",
|
||||
"s"
|
||||
],
|
||||
"show-item-context": false,
|
||||
"language": {
|
||||
"search-no-results-text": "No results",
|
||||
"search-matching-documents-text": "matching documents",
|
||||
"search-copy-link-title": "Copy link to search",
|
||||
"search-hide-matches-text": "Hide additional matches",
|
||||
"search-more-match-text": "more match in this document",
|
||||
"search-more-matches-text": "more matches in this document",
|
||||
"search-clear-button-title": "Clear",
|
||||
"search-text-placeholder": "",
|
||||
"search-detached-cancel-button-title": "Cancel",
|
||||
"search-submit-button-title": "Submit",
|
||||
"search-label": "Search"
|
||||
}
|
||||
}</script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body class="nav-sidebar docked nav-fixed">
|
||||
|
||||
<div id="quarto-search-results"></div>
|
||||
<header id="quarto-header" class="headroom fixed-top">
|
||||
<nav class="navbar navbar-expand-lg " data-bs-theme="dark">
|
||||
<div class="navbar-container container-fluid">
|
||||
<div class="navbar-brand-container mx-auto">
|
||||
<a class="navbar-brand" href="../index.html">
|
||||
<span class="navbar-title">DOCS</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav navbar-nav-scroll me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://virtuos.world">
|
||||
<span class="menu-text">Homepage</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div> <!-- /navcollapse -->
|
||||
<div class="quarto-navbar-tools">
|
||||
<a href="" class="quarto-reader-toggle quarto-navigation-tool px-1" onclick="window.quartoToggleReader(); return false;" title="Toggle reader mode">
|
||||
<div class="quarto-reader-toggle-btn">
|
||||
<i class="bi"></i>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div> <!-- /container-fluid -->
|
||||
</nav>
|
||||
<nav class="quarto-secondary-nav">
|
||||
<div class="container-fluid d-flex">
|
||||
<button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" role="button" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
<i class="bi bi-layout-text-sidebar-reverse"></i>
|
||||
</button>
|
||||
<nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="../sites/webservices.html">Webservices</a></li></ol></nav>
|
||||
<a class="flex-grow-1" role="navigation" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
</a>
|
||||
<button type="button" class="btn quarto-search-button" aria-label="Search" onclick="window.quartoOpenSearch();">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<!-- content -->
|
||||
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
|
||||
<!-- sidebar -->
|
||||
<nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal quarto-sidebar-collapse-item sidebar-navigation docked overflow-auto">
|
||||
<div class="mt-2 flex-shrink-0 align-items-center">
|
||||
<div class="sidebar-search">
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-menu-container">
|
||||
<ul class="list-unstyled mt-1">
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<span class="sidebar-item-text sidebar-link text-start">
|
||||
<span class="menu-text">Overview</span></span>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<div class="sidebar-item-container">
|
||||
<a href="../sites/styleguide.html" class="sidebar-item-text sidebar-link">
|
||||
<span class="menu-text">Styleguide</span></a>
|
||||
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" role="navigation" aria-expanded="true" aria-label="Toggle section">
|
||||
<i class="bi bi-chevron-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show">
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-knitr.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-jupyter.qmd</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<div class="sidebar-item-container">
|
||||
<a href="../sites/webservices.html" class="sidebar-item-text sidebar-link active">
|
||||
<span class="menu-text">Webservices</span></a>
|
||||
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" role="navigation" aria-expanded="true" aria-label="Toggle section">
|
||||
<i class="bi bi-chevron-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth1 show">
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-knitr.qmd</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<span class="menu-text">layout-jupyter.qmd</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="sidebar-item sidebar-item-section">
|
||||
<span class="sidebar-item-text sidebar-link text-start">
|
||||
<span class="menu-text">Getting Started</span></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="quarto-sidebar-glass" class="quarto-sidebar-collapse-item" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item"></div>
|
||||
<!-- margin-sidebar -->
|
||||
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
|
||||
<nav id="TOC" role="doc-toc" class="toc-active">
|
||||
<h2 id="toc-title">On this page</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="#forgejo" id="toc-forgejo" class="nav-link active" data-scroll-target="#forgejo">Forgejo</a>
|
||||
<ul class="collapse">
|
||||
<li><a href="#installation-on-ubuntu-server-22.04" id="toc-installation-on-ubuntu-server-22.04" class="nav-link" data-scroll-target="#installation-on-ubuntu-server-22.04">Installation on Ubuntu Server 22.04</a></li>
|
||||
<li><a href="#customizing-forgejogitea" id="toc-customizing-forgejogitea" class="nav-link" data-scroll-target="#customizing-forgejogitea">Customizing Forgejo/Gitea</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#leantime" id="toc-leantime" class="nav-link" data-scroll-target="#leantime">Leantime</a>
|
||||
<ul class="collapse">
|
||||
<li><a href="#installation-on-uberspace" id="toc-installation-on-uberspace" class="nav-link" data-scroll-target="#installation-on-uberspace">Installation on Uberspace</a></li>
|
||||
<li><a href="#updating-leantime" id="toc-updating-leantime" class="nav-link" data-scroll-target="#updating-leantime">Updating Leantime</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#wordpress" id="toc-wordpress" class="nav-link" data-scroll-target="#wordpress">Wordpress</a>
|
||||
<ul class="collapse">
|
||||
<li><a href="#installation-on-uberspace-1" id="toc-installation-on-uberspace-1" class="nav-link" data-scroll-target="#installation-on-uberspace-1">Installation on Uberspace</a></li>
|
||||
<li><a href="#updating-wordpress" id="toc-updating-wordpress" class="nav-link" data-scroll-target="#updating-wordpress">Updating Wordpress</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#wiki.js" id="toc-wiki.js" class="nav-link" data-scroll-target="#wiki.js">Wiki.js</a>
|
||||
<ul class="collapse">
|
||||
<li><a href="#installation-on-uberspace-2" id="toc-installation-on-uberspace-2" class="nav-link" data-scroll-target="#installation-on-uberspace-2">Installation on Uberspace</a></li>
|
||||
<li><a href="#updating-wiki.js" id="toc-updating-wiki.js" class="nav-link" data-scroll-target="#updating-wiki.js">Updating Wiki.js</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#pretix" id="toc-pretix" class="nav-link" data-scroll-target="#pretix">Pretix</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- main -->
|
||||
<main class="content" id="quarto-document-content">
|
||||
|
||||
<header id="title-block-header" class="quarto-title-block default">
|
||||
<div class="quarto-title">
|
||||
<h1 class="title">Websevices</h1>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="quarto-title-meta">
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
|
||||
<section id="forgejo" class="level1">
|
||||
<h1>Forgejo</h1>
|
||||
<p>Forgejo is an open source source control system. As game development not only needs to track text files but large binaries (Images, Videos, Audio etc.), traditional providers like GitHub or GitLab might not scale or become quite pricey. This is why a self-hosted solution was set up.</p>
|
||||
<p>The Forgejo instance is currently hosted on Hetzner Cloud cpx11. For storage, a 1tb Hetzner Storage Box is attached via CIFS. The Forgejo instance can be accessed on <a href="https://code.virtuos.world">https://code.virtuos.world</a>.</p>
|
||||
<section id="installation-on-ubuntu-server-22.04" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="installation-on-ubuntu-server-22.04">Installation on Ubuntu Server 22.04</h2>
|
||||
<ul>
|
||||
<li>On a new server, add a new user that is not root:</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">adduser</span> newusername</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ex">usermod</span> <span class="at">-aG</span> sudo newusername</span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> <span class="at">-i</span> <span class="at">-u</span> git newusername</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Create git user account and add it to the docker usergroup, then switch to the new user.</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> adduser <span class="at">--system</span> <span class="at">--shell</span> /bin/bash <span class="at">-gecos</span> <span class="st">'Git Version Control'</span> <span class="at">--group</span> <span class="at">--disabled-password</span> <span class="at">--home</span> /home/git/ git</span>
|
||||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> usermod <span class="at">-aG</span> docker git</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Automount the storage box by editing <code>/etc/fstab</code>. Important: Use the UID and GID of the newly created git user! You can get them by typing <code>id git</code>.</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> nano /etc/fstab</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Add this line</li>
|
||||
</ul>
|
||||
<pre><code>//<username>.your-storagebox.de/backup /mnt/<path> cifs iocharset=utf8,rw,credentials=/etc/backup-credentials.txt,uid=<system account>,gid=<system group>,file_mode=0660,dir_mode=0770 0 0</code></pre>
|
||||
<p>Create the credentials file…</p>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> nano /etc/backup-credentials.txt</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<p>…and fill it with your username and password.</p>
|
||||
<pre><code>username=uXXXXXX
|
||||
password=yourpassword</code></pre>
|
||||
<ul>
|
||||
<li>Install <code>cifs-utils</code></li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb7"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ex">apt</span> install cifs-utils</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Mounting might result in an error regarding the iocharset, to fix that do:</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb8"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">apt</span> install linux-generic</span>
|
||||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">apt</span> install linux-modules-extra-<span class="va">$(</span><span class="fu">uname</span> <span class="at">-r</span><span class="va">)</span></span>
|
||||
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">reboot</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Mount the storage</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> mount <span class="at">-a</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Install docker-compose</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> apt install docker-compose </span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Create docker directory</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb11"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> mkdir ~/forgejo</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Create docker-compose file</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb12"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> nano docker-compose.yml</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Paste the following content. This assumes your UID is 115 and your GID is 120. Use <code>id -u <username></code> to find your values. It also maps the repository to use the storage box.</li>
|
||||
</ul>
|
||||
<blockquote class="blockquote">
|
||||
<p>Edit: I removed <code>- /mnt/source/git/repositories:/data/git/repositories</code> as it’s slow and hooks won’t work on the Storage Box!</p>
|
||||
</blockquote>
|
||||
<div class="sourceCode" id="cb13"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="fu">version</span><span class="kw">:</span><span class="at"> </span><span class="st">'3'</span></span>
|
||||
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="fu">networks</span><span class="kw">:</span></span>
|
||||
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">forgejo</span><span class="kw">:</span></span>
|
||||
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">external</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
|
||||
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="fu">services</span><span class="kw">:</span></span>
|
||||
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">server</span><span class="kw">:</span></span>
|
||||
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">image</span><span class="kw">:</span><span class="at"> codeberg.org/forgejo/forgejo:1.20</span></span>
|
||||
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">container_name</span><span class="kw">:</span><span class="at"> forgejo</span></span>
|
||||
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">environment</span><span class="kw">:</span></span>
|
||||
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> USER_UID=115</span></span>
|
||||
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> USER_GID=120</span></span>
|
||||
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">restart</span><span class="kw">:</span><span class="at"> always</span></span>
|
||||
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">networks</span><span class="kw">:</span></span>
|
||||
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> forgejo</span></span>
|
||||
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">volumes</span><span class="kw">:</span></span>
|
||||
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> ./forgejo:/data</span></span>
|
||||
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /etc/timezone:/etc/timezone:ro</span></span>
|
||||
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /etc/localtime:/etc/localtime:ro</span></span>
|
||||
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /mnt/source/git/lfs:/data/lfs</span></span>
|
||||
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">ports</span><span class="kw">:</span></span>
|
||||
<span id="cb13-24"><a href="#cb13-24" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> </span><span class="st">'3000:3000'</span></span>
|
||||
<span id="cb13-25"><a href="#cb13-25" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> </span><span class="st">'222:22'</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<p>For some reason in my case, the app.ini pointed to <code>/data/git/lfs</code> instead of <code>data/lfs</code>. Fixing this resulted in actually using <code>/mnt/source/git/lfs</code> on the host.</p>
|
||||
<ul>
|
||||
<li>Install nginx</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb14"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> apt install nginx</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Setup firewall</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb15"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> ufw allow OpenSSH</span>
|
||||
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> ufw allow <span class="st">"Nginx Full"</span></span>
|
||||
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> ufw enable</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Open nginx config</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb16"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> nano /etc/nginx/sites-available/forgejo</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Add:</li>
|
||||
</ul>
|
||||
<pre class="nginx"><code>server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name my.domain.tld;
|
||||
|
||||
location / {
|
||||
client_max_body_size 4G;
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real_IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}</code></pre>
|
||||
<p>(This assumes you have registered a domain and added A and AAAA records.)</p>
|
||||
<ul>
|
||||
<li>Create symlink to actually enable the site</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb18"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> ln <span class="at">-s</span> /etc/nginx/sites-available/forgejo /etc/nginx/sites-enabled/</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Install Certbot</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb19"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> apt install snapd</span>
|
||||
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> snap install <span class="at">--classic</span> certbot</span>
|
||||
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> ln <span class="at">-s</span> /snap/bin/certbot /usr/bin/certbot</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Get Let’s Encrypt certificate. For testing, add <code>--test-cert</code>.</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb20"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> certbot <span class="at">--nginx</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Run your docker compose</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb21"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> ~/forgejo</span>
|
||||
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> docker-compose up <span class="at">-d</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>To redirect the homepage to the repository view:</li>
|
||||
</ul>
|
||||
<pre class="nginx"><code>server {
|
||||
server_name code.virtuos.world;
|
||||
|
||||
location / {
|
||||
client_max_body_size 4G;
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real_IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location = / {
|
||||
return 301 https://$host/explore/repos;
|
||||
}
|
||||
|
||||
listen [::]:443 ssl ipv6only=on; # managed by Certbot
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/code.virtuos.world/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/code.virtuos.world/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
}
|
||||
|
||||
server {
|
||||
if ($host = code.virtuos.world) {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name code.virtuos.world;
|
||||
return 404;
|
||||
}</code></pre>
|
||||
<p>Thanks to KeepItTechie for this tutorial: <a href="https://www.youtube.com/watch?v=I4OQMc1rIO4">https://www.youtube.com/watch?v=I4OQMc1rIO4</a></p>
|
||||
</section>
|
||||
<section id="customizing-forgejogitea" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="customizing-forgejogitea">Customizing Forgejo/Gitea</h2>
|
||||
<p>On the host, the path starts from the folder with your docker-compose file, <code>/forgejo/gitea/public/assets/</code></p>
|
||||
<p>Paste the images with the respective names listed below:</p>
|
||||
<ul>
|
||||
<li><code>public/img/logo.svg</code> - Used for site icon, app icon<br>
|
||||
</li>
|
||||
<li><code>public/img/logo.png</code> - Used for Open Graph<br>
|
||||
</li>
|
||||
<li><code>public/img/avatar_default.png</code> - Used as the default avatar image<br>
|
||||
</li>
|
||||
<li><code>public/img/apple-touch-icon.png</code> - Used on iOS devices for bookmarks<br>
|
||||
</li>
|
||||
<li><code>public/img/favicon.svg</code> - Used for favicon<br>
|
||||
</li>
|
||||
<li><code>public/img/favicon.png</code> - Used as fallback for browsers that don’t support SVG favicons</li>
|
||||
</ul>
|
||||
<hr>
|
||||
</section>
|
||||
</section>
|
||||
<section id="leantime" class="level1">
|
||||
<h1>Leantime</h1>
|
||||
<p>Leantime is an open source project management system. The Leantime instance is hosted on Uberspace.de and can be accessed on <a href="https://manage.virtuos.world">https://manage.virtuos.world</a>.</p>
|
||||
<section id="installation-on-uberspace" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="installation-on-uberspace">Installation on Uberspace</h2>
|
||||
<ul>
|
||||
<li>Download latest release package, upload and untar:</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb23"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="fu">tar</span> <span class="at">-xf</span> <span class="op"><</span>name.tar.gz<span class="op">></span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Create an empty MySQL database:</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb24"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="ex">mysql</span> <span class="at">-e</span> <span class="st">"CREATE DATABASE <username>_leantime"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Point your domain to the <code>public/</code> directory<br>
|
||||
Edit <code>/leantime/public/.htaccess</code>:</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb25"><pre class="sourceCode apache code-with-copy"><code class="sourceCode apache"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Options</span><span class="ch"> </span><span class="kw">+SymLinksIfOwnerMatch</span></span>
|
||||
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="ex">RewriteEngine</span><span class="ch"> </span><span class="kw">On</span></span>
|
||||
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>RewriteBase<span class="st"> /</span></span>
|
||||
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>RewriteCond<span class="st"> %{REQUEST_FILENAME} !-d</span></span>
|
||||
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a>RewriteCond<span class="st"> %{REQUEST_FILENAME} !-f</span></span>
|
||||
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a>RewriteRule<span class="st"> ^ index.php [L]</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Get your MySQL credentials:</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb26"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="ex">my_print_defaults</span> client</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<ul>
|
||||
<li>Fill in your database credentials (username, password, host, dbname) in <code>config/sample.env</code><br>
|
||||
</li>
|
||||
<li>Rename <code>config/sample.env</code> to <code>config/.env</code><br>
|
||||
</li>
|
||||
<li>Navigate to <code><yourdomain.com>/install</code><br>
|
||||
</li>
|
||||
<li>Follow instructions to install database and set up first user account</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="updating-leantime" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="updating-leantime">Updating Leantime</h2>
|
||||
<p>Leantime comes with an update script in <code>/leantime</code>:</p>
|
||||
<div class="sourceCode" id="cb27"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="ex">./updateLeantime.sh</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
|
||||
<hr>
|
||||
</section>
|
||||
</section>
|
||||
<section id="wordpress" class="level1">
|
||||
<h1>Wordpress</h1>
|
||||
<p>Wordpress is an open source Content Management System (CMS). The Wordpress instance is hosted on Uberspace.de and can be accessed on <a href="https://virtuos.world">https://virtuos.world</a>.</p>
|
||||
<section id="installation-on-uberspace-1" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="installation-on-uberspace-1">Installation on Uberspace</h2>
|
||||
<p>The Wordpress installation is well documented on<br>
|
||||
<a href="https://lab.uberspace.de/guide_wordpress/">https://lab.uberspace.de/guide_wordpress/</a></p>
|
||||
</section>
|
||||
<section id="updating-wordpress" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="updating-wordpress">Updating Wordpress</h2>
|
||||
<p>Wordpress updates itself. Plugins may need manual updating via the Wordpress Interface.</p>
|
||||
<hr>
|
||||
</section>
|
||||
</section>
|
||||
<section id="wiki.js" class="level1">
|
||||
<h1>Wiki.js</h1>
|
||||
<p>Wiki.js is an open source Wiki software. The Wiki.js instance is hosted on Uberspace.de and you are currently accessing it on <a href="https://docs.virtuos.world">https://docs.virtuos.world</a>.</p>
|
||||
<section id="installation-on-uberspace-2" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="installation-on-uberspace-2">Installation on Uberspace</h2>
|
||||
<p>The Wiki.js installation is well documented on<br>
|
||||
<a href="https://lab.uberspace.de/guide_wiki-js/">https://lab.uberspace.de/guide_wiki-js/</a></p>
|
||||
</section>
|
||||
<section id="updating-wiki.js" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="updating-wiki.js">Updating Wiki.js</h2>
|
||||
<p>An update script is available at the same location:<br>
|
||||
<a href="https://lab.uberspace.de/guide_wiki-js/">https://lab.uberspace.de/guide_wiki-js/</a></p>
|
||||
<hr>
|
||||
</section>
|
||||
</section>
|
||||
<section id="pretix" class="level1">
|
||||
<h1>Pretix</h1>
|
||||
<p>Pretix is an open source ticketing system. It’s currently not in use. This installation is not as easy, but well documented here:<br>
|
||||
<a href="https://docs.pretix.eu/en/latest/admin/installation/docker_smallscale.html">https://docs.pretix.eu/en/latest/admin/installation/docker_smallscale.html</a></p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
</main> <!-- /main -->
|
||||
<script id="quarto-html-after-body" type="application/javascript">
|
||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||
const toggleBodyColorMode = (bsSheetEl) => {
|
||||
const mode = bsSheetEl.getAttribute("data-mode");
|
||||
const bodyEl = window.document.querySelector("body");
|
||||
if (mode === "dark") {
|
||||
bodyEl.classList.add("quarto-dark");
|
||||
bodyEl.classList.remove("quarto-light");
|
||||
} else {
|
||||
bodyEl.classList.add("quarto-light");
|
||||
bodyEl.classList.remove("quarto-dark");
|
||||
}
|
||||
}
|
||||
const toggleBodyColorPrimary = () => {
|
||||
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
|
||||
if (bsSheetEl) {
|
||||
toggleBodyColorMode(bsSheetEl);
|
||||
}
|
||||
}
|
||||
toggleBodyColorPrimary();
|
||||
const icon = "";
|
||||
const anchorJS = new window.AnchorJS();
|
||||
anchorJS.options = {
|
||||
placement: 'right',
|
||||
icon: icon
|
||||
};
|
||||
anchorJS.add('.anchored');
|
||||
const isCodeAnnotation = (el) => {
|
||||
for (const clz of el.classList) {
|
||||
if (clz.startsWith('code-annotation-')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const onCopySuccess = function(e) {
|
||||
// button target
|
||||
const button = e.trigger;
|
||||
// don't keep focus
|
||||
button.blur();
|
||||
// flash "checked"
|
||||
button.classList.add('code-copy-button-checked');
|
||||
var currentTitle = button.getAttribute("title");
|
||||
button.setAttribute("title", "Copied!");
|
||||
let tooltip;
|
||||
if (window.bootstrap) {
|
||||
button.setAttribute("data-bs-toggle", "tooltip");
|
||||
button.setAttribute("data-bs-placement", "left");
|
||||
button.setAttribute("data-bs-title", "Copied!");
|
||||
tooltip = new bootstrap.Tooltip(button,
|
||||
{ trigger: "manual",
|
||||
customClass: "code-copy-button-tooltip",
|
||||
offset: [0, -8]});
|
||||
tooltip.show();
|
||||
}
|
||||
setTimeout(function() {
|
||||
if (tooltip) {
|
||||
tooltip.hide();
|
||||
button.removeAttribute("data-bs-title");
|
||||
button.removeAttribute("data-bs-toggle");
|
||||
button.removeAttribute("data-bs-placement");
|
||||
}
|
||||
button.setAttribute("title", currentTitle);
|
||||
button.classList.remove('code-copy-button-checked');
|
||||
}, 1000);
|
||||
// clear code selection
|
||||
e.clearSelection();
|
||||
}
|
||||
const getTextToCopy = function(trigger) {
|
||||
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
||||
for (const childEl of codeEl.children) {
|
||||
if (isCodeAnnotation(childEl)) {
|
||||
childEl.remove();
|
||||
}
|
||||
}
|
||||
return codeEl.innerText;
|
||||
}
|
||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||
text: getTextToCopy
|
||||
});
|
||||
clipboard.on('success', onCopySuccess);
|
||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||
text: getTextToCopy,
|
||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||
});
|
||||
clipboardModal.on('success', onCopySuccess);
|
||||
}
|
||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||
var mailtoRegex = new RegExp(/^mailto:/);
|
||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||
var isInternal = (href) => {
|
||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||
}
|
||||
// Inspect non-navigation links and adorn them if external
|
||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||
for (var i=0; i<links.length; i++) {
|
||||
const link = links[i];
|
||||
if (!isInternal(link.href)) {
|
||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||
// links that we want to consider external
|
||||
if (link.dataset.originalHref !== undefined) {
|
||||
link.href = link.dataset.originalHref;
|
||||
}
|
||||
}
|
||||
}
|
||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||
const config = {
|
||||
allowHTML: true,
|
||||
maxWidth: 500,
|
||||
delay: 100,
|
||||
arrow: false,
|
||||
appendTo: function(el) {
|
||||
return el.parentElement;
|
||||
},
|
||||
interactive: true,
|
||||
interactiveBorder: 10,
|
||||
theme: 'quarto',
|
||||
placement: 'bottom-start',
|
||||
};
|
||||
if (contentFn) {
|
||||
config.content = contentFn;
|
||||
}
|
||||
if (onTriggerFn) {
|
||||
config.onTrigger = onTriggerFn;
|
||||
}
|
||||
if (onUntriggerFn) {
|
||||
config.onUntrigger = onUntriggerFn;
|
||||
}
|
||||
window.tippy(el, config);
|
||||
}
|
||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||
for (var i=0; i<noterefs.length; i++) {
|
||||
const ref = noterefs[i];
|
||||
tippyHover(ref, function() {
|
||||
// use id or data attribute instead here
|
||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||
try { href = new URL(href).hash; } catch {}
|
||||
const id = href.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note) {
|
||||
return note.innerHTML;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||
const processXRef = (id, note) => {
|
||||
// Strip column container classes
|
||||
const stripColumnClz = (el) => {
|
||||
el.classList.remove("page-full", "page-columns");
|
||||
if (el.children) {
|
||||
for (const child of el.children) {
|
||||
stripColumnClz(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
stripColumnClz(note)
|
||||
if (id === null || id.startsWith('sec-')) {
|
||||
// Special case sections, only their first couple elements
|
||||
const container = document.createElement("div");
|
||||
if (note.children && note.children.length > 2) {
|
||||
container.appendChild(note.children[0].cloneNode(true));
|
||||
for (let i = 1; i < note.children.length; i++) {
|
||||
const child = note.children[i];
|
||||
if (child.tagName === "P" && child.innerText === "") {
|
||||
continue;
|
||||
} else {
|
||||
container.appendChild(child.cloneNode(true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(container);
|
||||
}
|
||||
return container.innerHTML
|
||||
} else {
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
return note.innerHTML;
|
||||
}
|
||||
} else {
|
||||
// Remove any anchor links if they are present
|
||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||
if (anchorLink) {
|
||||
anchorLink.remove();
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
if (note.classList.contains("callout")) {
|
||||
return note.outerHTML;
|
||||
} else {
|
||||
return note.innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i=0; i<xrefs.length; i++) {
|
||||
const xref = xrefs[i];
|
||||
tippyHover(xref, undefined, function(instance) {
|
||||
instance.disable();
|
||||
let url = xref.getAttribute('href');
|
||||
let hash = undefined;
|
||||
if (url.startsWith('#')) {
|
||||
hash = url;
|
||||
} else {
|
||||
try { hash = new URL(url).hash; } catch {}
|
||||
}
|
||||
if (hash) {
|
||||
const id = hash.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note !== null) {
|
||||
try {
|
||||
const html = processXRef(id, note.cloneNode(true));
|
||||
instance.setContent(html);
|
||||
} finally {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch this
|
||||
fetch(url.split('#')[0])
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.getElementById(id);
|
||||
if (note !== null) {
|
||||
const html = processXRef(id, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch a full url (with no hash to target)
|
||||
// This is a special case and we should probably do some content thinning / targeting
|
||||
fetch(url)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.querySelector('main.content');
|
||||
if (note !== null) {
|
||||
// This should only happen for chapter cross references
|
||||
// (since there is no id in the URL)
|
||||
// remove the first header
|
||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||
note.children[0].remove();
|
||||
}
|
||||
const html = processXRef(null, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
}, function(instance) {
|
||||
});
|
||||
}
|
||||
let selectedAnnoteEl;
|
||||
const selectorForAnnotation = ( cell, annotation) => {
|
||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||
return selector;
|
||||
}
|
||||
const selectCodeLines = (annoteEl) => {
|
||||
const doc = window.document;
|
||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||
const lineIds = lines.map((line) => {
|
||||
return targetCell + "-" + line;
|
||||
})
|
||||
let top = null;
|
||||
let height = null;
|
||||
let parent = null;
|
||||
if (lineIds.length > 0) {
|
||||
//compute the position of the single el (top and bottom and make a div)
|
||||
const el = window.document.getElementById(lineIds[0]);
|
||||
top = el.offsetTop;
|
||||
height = el.offsetHeight;
|
||||
parent = el.parentElement.parentElement;
|
||||
if (lineIds.length > 1) {
|
||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||
height = bottom - top;
|
||||
}
|
||||
if (top !== null && height !== null && parent !== null) {
|
||||
// cook up a div (if necessary) and position it
|
||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||
if (div === null) {
|
||||
div = window.document.createElement("div");
|
||||
div.setAttribute("id", "code-annotation-line-highlight");
|
||||
div.style.position = 'absolute';
|
||||
parent.appendChild(div);
|
||||
}
|
||||
div.style.top = top - 2 + "px";
|
||||
div.style.height = height + 4 + "px";
|
||||
div.style.left = 0;
|
||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||
if (gutterDiv === null) {
|
||||
gutterDiv = window.document.createElement("div");
|
||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||
gutterDiv.style.position = 'absolute';
|
||||
const codeCell = window.document.getElementById(targetCell);
|
||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||
gutter.appendChild(gutterDiv);
|
||||
}
|
||||
gutterDiv.style.top = top - 2 + "px";
|
||||
gutterDiv.style.height = height + 4 + "px";
|
||||
}
|
||||
selectedAnnoteEl = annoteEl;
|
||||
}
|
||||
};
|
||||
const unselectCodeLines = () => {
|
||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||
elementsIds.forEach((elId) => {
|
||||
const div = window.document.getElementById(elId);
|
||||
if (div) {
|
||||
div.remove();
|
||||
}
|
||||
});
|
||||
selectedAnnoteEl = undefined;
|
||||
};
|
||||
// Handle positioning of the toggle
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
elRect = undefined;
|
||||
if (selectedAnnoteEl) {
|
||||
selectCodeLines(selectedAnnoteEl);
|
||||
}
|
||||
}, 10)
|
||||
);
|
||||
function throttle(fn, ms) {
|
||||
let throttle = false;
|
||||
let timer;
|
||||
return (...args) => {
|
||||
if(!throttle) { // first call gets through
|
||||
fn.apply(this, args);
|
||||
throttle = true;
|
||||
} else { // all the others get throttled
|
||||
if(timer) clearTimeout(timer); // cancel #2
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
timer = throttle = false;
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
}
|
||||
// Attach click handler to the DT
|
||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||
for (const annoteDlNode of annoteDls) {
|
||||
annoteDlNode.addEventListener('click', (event) => {
|
||||
const clickedEl = event.target;
|
||||
if (clickedEl !== selectedAnnoteEl) {
|
||||
unselectCodeLines();
|
||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||
if (activeEl) {
|
||||
activeEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
selectCodeLines(clickedEl);
|
||||
clickedEl.classList.add('code-annotation-active');
|
||||
} else {
|
||||
// Unselect the line
|
||||
unselectCodeLines();
|
||||
clickedEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
const findCites = (el) => {
|
||||
const parentEl = el.parentElement;
|
||||
if (parentEl) {
|
||||
const cites = parentEl.dataset.cites;
|
||||
if (cites) {
|
||||
return {
|
||||
el,
|
||||
cites: cites.split(' ')
|
||||
};
|
||||
} else {
|
||||
return findCites(el.parentElement)
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||
for (var i=0; i<bibliorefs.length; i++) {
|
||||
const ref = bibliorefs[i];
|
||||
const citeInfo = findCites(ref);
|
||||
if (citeInfo) {
|
||||
tippyHover(citeInfo.el, function() {
|
||||
var popup = window.document.createElement('div');
|
||||
citeInfo.cites.forEach(function(cite) {
|
||||
var citeDiv = window.document.createElement('div');
|
||||
citeDiv.classList.add('hanging-indent');
|
||||
citeDiv.classList.add('csl-entry');
|
||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||
if (biblioDiv) {
|
||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||
}
|
||||
popup.appendChild(citeDiv);
|
||||
});
|
||||
return popup.innerHTML;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div> <!-- /content -->
|
||||
<footer class="footer">
|
||||
<div class="nav-footer">
|
||||
<div class="nav-footer-left">
|
||||
<p>Copyright 2025, Simeon Wallrath</p>
|
||||
</div>
|
||||
<div class="nav-footer-center">
|
||||
|
||||
</div>
|
||||
<div class="nav-footer-right">
|
||||
<ul class="footer-items list-unstyled">
|
||||
<li class="nav-item compact">
|
||||
<a class="nav-link" href="https://github.com/">
|
||||
<i class="bi bi-github" role="img">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item compact">
|
||||
<a class="nav-link" href="https://twitter.com/">
|
||||
<i class="bi bi-mastodon" role="img">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
|
||||
|
||||
</body></html>
|
BIN
_site/sites/webservices.pdf
Normal file
BIN
_site/sites/webservices.pdf
Normal file
Binary file not shown.
15
index.qmd
15
index.qmd
|
@ -1,7 +1,16 @@
|
|||
---
|
||||
title: "VIRTUOS WORLD Documentation"
|
||||
title: "Home"
|
||||
|
||||
---
|
||||
|
||||
This is a Quarto website.
|
||||
# Welcome to the Documentation!
|
||||
|
||||
To learn more about Quarto websites visit <https://quarto.org/docs/websites>.
|
||||
This is the main page of your documentation. You can add more sections or documentation as you need.
|
||||
|
||||
## Features
|
||||
|
||||
- Easy setup
|
||||
- User-friendly interface
|
||||
- Rich documentation
|
||||
|
||||
For more details, refer to the Getting Started section in the sidebar.
|
||||
|
|
23
sites/getstarted.qmd
Normal file
23
sites/getstarted.qmd
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
title: "Getting Started"
|
||||
---
|
||||
If you want to take a look inside a project, there are currently three important repositories:
|
||||
|
||||
- VIRTUOS_Playground: The repository contains the Unreal Engine Project
|
||||
- VIRTUOS_Assets: Contains all Project related assets like 3D-Models, Graphics etc.
|
||||
- VIRTUOS_Documents: Contains all written Documents
|
||||
|
||||
# Setting up the project with UE5
|
||||
|
||||
If you're familiar with Git, you'll likely already know how to get the files.
|
||||
|
||||
```bash
|
||||
git pull https://code.virtuos.world/VIRTUOS_WORLD/VIRTUOS_Docs.git
|
||||
```
|
||||
|
||||
If you're not comforatable with the command line, you can install a Git GUI like Github Desktop.
|
||||
|
||||
|
||||
```{=html}
|
||||
<iframe width="100%" height="500" src="https://blueprintue.com/render/-azlwrm2/" scrolling="no" allowfullscreen></iframe>
|
||||
```
|
5
sites/overview.qmd
Normal file
5
sites/overview.qmd
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: "About"
|
||||
---
|
||||
|
||||
About this site
|
31
sites/styleguide.aux
Normal file
31
sites/styleguide.aux
Normal file
|
@ -0,0 +1,31 @@
|
|||
\relax
|
||||
\providecommand*\new@tpo@label[2]{}
|
||||
\providecommand\hyper@newdestlabel[2]{}
|
||||
\providecommand*\HyPL@Entry[1]{}
|
||||
\HyPL@Entry{0<</S/D>>}
|
||||
\@writefile{toc}{\contentsline {subsection}{\nonumberline Important Terminology}{1}{subsection*.2}\protected@file@percent }
|
||||
\newlabel{important-terminology}{{}{1}{Important Terminology}{subsection*.2}{}}
|
||||
\@writefile{toc}{\contentsline {subparagraph}{\nonumberline Levels/Maps}{1}{subparagraph*.4}\protected@file@percent }
|
||||
\newlabel{levelsmaps}{{}{1}{Levels/Maps}{subparagraph*.4}{}}
|
||||
\@writefile{toc}{\contentsline {subparagraph}{\nonumberline Identifiers}{1}{subparagraph*.6}\protected@file@percent }
|
||||
\newlabel{identifiers}{{}{1}{Identifiers}{subparagraph*.6}{}}
|
||||
\@writefile{toc}{\contentsline {subparagraph}{\nonumberline Cases}{1}{subparagraph*.8}\protected@file@percent }
|
||||
\newlabel{cases}{{}{1}{Cases}{subparagraph*.8}{}}
|
||||
\@writefile{toc}{\contentsline {subparagraph}{\nonumberline Variables / Properties}{2}{subparagraph*.10}\protected@file@percent }
|
||||
\newlabel{variables-properties}{{}{2}{Variables / Properties}{subparagraph*.10}{}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\nonumberline 0. Principles}{2}{subsection*.12}\protected@file@percent }
|
||||
\newlabel{principles}{{}{2}{0. Principles}{subsection*.12}{}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{\nonumberline 0.1 If your UE4 project already has a style guide, you should follow it.}{3}{subsubsection*.14}\protected@file@percent }
|
||||
\newlabel{if-your-ue4-project-already-has-a-style-guide-you-should-follow-it.}{{}{3}{0.1 If your UE4 project already has a style guide, you should follow it}{subsubsection*.14}{}}
|
||||
\@writefile{toc}{\contentsline {paragraph}{\nonumberline ``Arguments over style are pointless. There should be a style guide, and you should follow it.''}{3}{paragraph*.16}\protected@file@percent }
|
||||
\newlabel{arguments-over-style-are-pointless.-there-should-be-a-style-guide-and-you-should-follow-it.}{{}{3}{``Arguments over style are pointless. There should be a style guide, and you should follow it.''}{paragraph*.16}{}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{\nonumberline 0.2 All structure, assets, and code in any Unreal Engine 4 project should look like a single person created it, no matter how many people contributed.}{3}{subsubsection*.18}\protected@file@percent }
|
||||
\newlabel{all-structure-assets-and-code-in-any-unreal-engine-4-project-should-look-like-a-single-person-created-it-no-matter-how-many-people-contributed.}{{}{3}{0.2 All structure, assets, and code in any Unreal Engine 4 project should look like a single person created it, no matter how many people contributed}{subsubsection*.18}{}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{\nonumberline 0.3 Friends do not let friends have bad style.}{3}{subsubsection*.20}\protected@file@percent }
|
||||
\newlabel{friends-do-not-let-friends-have-bad-style.}{{}{3}{0.3 Friends do not let friends have bad style}{subsubsection*.20}{}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{\nonumberline 0.4 A team without a style guide is no team of mine.}{4}{subsubsection*.22}\protected@file@percent }
|
||||
\newlabel{a-team-without-a-style-guide-is-no-team-of-mine.}{{}{4}{0.4 A team without a style guide is no team of mine}{subsubsection*.22}{}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{\nonumberline 0.5 Don't Break The Law}{4}{subsubsection*.24}\protected@file@percent }
|
||||
\newlabel{dont-break-the-law}{{}{4}{0.5 Don't Break The Law}{subsubsection*.24}{}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\nonumberline 00. Globally Enforced Opinions}{4}{subsection*.26}\protected@file@percent }
|
||||
\newlabel{globally-enforced-opinions}{{}{4}{00. Globally Enforced Opinions}{subsection*.26}{}}
|
1125
sites/styleguide.log
Normal file
1125
sites/styleguide.log
Normal file
File diff suppressed because it is too large
Load diff
BIN
sites/styleguide.pdf
Normal file
BIN
sites/styleguide.pdf
Normal file
Binary file not shown.
1638
sites/styleguide.qmd
Normal file
1638
sites/styleguide.qmd
Normal file
File diff suppressed because it is too large
Load diff
2397
sites/styleguide.tex
Normal file
2397
sites/styleguide.tex
Normal file
File diff suppressed because it is too large
Load diff
1817
sites/styleguide_files/mediabag/bp-graphs-align-wire.png
Normal file
1817
sites/styleguide_files/mediabag/bp-graphs-align-wire.png
Normal file
File diff suppressed because one or more lines are too long
1817
sites/styleguide_files/mediabag/bp-graphs-align-wire1.png
Normal file
1817
sites/styleguide_files/mediabag/bp-graphs-align-wire1.png
Normal file
File diff suppressed because one or more lines are too long
1817
sites/styleguide_files/mediabag/bp-graphs-align-wire12.png
Normal file
1817
sites/styleguide_files/mediabag/bp-graphs-align-wire12.png
Normal file
File diff suppressed because one or more lines are too long
333
sites/webservices.qmd
Normal file
333
sites/webservices.qmd
Normal file
|
@ -0,0 +1,333 @@
|
|||
---
|
||||
title: "Websevices"
|
||||
---
|
||||
# Forgejo
|
||||
|
||||
Forgejo is an open source source control system. As game development not only needs to track text files but large binaries (Images, Videos, Audio etc.), traditional providers like GitHub or GitLab might not scale or become quite pricey. This is why a self-hosted solution was set up.
|
||||
|
||||
The Forgejo instance is currently hosted on Hetzner Cloud cpx11. For storage, a 1tb Hetzner Storage Box is attached via CIFS. The Forgejo instance can be accessed on [https://code.virtuos.world](https://code.virtuos.world).
|
||||
|
||||
## Installation on Ubuntu Server 22.04
|
||||
|
||||
- On a new server, add a new user that is not root:
|
||||
|
||||
```bash
|
||||
adduser newusername
|
||||
usermod -aG sudo newusername
|
||||
sudo -i -u git newusername
|
||||
```
|
||||
|
||||
- Create git user account and add it to the docker usergroup, then switch to the new user.
|
||||
|
||||
```bash
|
||||
sudo adduser --system --shell /bin/bash -gecos 'Git Version Control' --group --disabled-password --home /home/git/ git
|
||||
sudo usermod -aG docker git
|
||||
```
|
||||
|
||||
- Automount the storage box by editing `/etc/fstab`. Important: Use the UID and GID of the newly created git user! You can get them by typing `id git`.
|
||||
|
||||
```bash
|
||||
sudo nano /etc/fstab
|
||||
```
|
||||
|
||||
- Add this line
|
||||
|
||||
```
|
||||
//<username>.your-storagebox.de/backup /mnt/<path> cifs iocharset=utf8,rw,credentials=/etc/backup-credentials.txt,uid=<system account>,gid=<system group>,file_mode=0660,dir_mode=0770 0 0
|
||||
```
|
||||
|
||||
Create the credentials file…
|
||||
|
||||
```bash
|
||||
sudo nano /etc/backup-credentials.txt
|
||||
```
|
||||
|
||||
…and fill it with your username and password.
|
||||
|
||||
```
|
||||
username=uXXXXXX
|
||||
password=yourpassword
|
||||
```
|
||||
|
||||
- Install `cifs-utils`
|
||||
|
||||
```bash
|
||||
apt install cifs-utils
|
||||
```
|
||||
|
||||
- Mounting might result in an error regarding the iocharset, to fix that do:
|
||||
|
||||
```bash
|
||||
apt install linux-generic
|
||||
apt install linux-modules-extra-$(uname -r)
|
||||
reboot
|
||||
```
|
||||
|
||||
- Mount the storage
|
||||
|
||||
```bash
|
||||
sudo mount -a
|
||||
```
|
||||
|
||||
- Install docker-compose
|
||||
|
||||
```bash
|
||||
sudo apt install docker-compose
|
||||
```
|
||||
|
||||
- Create docker directory
|
||||
|
||||
```bash
|
||||
sudo mkdir ~/forgejo
|
||||
```
|
||||
|
||||
- Create docker-compose file
|
||||
|
||||
```bash
|
||||
sudo nano docker-compose.yml
|
||||
```
|
||||
|
||||
- Paste the following content. This assumes your UID is 115 and your GID is 120. Use `id -u <username>` to find your values. It also maps the repository to use the storage box.
|
||||
|
||||
> Edit: I removed `- /mnt/source/git/repositories:/data/git/repositories` as it's slow and hooks won't work on the Storage Box!
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
networks:
|
||||
forgejo:
|
||||
external: false
|
||||
|
||||
services:
|
||||
server:
|
||||
image: codeberg.org/forgejo/forgejo:1.20
|
||||
container_name: forgejo
|
||||
environment:
|
||||
- USER_UID=115
|
||||
- USER_GID=120
|
||||
restart: always
|
||||
networks:
|
||||
- forgejo
|
||||
volumes:
|
||||
- ./forgejo:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /mnt/source/git/lfs:/data/lfs
|
||||
|
||||
ports:
|
||||
- '3000:3000'
|
||||
- '222:22'
|
||||
```
|
||||
|
||||
For some reason in my case, the app.ini pointed to `/data/git/lfs` instead of `data/lfs`. Fixing this resulted in actually using `/mnt/source/git/lfs` on the host.
|
||||
|
||||
- Install nginx
|
||||
|
||||
```bash
|
||||
sudo apt install nginx
|
||||
```
|
||||
|
||||
- Setup firewall
|
||||
|
||||
```bash
|
||||
sudo ufw allow OpenSSH
|
||||
sudo ufw allow "Nginx Full"
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
- Open nginx config
|
||||
|
||||
```bash
|
||||
sudo nano /etc/nginx/sites-available/forgejo
|
||||
```
|
||||
|
||||
- Add:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name my.domain.tld;
|
||||
|
||||
location / {
|
||||
client_max_body_size 4G;
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real_IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
(This assumes you have registered a domain and added A and AAAA records.)
|
||||
|
||||
- Create symlink to actually enable the site
|
||||
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/forgejo /etc/nginx/sites-enabled/
|
||||
```
|
||||
|
||||
- Install Certbot
|
||||
|
||||
```bash
|
||||
sudo apt install snapd
|
||||
sudo snap install --classic certbot
|
||||
sudo ln -s /snap/bin/certbot /usr/bin/certbot
|
||||
```
|
||||
|
||||
- Get Let's Encrypt certificate. For testing, add `--test-cert`.
|
||||
|
||||
```bash
|
||||
sudo certbot --nginx
|
||||
```
|
||||
|
||||
- Run your docker compose
|
||||
|
||||
```bash
|
||||
cd ~/forgejo
|
||||
sudo docker-compose up -d
|
||||
```
|
||||
|
||||
- To redirect the homepage to the repository view:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name code.virtuos.world;
|
||||
|
||||
location / {
|
||||
client_max_body_size 4G;
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real_IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location = / {
|
||||
return 301 https://$host/explore/repos;
|
||||
}
|
||||
|
||||
listen [::]:443 ssl ipv6only=on; # managed by Certbot
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/code.virtuos.world/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/code.virtuos.world/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
}
|
||||
|
||||
server {
|
||||
if ($host = code.virtuos.world) {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name code.virtuos.world;
|
||||
return 404;
|
||||
}
|
||||
```
|
||||
|
||||
Thanks to KeepItTechie for this tutorial: [https://www.youtube.com/watch?v=I4OQMc1rIO4](https://www.youtube.com/watch?v=I4OQMc1rIO4)
|
||||
|
||||
## Customizing Forgejo/Gitea
|
||||
|
||||
On the host, the path starts from the folder with your docker-compose file, `/forgejo/gitea/public/assets/`
|
||||
|
||||
Paste the images with the respective names listed below:
|
||||
|
||||
- `public/img/logo.svg` - Used for site icon, app icon
|
||||
- `public/img/logo.png` - Used for Open Graph
|
||||
- `public/img/avatar_default.png` - Used as the default avatar image
|
||||
- `public/img/apple-touch-icon.png` - Used on iOS devices for bookmarks
|
||||
- `public/img/favicon.svg` - Used for favicon
|
||||
- `public/img/favicon.png` - Used as fallback for browsers that don't support SVG favicons
|
||||
|
||||
---
|
||||
|
||||
# Leantime
|
||||
|
||||
Leantime is an open source project management system. The Leantime instance is hosted on Uberspace.de and can be accessed on [https://manage.virtuos.world](https://manage.virtuos.world).
|
||||
|
||||
## Installation on Uberspace
|
||||
|
||||
- Download latest release package, upload and untar:
|
||||
|
||||
```bash
|
||||
tar -xf <name.tar.gz>
|
||||
```
|
||||
|
||||
- Create an empty MySQL database:
|
||||
|
||||
```bash
|
||||
mysql -e "CREATE DATABASE <username>_leantime"
|
||||
```
|
||||
|
||||
- Point your domain to the `public/` directory
|
||||
Edit `/leantime/public/.htaccess`:
|
||||
|
||||
```apache
|
||||
Options +SymLinksIfOwnerMatch
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
```
|
||||
|
||||
- Get your MySQL credentials:
|
||||
|
||||
```bash
|
||||
my_print_defaults client
|
||||
```
|
||||
|
||||
- Fill in your database credentials (username, password, host, dbname) in `config/sample.env`
|
||||
- Rename `config/sample.env` to `config/.env`
|
||||
- Navigate to `<yourdomain.com>/install`
|
||||
- Follow instructions to install database and set up first user account
|
||||
|
||||
## Updating Leantime
|
||||
|
||||
Leantime comes with an update script in `/leantime`:
|
||||
|
||||
```bash
|
||||
./updateLeantime.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Wordpress
|
||||
|
||||
Wordpress is an open source Content Management System (CMS). The Wordpress instance is hosted on Uberspace.de and can be accessed on [https://virtuos.world](https://virtuos.world).
|
||||
|
||||
## Installation on Uberspace
|
||||
|
||||
The Wordpress installation is well documented on
|
||||
[https://lab.uberspace.de/guide_wordpress/](https://lab.uberspace.de/guide_wordpress/)
|
||||
|
||||
## Updating Wordpress
|
||||
|
||||
Wordpress updates itself. Plugins may need manual updating via the Wordpress Interface.
|
||||
|
||||
---
|
||||
|
||||
# Wiki.js
|
||||
|
||||
Wiki.js is an open source Wiki software. The Wiki.js instance is hosted on Uberspace.de and you are currently accessing it on [https://docs.virtuos.world](https://docs.virtuos.world).
|
||||
|
||||
## Installation on Uberspace
|
||||
|
||||
The Wiki.js installation is well documented on
|
||||
[https://lab.uberspace.de/guide_wiki-js/](https://lab.uberspace.de/guide_wiki-js/)
|
||||
|
||||
## Updating Wiki.js
|
||||
|
||||
An update script is available at the same location:
|
||||
[https://lab.uberspace.de/guide_wiki-js/](https://lab.uberspace.de/guide_wiki-js/)
|
||||
|
||||
---
|
||||
|
||||
# Pretix
|
||||
|
||||
Pretix is an open source ticketing system. It's currently not in use. This installation is not as easy, but well documented here:
|
||||
[https://docs.pretix.eu/en/latest/admin/installation/docker_smallscale.html](https://docs.pretix.eu/en/latest/admin/installation/docker_smallscale.html)
|
37
theme.scss
Normal file
37
theme.scss
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-- scss:defaults --*/
|
||||
/* Define any default settings for the theme */
|
||||
|
||||
$primary: #009fe3;
|
||||
|
||||
/*-- scss:rules --*/
|
||||
/* Add custom rules for sidebar items and sections */
|
||||
.sidebar-item {
|
||||
padding-bottom: 5px; /* Optional: spacing between items */
|
||||
}
|
||||
|
||||
.sidebar-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.sidebar-item-section:not(:first-child) {
|
||||
margin-top: 20px; /* Add space above each *non-first* section */
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.sidebar-item-text {
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*-- scss:mixins --*/
|
||||
/* Add any reusable mixins if necessary */
|
||||
|
||||
/*-- scss:functions --*/
|
||||
/* Define any helper functions */
|
||||
|
||||
/*-- scss:uses --*/
|
||||
/* Any specific imports or additional styles */
|
Loading…
Add table
Reference in a new issue