4c05c1067e
- Fix YAML fallback parser to properly handle folded scalars (>-) at
both top-level (description, outcome, practice) and step-level
(step descriptions). Previously stored '>-' as the literal value
instead of the folded text.
- Fix delete protocol/collection: reset currentRoute guard so
navigate('library') actually works after deletion.
- Change #library hash to #protocols throughout (routing, nav links,
breadcrumb shows 'protocols/' on the main page).
- Fix breadcrumb home click not working from detail pages (allow
re-navigation to library even if currentRoute matches).
- Fix forked_from: null showing as a clickable link — now suppressed
when value is null or the string 'null'.
- README: replace curl seed instructions with About page button,
add About page customization instructions for whitelabeling.
237 lines
11 KiB
HTML
237 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Protocol Droid</title>
|
|
<link rel="stylesheet" href="/frontend/style.css">
|
|
<meta name="theme-color" content="#0a1929">
|
|
</head>
|
|
<body>
|
|
|
|
<header>
|
|
<div class="breadcrumb" onclick="navigate('library')">
|
|
<span><span class="prompt">$</span> protocol-droid</span>
|
|
<span class="crumb-path" id="crumbPath"></span>
|
|
</div>
|
|
<nav id="navBar">
|
|
<a href="#protocols" class="active" data-view="library">PROTOCOLS</a>
|
|
<a href="#collections" data-view="collections">COLLECTIONS</a>
|
|
<a href="#about" data-view="about">ABOUT</a>
|
|
</nav>
|
|
<div class="auth-area" id="authArea"></div>
|
|
<button class="hamburger" id="hamburger" onclick="toggleMenu()">☰</button>
|
|
</header>
|
|
|
|
<div class="mobile-panel" id="mobilePanel">
|
|
<a href="#protocols" data-view="library" class="active" onclick="mobileNav('library')">PROTOCOLS</a>
|
|
<a href="#collections" data-view="collections" onclick="mobileNav('collections')">COLLECTIONS</a>
|
|
<a href="#about" data-view="about" onclick="mobileNav('about')">ABOUT</a>
|
|
<div class="mobile-auth" id="mobileAuth"></div>
|
|
</div>
|
|
|
|
<main class="main">
|
|
|
|
<!-- LIBRARY VIEW -->
|
|
<section class="view" id="view-library" style="display:none">
|
|
<div class="toolbar">
|
|
<div class="search-bar">
|
|
<span class="prompt">></span>
|
|
<input type="text" id="searchInput" placeholder="search protocols..." oninput="debouncedLoadProtocols()">
|
|
</div>
|
|
<button class="btn create-btn" onclick="navigate('create')"><span class="create-text">+ Create</span><span class="create-plus">+</span></button>
|
|
</div>
|
|
<div class="sort-bar" id="sortBar">
|
|
<span class="sort-label">sort:</span>
|
|
<span class="sort-option active" onclick="setSort('date')">date added</span>
|
|
<span class="sort-option" onclick="setSort('relevance')">relevance</span>
|
|
<span class="filter-toggle" onclick="toggleFilterPanel()">☰ filter</span>
|
|
</div>
|
|
<div class="filter-panel" id="filterPanel">
|
|
<div class="search-bar" style="margin-bottom:10px">
|
|
<span class="prompt">></span>
|
|
<input type="text" id="tagSearch" placeholder="search tags..." oninput="renderFilteredTags()">
|
|
</div>
|
|
<div class="filters" id="filterBar"></div>
|
|
</div>
|
|
<div class="protocol-grid" id="protocolGrid"></div>
|
|
</section>
|
|
|
|
<!-- ABOUT VIEW -->
|
|
<section class="view" id="view-about" style="display:none">
|
|
<div class="detail-header">
|
|
<h1>About Protocol Droid</h1>
|
|
<p class="description">A tool for authoring, sharing, and curating social protocols.</p>
|
|
</div>
|
|
<div class="detail-section">
|
|
<p class="outcome">Protocol Droid is a project of the <a href="https://MEDLab.host" target="_blank">Media Economies Design Lab</a> at the University of Colorado Boulder. The name is inspired by the class of droids in Star Wars known as protocol droids, which help facilitate cross-cultural interactions.</p>
|
|
<p class="outcome" style="margin-top:12px">This project is inspired by RegenHub's <a href="https://library.regenhub.xyz/" target="_blank">Protocol Library</a>, developed by Kevin Owocki, and draws on the experience of MEDLab's <a href="https://communityrule.info" target="_blank">CommunityRule</a> platform.</p>
|
|
</div>
|
|
<div class="detail-section">
|
|
<h2>What is a protocol?</h2>
|
|
<p class="outcome">A protocol is a pattern of interaction among people, generally in the form of a particular sequence of actions. Protocols are micro-practices — more specific than patterns and more interaction-focused than rules. A rule says "decisions are made by consensus." A protocol says "here's the step-by-step process for reaching consensus in a meeting."</p>
|
|
</div>
|
|
<div class="detail-section">
|
|
<h2>Features</h2>
|
|
<p class="outcome">Browse a library of protocols contributed by the community. Author your own protocols with structured fields — steps, outcomes, practice tips. Fork existing protocols and adapt them to your context. Curate collections of protocols and share them. Tag protocols for discoverability. Export and import protocols as portable YAML files.</p>
|
|
</div>
|
|
<div class="detail-section">
|
|
<h2>Self-hosting</h2>
|
|
<p class="outcome">Protocol Droid is designed to be self-hostable and whitelabel-able. It runs on a standard LAMP stack with no external dependencies — no web fonts, no CDNs, no tracking. Deploy on Cloudron, any LAMP server, or your own infrastructure. Configure your site name, tagline, and theme through a simple config file.</p>
|
|
</div>
|
|
<div class="detail-section">
|
|
<h2>Sister project</h2>
|
|
<p class="outcome">Protocol Droid has a sister project: the <a href="https://git.medlab.host/ntnsndr/protocol-bicorder" target="_blank">Protocol Bicorder</a> — a diagnostic tool for evaluating protocols along a series of gradients between opposing terms. Where Protocol Droid is for documenting and sharing protocols, the Bicorder is for analyzing and comparing them.</p>
|
|
</div>
|
|
<div class="detail-section">
|
|
<h2>License</h2>
|
|
<p class="outcome">Hippocratic License (HL3-CORE) — do no harm. See <a href="https://firstdonoharm.dev/" target="_blank">firstdonoharm.dev</a>. Source code available on <a href="https://git.medlab.host/ntnsndr/protocol-droid" target="_blank">Gitea</a>.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- PROTOCOL DETAIL VIEW -->
|
|
<section class="view" id="view-detail" style="display:none">
|
|
<div id="detailContent"></div>
|
|
<div class="actions" id="detailActions"></div>
|
|
</section>
|
|
|
|
<!-- CREATE/EDIT PROTOCOL VIEW -->
|
|
<section class="view" id="view-create" style="display:none">
|
|
<form id="protocolForm" onsubmit="saveProtocol(event)">
|
|
<div class="form-group">
|
|
<label>Title</label>
|
|
<input type="text" name="title" required maxlength="255" placeholder="Round Robin Check-In">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Description</label>
|
|
<textarea name="description" rows="2" maxlength="280" placeholder="A sentence or two about its context and purpose"></textarea>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Tags</label>
|
|
<div class="tag-input-wrapper">
|
|
<div class="tag-chips" id="tagChips"></div>
|
|
<input type="text" id="tagInput" placeholder="type a tag and press enter..." onkeydown="handleTagKeydown(event)" oninput="showTagSuggestions()">
|
|
<div class="tag-suggestions" id="tagSuggestions"></div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Source</label>
|
|
<input type="text" name="source" placeholder="Group Works Deck (or @username)">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Source URL</label>
|
|
<input type="text" name="source_url" placeholder="https://...">
|
|
</div>
|
|
<div id="stepsEditor"></div>
|
|
<button type="button" class="btn add-step" onclick="addStep()">+ Add Step</button>
|
|
<div class="form-group">
|
|
<label>Outcome</label>
|
|
<textarea name="outcome" rows="2" placeholder="What should happen if it is done right"></textarea>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Practice</label>
|
|
<textarea name="practice" rows="3" placeholder="Tips for learning to do it better"></textarea>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Visibility</label>
|
|
<select name="visibility">
|
|
<option value="public">Public — visible in the library</option>
|
|
<option value="unlisted">Unlisted — accessible by URL only</option>
|
|
<option value="private">Private — only visible to you</option>
|
|
</select>
|
|
</div>
|
|
<div class="actions">
|
|
<button type="submit" class="btn primary">Save Protocol</button>
|
|
<button type="button" class="btn" onclick="navigate('library')">Cancel</button>
|
|
</div>
|
|
</form>
|
|
</section>
|
|
|
|
<!-- COLLECTIONS VIEW -->
|
|
<section class="view" id="view-collections" style="display:none">
|
|
<div class="toolbar">
|
|
<div class="search-bar">
|
|
<span class="prompt">></span>
|
|
<input type="text" id="collectionSearch" placeholder="search collections..." oninput="loadCollections()">
|
|
</div>
|
|
<button class="btn create-btn" onclick="navigate('create-collection')"><span class="create-text">+ Create</span><span class="create-plus">+</span></button>
|
|
</div>
|
|
<div class="protocol-grid" id="collectionsGrid"></div>
|
|
</section>
|
|
|
|
<!-- CREATE/EDIT COLLECTION VIEW -->
|
|
<section class="view" id="view-create-collection" style="display:none">
|
|
<form id="collectionForm" onsubmit="saveCollection(event)">
|
|
<div class="form-group">
|
|
<label>Title</label>
|
|
<input type="text" name="coll-title" required maxlength="255" placeholder="Protocols for Mutual Aid Groups">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Description</label>
|
|
<textarea name="coll-description" rows="2" maxlength="280" placeholder="A sentence or two about the collection's context and purpose"></textarea>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Source</label>
|
|
<input type="text" name="coll-source" placeholder="Author or community (or @username)">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Visibility</label>
|
|
<select name="coll-visibility">
|
|
<option value="public">Public — visible in the library</option>
|
|
<option value="unlisted">Unlisted — accessible by URL only</option>
|
|
<option value="private">Private — only visible to you</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Add protocols to this collection</label>
|
|
<div id="collProtocolPicker"></div>
|
|
</div>
|
|
<div class="actions">
|
|
<button type="submit" class="btn primary">Save Collection</button>
|
|
<button type="button" class="btn" onclick="navigate('collections')">Cancel</button>
|
|
</div>
|
|
</form>
|
|
</section>
|
|
|
|
<!-- COLLECTION DETAIL VIEW -->
|
|
<section class="view" id="view-collection-detail" style="display:none">
|
|
<div id="collectionDetailContent"></div>
|
|
<div class="actions" id="collectionDetailActions"></div>
|
|
</section>
|
|
|
|
<!-- AUTH MODAL -->
|
|
<div class="modal-overlay" id="authModal" style="display:none">
|
|
<div class="modal">
|
|
<h2 id="authModalTitle">Sign In</h2>
|
|
<form onsubmit="handleAuth(event)">
|
|
<div id="authFormArea">
|
|
<div class="form-group">
|
|
<label>Username</label>
|
|
<input type="text" id="authUsername" required pattern="[a-zA-Z0-9_]{3,32}" placeholder="username">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Password</label>
|
|
<input type="password" id="authPassword" required minlength="6" placeholder="••••••••">
|
|
</div>
|
|
<div class="form-group" id="displayNameGroup">
|
|
<label>Display Name (optional)</label>
|
|
<input type="text" id="authDisplayName" placeholder="Jane Doe">
|
|
</div>
|
|
</div>
|
|
<div class="actions">
|
|
<button type="submit" class="btn primary" id="authSubmit">Sign In</button>
|
|
<button type="button" class="btn" onclick="closeAuthModal()">Cancel</button>
|
|
</div>
|
|
<div class="auth-toggle" id="authToggle"></div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- TOAST -->
|
|
<div class="toast" id="toast" style="display:none"></div>
|
|
|
|
</main>
|
|
|
|
<script src="/frontend/app.js"></script>
|
|
</body>
|
|
</html> |