Initial commit
This commit is contained in:
20
themes/dispute-protocol-theme/LICENSE
Normal file
20
themes/dispute-protocol-theme/LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2025 YOUR_NAME_HERE
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
2
themes/dispute-protocol-theme/archetypes/default.md
Normal file
2
themes/dispute-protocol-theme/archetypes/default.md
Normal file
@ -0,0 +1,2 @@
|
||||
+++
|
||||
+++
|
0
themes/dispute-protocol-theme/layouts/404.html
Normal file
0
themes/dispute-protocol-theme/layouts/404.html
Normal file
11
themes/dispute-protocol-theme/layouts/_default/baseof.html
Normal file
11
themes/dispute-protocol-theme/layouts/_default/baseof.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
{{- partial "head.html" . -}}
|
||||
<body>
|
||||
{{- partial "header.html" . -}}
|
||||
<div id="content">
|
||||
{{- block "main" . }}{{- end }}
|
||||
</div>
|
||||
{{- partial "footer.html" . -}}
|
||||
</body>
|
||||
</html>
|
290
themes/dispute-protocol-theme/layouts/_default/builder.html
Normal file
290
themes/dispute-protocol-theme/layouts/_default/builder.html
Normal file
@ -0,0 +1,290 @@
|
||||
{{ define "main" }}
|
||||
<div class="builder-container">
|
||||
<h1>{{ .Title }}</h1>
|
||||
{{ .Content }}
|
||||
|
||||
<div id="protocol-builder" class="builder">
|
||||
<div class="builder-main">
|
||||
<div class="protocol-metadata">
|
||||
<div class="metadata-field">
|
||||
<label for="community-name">Community Name:</label>
|
||||
<input type="text" id="community-name" name="community-name" placeholder="Enter your community name...">
|
||||
</div>
|
||||
|
||||
<div class="metadata-field">
|
||||
<label for="protocol-summary">Protocol Summary:</label>
|
||||
<textarea id="protocol-summary" name="protocol-summary" placeholder="Briefly describe this dispute resolution protocol and its purpose..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="protocol-template-selector">
|
||||
<label for="protocol-template">Select a Protocol Template:</label>
|
||||
<select id="protocol-template" class="protocol-template-select">
|
||||
<option value="">-- Create Your Own Protocol --</option>
|
||||
<!-- Template options will be populated by JavaScript -->
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="builder-content">
|
||||
{{ range $.Site.Data.stages.stages }}
|
||||
<div class="stage-section" id="stage-{{ .id }}">
|
||||
<div class="stage-header" data-stage="{{ .id }}">
|
||||
<div class="stage-header-content">
|
||||
<h2>{{ .title }}</h2>
|
||||
<p class="stage-brief">{{ .description }}</p>
|
||||
</div>
|
||||
<button type="button" class="toggle-btn" aria-label="Toggle section" onclick="toggleStage(this)">+</button>
|
||||
</div>
|
||||
<div class="stage-body">
|
||||
<div class="components">
|
||||
{{ $stageId := .id }}
|
||||
{{ $componentFile := printf "%s" $stageId }}
|
||||
{{ range index $.Site.Data.components $componentFile }}
|
||||
{{ $componentId := .id }}
|
||||
<div class="component-card" id="component-{{ $componentId }}">
|
||||
<div class="component-header">
|
||||
<div class="component-title-wrapper">
|
||||
<div class="component-short-label">{{ $componentId | humanize }}</div>
|
||||
<h3>{{ .title }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="component-body">
|
||||
{{ range .fields }}
|
||||
<div class="field" id="field-{{ .id }}">
|
||||
<div class="module-selector">
|
||||
<label for="module-{{ .id }}">Select a module:</label>
|
||||
<select id="module-{{ .id }}" class="module-select" data-field-id="{{ .id }}" data-component-id="{{ $componentId }}">
|
||||
<option value="">-- Choose a module --</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<textarea id="{{ .id }}" name="{{ .id }}" placeholder="{{ .placeholder }}" {{ if .required }}required{{ end }}></textarea>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<!-- Export buttons moved to sidebar -->
|
||||
|
||||
</div>
|
||||
|
||||
<div class="builder-sidebar">
|
||||
<div class="sidebar-section">
|
||||
<h3>Tools</h3>
|
||||
<div id="sidebar-nav" class="sidebar-nav">
|
||||
<h4>Jump to Section</h4>
|
||||
<div class="sidebar-nav-content">
|
||||
<div class="nav-tree">
|
||||
{{ range $.Site.Data.stages.stages }}
|
||||
<div class="nav-stage">
|
||||
<a href="#stage-{{ .id }}" class="nav-stage-link">{{ .title }}</a>
|
||||
<div class="nav-components">
|
||||
{{ $stageId := .id }}
|
||||
{{ $componentFile := printf "%s" $stageId }}
|
||||
{{ range index $.Site.Data.components $componentFile }}
|
||||
<a href="#component-{{ .id }}" class="nav-component-link">{{ .title }}</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-toggle" style="margin-top: 1.5rem;">
|
||||
<label class="toggle-switch" for="preview-toggle">
|
||||
<input type="checkbox" id="preview-toggle">
|
||||
<span class="toggle-slider"></span>
|
||||
<span class="toggle-label">Preview Mode</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="sidebar-info">
|
||||
<p>Preview mode shows only completed elements.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-section">
|
||||
<h3>Export Options</h3>
|
||||
<div class="sidebar-export-options">
|
||||
<a href="#" id="export-md" class="sidebar-btn">Export Markdown</a>
|
||||
<a href="#" id="export-pdf" class="sidebar-btn">Export PDF</a>
|
||||
<a href="#" id="export-json" class="sidebar-btn">Export JSON</a>
|
||||
<button id="import-btn" class="sidebar-btn">Import JSON</button>
|
||||
<input type="file" id="import-json" accept=".json" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts are loaded in head.html -->
|
||||
<script>
|
||||
function toggleStage(button) {
|
||||
const section = button.closest('.stage-section');
|
||||
const body = section.querySelector('.stage-body');
|
||||
|
||||
if (body.style.display === 'block') {
|
||||
body.style.display = 'none';
|
||||
button.textContent = '+';
|
||||
} else {
|
||||
body.style.display = 'block';
|
||||
button.textContent = '-';
|
||||
}
|
||||
|
||||
// Prevent event from propagating
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
// Make headers also toggle sections
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const headers = document.querySelectorAll('.stage-header-content');
|
||||
headers.forEach(header => {
|
||||
header.addEventListener('click', function() {
|
||||
const stageHeader = this.closest('.stage-header');
|
||||
const toggleButton = stageHeader.querySelector('.toggle-btn');
|
||||
toggleButton.click();
|
||||
});
|
||||
});
|
||||
|
||||
// Export dropdown removed (moved to sidebar)
|
||||
|
||||
// Preview Mode Toggle
|
||||
const previewToggle = document.getElementById('preview-toggle');
|
||||
if (previewToggle) {
|
||||
previewToggle.addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
enablePreviewMode();
|
||||
} else {
|
||||
disablePreviewMode();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function enablePreviewMode() {
|
||||
// Create style element
|
||||
let style = document.createElement('style');
|
||||
style.id = 'preview-style';
|
||||
style.innerHTML = `
|
||||
.module-selector { display: none !important; }
|
||||
.field:not(.has-content) { display: none !important; }
|
||||
.component-card:not(.has-content) { display: none !important; }
|
||||
.stage-section:not(.has-content) { display: none !important; }
|
||||
.protocol-template-selector { display: none !important; }
|
||||
.stage-body { display: block !important; }
|
||||
textarea {
|
||||
border: none !important;
|
||||
background-color: transparent !important;
|
||||
padding: 0 !important;
|
||||
min-height: unset !important;
|
||||
height: auto !important;
|
||||
resize: none !important;
|
||||
pointer-events: none !important;
|
||||
overflow: visible !important;
|
||||
white-space: pre-wrap !important;
|
||||
width: 100% !important;
|
||||
word-wrap: break-word !important;
|
||||
}
|
||||
.component-header {
|
||||
background-color: transparent !important;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
.component-short-label { display: none !important; }
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Mark elements with content
|
||||
document.querySelectorAll('textarea').forEach(textarea => {
|
||||
if (textarea.value && textarea.value.trim()) {
|
||||
const field = textarea.closest('.field');
|
||||
if (field) field.classList.add('has-content');
|
||||
|
||||
const component = textarea.closest('.component-card');
|
||||
if (component) component.classList.add('has-content');
|
||||
|
||||
const stage = textarea.closest('.stage-section');
|
||||
if (stage) stage.classList.add('has-content');
|
||||
}
|
||||
});
|
||||
|
||||
// Make fields read-only
|
||||
document.querySelectorAll('textarea, #community-name, #protocol-summary').forEach(el => {
|
||||
el.readOnly = true;
|
||||
});
|
||||
}
|
||||
|
||||
function disablePreviewMode() {
|
||||
// Remove preview styles
|
||||
const style = document.getElementById('preview-style');
|
||||
if (style) {
|
||||
style.parentNode.removeChild(style);
|
||||
}
|
||||
|
||||
// Remove content markers
|
||||
document.querySelectorAll('.has-content').forEach(el => {
|
||||
el.classList.remove('has-content');
|
||||
});
|
||||
|
||||
// Make fields editable again
|
||||
document.querySelectorAll('textarea, #community-name, #protocol-summary').forEach(el => {
|
||||
el.readOnly = false;
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize the sidebar navigation
|
||||
initSidebarNavigation();
|
||||
});
|
||||
|
||||
// Initialize the sidebar navigation
|
||||
function initSidebarNavigation() {
|
||||
// Set up click handlers for navigation links
|
||||
document.querySelectorAll('.nav-stage-link, .nav-component-link').forEach(link => {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Get the target element's ID from the href
|
||||
const targetId = this.getAttribute('href').substring(1);
|
||||
const targetElement = document.getElementById(targetId);
|
||||
|
||||
if (targetElement) {
|
||||
// If it's a stage, make sure it's expanded
|
||||
if (targetId.startsWith('stage-')) {
|
||||
const stageBody = targetElement.querySelector('.stage-body');
|
||||
const toggleBtn = targetElement.querySelector('.toggle-btn');
|
||||
|
||||
if (stageBody && stageBody.style.display !== 'block') {
|
||||
stageBody.style.display = 'block';
|
||||
if (toggleBtn) toggleBtn.textContent = '-';
|
||||
}
|
||||
}
|
||||
|
||||
// If it's a component, make sure its parent stage is expanded
|
||||
if (targetId.startsWith('component-')) {
|
||||
const stageSection = targetElement.closest('.stage-section');
|
||||
if (stageSection) {
|
||||
const stageBody = stageSection.querySelector('.stage-body');
|
||||
const toggleBtn = stageSection.querySelector('.toggle-btn');
|
||||
|
||||
if (stageBody && stageBody.style.display !== 'block') {
|
||||
stageBody.style.display = 'block';
|
||||
if (toggleBtn) toggleBtn.textContent = '-';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll to the target with some offset to account for sticky headers
|
||||
window.scrollTo({
|
||||
top: targetElement.offsetTop - 20,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{{ end }}
|
36
themes/dispute-protocol-theme/layouts/_default/modules.html
Normal file
36
themes/dispute-protocol-theme/layouts/_default/modules.html
Normal file
@ -0,0 +1,36 @@
|
||||
{{ define "main" }}
|
||||
<div class="container">
|
||||
<div class="page-header">
|
||||
<h1>{{ .Title }}</h1>
|
||||
<p>{{ .Description }}</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
|
||||
<div class="search-filter">
|
||||
<input type="text" id="module-search" placeholder="Search modules...">
|
||||
<select id="stage-filter">
|
||||
<option value="">All Stages</option>
|
||||
</select>
|
||||
<select id="component-filter">
|
||||
<option value="">All Components</option>
|
||||
</select>
|
||||
<select id="template-filter">
|
||||
<option value="">All Templates</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="modules-container" class="modules-container">
|
||||
<!-- Modules will be loaded here via JavaScript -->
|
||||
<div class="loading">Loading modules...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Load the module data -->
|
||||
<script src="{{ "js/data/modules.js" | relURL }}"></script>
|
||||
<script src="{{ "js/data/templates.js" | relURL }}"></script>
|
||||
<script src="{{ "js/data/template-mapper.js" | relURL }}"></script>
|
||||
<script src="{{ "js/modules-page.js" | relURL }}"></script>
|
||||
{{ end }}
|
@ -0,0 +1,7 @@
|
||||
{{ define "main" }}
|
||||
<div class="content-container">
|
||||
<article class="page-content">
|
||||
{{ .Content }}
|
||||
</article>
|
||||
</div>
|
||||
{{ end }}
|
26
themes/dispute-protocol-theme/layouts/index.html
Normal file
26
themes/dispute-protocol-theme/layouts/index.html
Normal file
@ -0,0 +1,26 @@
|
||||
{{ define "main" }}
|
||||
<div class="home-content">
|
||||
<div class="hero">
|
||||
<h1>{{ .Title }}</h1>
|
||||
<p class="lead">Create a customized dispute resolution protocol for your community</p>
|
||||
<a href="/builder/" class="btn-primary">Start Building</a>
|
||||
<a href="/about/" class="btn-secondary">Learn More</a>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
|
||||
<div class="stages-overview">
|
||||
<h2>The Dispute Resolution Process</h2>
|
||||
<div class="stages-grid">
|
||||
{{ range $.Site.Data.stages.stages }}
|
||||
<div class="stage-card">
|
||||
<h3>{{ .title }}</h3>
|
||||
<p>{{ .description }}</p>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
@ -0,0 +1,6 @@
|
||||
<footer>
|
||||
<div class="container">
|
||||
<p>© {{ now.Format "2006" }} Community Dispute Protocol Builder. All rights reserved.</p>
|
||||
<p>Built with <a href="https://gohugo.io/" target="_blank">Hugo</a></p>
|
||||
</div>
|
||||
</footer>
|
36
themes/dispute-protocol-theme/layouts/partials/head.html
Normal file
36
themes/dispute-protocol-theme/layouts/partials/head.html
Normal file
@ -0,0 +1,36 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ .Title }} | {{ .Site.Title }}</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ "css/main.css" | relURL }}">
|
||||
<link rel="shortcut icon" href="{{ "favicon.ico" | relURL }}" type="image/x-icon">
|
||||
|
||||
<!-- JS libraries for PDF export -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
||||
|
||||
<!-- Custom JS for the builder -->
|
||||
{{ if eq .Layout "builder" }}
|
||||
<script defer src="{{ "js/data/modules.js" | relURL }}"></script>
|
||||
<script defer src="{{ "js/data/templates.js" | relURL }}"></script>
|
||||
<script defer src="{{ "js/data/template-mapper.js" | relURL }}"></script>
|
||||
<script defer src="{{ "js/debug.js" | relURL }}"></script>
|
||||
<script defer src="{{ "js/builder.js" | relURL }}"></script>
|
||||
{{ end }}
|
||||
|
||||
<!-- Additional custom JS from site parameters -->
|
||||
{{ range .Site.Params.customJS }}
|
||||
{{ if not (in . "modules.js" ) }}
|
||||
{{ if not (in . "templates.js" ) }}
|
||||
{{ if not (in . "template-mapper.js" ) }}
|
||||
{{ if not (in . "builder.js" ) }}
|
||||
<script defer src="{{ . | relURL }}"></script>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</head>
|
15
themes/dispute-protocol-theme/layouts/partials/header.html
Normal file
15
themes/dispute-protocol-theme/layouts/partials/header.html
Normal file
@ -0,0 +1,15 @@
|
||||
<header>
|
||||
<div class="container">
|
||||
<div class="logo">
|
||||
<a href="{{ "/" | relURL }}">{{ .Site.Title }}</a>
|
||||
</div>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="{{ "/" | relURL }}">Home</a></li>
|
||||
<li><a href="{{ "builder/" | relURL }}">Protocol Builder</a></li>
|
||||
<li><a href="{{ "modules/" | relURL }}">Modules Library</a></li>
|
||||
<li><a href="{{ "about/" | relURL }}">About</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
21
themes/dispute-protocol-theme/theme.toml
Normal file
21
themes/dispute-protocol-theme/theme.toml
Normal file
@ -0,0 +1,21 @@
|
||||
# theme.toml template for a Hugo theme
|
||||
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
|
||||
|
||||
name = "Dispute Protocol Theme"
|
||||
license = "MIT"
|
||||
licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE"
|
||||
description = ""
|
||||
homepage = "http://example.com/"
|
||||
tags = []
|
||||
features = []
|
||||
min_version = "0.41.0"
|
||||
|
||||
[author]
|
||||
name = ""
|
||||
homepage = ""
|
||||
|
||||
# If porting an existing theme
|
||||
[original]
|
||||
name = ""
|
||||
homepage = ""
|
||||
repo = ""
|
Reference in New Issue
Block a user