work in progress on publishing docs
@@ -0,0 +1,3 @@
|
|||||||
|
FROM nginx:latest
|
||||||
|
|
||||||
|
COPY ./web /usr/share/nginx/html
|
||||||
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 296 KiB After Width: | Height: | Size: 296 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 2.8 MiB |
|
Before Width: | Height: | Size: 330 KiB After Width: | Height: | Size: 330 KiB |
|
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 2.8 MiB |
|
Before Width: | Height: | Size: 2.9 MiB After Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 332 KiB After Width: | Height: | Size: 332 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 3.2 MiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
@@ -1,29 +1,29 @@
|
|||||||
class CodeBlock extends HTMLElement {
|
class CodeBlock extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
// Get the code content as text, preserving whitespace
|
// Get the code content as text, preserving whitespace
|
||||||
let code = this.textContent.replace(/\r\n?/g, "\n");
|
let code = this.textContent.replace(/\r\n?/g, "\n");
|
||||||
// Remove leading/trailing blank lines
|
// Remove leading/trailing blank lines
|
||||||
code = code.replace(/^\s*\n/, '').replace(/\n\s*$/, '');
|
code = code.replace(/^\s*\n/, '').replace(/\n\s*$/, '');
|
||||||
// Find leading spaces from the first non-empty line
|
// Find leading spaces from the first non-empty line
|
||||||
const lines = code.split("\n");
|
const lines = code.split("\n");
|
||||||
const firstLine = lines.find(line => line.trim().length > 0) || '';
|
const firstLine = lines.find(line => line.trim().length > 0) || '';
|
||||||
const leadingSpaces = firstLine.match(/^\s*/)[0].length;
|
const leadingSpaces = firstLine.match(/^\s*/)[0].length;
|
||||||
// Remove that many leading spaces from all lines
|
// Remove that many leading spaces from all lines
|
||||||
const stripped = lines.map(line => line.slice(leadingSpaces)).join("\n");
|
const stripped = lines.map(line => line.slice(leadingSpaces)).join("\n");
|
||||||
// Escape HTML special characters
|
// Escape HTML special characters
|
||||||
const escaped = stripped
|
const escaped = stripped
|
||||||
.replace(/&/g, "&")
|
.replace(/&/g, "&")
|
||||||
.replace(/</g, "<")
|
.replace(/</g, "<")
|
||||||
.replace(/>/g, ">");
|
.replace(/>/g, ">");
|
||||||
const lang = this.getAttribute('lang') || '';
|
const lang = this.getAttribute('lang') || '';
|
||||||
const langClass = lang ? `language-${lang}` : '';
|
const langClass = lang ? `language-${lang}` : '';
|
||||||
this.innerHTML = `<pre class=\"custom-code-block\"><code class=\"${langClass}\">${escaped}</code></pre>`;
|
this.innerHTML = `<pre class=\"custom-code-block\"><code class=\"${langClass}\">${escaped}</code></pre>`;
|
||||||
// If Prism or highlight.js is present, trigger highlighting
|
// If Prism or highlight.js is present, trigger highlighting
|
||||||
if (window.Prism && Prism.highlightElement) {
|
if (window.Prism && Prism.highlightElement) {
|
||||||
Prism.highlightElement(this.querySelector('code'));
|
Prism.highlightElement(this.querySelector('code'));
|
||||||
} else if (window.hljs && hljs.highlightElement) {
|
} else if (window.hljs && hljs.highlightElement) {
|
||||||
hljs.highlightElement(this.querySelector('code'));
|
hljs.highlightElement(this.querySelector('code'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define('code-block', CodeBlock);
|
customElements.define('code-block', CodeBlock);
|
||||||
@@ -1,32 +1,32 @@
|
|||||||
class CodeInline extends HTMLElement {
|
class CodeInline extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
// Get the code content as text
|
// Get the code content as text
|
||||||
let code = this.textContent;
|
let code = this.textContent;
|
||||||
|
|
||||||
// Escape HTML special characters
|
// Escape HTML special characters
|
||||||
code = code
|
code = code
|
||||||
.replace(/&/g, "&")
|
.replace(/&/g, "&")
|
||||||
.replace(/</g, "<")
|
.replace(/</g, "<")
|
||||||
.replace(/>/g, ">");
|
.replace(/>/g, ">");
|
||||||
|
|
||||||
// Highlight variables: $variable, {variable}, or %variable%
|
// Highlight variables: $variable, {variable}, or %variable%
|
||||||
code = code.replace(/(\$[a-zA-Z_][\w]*)|(\{[^\}]+\})|(%[^%]+%)/g, match =>
|
code = code.replace(/(\$[a-zA-Z_][\w]*)|(\{[^\}]+\})|(%[^%]+%)/g, match =>
|
||||||
`<span class="inline-var">${match}</span>`
|
`<span class="inline-var">${match}</span>`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get language attribute for potential syntax highlighting
|
// Get language attribute for potential syntax highlighting
|
||||||
const lang = this.getAttribute('lang') || '';
|
const lang = this.getAttribute('lang') || '';
|
||||||
const langClass = lang ? `language-${lang}` : '';
|
const langClass = lang ? `language-${lang}` : '';
|
||||||
|
|
||||||
this.innerHTML = `<code class="custom-inline-code ${langClass}">${code}</code>`;
|
this.innerHTML = `<code class="custom-inline-code ${langClass}">${code}</code>`;
|
||||||
|
|
||||||
// If Prism or highlight.js is present, trigger highlighting
|
// If Prism or highlight.js is present, trigger highlighting
|
||||||
if (window.Prism && Prism.highlightElement) {
|
if (window.Prism && Prism.highlightElement) {
|
||||||
Prism.highlightElement(this.querySelector('code'));
|
Prism.highlightElement(this.querySelector('code'));
|
||||||
} else if (window.hljs && hljs.highlightElement) {
|
} else if (window.hljs && hljs.highlightElement) {
|
||||||
hljs.highlightElement(this.querySelector('code'));
|
hljs.highlightElement(this.querySelector('code'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('code-inline', CodeInline);
|
customElements.define('code-inline', CodeInline);
|
||||||
@@ -1,35 +1,35 @@
|
|||||||
class Note extends HTMLElement {
|
class Note extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
// Get the note content
|
// Get the note content
|
||||||
const content = this.innerHTML;
|
const content = this.innerHTML;
|
||||||
|
|
||||||
// Get optional type attribute for different note styles
|
// Get optional type attribute for different note styles
|
||||||
const type = this.getAttribute('type') || 'default';
|
const type = this.getAttribute('type') || 'default';
|
||||||
|
|
||||||
// Get optional title attribute
|
// Get optional title attribute
|
||||||
const title = this.getAttribute('title');
|
const title = this.getAttribute('title');
|
||||||
|
|
||||||
// Build the note HTML
|
// Build the note HTML
|
||||||
let noteHTML = '<div class="note';
|
let noteHTML = '<div class="note';
|
||||||
|
|
||||||
// Add type-specific class if provided
|
// Add type-specific class if provided
|
||||||
if (type !== 'default') {
|
if (type !== 'default') {
|
||||||
noteHTML += ` note-${type}`;
|
noteHTML += ` note-${type}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
noteHTML += '">';
|
noteHTML += '">';
|
||||||
|
|
||||||
// Add title if provided
|
// Add title if provided
|
||||||
if (title) {
|
if (title) {
|
||||||
noteHTML += `<h4 class="note-title">${title}</h4>`;
|
noteHTML += `<h4 class="note-title">${title}</h4>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the content
|
// Add the content
|
||||||
noteHTML += content;
|
noteHTML += content;
|
||||||
noteHTML += '</div>';
|
noteHTML += '</div>';
|
||||||
|
|
||||||
this.innerHTML = noteHTML;
|
this.innerHTML = noteHTML;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('note-box', Note);
|
customElements.define('note-box', Note);
|
||||||
@@ -1,198 +1,198 @@
|
|||||||
class Sidebar extends HTMLElement {
|
class Sidebar extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.navItems = [];
|
this.navItems = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.render();
|
this.render();
|
||||||
this.scanHeaders();
|
this.scanHeaders();
|
||||||
this.setupScrollListener();
|
this.setupScrollListener();
|
||||||
this.highlightActiveSection();
|
this.highlightActiveSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
scanHeaders() {
|
scanHeaders() {
|
||||||
// Clear existing nav items
|
// Clear existing nav items
|
||||||
this.navItems = [];
|
this.navItems = [];
|
||||||
|
|
||||||
// Find all h2, h3, and h4 elements with IDs in the content area
|
// Find all h2, h3, and h4 elements with IDs in the content area
|
||||||
const contentWrapper = document.querySelector('.content-wrapper');
|
const contentWrapper = document.querySelector('.content-wrapper');
|
||||||
if (!contentWrapper) return;
|
if (!contentWrapper) return;
|
||||||
|
|
||||||
const headers = contentWrapper.querySelectorAll('h2[id], h3[id], h4[id]');
|
const headers = contentWrapper.querySelectorAll('h2[id], h3[id], h4[id]');
|
||||||
|
|
||||||
headers.forEach(header => {
|
headers.forEach(header => {
|
||||||
const id = header.getAttribute('id');
|
const id = header.getAttribute('id');
|
||||||
const text = header.textContent.trim();
|
const text = header.textContent.trim();
|
||||||
const level = header.tagName.toLowerCase();
|
const level = header.tagName.toLowerCase();
|
||||||
|
|
||||||
this.navItems.push({
|
this.navItems.push({
|
||||||
id,
|
id,
|
||||||
text,
|
text,
|
||||||
level,
|
level,
|
||||||
element: header
|
element: header
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.renderNavigation();
|
this.renderNavigation();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNavigation() {
|
renderNavigation() {
|
||||||
const ul = this.querySelector('ul');
|
const ul = this.querySelector('ul');
|
||||||
if (!ul) return;
|
if (!ul) return;
|
||||||
|
|
||||||
// Clear existing content
|
// Clear existing content
|
||||||
ul.innerHTML = '';
|
ul.innerHTML = '';
|
||||||
|
|
||||||
let currentH2Li = null;
|
let currentH2Li = null;
|
||||||
let currentH3Li = null;
|
let currentH3Li = null;
|
||||||
|
|
||||||
this.navItems.forEach(item => {
|
this.navItems.forEach(item => {
|
||||||
if (item.level === 'h2') {
|
if (item.level === 'h2') {
|
||||||
// Create h2 item
|
// Create h2 item
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = `#${item.id}`;
|
a.href = `#${item.id}`;
|
||||||
a.className = 'side-nav-h2';
|
a.className = 'side-nav-h2';
|
||||||
a.textContent = item.text;
|
a.textContent = item.text;
|
||||||
a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
|
a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
|
||||||
|
|
||||||
li.appendChild(a);
|
li.appendChild(a);
|
||||||
ul.appendChild(li);
|
ul.appendChild(li);
|
||||||
currentH2Li = li;
|
currentH2Li = li;
|
||||||
currentH3Li = null;
|
currentH3Li = null;
|
||||||
} else if (item.level === 'h3' && currentH2Li) {
|
} else if (item.level === 'h3' && currentH2Li) {
|
||||||
// Create h3 item under current h2
|
// Create h3 item under current h2
|
||||||
let subUl = currentH2Li.querySelector('ul');
|
let subUl = currentH2Li.querySelector('ul');
|
||||||
if (!subUl) {
|
if (!subUl) {
|
||||||
subUl = document.createElement('ul');
|
subUl = document.createElement('ul');
|
||||||
currentH2Li.appendChild(subUl);
|
currentH2Li.appendChild(subUl);
|
||||||
}
|
}
|
||||||
|
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = `#${item.id}`;
|
a.href = `#${item.id}`;
|
||||||
a.className = 'side-nav-h3';
|
a.className = 'side-nav-h3';
|
||||||
a.textContent = item.text;
|
a.textContent = item.text;
|
||||||
a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
|
a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
|
||||||
|
|
||||||
li.appendChild(a);
|
li.appendChild(a);
|
||||||
subUl.appendChild(li);
|
subUl.appendChild(li);
|
||||||
currentH3Li = li;
|
currentH3Li = li;
|
||||||
} else if (item.level === 'h4' && currentH3Li) {
|
} else if (item.level === 'h4' && currentH3Li) {
|
||||||
// Create h4 item under current h3
|
// Create h4 item under current h3
|
||||||
let subUl = currentH3Li.querySelector('ul');
|
let subUl = currentH3Li.querySelector('ul');
|
||||||
if (!subUl) {
|
if (!subUl) {
|
||||||
subUl = document.createElement('ul');
|
subUl = document.createElement('ul');
|
||||||
currentH3Li.appendChild(subUl);
|
currentH3Li.appendChild(subUl);
|
||||||
}
|
}
|
||||||
|
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = `#${item.id}`;
|
a.href = `#${item.id}`;
|
||||||
a.className = 'side-nav-h4';
|
a.className = 'side-nav-h4';
|
||||||
a.textContent = item.text;
|
a.textContent = item.text;
|
||||||
a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
|
a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
|
||||||
|
|
||||||
li.appendChild(a);
|
li.appendChild(a);
|
||||||
subUl.appendChild(li);
|
subUl.appendChild(li);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNavClick(e, targetId) {
|
handleNavClick(e, targetId) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// Remove active class from all links
|
// Remove active class from all links
|
||||||
this.querySelectorAll('a').forEach(link => {
|
this.querySelectorAll('a').forEach(link => {
|
||||||
link.classList.remove('active');
|
link.classList.remove('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add active class to clicked link
|
// Add active class to clicked link
|
||||||
e.target.classList.add('active');
|
e.target.classList.add('active');
|
||||||
|
|
||||||
// Smooth scroll to target
|
// Smooth scroll to target
|
||||||
const targetElement = document.getElementById(targetId);
|
const targetElement = document.getElementById(targetId);
|
||||||
if (targetElement) {
|
if (targetElement) {
|
||||||
targetElement.scrollIntoView({
|
targetElement.scrollIntoView({
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
block: 'start'
|
block: 'start'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setupScrollListener() {
|
setupScrollListener() {
|
||||||
let ticking = false;
|
let ticking = false;
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
if (!ticking) {
|
if (!ticking) {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
this.highlightActiveSection();
|
this.highlightActiveSection();
|
||||||
ticking = false;
|
ticking = false;
|
||||||
});
|
});
|
||||||
ticking = true;
|
ticking = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('scroll', handleScroll);
|
window.addEventListener('scroll', handleScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
highlightActiveSection() {
|
highlightActiveSection() {
|
||||||
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||||
const offset = 100; // Offset for highlighting
|
const offset = 100; // Offset for highlighting
|
||||||
|
|
||||||
let activeId = '';
|
let activeId = '';
|
||||||
|
|
||||||
// Find the currently visible section
|
// Find the currently visible section
|
||||||
this.navItems.forEach(item => {
|
this.navItems.forEach(item => {
|
||||||
const element = item.element;
|
const element = item.element;
|
||||||
const rect = element.getBoundingClientRect();
|
const rect = element.getBoundingClientRect();
|
||||||
const elementTop = rect.top + scrollTop;
|
const elementTop = rect.top + scrollTop;
|
||||||
|
|
||||||
if (elementTop <= scrollTop + offset) {
|
if (elementTop <= scrollTop + offset) {
|
||||||
activeId = item.id;
|
activeId = item.id;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update active state
|
// Update active state
|
||||||
this.querySelectorAll('a').forEach(link => {
|
this.querySelectorAll('a').forEach(link => {
|
||||||
link.classList.remove('active');
|
link.classList.remove('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
if (activeId !== nil && activeId !== '') {
|
if (activeId !== nil && activeId !== '') {
|
||||||
const activeLink = this.querySelector(`a[href="#${activeId}"]`);
|
const activeLink = this.querySelector(`a[href="#${activeId}"]`);
|
||||||
if (activeLink) {
|
if (activeLink) {
|
||||||
activeLink.classList.add('active');
|
activeLink.classList.add('active');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
this.innerHTML = `
|
this.innerHTML = `
|
||||||
<div class="side-nav">
|
<div class="side-nav">
|
||||||
<h4 class="side-nav-title"></h4>
|
<h4 class="side-nav-title"></h4>
|
||||||
<ul>
|
<ul>
|
||||||
<!-- Navigation items will be populated automatically -->
|
<!-- Navigation items will be populated automatically -->
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to refresh the sidebar when content changes
|
// Method to refresh the sidebar when content changes
|
||||||
refresh() {
|
refresh() {
|
||||||
this.scanHeaders();
|
this.scanHeaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to set the sidebar title
|
// Method to set the sidebar title
|
||||||
setTitle(title) {
|
setTitle(title) {
|
||||||
const titleElement = this.querySelector('.side-nav-title');
|
const titleElement = this.querySelector('.side-nav-title');
|
||||||
if (titleElement) {
|
if (titleElement) {
|
||||||
titleElement.textContent = title;
|
titleElement.textContent = title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the custom element
|
// Register the custom element
|
||||||
customElements.define('app-sidebar', Sidebar);
|
customElements.define('app-sidebar', Sidebar);
|
||||||
|
|
||||||
export default Sidebar;
|
export default Sidebar;
|
||||||
@@ -1,91 +1,91 @@
|
|||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const themeToggle = document.getElementById('theme-toggle');
|
const themeToggle = document.getElementById('theme-toggle');
|
||||||
const sunIcon = document.getElementById('sun-icon');
|
const sunIcon = document.getElementById('sun-icon');
|
||||||
const moonIcon = document.getElementById('moon-icon');
|
const moonIcon = document.getElementById('moon-icon');
|
||||||
if (!themeToggle || !sunIcon || !moonIcon) return;
|
if (!themeToggle || !sunIcon || !moonIcon) return;
|
||||||
|
|
||||||
function setTheme(theme) {
|
function setTheme(theme) {
|
||||||
document.documentElement.setAttribute('data-theme', theme);
|
document.documentElement.setAttribute('data-theme', theme);
|
||||||
localStorage.setItem('theme', theme);
|
localStorage.setItem('theme', theme);
|
||||||
sunIcon.style.display = theme === 'light' ? 'block' : 'none';
|
sunIcon.style.display = theme === 'light' ? 'block' : 'none';
|
||||||
moonIcon.style.display = theme === 'light' ? 'none' : 'block';
|
moonIcon.style.display = theme === 'light' ? 'none' : 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
themeToggle.addEventListener('click', function() {
|
themeToggle.addEventListener('click', function() {
|
||||||
const current = document.documentElement.getAttribute('data-theme') || 'dark';
|
const current = document.documentElement.getAttribute('data-theme') || 'dark';
|
||||||
setTheme(current === 'dark' ? 'light' : 'dark');
|
setTheme(current === 'dark' ? 'light' : 'dark');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
const saved = localStorage.getItem('theme') || 'dark';
|
const saved = localStorage.getItem('theme') || 'dark';
|
||||||
setTheme(saved);
|
setTheme(saved);
|
||||||
|
|
||||||
// Set side-nav-title to the first h1's text
|
// Set side-nav-title to the first h1's text
|
||||||
var h1 = document.querySelector('.content-wrapper h1');
|
var h1 = document.querySelector('.content-wrapper h1');
|
||||||
var sideNavTitle = document.querySelector('.side-nav-title');
|
var sideNavTitle = document.querySelector('.side-nav-title');
|
||||||
if (h1 && sideNavTitle) {
|
if (h1 && sideNavTitle) {
|
||||||
sideNavTitle.textContent = h1.textContent;
|
sideNavTitle.textContent = h1.textContent;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Highlight sidenav link on scroll (shared for all pages)
|
// Highlight sidenav link on scroll (shared for all pages)
|
||||||
function setupSideNavHighlight() {
|
function setupSideNavHighlight() {
|
||||||
const navLinks = document.querySelectorAll('.side-nav a');
|
const navLinks = document.querySelectorAll('.side-nav a');
|
||||||
if (!navLinks.length) return;
|
if (!navLinks.length) return;
|
||||||
const sections = Array.from(navLinks).map(link => {
|
const sections = Array.from(navLinks).map(link => {
|
||||||
const id = link.getAttribute('href').replace('#', '');
|
const id = link.getAttribute('href').replace('#', '');
|
||||||
return document.getElementById(id);
|
return document.getElementById(id);
|
||||||
});
|
});
|
||||||
function getHeaderOffset() {
|
function getHeaderOffset() {
|
||||||
const header = document.querySelector('header');
|
const header = document.querySelector('header');
|
||||||
return header ? header.offsetHeight : 0;
|
return header ? header.offsetHeight : 0;
|
||||||
}
|
}
|
||||||
// Custom scroll on nav click
|
// Custom scroll on nav click
|
||||||
navLinks.forEach((link, i) => {
|
navLinks.forEach((link, i) => {
|
||||||
link.addEventListener('click', function(e) {
|
link.addEventListener('click', function(e) {
|
||||||
const section = sections[i];
|
const section = sections[i];
|
||||||
if (section) {
|
if (section) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const headerOffset = getHeaderOffset();
|
const headerOffset = getHeaderOffset();
|
||||||
const targetY = window.innerHeight * 0.10;
|
const targetY = window.innerHeight * 0.10;
|
||||||
const sectionTop = section.getBoundingClientRect().top + window.scrollY;
|
const sectionTop = section.getBoundingClientRect().top + window.scrollY;
|
||||||
const scrollTo = sectionTop - headerOffset - targetY;
|
const scrollTo = sectionTop - headerOffset - targetY;
|
||||||
window.scrollTo({ top: scrollTo, behavior: 'smooth' });
|
window.scrollTo({ top: scrollTo, behavior: 'smooth' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
function onScroll() {
|
function onScroll() {
|
||||||
const headerOffset = getHeaderOffset();
|
const headerOffset = getHeaderOffset();
|
||||||
const targetY = window.innerHeight * 0.1; // 30% from the top
|
const targetY = window.innerHeight * 0.1; // 30% from the top
|
||||||
let closestIdx = 0;
|
let closestIdx = 0;
|
||||||
let minDist = Infinity;
|
let minDist = Infinity;
|
||||||
for (let i = 0; i < sections.length; i++) {
|
for (let i = 0; i < sections.length; i++) {
|
||||||
const section = sections[i];
|
const section = sections[i];
|
||||||
if (section) {
|
if (section) {
|
||||||
const dist = Math.abs(section.getBoundingClientRect().top - headerOffset - targetY);
|
const dist = Math.abs(section.getBoundingClientRect().top - headerOffset - targetY);
|
||||||
if (dist < minDist) {
|
if (dist < minDist) {
|
||||||
minDist = dist;
|
minDist = dist;
|
||||||
closestIdx = i;
|
closestIdx = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
navLinks.forEach((link, i) => {
|
navLinks.forEach((link, i) => {
|
||||||
if (i === closestIdx) {
|
if (i === closestIdx) {
|
||||||
link.classList.add('active');
|
link.classList.add('active');
|
||||||
} else {
|
} else {
|
||||||
link.classList.remove('active');
|
link.classList.remove('active');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
window.addEventListener('scroll', onScroll, { passive: true });
|
window.addEventListener('scroll', onScroll, { passive: true });
|
||||||
window.addEventListener('resize', onScroll);
|
window.addEventListener('resize', onScroll);
|
||||||
onScroll(); // Initial call
|
onScroll(); // Initial call
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run on DOMContentLoaded
|
// Run on DOMContentLoaded
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', setupSideNavHighlight);
|
document.addEventListener('DOMContentLoaded', setupSideNavHighlight);
|
||||||
} else {
|
} else {
|
||||||
setupSideNavHighlight();
|
setupSideNavHighlight();
|
||||||
}
|
}
|
||||||
@@ -1,60 +1,60 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" data-theme="dark">
|
<html lang="en" data-theme="dark">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Spearhead API</title>
|
<title>Spearhead API</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="/style/prism.css">
|
<link rel="stylesheet" href="/style/prism.css">
|
||||||
<link rel="stylesheet" href="/style/style.css">
|
<link rel="stylesheet" href="/style/style.css">
|
||||||
|
|
||||||
<script src="/js/prism.js"></script>
|
<script src="/js/prism.js"></script>
|
||||||
<script src="/js/site.js"></script>
|
<script src="/js/site.js"></script>
|
||||||
<script type="module" src="../js/components.js"></script>
|
<script type="module" src="../js/components.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<app-header></app-header>
|
<app-header></app-header>
|
||||||
</header> <main>
|
</header> <main>
|
||||||
<div class="reference-container">
|
<div class="reference-container">
|
||||||
<app-sidebar></app-sidebar>
|
<app-sidebar></app-sidebar>
|
||||||
|
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<h1>Spearhead API</h1>
|
<h1>Spearhead API</h1>
|
||||||
|
|
||||||
<div class="note">
|
<div class="note">
|
||||||
<p><strong>NOTE:</strong> The Spearhead.API space is only released in the Beta branch at the moment.</p>
|
<p><strong>NOTE:</strong> The Spearhead.API space is only released in the Beta branch at the moment.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 id="introduction">Introduction</h2>
|
<h2 id="introduction">Introduction</h2>
|
||||||
<p>
|
<p>
|
||||||
The <span class="inline-lua"><span class="lua-variable">Spearhead.API</span></span> space is specifically created to make sure mission makers can interact with the framework.
|
The <span class="inline-lua"><span class="lua-variable">Spearhead.API</span></span> space is specifically created to make sure mission makers can interact with the framework.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Simply alter logic, get the current state in Spearhead, and give the whole Mission Editor more control.
|
Simply alter logic, get the current state in Spearhead, and give the whole Mission Editor more control.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
For example, late activate the entire framework by calling <span class="inline-lua"><span class="lua-function">Spearhead.API.Stages.changeStage</span>(<span class="lua-variable">1</span>)</span> later or on demand and setting the starting config stage to -1 in the Spearhead configuration file.
|
For example, late activate the entire framework by calling <span class="inline-lua"><span class="lua-function">Spearhead.API.Stages.changeStage</span>(<span class="lua-variable">1</span>)</span> later or on demand and setting the starting config stage to -1 in the Spearhead configuration file.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="stages">Stages</h2>
|
<h2 id="stages">Stages</h2>
|
||||||
<pre>
|
<pre>
|
||||||
@@API_CODE@@
|
@@API_CODE@@
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<p>© 2025 Spearhead Project</p>
|
<p>© 2025 Spearhead Project</p>
|
||||||
</footer>
|
</footer>
|
||||||
<style>
|
<style>
|
||||||
.side-nav a.active {
|
.side-nav a.active {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #4fc3f7;
|
color: #4fc3f7;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
/* PrismJS 1.30.0
|
/* PrismJS 1.30.0
|
||||||
https://prismjs.com/download#themes=prism-okaidia&languages=lua */
|
https://prismjs.com/download#themes=prism-okaidia&languages=lua */
|
||||||
code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|
code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|
||||||
@@ -20,8 +20,10 @@ jobs:
|
|||||||
- name: Upload spearhead.lua artifact
|
- name: Upload spearhead.lua artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: spearhead-lua
|
name: spearhead-docs
|
||||||
path: ./output/spearhead.lua
|
path: ./.docs/**/*
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
|
||||||
build-image:
|
build-image:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
FROM nginx:latest
|
|
||||||
|
|
||||||
COPY ./ /usr/share/nginx/html
|
|
||||||