Initial commit
This commit is contained in:
.gitignore.gitlab-ci.ymlCLAUDE.mdGITLAB_DEPLOYMENT.mdLICENSEREADME.mddeploy.sh
archetypes
build-test.shconfig.tomlcontent
data
components
appeal.yamlassessment.yamlbecome_aware.yamldelegation.yamldeliberation.yamlinitiation.yamlintake.yamlpreparation.yamlprepare.yamlprocess.yamlresolution.yaml
modules
assessment.yamldelegation.yamlfiling.yamlintake.yamlnotification.yamlparticipants.yamlprinciples.yamlprocess.yamlresolution.yaml
stages
static
css
js
themes/dispute-protocol-theme
44
.gitignore
vendored
Normal file
44
.gitignore
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
# Hugo default output directory
|
||||
/public/
|
||||
|
||||
# Generated files by hugo
|
||||
/resources/_gen/
|
||||
/assets/jsconfig.json
|
||||
hugo_stats.json
|
||||
|
||||
# Temporary lock file while building
|
||||
/.hugo_build.lock
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# IDE specific files
|
||||
.idea
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Node modules if you're using npm
|
||||
node_modules/
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
|
||||
# Local Netlify folder
|
||||
.netlify
|
||||
|
||||
# Build files
|
||||
dist/
|
||||
|
||||
# Temporary files
|
||||
*~
|
||||
\#*\#
|
49
.gitlab-ci.yml
Normal file
49
.gitlab-ci.yml
Normal file
@ -0,0 +1,49 @@
|
||||
image: registry.gitlab.com/pages/hugo:latest
|
||||
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- hugo --minify
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
- master
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
script:
|
||||
- echo "Deploying to GitLab Pages..."
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
- master
|
||||
|
||||
# Self-hosted deployment using rsync
|
||||
# Uncomment and configure this job for deploying to your own server
|
||||
# deploy:
|
||||
# stage: deploy
|
||||
# image: alpine:latest
|
||||
# before_script:
|
||||
# - apk add --no-cache openssh-client rsync
|
||||
# - eval $(ssh-agent -s)
|
||||
# - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
|
||||
# - mkdir -p ~/.ssh
|
||||
# - chmod 700 ~/.ssh
|
||||
# - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
|
||||
# - chmod 644 ~/.ssh/known_hosts
|
||||
# script:
|
||||
# - rsync -avuz --delete public/ $SSH_USER@$SSH_HOST:$DEPLOY_PATH
|
||||
# only:
|
||||
# - master
|
||||
# environment:
|
||||
# name: production
|
||||
# url: https://your-domain.com
|
63
CLAUDE.md
Normal file
63
CLAUDE.md
Normal file
@ -0,0 +1,63 @@
|
||||
# Dispute Protocol Builder
|
||||
|
||||
This is a prototype website, built in Hugo, to enable communities to develop customizable protocols for dispute resolution processes. It guides users through an accessible process that provides best practices while allowing for customization.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- **Static Site Generator**: Hugo
|
||||
- **Main Builder Interface**: `/themes/dispute-protocol-theme/layouts/_default/builder.html`
|
||||
- **JavaScript Files**:
|
||||
- `/static/js/builder.js`: Main application logic
|
||||
- `/static/js/data/modules.js`: Predefined module options
|
||||
- `/static/js/data/templates.js`: Complete protocol templates
|
||||
- `/static/js/data/template-mapper.js`: Maps raw content to module references
|
||||
|
||||
## Content Organization
|
||||
|
||||
- **Components**: Building blocks of a protocol, defined in `/data/components/*.yaml`
|
||||
- **Modules**: Reusable text blocks for specific fields, defined in `modules.js`
|
||||
- **Templates**: Complete predefined protocols combining multiple modules
|
||||
|
||||
## Data Model
|
||||
|
||||
The application maintains a hierarchical data model:
|
||||
- **Stages** → **Components** → **Fields**
|
||||
- Each field can be populated with content from a **Module**
|
||||
|
||||
## Core Features
|
||||
|
||||
1. **Black & white UI**: Clean, accessible interface with vertical accordion sections
|
||||
2. **Template selection**: Users can start with a predefined protocol template
|
||||
3. **Module selection**: Users can choose from multiple pre-written modules for each field
|
||||
4. **Customization**: Direct text editing in fields
|
||||
5. **Export options**: Markdown, PDF, and JSON formats
|
||||
6. **Import capability**: Load previously saved protocols
|
||||
|
||||
## Module System
|
||||
|
||||
Modules are the heart of the customization system:
|
||||
- Each module has: `id`, `title`, `componentId`, `fieldId`, and `content`
|
||||
- Modules are categorized by type (principles, participants, filing, etc.)
|
||||
- Custom modules are generated from templates via `template-mapper.js`
|
||||
- Module selector dropdowns display available options for each field
|
||||
|
||||
## Recent Improvements
|
||||
|
||||
1. **Template mapping**: Fixed custom module generation to create descriptive titles
|
||||
2. **Module presentation**: Removed category labels from dropdowns
|
||||
3. **Module coverage**: Added comprehensive modules for all components
|
||||
4. **Name formatting**: Enhanced logic to extract meaningful titles from content
|
||||
|
||||
## Deployment
|
||||
|
||||
- Deployable from a self-hosted GitLab server
|
||||
- Data is maintained in YAML files for components and stages
|
||||
- Module content is defined in JavaScript for easy client-side use
|
||||
|
||||
## Key Files to Modify
|
||||
|
||||
- `/static/js/data/modules.js`: Add, edit or remove module options
|
||||
- `/static/js/data/template-mapper.js`: Adjust how custom modules are generated
|
||||
- `/static/js/data/templates.js`: Define new protocol templates
|
||||
- `/static/js/builder.js`: Modify core interface functionality
|
||||
- `/static/css/main.css`: Adjust styling and responsive behavior
|
167
GITLAB_DEPLOYMENT.md
Normal file
167
GITLAB_DEPLOYMENT.md
Normal file
@ -0,0 +1,167 @@
|
||||
# Deploying from a Self-Hosted GitLab Server
|
||||
|
||||
This guide provides detailed instructions for deploying the Dispute Protocol application from a self-hosted GitLab server.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A self-hosted GitLab server (GitLab Community Edition or Enterprise Edition)
|
||||
- GitLab Runner installed and configured on your server
|
||||
- Basic familiarity with GitLab CI/CD
|
||||
|
||||
## Deployment Options
|
||||
|
||||
The project includes a `.gitlab-ci.yml` file that supports two deployment methods:
|
||||
|
||||
1. **GitLab Pages** - For hosting directly on your GitLab instance
|
||||
2. **Custom Server Deployment** - For deploying to an external web server
|
||||
|
||||
## Option 1: Deploying to GitLab Pages
|
||||
|
||||
GitLab Pages provides an easy way to host static websites directly from your GitLab repository.
|
||||
|
||||
### Configuration Steps:
|
||||
|
||||
1. Ensure GitLab Pages is enabled on your self-hosted GitLab instance:
|
||||
- Go to Admin Area > Settings > Pages
|
||||
- Enable GitLab Pages and configure the domain settings
|
||||
|
||||
2. The existing `.gitlab-ci.yml` file already includes the necessary configuration for GitLab Pages. When you push to the `master` branch, the site will be automatically built and deployed.
|
||||
|
||||
3. Access your site at `https://[group-or-username].gitlab-instance.com/dispute-protocol`
|
||||
|
||||
## Option 2: Deploying to a Custom Web Server
|
||||
|
||||
For more control, you can deploy to your own web server using rsync over SSH.
|
||||
|
||||
### Configuration Steps:
|
||||
|
||||
1. In your GitLab repository, go to **Settings > CI/CD > Variables**
|
||||
|
||||
2. Add the following variables:
|
||||
- `SSH_PRIVATE_KEY`: The private SSH key for connecting to your deployment server
|
||||
- `SSH_KNOWN_HOSTS`: Output of `ssh-keyscan your-server.com`
|
||||
- `SSH_USER`: Username on your deployment server
|
||||
- `SSH_HOST`: Hostname or IP address of your deployment server
|
||||
- `DEPLOY_PATH`: Path on your server where the site should be deployed
|
||||
|
||||
3. Edit the `.gitlab-ci.yml` file and uncomment the `deploy` job
|
||||
|
||||
4. Update the `url` parameter in the environment section with your actual domain
|
||||
|
||||
5. Push your changes to the `master` branch to trigger the deployment
|
||||
|
||||
### How to generate SSH_KNOWN_HOSTS value:
|
||||
|
||||
```bash
|
||||
ssh-keyscan -H your-server.com
|
||||
```
|
||||
|
||||
### How to generate and configure SSH keys:
|
||||
|
||||
1. Generate a new SSH key pair (without a passphrase for automated use):
|
||||
```bash
|
||||
ssh-keygen -t ed25519 -C "gitlab-deploy" -f gitlab-deploy-key
|
||||
```
|
||||
|
||||
2. Add the public key to your server's authorized_keys:
|
||||
```bash
|
||||
cat gitlab-deploy-key.pub >> ~/.ssh/authorized_keys
|
||||
```
|
||||
|
||||
3. Copy the private key content (including BEGIN and END lines) and paste it into the `SSH_PRIVATE_KEY` variable in GitLab
|
||||
|
||||
## Web Server Configuration
|
||||
|
||||
### Nginx Configuration
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com;
|
||||
|
||||
root /path/to/deployment;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# Optional: Enable gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
}
|
||||
```
|
||||
|
||||
### Apache Configuration
|
||||
|
||||
Create a .htaccess file in your deployment directory:
|
||||
|
||||
```apache
|
||||
# Enable rewriting
|
||||
RewriteEngine On
|
||||
|
||||
# If the requested resource doesn't exist as a file or directory
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
|
||||
# Rewrite to index.html
|
||||
RewriteRule ^(.*)$ /index.html [L]
|
||||
|
||||
# Cache control for static assets
|
||||
<FilesMatch "\.(css|js|png|jpg|jpeg|gif|ico)$">
|
||||
Header set Cache-Control "max-age=604800, public"
|
||||
</FilesMatch>
|
||||
```
|
||||
|
||||
## Manual Deployment
|
||||
|
||||
If you prefer to deploy manually without GitLab CI/CD, you can use the included scripts:
|
||||
|
||||
### Testing the Build Locally
|
||||
|
||||
Before deploying, you can test the build locally using the included `build-test.sh` script:
|
||||
|
||||
```bash
|
||||
./build-test.sh [port]
|
||||
```
|
||||
|
||||
Example:
|
||||
```bash
|
||||
./build-test.sh 8080
|
||||
```
|
||||
|
||||
This will build the site and start a temporary web server on the specified port (default: 8080), allowing you to verify that everything works correctly before deployment.
|
||||
|
||||
### Deploying to a Remote Server
|
||||
|
||||
To deploy to your own server manually, use the included `deploy.sh` script:
|
||||
|
||||
```bash
|
||||
./deploy.sh [username] [server] [deploy-path]
|
||||
```
|
||||
|
||||
Example:
|
||||
```bash
|
||||
./deploy.sh deploy-user example.com /var/www/dispute-protocol
|
||||
```
|
||||
|
||||
This script will build the site and then use rsync to deploy it to your server.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### CI/CD Pipeline Fails
|
||||
|
||||
1. Check the pipeline logs for detailed error messages
|
||||
2. Verify that the GitLab Runner is properly configured and running
|
||||
3. Ensure the SSH key has the correct permissions on the target server
|
||||
4. Try running the build and deploy steps manually to identify issues
|
||||
|
||||
### Site Not Accessible After Deployment
|
||||
|
||||
1. Check web server logs for errors
|
||||
2. Verify file permissions in the deployment directory
|
||||
3. Ensure the web server configuration is correct
|
||||
4. Check that the domain DNS is pointing to the correct server
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Community Dispute Protocol Builder
|
||||
|
||||
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.
|
196
README.md
Normal file
196
README.md
Normal file
@ -0,0 +1,196 @@
|
||||
# Community Dispute Protocol Builder
|
||||
|
||||
A Hugo-based web application that helps communities create structured processes for resolving conflicts and disputes.
|
||||
|
||||
Created as a prototype by Nathan Schneider with Claude Code.
|
||||
|
||||
## Features
|
||||
|
||||
- Interactive protocol builder with multi-stage process
|
||||
- Pre-defined modules for common dispute resolution approaches
|
||||
- Complete protocol templates for different facilitation styles
|
||||
- Export protocols as Markdown, PDF, or JSON
|
||||
- Import previously created protocols (JSON format)
|
||||
- Responsive design for desktop and mobile
|
||||
|
||||
## Setup and Installation
|
||||
|
||||
1. Make sure you have [Hugo](https://gohugo.io/installation/) installed
|
||||
2. Clone this repository
|
||||
3. Run the local development server:
|
||||
|
||||
```bash
|
||||
cd dispute-protocol
|
||||
hugo server -D
|
||||
```
|
||||
|
||||
4. Access the site at http://localhost:1313/
|
||||
|
||||
## Customizing the Dispute Protocol
|
||||
|
||||
### Adding or Modifying Stages
|
||||
|
||||
Edit the file `data/stages/stages.yaml` to modify the stages of the dispute resolution process.
|
||||
|
||||
```yaml
|
||||
- id: new-stage
|
||||
title: New Stage Name
|
||||
description: Description of this stage
|
||||
order: 7 # This determines the order in which stages appear
|
||||
```
|
||||
|
||||
### Adding or Modifying Components
|
||||
|
||||
Components are grouped by stage. Create or edit files in the `data/components/` directory, naming the file after the stage ID.
|
||||
|
||||
For example, to add components to a stage with ID "new-stage", create `data/components/new-stage.yaml`:
|
||||
|
||||
```yaml
|
||||
- id: new-component
|
||||
title: New Component Title
|
||||
description: Description of what this component addresses
|
||||
stageId: new-stage
|
||||
order: 1
|
||||
fields:
|
||||
- id: newComponentField
|
||||
type: text
|
||||
label: Field Label
|
||||
placeholder: Placeholder text...
|
||||
required: true
|
||||
```
|
||||
|
||||
### Adding Pre-defined Modules
|
||||
|
||||
Modules provide pre-written content that users can select for specific fields. There are two places where modules are defined:
|
||||
|
||||
1. **YAML Definition (source of truth):** Create or edit files in the `data/modules/` directory.
|
||||
|
||||
```yaml
|
||||
- id: new-module
|
||||
title: New Module Title
|
||||
componentId: new-component
|
||||
fieldId: newComponentField
|
||||
content: |
|
||||
This is the pre-defined content that will be inserted when
|
||||
the user selects this module. It can include multiple lines.
|
||||
```
|
||||
|
||||
2. **JavaScript Implementation:** The frontend uses modules defined in `static/js/data/modules.js`. When adding new modules to the YAML files, you should also add them to this JavaScript file to make them available in the builder interface.
|
||||
|
||||
```javascript
|
||||
const moduleData = {
|
||||
module_category: [
|
||||
{
|
||||
id: "new-module",
|
||||
title: "New Module Title",
|
||||
componentId: "new-component",
|
||||
fieldId: "newComponentField",
|
||||
content: `This is the pre-defined content that will be inserted when
|
||||
the user selects this module. It can include multiple lines.`
|
||||
}
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
**Important:** Make sure the `componentId` and `fieldId` values match exactly with the component and field IDs defined in the `data/components/` directory.
|
||||
|
||||
### Using Protocol Templates
|
||||
|
||||
The application includes complete protocol templates that pre-fill all components with consistent content. Three templates are provided:
|
||||
|
||||
1. **Peer-to-Peer Protocol**: A self-facilitated process where participants work together directly to resolve disputes without a formal facilitator.
|
||||
|
||||
2. **Chosen Facilitator Protocol**: A process where participants mutually select a facilitator who may not have specialized skills but can help guide the discussion.
|
||||
|
||||
3. **Facilitation Council Protocol**: A structured process with a trained council of facilitators who manage the dispute resolution process.
|
||||
|
||||
Users can select a template from the dropdown at the top of the builder page to automatically populate all fields. They can then customize the content as needed for their community's specific requirements.
|
||||
|
||||
#### Adding New Protocol Templates
|
||||
|
||||
To add a new protocol template, edit the file `static/js/data/templates.js`. Each template follows this structure:
|
||||
|
||||
```javascript
|
||||
{
|
||||
id: "template-id",
|
||||
title: "Template Name",
|
||||
description: "Brief description of this template approach",
|
||||
data: {
|
||||
stages: {
|
||||
// Full protocol data structure with content for all stages and components
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
### Building for Production
|
||||
|
||||
To build the site for production:
|
||||
|
||||
```bash
|
||||
hugo --minify
|
||||
```
|
||||
|
||||
The generated site will be in the `public` directory, which you can deploy to any static hosting service.
|
||||
|
||||
### Deploying from a Self-Hosted GitLab Server
|
||||
|
||||
This project includes GitLab CI/CD configuration for easy deployment. The included `.gitlab-ci.yml` file supports two deployment options:
|
||||
|
||||
1. **GitLab Pages** - Automatically deployed when you push to the master branch
|
||||
2. **Custom Server Deployment** - Deploy to your own server using rsync
|
||||
|
||||
#### Setting Up Custom Server Deployment
|
||||
|
||||
1. In your GitLab repository, go to **Settings > CI/CD > Variables**
|
||||
|
||||
2. Add the following variables:
|
||||
- `SSH_PRIVATE_KEY`: Your private SSH key for the deployment server
|
||||
- `SSH_KNOWN_HOSTS`: Output of `ssh-keyscan your-server.com`
|
||||
- `SSH_USER`: Username on your deployment server
|
||||
- `SSH_HOST`: Hostname or IP of your deployment server
|
||||
- `DEPLOY_PATH`: Path on your server where the site should be deployed
|
||||
|
||||
3. Uncomment the `deploy` job in `.gitlab-ci.yml`
|
||||
|
||||
4. Update the `url` parameter in the environment section with your actual domain
|
||||
|
||||
5. Push your changes to the master branch to trigger the deployment
|
||||
|
||||
#### Web Server Configuration
|
||||
|
||||
For Nginx, use a configuration similar to this:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com;
|
||||
|
||||
location / {
|
||||
root /path/to/deployment;
|
||||
index index.html;
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For Apache, create a .htaccess file in your deployment directory:
|
||||
|
||||
```apache
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ /index.html [L]
|
||||
```
|
||||
|
||||
## Technologies Used
|
||||
|
||||
- Hugo static site generator
|
||||
- JavaScript for interactive features
|
||||
- jsPDF for PDF generation
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the LICENSE file for details.
|
6
archetypes/default.md
Normal file
6
archetypes/default.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "{{ replace .Name "-" " " | title }}"
|
||||
date: {{ .Date }}
|
||||
draft: true
|
||||
---
|
||||
|
41
build-test.sh
Executable file
41
build-test.sh
Executable file
@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Test build script for the Dispute Protocol site
|
||||
# This script builds the site and runs a temporary server to check it works
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
BUILD_DIR="public"
|
||||
PORT=${1:-8080}
|
||||
|
||||
# Check if Hugo is installed
|
||||
if ! command -v hugo &> /dev/null; then
|
||||
echo -e "${RED}Error: Hugo is not installed. Please install Hugo first.${NC}"
|
||||
echo "Visit https://gohugo.io/installation/ for installation instructions."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Building site...${NC}"
|
||||
hugo --minify
|
||||
|
||||
# Check if build succeeded
|
||||
if [ ! -d "$BUILD_DIR" ]; then
|
||||
echo -e "${RED}Error: Build failed. The '$BUILD_DIR' directory doesn't exist.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Build completed successfully!${NC}"
|
||||
echo -e "${YELLOW}Starting a temporary server on port $PORT...${NC}"
|
||||
echo -e "${YELLOW}Press Ctrl+C to stop the server.${NC}"
|
||||
|
||||
cd $BUILD_DIR
|
||||
python3 -m http.server $PORT
|
||||
|
||||
exit 0
|
41
config.toml
Normal file
41
config.toml
Normal file
@ -0,0 +1,41 @@
|
||||
baseURL = '/'
|
||||
languageCode = 'en-us'
|
||||
title = 'Community Dispute Protocol'
|
||||
theme = 'dispute-protocol-theme'
|
||||
|
||||
# Enable relative URLs for easier deployment in different environments
|
||||
relativeURLs = true
|
||||
canonifyURLs = false
|
||||
|
||||
# Output configuration
|
||||
[outputs]
|
||||
home = ["HTML", "RSS"]
|
||||
|
||||
# Configure static resources
|
||||
[params]
|
||||
# Custom CSS
|
||||
customCSS = ["css/main.css"]
|
||||
|
||||
# Custom JS
|
||||
customJS = ["js/builder.js", "js/data/modules.js", "js/data/templates.js"]
|
||||
|
||||
# Site description
|
||||
description = "A tool for communities to develop customized dispute resolution protocols"
|
||||
|
||||
# Footer text
|
||||
footer = "Powered by Hugo and hosted on GitLab"
|
||||
|
||||
# Menu configuration
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
name = "Home"
|
||||
url = "/"
|
||||
weight = 1
|
||||
[[menu.main]]
|
||||
name = "Builder"
|
||||
url = "/builder/"
|
||||
weight = 2
|
||||
[[menu.main]]
|
||||
name = "About"
|
||||
url = "/about/"
|
||||
weight = 3
|
8
content/_index.md
Normal file
8
content/_index.md
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: "Community Dispute Protocol Builder"
|
||||
date: 2023-07-10
|
||||
draft: false
|
||||
---
|
||||
|
||||
Welcome to the Community Dispute Protocol Builder. This tool helps communities create structured processes for resolving conflicts and disputes.
|
||||
|
95
content/about.md
Normal file
95
content/about.md
Normal file
@ -0,0 +1,95 @@
|
||||
---
|
||||
title: "About"
|
||||
date: 2023-07-10
|
||||
draft: false
|
||||
---
|
||||
|
||||
# About the Community Dispute Protocol Builder
|
||||
|
||||
The Dispute Protocol Builder is a collaborative tool designed to help communities develop customized frameworks for addressing and resolving conflicts. Rather than imposing a one-size-fits-all solution, this tool empowers communities to create protocols that reflect their unique values, culture, and specific needs.
|
||||
|
||||
## Why Create a Dispute Protocol?
|
||||
|
||||
Every community experiences conflicts. Whether in neighborhoods, workplaces, cooperatives, online spaces, or cultural groups, disagreements and tensions are inevitable. Having a thoughtful, agreed-upon process for addressing these conflicts provides numerous benefits:
|
||||
|
||||
- **Prevents escalation** of small issues into major conflicts
|
||||
- **Creates consistency** and predictability during challenging times
|
||||
- **Ensures fairness and transparency** in how issues are addressed
|
||||
- **Reduces harm** during the resolution process
|
||||
- **Builds community capacity** to handle future conflicts
|
||||
- **Strengthens relationships** by demonstrating commitment to healthy conflict engagement
|
||||
- **Embodies community values** in practical, actionable ways
|
||||
- **Provides guidance** when emotions are running high
|
||||
|
||||
Without a clear protocol, communities often default to ad-hoc approaches that can amplify harm, reinforce power imbalances, or leave conflicts unresolved.
|
||||
|
||||
## How the Builder Works
|
||||
|
||||
The Protocol Builder guides you through creating a comprehensive dispute resolution framework using a modular approach:
|
||||
|
||||
### 1. Start from Templates or Build from Scratch
|
||||
|
||||
Begin with one of our pre-designed templates based on restorative justice, transformative justice, or consensus-based approaches—or start with a blank slate and build your own custom protocol.
|
||||
|
||||
### 2. Customize Each Stage
|
||||
|
||||
The builder walks you through six key stages of dispute resolution:
|
||||
|
||||
1. **Preparation**: Establishing core values, principles, and participant roles
|
||||
2. **Initiation**: Defining how disputes are raised, acknowledged, and entered into the process
|
||||
3. **Exploration**: Investigating and understanding the facts, perspectives, and underlying needs
|
||||
4. **Deliberation**: Discussing potential solutions and working toward agreements
|
||||
5. **Resolution**: Finalizing, documenting, and implementing solutions
|
||||
6. **Follow-up**: Evaluating outcomes, ensuring accountability, and making improvements
|
||||
|
||||
### 3. Mix and Match Modules
|
||||
|
||||
For each component within these stages, you can select from pre-written modules or craft your own content. This modular approach lets you:
|
||||
|
||||
- Choose elements that align with your community's values
|
||||
- Adapt the protocol based on your community's capacity and resources
|
||||
- Create a coherent process that addresses your specific needs
|
||||
- Ensure nothing important is overlooked
|
||||
|
||||
### 4. Export and Share
|
||||
|
||||
When your protocol is complete, export it as:
|
||||
- A formatted PDF to share with your community
|
||||
- A Markdown document for easy editing and version control
|
||||
- A JSON file that can be imported back into the builder for future updates
|
||||
|
||||
## Design Principles
|
||||
|
||||
The Dispute Protocol Builder is designed around these core principles:
|
||||
|
||||
- **Accessibility**: Simple, clear language and an intuitive interface make this tool usable by anyone, regardless of technical expertise or familiarity with conflict resolution terminology.
|
||||
|
||||
- **Flexibility**: Every component is customizable to accommodate diverse community contexts and needs.
|
||||
|
||||
- **Comprehensiveness**: The tool addresses all aspects of dispute resolution, from initial values to final implementation.
|
||||
|
||||
- **Educational**: Pre-written modules offer best practices drawn from various dispute resolution traditions.
|
||||
|
||||
- **Privacy-Focused**: All work happens locally in your browser—no data is sent to our servers.
|
||||
|
||||
## Who Is This For?
|
||||
|
||||
This tool is designed for any group that wants to improve how they handle internal conflicts:
|
||||
|
||||
- **Intentional Communities and Cooperatives**
|
||||
- **Neighborhood Associations**
|
||||
- **Activist Groups and Collectives**
|
||||
- **Small Businesses and Worker Cooperatives**
|
||||
- **Faith Communities**
|
||||
- **Online Communities and Forums**
|
||||
- **Educational Institutions**
|
||||
- **Non-Profit Organizations**
|
||||
- **Artistic and Cultural Collectives**
|
||||
|
||||
## Get Started
|
||||
|
||||
<div class="cta-container">
|
||||
Ready to create your community's dispute protocol?
|
||||
|
||||
<a href="/builder" class="cta-button">Start Building Your Protocol</a>
|
||||
</div>
|
8
content/builder.md
Normal file
8
content/builder.md
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: "Protocol Builder"
|
||||
date: 2023-07-10
|
||||
draft: false
|
||||
layout: "builder"
|
||||
---
|
||||
|
||||
Use this interactive builder to create your community's dispute resolution protocol.
|
8
content/modules.md
Normal file
8
content/modules.md
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: "Modules Library"
|
||||
description: "Browse all available modules for the Dispute Protocol Builder"
|
||||
layout: "modules"
|
||||
draft: false
|
||||
---
|
||||
|
||||
This page displays all available modules in the Dispute Protocol Builder, organized by Stage and Component. You can see which Templates use each module.
|
23
data/components/appeal.yaml
Normal file
23
data/components/appeal.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
- id: appeal_criteria
|
||||
title: "What are the criteria for a permissible appeal?"
|
||||
description: "Standards for allowing an appeal of a resolution"
|
||||
stageId: appeal
|
||||
order: 1
|
||||
fields:
|
||||
- id: appealCriteriaText
|
||||
type: text
|
||||
label: "What are the criteria for a permissible appeal?"
|
||||
placeholder: "Describe what circumstances justify an appeal of a resolution..."
|
||||
required: true
|
||||
|
||||
- id: appeal_process
|
||||
title: "What happens when an appeal occurs?"
|
||||
description: "Process for handling appeals"
|
||||
stageId: appeal
|
||||
order: 2
|
||||
fields:
|
||||
- id: appealProcessText
|
||||
type: text
|
||||
label: "What happens when an appeal occurs?"
|
||||
placeholder: "Describe the process that follows when an appeal is initiated..."
|
||||
required: true
|
59
data/components/assessment.yaml
Normal file
59
data/components/assessment.yaml
Normal file
@ -0,0 +1,59 @@
|
||||
- id: dispute_assessment
|
||||
title: "How to assess the state of the dispute?"
|
||||
description: "Methods for evaluating the current status of a dispute"
|
||||
stageId: assessment
|
||||
order: 1
|
||||
fields:
|
||||
- id: disputeAssessmentText
|
||||
type: text
|
||||
label: "How is the state of the dispute assessed?"
|
||||
placeholder: "Describe methods used to evaluate the current status of a dispute..."
|
||||
required: true
|
||||
|
||||
- id: values_adherence
|
||||
title: "Are community values being followed?"
|
||||
description: "Evaluating whether the process is aligned with community values"
|
||||
stageId: assessment
|
||||
order: 2
|
||||
fields:
|
||||
- id: valuesAdherenceText
|
||||
type: text
|
||||
label: "How do you ensure community values are being followed?"
|
||||
placeholder: "Describe how you evaluate whether the process adheres to community values..."
|
||||
required: true
|
||||
|
||||
- id: jurisdiction
|
||||
title: "Is the dispute within the jurisdiction of this process?"
|
||||
description: "Determining whether this is the appropriate forum for the dispute"
|
||||
stageId: assessment
|
||||
order: 3
|
||||
fields:
|
||||
- id: jurisdictionText
|
||||
type: text
|
||||
label: "How do you determine if a dispute falls within this process's jurisdiction?"
|
||||
placeholder: "Describe how you determine whether this process is appropriate for a given dispute..."
|
||||
required: true
|
||||
|
||||
- id: non_participation
|
||||
title: "What happens when someone fails to participate?"
|
||||
description: "Handling non-participation in the process"
|
||||
stageId: assessment
|
||||
order: 4
|
||||
fields:
|
||||
- id: nonParticipationText
|
||||
type: text
|
||||
label: "What happens when someone fails to participate?"
|
||||
placeholder: "Describe procedures for handling situations where someone refuses to participate..."
|
||||
required: true
|
||||
|
||||
- id: process_change
|
||||
title: "What if the process needs to be changed?"
|
||||
description: "Adapting the process when necessary"
|
||||
stageId: assessment
|
||||
order: 5
|
||||
fields:
|
||||
- id: processChangeText
|
||||
type: text
|
||||
label: "What if the process needs to be changed?"
|
||||
placeholder: "Describe how the process can be adapted if it's not working effectively..."
|
||||
required: true
|
23
data/components/become_aware.yaml
Normal file
23
data/components/become_aware.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
- id: reporting
|
||||
title: "Reporting"
|
||||
description: "Methods for reporting conflicts or disputes"
|
||||
stageId: become_aware
|
||||
order: 1
|
||||
fields:
|
||||
- id: reportingText
|
||||
type: text
|
||||
label: "How are conflicts or disputes reported?"
|
||||
placeholder: "Describe the mechanisms for reporting conflicts..."
|
||||
required: true
|
||||
|
||||
- id: monitoring
|
||||
title: "Monitoring"
|
||||
description: "Proactive monitoring for potential conflicts"
|
||||
stageId: become_aware
|
||||
order: 2
|
||||
fields:
|
||||
- id: monitoringText
|
||||
type: text
|
||||
label: "How does your community monitor for potential conflicts?"
|
||||
placeholder: "Describe approaches to monitoring for potential conflicts..."
|
||||
required: true
|
11
data/components/delegation.yaml
Normal file
11
data/components/delegation.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
- id: delegation_options
|
||||
title: "Where can the dispute be delegated if this process is inadequate?"
|
||||
description: "Alternative processes for disputes that cannot be handled by this process"
|
||||
stageId: delegation
|
||||
order: 1
|
||||
fields:
|
||||
- id: delegationOptionsText
|
||||
type: text
|
||||
label: "Where can the dispute be delegated if this process is inadequate?"
|
||||
placeholder: "Describe alternative processes for disputes that cannot be handled internally..."
|
||||
required: true
|
35
data/components/deliberation.yaml
Normal file
35
data/components/deliberation.yaml
Normal file
@ -0,0 +1,35 @@
|
||||
- id: deliberation_process
|
||||
title: "How do participants deliberate about the dispute?"
|
||||
description: "Methods for deliberation during the dispute process"
|
||||
stageId: deliberation
|
||||
order: 1
|
||||
fields:
|
||||
- id: deliberationProcessText
|
||||
type: text
|
||||
label: "How do participants deliberate about the dispute?"
|
||||
placeholder: "Describe the format and structure of deliberations..."
|
||||
required: true
|
||||
|
||||
- id: additional_voices
|
||||
title: "Who, beyond the main participants, can be heard?"
|
||||
description: "Including additional perspectives in the deliberation"
|
||||
stageId: deliberation
|
||||
order: 2
|
||||
fields:
|
||||
- id: additionalVoicesText
|
||||
type: text
|
||||
label: "Who, beyond the main participants, can be heard?"
|
||||
placeholder: "Describe whose voices are included in deliberations beyond the main parties..."
|
||||
required: true
|
||||
|
||||
- id: deliberation_conclusion
|
||||
title: "When is the deliberation over?"
|
||||
description: "Criteria for concluding the deliberation phase"
|
||||
stageId: deliberation
|
||||
order: 3
|
||||
fields:
|
||||
- id: deliberationConclusionText
|
||||
type: text
|
||||
label: "When is the deliberation over?"
|
||||
placeholder: "Describe how you determine when deliberation is complete..."
|
||||
required: true
|
23
data/components/initiation.yaml
Normal file
23
data/components/initiation.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
- id: filing
|
||||
title: Filing a Complaint
|
||||
description: Process for submitting a dispute
|
||||
stageId: initiation
|
||||
order: 1
|
||||
fields:
|
||||
- id: filingProcess
|
||||
type: text
|
||||
label: Filing Process
|
||||
placeholder: Describe how disputes are submitted...
|
||||
required: true
|
||||
|
||||
- id: notification
|
||||
title: Notification Process
|
||||
description: How parties are informed of the dispute
|
||||
stageId: initiation
|
||||
order: 2
|
||||
fields:
|
||||
- id: notificationMethod
|
||||
type: text
|
||||
label: Notification Method
|
||||
placeholder: Describe how involved parties are notified...
|
||||
required: true
|
71
data/components/intake.yaml
Normal file
71
data/components/intake.yaml
Normal file
@ -0,0 +1,71 @@
|
||||
- id: process_start
|
||||
title: "How does the process begin?"
|
||||
description: "The mechanism for initiating the dispute process"
|
||||
stageId: intake
|
||||
order: 1
|
||||
fields:
|
||||
- id: processStartText
|
||||
type: text
|
||||
label: "How does the process begin?"
|
||||
placeholder: "Describe how disputes are initiated in your community..."
|
||||
required: true
|
||||
|
||||
- id: rules_access
|
||||
title: "Where does the community keep its rules?"
|
||||
description: "Location and accessibility of community rules and guidelines"
|
||||
stageId: intake
|
||||
order: 2
|
||||
fields:
|
||||
- id: rulesAccessText
|
||||
type: text
|
||||
label: "Where does the community keep its rules?"
|
||||
placeholder: "Describe where community rules are documented and how they can be accessed..."
|
||||
required: true
|
||||
|
||||
- id: information_access
|
||||
title: "Who has access to information about the process?"
|
||||
description: "Transparency and confidentiality policies"
|
||||
stageId: intake
|
||||
order: 3
|
||||
fields:
|
||||
- id: informationAccessText
|
||||
type: text
|
||||
label: "Who has access to information about the process?"
|
||||
placeholder: "Describe who can access information about ongoing dispute processes..."
|
||||
required: true
|
||||
|
||||
- id: participant_inclusion
|
||||
title: "How are other participants brought into the process?"
|
||||
description: "Methods for notifying and including relevant parties"
|
||||
stageId: intake
|
||||
order: 4
|
||||
fields:
|
||||
- id: participantInclusionText
|
||||
type: text
|
||||
label: "How are other participants brought into the process?"
|
||||
placeholder: "Describe how relevant parties are notified and included in the process..."
|
||||
required: true
|
||||
|
||||
- id: participation_requirement
|
||||
title: "Is participation in the process required or voluntary for involved parties?"
|
||||
description: "Expectations regarding participation"
|
||||
stageId: intake
|
||||
order: 5
|
||||
fields:
|
||||
- id: participationRequirementText
|
||||
type: text
|
||||
label: "Is participation required or voluntary?"
|
||||
placeholder: "Describe whether participation is mandatory or optional for involved parties..."
|
||||
required: true
|
||||
|
||||
- id: participation_commitments
|
||||
title: "What commitments does participation involve?"
|
||||
description: "Expectations of participants in the process"
|
||||
stageId: intake
|
||||
order: 6
|
||||
fields:
|
||||
- id: participationCommitmentsText
|
||||
type: text
|
||||
label: "What commitments does participation involve?"
|
||||
placeholder: "Describe what participants are committing to when they engage in the process..."
|
||||
required: true
|
23
data/components/preparation.yaml
Normal file
23
data/components/preparation.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
- id: principles
|
||||
title: Guiding Principles
|
||||
description: Core values that guide the dispute resolution process
|
||||
stageId: preparation
|
||||
order: 1
|
||||
fields:
|
||||
- id: principlesText
|
||||
type: text
|
||||
label: Principles
|
||||
placeholder: List the guiding principles for your dispute resolution process...
|
||||
required: true
|
||||
|
||||
- id: participants
|
||||
title: Participants
|
||||
description: Roles and responsibilities in the dispute resolution process
|
||||
stageId: preparation
|
||||
order: 2
|
||||
fields:
|
||||
- id: participantsRoles
|
||||
type: text
|
||||
label: Roles and Responsibilities
|
||||
placeholder: Define the roles involved in your dispute resolution process...
|
||||
required: true
|
35
data/components/prepare.yaml
Normal file
35
data/components/prepare.yaml
Normal file
@ -0,0 +1,35 @@
|
||||
- id: values
|
||||
title: "Values"
|
||||
description: "Core values that guide the dispute resolution process"
|
||||
stageId: prepare
|
||||
order: 1
|
||||
fields:
|
||||
- id: valuesText
|
||||
type: text
|
||||
label: "What values guide your dispute resolution process?"
|
||||
placeholder: "List the values that inform your approach to conflict..."
|
||||
required: true
|
||||
|
||||
- id: agreements
|
||||
title: "Agreements"
|
||||
description: "Agreements about how conflicts will be handled"
|
||||
stageId: prepare
|
||||
order: 2
|
||||
fields:
|
||||
- id: agreementsText
|
||||
type: text
|
||||
label: "What agreements do community members make about handling conflicts?"
|
||||
placeholder: "Describe the agreements community members make about how conflicts will be handled..."
|
||||
required: true
|
||||
|
||||
- id: skills
|
||||
title: "Skills"
|
||||
description: "Skills needed for handling disputes effectively"
|
||||
stageId: prepare
|
||||
order: 3
|
||||
fields:
|
||||
- id: skillsText
|
||||
type: text
|
||||
label: "What skills do community members need for handling disputes?"
|
||||
placeholder: "Describe the skills that community members should develop..."
|
||||
required: true
|
35
data/components/process.yaml
Normal file
35
data/components/process.yaml
Normal file
@ -0,0 +1,35 @@
|
||||
- id: community_values
|
||||
title: "What values does the community hold in disputes?"
|
||||
description: "Core values that guide the dispute resolution process"
|
||||
stageId: process
|
||||
order: 1
|
||||
fields:
|
||||
- id: communityValuesText
|
||||
type: text
|
||||
label: "What values does the community hold in disputes?"
|
||||
placeholder: "Describe the core values that guide your community's approach to conflicts..."
|
||||
required: true
|
||||
|
||||
- id: facilitation
|
||||
title: "How is the process facilitated?"
|
||||
description: "Methods of facilitation during the dispute process"
|
||||
stageId: process
|
||||
order: 2
|
||||
fields:
|
||||
- id: facilitationText
|
||||
type: text
|
||||
label: "How is the process facilitated?"
|
||||
placeholder: "Describe who facilitates the process and how they are selected/trained..."
|
||||
required: true
|
||||
|
||||
- id: ground_rules
|
||||
title: "What are the ground-rules of the process?"
|
||||
description: "Basic rules of conduct during the dispute process"
|
||||
stageId: process
|
||||
order: 3
|
||||
fields:
|
||||
- id: groundRulesText
|
||||
type: text
|
||||
label: "What are the ground-rules of the process?"
|
||||
placeholder: "Describe the rules of engagement that all participants must follow..."
|
||||
required: true
|
23
data/components/resolution.yaml
Normal file
23
data/components/resolution.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
- id: resolution_process
|
||||
title: "How does resolution of the dispute occur?"
|
||||
description: "Methods for reaching a resolution"
|
||||
stageId: resolution
|
||||
order: 1
|
||||
fields:
|
||||
- id: resolutionProcessText
|
||||
type: text
|
||||
label: "How does resolution of the dispute occur?"
|
||||
placeholder: "Describe the process by which disputes are resolved..."
|
||||
required: true
|
||||
|
||||
- id: resolution_failure
|
||||
title: "What if a resolution cannot be reached?"
|
||||
description: "Handling situations where resolution is not achieved"
|
||||
stageId: resolution
|
||||
order: 2
|
||||
fields:
|
||||
- id: resolutionFailureText
|
||||
type: text
|
||||
label: "What if a resolution cannot be reached?"
|
||||
placeholder: "Describe what happens when parties cannot come to a resolution..."
|
||||
required: true
|
27
data/modules/assessment.yaml
Normal file
27
data/modules/assessment.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
- id: participant-goal-assessment
|
||||
title: "Participant Goal Assessment"
|
||||
componentId: dispute_assessment
|
||||
fieldId: disputeAssessmentText
|
||||
content: |
|
||||
The dispute is assessed by focusing on the goals of all participants:
|
||||
|
||||
1. Each participant articulates what they hope to achieve through the process
|
||||
2. Participants identify areas of common ground and shared interests
|
||||
3. The facilitator helps frame the dispute in terms of compatible and competing goals
|
||||
4. Participants rate the importance of different goals to help prioritize
|
||||
5. Assessment continues throughout the process as goals may evolve
|
||||
6. Resolution options are evaluated against the stated goals of participants
|
||||
|
||||
- id: fact-assessment
|
||||
title: "Fact Assessment"
|
||||
componentId: dispute_assessment
|
||||
fieldId: disputeAssessmentText
|
||||
content: |
|
||||
The dispute is assessed through a structured fact-finding process:
|
||||
|
||||
1. Facilitators interview all parties separately to gather initial accounts
|
||||
2. Documentary evidence and other materials are collected and cataloged
|
||||
3. Areas of factual agreement and disagreement are identified
|
||||
4. Where possible, neutral verification of disputed facts is sought
|
||||
5. A written summary of established facts is created and shared with participants
|
||||
6. The dispute assessment is updated as new information becomes available
|
41
data/modules/delegation.yaml
Normal file
41
data/modules/delegation.yaml
Normal file
@ -0,0 +1,41 @@
|
||||
- id: police-report
|
||||
title: "Refer to Police Report"
|
||||
componentId: delegation_options
|
||||
fieldId: delegationOptionsText
|
||||
content: |
|
||||
In cases where this process is inadequate, disputes may be referred to law enforcement:
|
||||
|
||||
1. Situations involving immediate danger or criminal behavior are referred to police
|
||||
2. The community does not attempt to handle issues of criminal law internally
|
||||
3. Support is offered to community members who need to file police reports
|
||||
4. Community members may request an advocate to accompany them
|
||||
5. The community maintains relationships with local law enforcement liaisons
|
||||
6. Community process may resume after legal proceedings if appropriate
|
||||
|
||||
- id: internal-process
|
||||
title: "Refer to Another Internal Process"
|
||||
componentId: delegation_options
|
||||
fieldId: delegationOptionsText
|
||||
content: |
|
||||
In cases where this process is inadequate, disputes may be referred to other internal processes:
|
||||
|
||||
1. The community maintains several conflict resolution pathways for different situations
|
||||
2. Disputes involving multiple community groups are referred to the inter-group resolution committee
|
||||
3. Disputes requiring specialized knowledge may be referred to relevant working groups
|
||||
4. Cases requiring more structured intervention may be referred to the elder council
|
||||
5. Mediation services are available as an alternative to the standard process
|
||||
6. The community maintains clear guidelines for which process is appropriate for different situations
|
||||
|
||||
- id: external-process
|
||||
title: "Refer to External Process"
|
||||
componentId: delegation_options
|
||||
fieldId: delegationOptionsText
|
||||
content: |
|
||||
In cases where this process is inadequate, disputes may be referred to external resolution services:
|
||||
|
||||
1. The community maintains partnerships with professional mediation services
|
||||
2. Complex cases may be referred to specialized conflict resolution organizations
|
||||
3. Cases involving legal questions may be referred to legal aid services
|
||||
4. The community maintains a fund to help members access external services when needed
|
||||
5. A list of recommended external resources is maintained and regularly updated
|
||||
6. The community liaison helps ensure smooth handoff to external processes
|
21
data/modules/filing.yaml
Normal file
21
data/modules/filing.yaml
Normal file
@ -0,0 +1,21 @@
|
||||
- id: written-filing
|
||||
title: Written Filing Process
|
||||
componentId: filing
|
||||
fieldId: filingProcess
|
||||
content: |
|
||||
1. Complainant fills out a standard form describing the dispute
|
||||
2. Form includes sections for: parties involved, description of the issue, desired outcome
|
||||
3. Submission can be made via email, website, or physical drop-off
|
||||
4. Complainant receives confirmation of receipt
|
||||
5. Submission is reviewed for completeness within 48 hours
|
||||
|
||||
- id: verbal-filing
|
||||
title: Verbal Filing Process
|
||||
componentId: filing
|
||||
fieldId: filingProcess
|
||||
content: |
|
||||
1. Complainant schedules a meeting with a designated intake person
|
||||
2. During the meeting, the intake person documents the dispute details
|
||||
3. The intake person reviews the documented information with the complainant
|
||||
4. Once approved, the complaint is officially filed
|
||||
5. Complainant receives a copy of the documented complaint
|
104
data/modules/intake.yaml
Normal file
104
data/modules/intake.yaml
Normal file
@ -0,0 +1,104 @@
|
||||
- id: incident-report-form
|
||||
title: "Incident Report Form"
|
||||
componentId: process_start
|
||||
fieldId: processStartText
|
||||
content: |
|
||||
The dispute process begins when a community member fills out an incident report form. This form includes:
|
||||
|
||||
1. Details about the parties involved in the dispute
|
||||
2. A description of what happened, including dates and times
|
||||
3. Any relevant evidence or documentation
|
||||
4. A description of the outcome the person is seeking
|
||||
|
||||
The form can be submitted electronically through our community portal or as a paper form to the designated community coordinator.
|
||||
|
||||
- id: strong-confidentiality
|
||||
title: "Strong Confidentiality"
|
||||
componentId: information_access
|
||||
fieldId: informationAccessText
|
||||
content: |
|
||||
Our community practices strong confidentiality in dispute processes:
|
||||
|
||||
1. Only the designated facilitator(s) and directly involved parties have access to full information
|
||||
2. All participants must sign confidentiality agreements
|
||||
3. Records are kept secure and are accessible only to the dispute resolution committee
|
||||
4. Only general statistics and anonymized outcomes may be shared with the broader community
|
||||
5. Breaches of confidentiality may result in removal from the process
|
||||
|
||||
- id: strong-transparency
|
||||
title: "Strong Transparency"
|
||||
componentId: information_access
|
||||
fieldId: informationAccessText
|
||||
content: |
|
||||
Our community practices strong transparency in dispute processes:
|
||||
|
||||
1. Basic information about active disputes is available to all community members
|
||||
2. Proceedings are documented and records are available for community review
|
||||
3. Regular updates on the status of disputes are shared at community meetings
|
||||
4. Only personal identifying information and sensitive details are redacted
|
||||
5. All decisions and their rationales are published internally
|
||||
|
||||
- id: notification-message
|
||||
title: "Notification Message"
|
||||
componentId: participant_inclusion
|
||||
fieldId: participantInclusionText
|
||||
content: |
|
||||
Additional participants are brought into the process through a formal notification message:
|
||||
|
||||
1. The facilitator sends a written notification to all identified relevant parties
|
||||
2. The notification includes the nature of the dispute, the process that will be followed, and their role
|
||||
3. Recipients are given information about how to respond and participate
|
||||
4. The notification includes resources to help participants understand the process
|
||||
5. Participants have 7 days to acknowledge receipt and confirm their participation
|
||||
|
||||
- id: summons
|
||||
title: "Summons"
|
||||
componentId: participant_inclusion
|
||||
fieldId: participantInclusionText
|
||||
content: |
|
||||
Additional participants are brought into the process through a formal summons:
|
||||
|
||||
1. The dispute committee issues an official summons to all identified relevant parties
|
||||
2. The summons clearly states that participation is required according to community agreements
|
||||
3. It specifies the date, time, and method of required appearance
|
||||
4. The summons outlines potential consequences of non-participation
|
||||
5. Delivery of the summons is documented to ensure proper notification
|
||||
|
||||
- id: voluntary-participation
|
||||
title: "Voluntary Participation"
|
||||
componentId: participation_requirement
|
||||
fieldId: participationRequirementText
|
||||
content: |
|
||||
Participation in our dispute resolution process is entirely voluntary:
|
||||
|
||||
1. All parties must consent to participate in the process
|
||||
2. Any party may withdraw from the process at any time
|
||||
3. No negative consequences result from declining to participate
|
||||
4. Alternative means of resolution are suggested for those who decline
|
||||
5. The community respects individuals' autonomy in choosing whether to engage
|
||||
|
||||
- id: required-participation
|
||||
title: "Required Participation"
|
||||
componentId: participation_requirement
|
||||
fieldId: participationRequirementText
|
||||
content: |
|
||||
Participation in our dispute resolution process is required for all community members:
|
||||
|
||||
1. By joining our community, members agree to participate in the dispute process when necessary
|
||||
2. Participation is mandatory for all named parties in a dispute
|
||||
3. Failure to participate may result in consequences as outlined in our community agreement
|
||||
4. Only in exceptional circumstances may exemptions be granted
|
||||
5. Repeated refusal to participate may result in review of community membership
|
||||
|
||||
- id: stake-based-participation
|
||||
title: "Stake-based Participation"
|
||||
componentId: participation_commitments
|
||||
fieldId: participationCommitmentsText
|
||||
content: |
|
||||
Participants in the dispute process must place a meaningful stake into the process:
|
||||
|
||||
1. Each participant contributes a small financial deposit (adjusted based on ability to pay)
|
||||
2. Deposits are returned when parties fulfill all process commitments
|
||||
3. Participants commit a specified amount of time to the process
|
||||
4. Participants agree to adhere to all ground rules and procedural guidelines
|
||||
5. All parties agree to implement the resolution in good faith
|
21
data/modules/notification.yaml
Normal file
21
data/modules/notification.yaml
Normal file
@ -0,0 +1,21 @@
|
||||
- id: direct-notification
|
||||
title: Direct Notification Process
|
||||
componentId: notification
|
||||
fieldId: notificationMethod
|
||||
content: |
|
||||
1. All parties are notified in writing within 72 hours of a filed complaint
|
||||
2. Notification includes a copy of the complaint and next steps
|
||||
3. Parties confirm receipt of notification
|
||||
4. If no confirmation is received within 48 hours, a secondary contact method is used
|
||||
5. All notifications maintain privacy and confidentiality standards
|
||||
|
||||
- id: facilitated-notification
|
||||
title: Facilitated Notification Process
|
||||
componentId: notification
|
||||
fieldId: notificationMethod
|
||||
content: |
|
||||
1. A neutral facilitator contacts all parties individually
|
||||
2. The facilitator explains the process and shares the complaint details
|
||||
3. Parties have an opportunity to ask questions about the process
|
||||
4. The facilitator documents that notification has occurred
|
||||
5. Follow-up written summary is provided to all parties
|
33
data/modules/participants.yaml
Normal file
33
data/modules/participants.yaml
Normal file
@ -0,0 +1,33 @@
|
||||
- id: community-circle
|
||||
title: Community Circle Model
|
||||
componentId: participants
|
||||
fieldId: participantsRoles
|
||||
content: |
|
||||
1. Facilitator: Guides the process, ensures fairness, and helps maintain focus
|
||||
2. Affected Parties: Those directly impacted by the dispute
|
||||
3. Support Persons: Friends, family, or advocates who support affected parties
|
||||
4. Community Members: Representatives who bring wider perspective
|
||||
5. Resource People: Those with relevant expertise to inform the process
|
||||
|
||||
- id: mediation-model
|
||||
title: Mediation Model
|
||||
componentId: participants
|
||||
fieldId: participantsRoles
|
||||
content: |
|
||||
1. Mediator: Neutral third party who facilitates the process
|
||||
2. Disputants: Primary parties involved in the conflict
|
||||
3. Advocates: Optional support persons who may speak on behalf of disputants
|
||||
4. Witnesses: Those who provide information relevant to the dispute
|
||||
5. Implementers: Those responsible for helping carry out any agreements
|
||||
|
||||
- id: council-model
|
||||
title: Council Model
|
||||
componentId: participants
|
||||
fieldId: participantsRoles
|
||||
content: |
|
||||
1. Council Members: A designated group responsible for hearing disputes
|
||||
2. Complainant: Person bringing the dispute
|
||||
3. Respondent: Person responding to the complaint
|
||||
4. Witnesses: Those providing testimony or evidence
|
||||
5. Advisors: Those who support the council with expertise
|
||||
6. Community Observers: Those who may witness proceedings for transparency
|
32
data/modules/principles.yaml
Normal file
32
data/modules/principles.yaml
Normal file
@ -0,0 +1,32 @@
|
||||
- id: restorative
|
||||
title: Restorative Justice Principles
|
||||
componentId: principles
|
||||
fieldId: principlesText
|
||||
content: |
|
||||
1. Focus on harm and needs of those affected
|
||||
2. Address obligations resulting from harm
|
||||
3. Use inclusive, collaborative processes
|
||||
4. Involve all stakeholders (victims, offenders, community)
|
||||
5. Work toward repairing harm and healing relationships
|
||||
|
||||
- id: transformative
|
||||
title: Transformative Justice Principles
|
||||
componentId: principles
|
||||
fieldId: principlesText
|
||||
content: |
|
||||
1. Seek to address immediate safety, healing, and agency
|
||||
2. Work to transform the conditions that allowed violence to occur
|
||||
3. Build community accountability systems
|
||||
4. Focus on community-based responses without relying on punitive systems
|
||||
5. Acknowledge interconnection of all forms of violence
|
||||
|
||||
- id: consensus
|
||||
title: Consensus-Based Principles
|
||||
componentId: principles
|
||||
fieldId: principlesText
|
||||
content: |
|
||||
1. All members have equal input in decision-making
|
||||
2. Seek solutions that address everyone's fundamental concerns
|
||||
3. Prioritize listening and understanding diverse perspectives
|
||||
4. Work toward outcomes that all parties can accept
|
||||
5. Focus on collaborative problem-solving over adversarial positions
|
65
data/modules/process.yaml
Normal file
65
data/modules/process.yaml
Normal file
@ -0,0 +1,65 @@
|
||||
- id: participant-facilitation
|
||||
title: "Participant Facilitation"
|
||||
componentId: facilitation
|
||||
fieldId: facilitationText
|
||||
content: |
|
||||
The dispute process is facilitated by the participants themselves:
|
||||
|
||||
1. Participants take turns leading different parts of the conversation
|
||||
2. A written guide provides structure to ensure all voices are heard
|
||||
3. All participants receive basic training in productive dialogue techniques
|
||||
4. Time limits and speaking guidelines ensure fair participation
|
||||
5. Any participant can call for a break or reset if the process becomes unproductive
|
||||
|
||||
- id: peer-facilitation
|
||||
title: "Peer Facilitation"
|
||||
componentId: facilitation
|
||||
fieldId: facilitationText
|
||||
content: |
|
||||
The dispute process is facilitated by peers from within the community:
|
||||
|
||||
1. A pool of trained peer facilitators is maintained within the community
|
||||
2. Facilitators are selected who have no direct involvement in the dispute
|
||||
3. Peer facilitators receive regular training in conflict resolution techniques
|
||||
4. Typically, two peer facilitators work together on each case
|
||||
5. Peer facilitators help maintain structure but do not make decisions
|
||||
|
||||
- id: trained-facilitation
|
||||
title: "Trained Facilitation (e.g. mediator)"
|
||||
componentId: facilitation
|
||||
fieldId: facilitationText
|
||||
content: |
|
||||
The dispute process is facilitated by professionally trained mediators:
|
||||
|
||||
1. Professional mediators with formal certification lead the process
|
||||
2. Mediators are selected from outside the community to ensure neutrality
|
||||
3. Mediators have specific training in the type of conflict being addressed
|
||||
4. The community maintains a roster of approved mediators
|
||||
5. Mediators are paid for their services according to a pre-established rate
|
||||
|
||||
- id: facilitation-committee
|
||||
title: "Facilitation Committee"
|
||||
componentId: facilitation
|
||||
fieldId: facilitationText
|
||||
content: |
|
||||
The dispute process is facilitated by a standing committee:
|
||||
|
||||
1. A dedicated committee of 5-7 members oversees all dispute processes
|
||||
2. Committee members serve rotating terms and receive ongoing training
|
||||
3. For each dispute, a subgroup of 2-3 committee members is assigned
|
||||
4. Committee members with conflicts of interest must recuse themselves
|
||||
5. The committee follows established procedures and maintains records of all cases
|
||||
|
||||
- id: nonviolent-communication
|
||||
title: "Nonviolent Communication"
|
||||
componentId: ground_rules
|
||||
fieldId: groundRulesText
|
||||
content: |
|
||||
Our dispute process follows the principles of Nonviolent Communication (NVC):
|
||||
|
||||
1. Participants focus on observations rather than evaluations or judgments
|
||||
2. Participants express feelings using "I" statements rather than blaming others
|
||||
3. Participants identify needs that are or are not being met by the situation
|
||||
4. Participants make clear, actionable requests rather than demands
|
||||
5. Facilitators help participants translate judgmental language into NVC format
|
||||
6. Active listening is practiced, with participants reflecting back what they've heard
|
41
data/modules/resolution.yaml
Normal file
41
data/modules/resolution.yaml
Normal file
@ -0,0 +1,41 @@
|
||||
- id: participant-consensus
|
||||
title: "Participant Consensus"
|
||||
componentId: resolution_process
|
||||
fieldId: resolutionProcessText
|
||||
content: |
|
||||
Resolution occurs through consensus of all involved participants:
|
||||
|
||||
1. Participants collaboratively develop possible solutions
|
||||
2. All parties must agree to the final resolution
|
||||
3. Consensus does not mean everyone's first choice, but a solution everyone can accept
|
||||
4. Multiple rounds of proposal and revision may be necessary
|
||||
5. Facilitators help test solutions against participants' stated needs
|
||||
6. Once consensus is reached, the agreement is documented in writing
|
||||
|
||||
- id: facilitator-adjudication
|
||||
title: "Facilitator Adjudication"
|
||||
componentId: resolution_process
|
||||
fieldId: resolutionProcessText
|
||||
content: |
|
||||
Resolution occurs through a decision made by the facilitator(s):
|
||||
|
||||
1. After full deliberation, the facilitator(s) makes a binding decision
|
||||
2. The decision is based on community guidelines and the specifics of the case
|
||||
3. Facilitators provide a written explanation of their decision and reasoning
|
||||
4. All parties agree in advance to abide by the facilitator's decision
|
||||
5. Decisions establish precedent for future similar cases
|
||||
6. Decisions may be appealed only on specific grounds
|
||||
|
||||
- id: jury-adjudication
|
||||
title: "Jury Adjudication"
|
||||
componentId: resolution_process
|
||||
fieldId: resolutionProcessText
|
||||
content: |
|
||||
Resolution occurs through a decision made by a jury of community peers:
|
||||
|
||||
1. A jury of 5-7 community members is randomly selected
|
||||
2. Jury members receive an orientation to their role and responsibilities
|
||||
3. After hearing all perspectives, the jury deliberates privately
|
||||
4. The jury reaches a decision by two-thirds majority
|
||||
5. The jury provides a written explanation of their decision
|
||||
6. All community members agree in advance to respect jury decisions
|
34
data/stages/stages.yaml
Normal file
34
data/stages/stages.yaml
Normal file
@ -0,0 +1,34 @@
|
||||
- id: intake
|
||||
title: "Intake"
|
||||
description: "How disputes enter the process"
|
||||
order: 1
|
||||
|
||||
- id: process
|
||||
title: "Process"
|
||||
description: "How the dispute resolution operates"
|
||||
order: 2
|
||||
|
||||
- id: assessment
|
||||
title: "Assessment"
|
||||
description: "Evaluating the state of the dispute"
|
||||
order: 3
|
||||
|
||||
- id: deliberation
|
||||
title: "Deliberation"
|
||||
description: "Discussing the dispute"
|
||||
order: 4
|
||||
|
||||
- id: resolution
|
||||
title: "Resolution"
|
||||
description: "Determining outcomes for the dispute"
|
||||
order: 5
|
||||
|
||||
- id: appeal
|
||||
title: "Appeal"
|
||||
description: "Process for reconsidering dispute decisions"
|
||||
order: 6
|
||||
|
||||
- id: delegation
|
||||
title: "Delegation"
|
||||
description: "Alternative processes when this one is inadequate"
|
||||
order: 7
|
47
deploy.sh
Executable file
47
deploy.sh
Executable file
@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Dispute Protocol Deployment Script
|
||||
# This script builds and deploys the dispute protocol site to a remote server
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
SSH_USER=${1:-$USER}
|
||||
SSH_HOST=${2:-"example.com"}
|
||||
DEPLOY_PATH=${3:-"/var/www/dispute-protocol"}
|
||||
BUILD_DIR="public"
|
||||
|
||||
# Check if Hugo is installed
|
||||
if ! command -v hugo &> /dev/null; then
|
||||
echo -e "${RED}Error: Hugo is not installed. Please install Hugo first.${NC}"
|
||||
echo "Visit https://gohugo.io/installation/ for installation instructions."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Building site...${NC}"
|
||||
hugo --minify
|
||||
|
||||
# Check if build succeeded
|
||||
if [ ! -d "$BUILD_DIR" ]; then
|
||||
echo -e "${RED}Error: Build failed. The '$BUILD_DIR' directory doesn't exist.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Deploying to $SSH_USER@$SSH_HOST:$DEPLOY_PATH...${NC}"
|
||||
|
||||
# Create directory if it doesn't exist
|
||||
ssh $SSH_USER@$SSH_HOST "mkdir -p $DEPLOY_PATH"
|
||||
|
||||
# Deploy using rsync
|
||||
rsync -avz --delete $BUILD_DIR/ $SSH_USER@$SSH_HOST:$DEPLOY_PATH
|
||||
|
||||
echo -e "${GREEN}Deployment completed successfully!${NC}"
|
||||
echo -e "${YELLOW}NOTE: Make sure your web server is configured correctly to serve the site.${NC}"
|
||||
|
||||
exit 0
|
1359
static/css/main.css
Normal file
1359
static/css/main.css
Normal file
File diff suppressed because it is too large
Load Diff
970
static/js/builder.js
Normal file
970
static/js/builder.js
Normal file
@ -0,0 +1,970 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('DOM loaded - initializing builder');
|
||||
|
||||
// Initialize preview mode state
|
||||
let previewModeActive = false;
|
||||
|
||||
// Preview Mode Toggle
|
||||
const previewToggle = document.getElementById('preview-toggle');
|
||||
if (previewToggle) {
|
||||
console.log('Preview toggle found, adding event listener');
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
// Hacky way: find any click anywhere near the toggle and check status
|
||||
if (e.target.closest('.toggle-switch') || e.target.id === 'preview-toggle') {
|
||||
// Give time for the checkbox to update
|
||||
setTimeout(function() {
|
||||
previewModeActive = previewToggle.checked;
|
||||
console.log('Preview toggle changed to:', previewModeActive);
|
||||
|
||||
// Add a direct style change to visually confirm toggle works
|
||||
document.querySelector('.toggle-label').style.color = previewModeActive ? 'blue' : '';
|
||||
|
||||
togglePreviewMode(previewModeActive);
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error('Preview toggle element not found!');
|
||||
}
|
||||
|
||||
// Function to toggle preview mode
|
||||
function togglePreviewMode(active) {
|
||||
console.log('Toggle preview mode called with active =', active);
|
||||
|
||||
// Use inline styles for preview mode
|
||||
// This directly styles elements without relying on classes
|
||||
const styleId = 'preview-mode-style';
|
||||
let styleElement = document.getElementById(styleId);
|
||||
|
||||
if (active) {
|
||||
// Create style element if it doesn't exist
|
||||
if (!styleElement) {
|
||||
styleElement = document.createElement('style');
|
||||
styleElement.id = styleId;
|
||||
document.head.appendChild(styleElement);
|
||||
}
|
||||
|
||||
// Find all textareas with content to mark for display
|
||||
const contentTextareas = [];
|
||||
document.querySelectorAll('textarea').forEach(textarea => {
|
||||
if (textarea.value && textarea.value.trim()) {
|
||||
// Get the ID for later targeting
|
||||
contentTextareas.push('#' + textarea.id);
|
||||
|
||||
// Mark parents for visibility
|
||||
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');
|
||||
|
||||
// Ensure stage is expanded
|
||||
if (stage) {
|
||||
const stageBody = stage.querySelector('.stage-body');
|
||||
if (stageBody) stageBody.style.display = 'block';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Apply direct CSS to create preview mode
|
||||
styleElement.textContent = `
|
||||
/* Hide module selectors and empty fields */
|
||||
.module-selector { display: none !important; }
|
||||
.field:not(.has-content) { display: none !important; }
|
||||
|
||||
/* Hide empty components and sections */
|
||||
.component-card:not(.has-content) { display: none !important; }
|
||||
.stage-section:not(.has-content) { display: none !important; }
|
||||
|
||||
/* Hide template selector */
|
||||
.protocol-template-selector { display: none !important; }
|
||||
|
||||
/* Expand all sections */
|
||||
.stage-body { display: block !important; }
|
||||
|
||||
/* Make textareas read-only appearance */
|
||||
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;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* Only show filled textareas */
|
||||
textarea:not(${contentTextareas.join(',')}) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Clean styling for components */
|
||||
.component-header {
|
||||
background-color: transparent !important;
|
||||
border-bottom: none !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.component-short-label { display: none !important; }
|
||||
|
||||
/* Improved typography for preview mode */
|
||||
.component-header h3 {
|
||||
font-size: 1.4rem !important;
|
||||
margin-bottom: 1rem !important;
|
||||
color: #000 !important;
|
||||
border-bottom: 1px solid #eee !important;
|
||||
padding-bottom: 0.5rem !important;
|
||||
}
|
||||
`;
|
||||
|
||||
// Replace textareas with divs for better display in preview mode
|
||||
updatePreviewContent();
|
||||
|
||||
// Make other fields read-only
|
||||
document.querySelectorAll('#community-name, #protocol-summary').forEach(el => {
|
||||
el.setAttribute('readonly', 'readonly');
|
||||
});
|
||||
} else {
|
||||
// Remove preview styles
|
||||
if (styleElement) {
|
||||
styleElement.textContent = '';
|
||||
}
|
||||
|
||||
// Remove preview content divs and show textareas again
|
||||
document.querySelectorAll('.preview-content').forEach(div => {
|
||||
const textareaId = div.dataset.forTextarea;
|
||||
if (textareaId) {
|
||||
const textarea = document.getElementById(textareaId);
|
||||
if (textarea) {
|
||||
textarea.style.display = '';
|
||||
}
|
||||
}
|
||||
div.parentNode.removeChild(div);
|
||||
});
|
||||
|
||||
// Make fields editable again
|
||||
document.querySelectorAll('textarea, #community-name, #protocol-summary').forEach(el => {
|
||||
el.removeAttribute('readonly');
|
||||
});
|
||||
|
||||
// Remove content markers
|
||||
document.querySelectorAll('.has-content').forEach(el => {
|
||||
el.classList.remove('has-content');
|
||||
});
|
||||
|
||||
// Reset any display properties that were directly set
|
||||
document.querySelectorAll('.stage-body').forEach(el => {
|
||||
el.style.display = '';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Function to mark components and stages that have content
|
||||
function markComponentsWithContent() {
|
||||
// First reset all markers
|
||||
document.querySelectorAll('.has-content').forEach(el => {
|
||||
el.classList.remove('has-content');
|
||||
});
|
||||
|
||||
// Mark fields 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');
|
||||
}
|
||||
});
|
||||
|
||||
// Show all expanded sections that have content
|
||||
document.querySelectorAll('.stage-section.has-content').forEach(stage => {
|
||||
const stageBody = stage.querySelector('.stage-body');
|
||||
if (stageBody) {
|
||||
stageBody.style.display = 'block';
|
||||
const toggleBtn = stage.querySelector('.toggle-btn');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.textContent = '-';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Load module data
|
||||
let allModules = {};
|
||||
try {
|
||||
// Check if moduleData is defined (from modules.js)
|
||||
if (typeof moduleData !== 'undefined') {
|
||||
allModules = moduleData;
|
||||
console.log('Module data loaded from modules.js');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error loading module data:', e);
|
||||
allModules = {};
|
||||
}
|
||||
|
||||
// Load and process template data
|
||||
let templates = [];
|
||||
try {
|
||||
// Check if raw templates are defined (from templates.js)
|
||||
if (typeof rawProtocolTemplates !== 'undefined' && typeof templateMapper !== 'undefined') {
|
||||
console.log('Raw protocol templates loaded from templates.js');
|
||||
|
||||
// Process each template to use module references
|
||||
rawProtocolTemplates.forEach(rawTemplate => {
|
||||
const processedTemplate = templateMapper.convertTemplateToModules(rawTemplate, allModules);
|
||||
templates.push(processedTemplate);
|
||||
});
|
||||
|
||||
console.log('Processed templates to use module references:', templates);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error processing protocol templates:', e);
|
||||
templates = [];
|
||||
}
|
||||
|
||||
// Protocol data structure
|
||||
let protocol = {
|
||||
metadata: {
|
||||
communityName: "",
|
||||
summary: ""
|
||||
},
|
||||
stages: {}
|
||||
};
|
||||
|
||||
// DOM elements
|
||||
const stageHeaders = document.querySelectorAll('.stage-header');
|
||||
console.log('Found stage headers:', stageHeaders.length);
|
||||
|
||||
const stageContents = document.querySelectorAll('.stage-body');
|
||||
console.log('Found stage bodies:', stageContents.length);
|
||||
|
||||
const moduleSelects = document.querySelectorAll('.module-select');
|
||||
console.log('Found module selects:', moduleSelects.length);
|
||||
|
||||
const protocolTemplateSelect = document.getElementById('protocol-template');
|
||||
const communityNameInput = document.getElementById('community-name');
|
||||
const protocolSummaryTextarea = document.getElementById('protocol-summary');
|
||||
|
||||
const exportBtn = document.getElementById('export-btn');
|
||||
const exportMdBtn = document.getElementById('export-md');
|
||||
const exportPdfBtn = document.getElementById('export-pdf');
|
||||
const exportJsonBtn = document.getElementById('export-json');
|
||||
const importJsonInput = document.getElementById('import-json');
|
||||
const importBtn = document.getElementById('import-btn');
|
||||
|
||||
// Populate protocol template select
|
||||
if (protocolTemplateSelect && templates.length > 0) {
|
||||
templates.forEach(template => {
|
||||
const option = document.createElement('option');
|
||||
option.value = template.id;
|
||||
option.textContent = template.title;
|
||||
protocolTemplateSelect.appendChild(option);
|
||||
});
|
||||
|
||||
// Add template selection event handler
|
||||
protocolTemplateSelect.addEventListener('change', function() {
|
||||
const selectedTemplateId = this.value;
|
||||
|
||||
if (selectedTemplateId) {
|
||||
// Find the selected template
|
||||
const selectedTemplate = templates.find(t => t.id === selectedTemplateId);
|
||||
|
||||
if (selectedTemplate) {
|
||||
console.log('Applying template:', selectedTemplate);
|
||||
|
||||
console.log('Selected template:', selectedTemplate.title);
|
||||
|
||||
// Reset protocol data while preserving metadata
|
||||
protocol = {
|
||||
metadata: {
|
||||
communityName: communityNameInput.value || "",
|
||||
summary: protocolSummaryTextarea.value || ""
|
||||
},
|
||||
stages: {},
|
||||
templateId: selectedTemplate.id,
|
||||
templateTitle: selectedTemplate.title,
|
||||
templateDescription: selectedTemplate.description
|
||||
};
|
||||
|
||||
// If summary is empty, use template description
|
||||
if (!protocol.metadata.summary) {
|
||||
protocolSummaryTextarea.value = selectedTemplate.description;
|
||||
protocol.metadata.summary = selectedTemplate.description;
|
||||
}
|
||||
|
||||
// Apply the template module references to the form
|
||||
for (const stageId in selectedTemplate.moduleRefs) {
|
||||
if (!protocol.stages[stageId]) {
|
||||
protocol.stages[stageId] = {};
|
||||
}
|
||||
|
||||
for (const componentId in selectedTemplate.moduleRefs[stageId]) {
|
||||
if (!protocol.stages[stageId][componentId]) {
|
||||
protocol.stages[stageId][componentId] = {};
|
||||
}
|
||||
|
||||
for (const fieldId in selectedTemplate.moduleRefs[stageId][componentId]) {
|
||||
const moduleId = selectedTemplate.moduleRefs[stageId][componentId][fieldId];
|
||||
const textarea = document.getElementById(fieldId);
|
||||
|
||||
if (textarea) {
|
||||
// Find the module with this ID
|
||||
let moduleContent = '';
|
||||
|
||||
for (const category in allModules) {
|
||||
const foundModule = allModules[category].find(m => m.id === moduleId);
|
||||
if (foundModule) {
|
||||
moduleContent = foundModule.content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the module content to the textarea
|
||||
textarea.value = moduleContent;
|
||||
|
||||
// Store in protocol data
|
||||
protocol.stages[stageId][componentId][fieldId] = moduleContent;
|
||||
|
||||
// If there's a template selector for this field, update it
|
||||
const moduleSelector = document.querySelector(`select.module-select[data-field-id="${fieldId}"][data-component-id="${componentId}"]`);
|
||||
if (moduleSelector) {
|
||||
moduleSelector.value = moduleId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expand all sections to show the populated content
|
||||
stageContents.forEach(content => {
|
||||
content.style.display = 'block';
|
||||
const toggleBtn = content.parentElement.querySelector('.toggle-btn');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.textContent = '-';
|
||||
}
|
||||
});
|
||||
|
||||
// Update preview mode if active
|
||||
if (previewModeActive) {
|
||||
markComponentsWithContent();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Clear all fields if "Create Your Own" is selected
|
||||
|
||||
document.querySelectorAll('textarea').forEach(textarea => {
|
||||
textarea.value = '';
|
||||
});
|
||||
|
||||
// Reset protocol data
|
||||
protocol = { stages: {} };
|
||||
|
||||
// Collapse all sections
|
||||
stageContents.forEach(content => {
|
||||
content.style.display = 'none';
|
||||
const toggleBtn = content.parentElement.querySelector('.toggle-btn');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.textContent = '+';
|
||||
}
|
||||
});
|
||||
|
||||
// Update preview mode if active
|
||||
if (previewModeActive) {
|
||||
markComponentsWithContent();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize all module selects
|
||||
populateModuleSelects();
|
||||
|
||||
// Module selection handlers
|
||||
moduleSelects.forEach(select => {
|
||||
select.addEventListener('change', function() {
|
||||
const fieldId = this.getAttribute('data-field-id');
|
||||
const componentId = this.getAttribute('data-component-id');
|
||||
const targetTextarea = document.getElementById(fieldId);
|
||||
|
||||
if (targetTextarea && this.value) {
|
||||
// Find the selected module
|
||||
for (const category in allModules) {
|
||||
const selectedModule = allModules[category].find(m => m.id === this.value);
|
||||
if (selectedModule) {
|
||||
targetTextarea.value = selectedModule.content;
|
||||
|
||||
// Update protocol data
|
||||
updateProtocolData();
|
||||
|
||||
// Update preview mode if active
|
||||
if (previewModeActive) {
|
||||
markComponentsWithContent();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Function to populate module select dropdowns
|
||||
function populateModuleSelects() {
|
||||
console.log('Populating module selects...');
|
||||
console.log('Available module categories:', Object.keys(allModules));
|
||||
|
||||
// Debugging: Log all modules to check componentId and fieldId
|
||||
console.log('All module mapping:');
|
||||
for (const category in allModules) {
|
||||
console.log(`Category: ${category}`);
|
||||
allModules[category].forEach(module => {
|
||||
console.log(` Module: ${module.id}, Component: ${module.componentId}, Field: ${module.fieldId}`);
|
||||
});
|
||||
}
|
||||
|
||||
moduleSelects.forEach(select => {
|
||||
const fieldId = select.getAttribute('data-field-id');
|
||||
const componentId = select.getAttribute('data-component-id');
|
||||
|
||||
console.log(`Processing module select for fieldId: ${fieldId}, componentId: ${componentId}`);
|
||||
|
||||
// Clear existing options except the first one
|
||||
while (select.options.length > 1) {
|
||||
select.remove(1);
|
||||
}
|
||||
|
||||
// Find modules that match this field and component
|
||||
let hasOptions = false;
|
||||
|
||||
// Always show select first - we'll hide it later if no options found
|
||||
select.closest('.module-selector').style.display = 'flex';
|
||||
|
||||
// Check for case matching issues and missing references
|
||||
for (const category in allModules) {
|
||||
let exactMatches = allModules[category].filter(m =>
|
||||
m.fieldId === fieldId && m.componentId === componentId
|
||||
);
|
||||
|
||||
let caseInsensitiveMatches = allModules[category].filter(m =>
|
||||
m.fieldId.toLowerCase() === fieldId.toLowerCase() &&
|
||||
m.componentId.toLowerCase() === componentId.toLowerCase() &&
|
||||
!exactMatches.includes(m)
|
||||
);
|
||||
|
||||
if (caseInsensitiveMatches.length > 0) {
|
||||
console.warn(`Found ${caseInsensitiveMatches.length} case-insensitive matches for ${componentId}/${fieldId}. Consider fixing these module references.`);
|
||||
|
||||
// Add case-insensitive matches to the collection
|
||||
caseInsensitiveMatches.forEach(module => {
|
||||
// Create a copy with corrected references
|
||||
const correctedModule = {
|
||||
...module,
|
||||
componentId: componentId,
|
||||
fieldId: fieldId
|
||||
};
|
||||
|
||||
// Add to the exact matches
|
||||
exactMatches.push(correctedModule);
|
||||
});
|
||||
}
|
||||
|
||||
if (exactMatches.length > 0) {
|
||||
console.log(`Found ${exactMatches.length} modules in category ${category} for ${componentId}/${fieldId}`);
|
||||
hasOptions = true;
|
||||
|
||||
// Don't use option groups - add options directly to the select
|
||||
// This avoids showing category labels which can be confusing
|
||||
exactMatches.forEach(module => {
|
||||
const option = document.createElement('option');
|
||||
option.value = module.id;
|
||||
|
||||
// Use the module title directly from the definition
|
||||
// This relies on proper module titles being defined in modules.js
|
||||
option.textContent = module.title;
|
||||
|
||||
// Add directly to select instead of to a group
|
||||
select.appendChild(option);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// If no modules found, hide the selector
|
||||
if (!hasOptions) {
|
||||
console.log(`No modules found for ${componentId}/${fieldId}, hiding selector`);
|
||||
select.closest('.module-selector').style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Update protocol data from form inputs
|
||||
function updateProtocolData() {
|
||||
// Update metadata
|
||||
protocol.metadata = {
|
||||
communityName: communityNameInput.value || "",
|
||||
summary: protocolSummaryTextarea.value || ""
|
||||
};
|
||||
|
||||
// Reset the stages data
|
||||
protocol.stages = {};
|
||||
|
||||
// Get all textareas and their values
|
||||
const textareas = document.querySelectorAll('textarea');
|
||||
textareas.forEach(textarea => {
|
||||
const fieldId = textarea.id;
|
||||
const fieldValue = textarea.value;
|
||||
|
||||
// Skip empty fields
|
||||
if (!fieldValue || !fieldValue.trim()) return;
|
||||
|
||||
// Find the component and stage for this field
|
||||
const componentCard = textarea.closest('.component-card');
|
||||
if (!componentCard) return;
|
||||
|
||||
const componentId = componentCard.id.replace('component-', '');
|
||||
|
||||
const stageSection = textarea.closest('.stage-section');
|
||||
if (!stageSection) return;
|
||||
|
||||
const stageId = stageSection.id.replace('stage-', '');
|
||||
|
||||
// Initialize stage and component if they don't exist
|
||||
if (!protocol.stages[stageId]) {
|
||||
protocol.stages[stageId] = {};
|
||||
}
|
||||
|
||||
if (!protocol.stages[stageId][componentId]) {
|
||||
protocol.stages[stageId][componentId] = {};
|
||||
}
|
||||
|
||||
// Set the field value
|
||||
protocol.stages[stageId][componentId][fieldId] = fieldValue;
|
||||
});
|
||||
|
||||
// If a template is selected, preserve the template information
|
||||
const selectedTemplateId = protocolTemplateSelect ? protocolTemplateSelect.value : '';
|
||||
|
||||
if (selectedTemplateId) {
|
||||
const selectedTemplate = templates.find(t => t.id === selectedTemplateId);
|
||||
if (selectedTemplate) {
|
||||
protocol.templateId = selectedTemplateId;
|
||||
protocol.templateTitle = selectedTemplate.title;
|
||||
protocol.templateDescription = selectedTemplate.description;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove empty components and stages
|
||||
for (const stageId in protocol.stages) {
|
||||
// Check if stage has any non-empty components
|
||||
const stageComponents = protocol.stages[stageId];
|
||||
let stageHasContent = false;
|
||||
|
||||
for (const componentId in stageComponents) {
|
||||
// Check if component has any fields
|
||||
const component = stageComponents[componentId];
|
||||
const fieldCount = Object.keys(component).length;
|
||||
|
||||
if (fieldCount > 0) {
|
||||
stageHasContent = true;
|
||||
} else {
|
||||
// Remove empty component
|
||||
delete stageComponents[componentId];
|
||||
}
|
||||
}
|
||||
|
||||
// If stage has no content, remove it
|
||||
if (!stageHasContent) {
|
||||
delete protocol.stages[stageId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Export to Markdown
|
||||
exportMdBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
updateProtocolData();
|
||||
|
||||
// Use community name if available, otherwise default
|
||||
const communityName = protocol.metadata.communityName || "Community";
|
||||
let markdown = `# ${communityName} Dispute Protocol\n\n`;
|
||||
|
||||
// Include protocol summary if available
|
||||
if (protocol.metadata.summary) {
|
||||
markdown += `${protocol.metadata.summary}\n\n`;
|
||||
markdown += '---\n\n';
|
||||
}
|
||||
|
||||
// Include template information if a template was used
|
||||
if (protocol.templateTitle) {
|
||||
markdown += `**Template Used:** ${protocol.templateTitle}\n\n`;
|
||||
markdown += '---\n\n';
|
||||
}
|
||||
|
||||
// Loop through the stages in order
|
||||
stageHeaders.forEach(header => {
|
||||
const stageId = header.getAttribute('data-stage');
|
||||
const stageName = header.querySelector('h2').textContent;
|
||||
|
||||
let stageContent = '';
|
||||
let hasContent = false;
|
||||
|
||||
// Get components for this stage
|
||||
const stageComponents = protocol.stages[stageId];
|
||||
if (stageComponents) {
|
||||
// Loop through components
|
||||
for (const componentId in stageComponents) {
|
||||
const componentCard = document.getElementById(`component-${componentId}`);
|
||||
if (componentCard) {
|
||||
const componentName = componentCard.querySelector('h3').textContent;
|
||||
|
||||
let componentContent = '';
|
||||
let componentHasContent = false;
|
||||
|
||||
// Loop through fields
|
||||
for (const fieldId in stageComponents[componentId]) {
|
||||
const fieldValue = stageComponents[componentId][fieldId];
|
||||
|
||||
// Skip empty fields
|
||||
if (fieldValue && fieldValue.trim()) {
|
||||
const fieldLabel = document.querySelector(`label[for="${fieldId}"]`).textContent;
|
||||
componentContent += `#### ${fieldLabel}\n\n${fieldValue}\n\n`;
|
||||
componentHasContent = true;
|
||||
hasContent = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Only add component if it has content
|
||||
if (componentHasContent) {
|
||||
stageContent += `### ${componentName}\n\n${componentContent}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only add stage if it has content
|
||||
if (hasContent) {
|
||||
markdown += `## ${stageName}\n\n${stageContent}`;
|
||||
}
|
||||
});
|
||||
|
||||
// Create and download the file
|
||||
downloadFile('community_dispute_protocol.md', markdown);
|
||||
});
|
||||
|
||||
// Export to PDF
|
||||
exportPdfBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
updateProtocolData();
|
||||
|
||||
// Create a styled HTML version for PDF export
|
||||
const { jsPDF } = window.jspdf;
|
||||
const doc = new jsPDF();
|
||||
|
||||
let yPos = 20;
|
||||
|
||||
// Use community name if available, otherwise default
|
||||
const communityName = protocol.metadata.communityName || "Community";
|
||||
|
||||
// Add title
|
||||
doc.setFontSize(18);
|
||||
doc.text(`${communityName} Dispute Protocol`, 105, yPos, { align: 'center' });
|
||||
yPos += 15;
|
||||
|
||||
// Add protocol summary if available
|
||||
if (protocol.metadata.summary) {
|
||||
doc.setFontSize(12);
|
||||
const summaryLines = doc.splitTextToSize(protocol.metadata.summary, 180);
|
||||
doc.text(summaryLines, 14, yPos);
|
||||
yPos += summaryLines.length * 7 + 8;
|
||||
}
|
||||
|
||||
// Add template info if available
|
||||
if (protocol.templateTitle) {
|
||||
doc.setFontSize(10);
|
||||
doc.text(`Template Used: ${protocol.templateTitle}`, 14, yPos);
|
||||
yPos += 10;
|
||||
}
|
||||
|
||||
// Loop through the stages
|
||||
stageHeaders.forEach(header => {
|
||||
const stageId = header.getAttribute('data-stage');
|
||||
const stageName = header.querySelector('h2').textContent;
|
||||
|
||||
let stageHasContent = false;
|
||||
let stageStartYPos = yPos;
|
||||
|
||||
// Save current position to add stage heading later if content is found
|
||||
if (yPos > 250) {
|
||||
doc.addPage();
|
||||
stageStartYPos = 20;
|
||||
yPos = 20;
|
||||
}
|
||||
|
||||
// Skip stage heading for now - we'll add it if the stage has content
|
||||
let currentYPos = stageStartYPos + 10; // Space for the heading
|
||||
|
||||
// Get components for this stage
|
||||
const stageComponents = protocol.stages[stageId];
|
||||
if (stageComponents) {
|
||||
// Loop through components
|
||||
for (const componentId in stageComponents) {
|
||||
const componentCard = document.getElementById(`component-${componentId}`);
|
||||
if (componentCard) {
|
||||
let componentHasContent = false;
|
||||
let componentStartYPos = currentYPos;
|
||||
|
||||
// Check for page break
|
||||
if (currentYPos > 250) {
|
||||
doc.addPage();
|
||||
componentStartYPos = 20;
|
||||
currentYPos = 20;
|
||||
}
|
||||
|
||||
// Skip component heading for now - add if it has content
|
||||
const componentFieldStartYPos = componentStartYPos + 8;
|
||||
let fieldYPos = componentFieldStartYPos;
|
||||
|
||||
const componentName = componentCard.querySelector('h3').textContent;
|
||||
|
||||
// Loop through fields
|
||||
for (const fieldId in stageComponents[componentId]) {
|
||||
const fieldValue = stageComponents[componentId][fieldId];
|
||||
|
||||
// Skip empty fields
|
||||
if (fieldValue && fieldValue.trim()) {
|
||||
const fieldLabel = document.querySelector(`label[for="${fieldId}"]`).textContent;
|
||||
|
||||
// Add page break if needed
|
||||
if (fieldYPos > 250) {
|
||||
doc.addPage();
|
||||
fieldYPos = 20;
|
||||
}
|
||||
|
||||
// We have content - if this is the first content in the component,
|
||||
// add the component heading
|
||||
if (!componentHasContent) {
|
||||
componentHasContent = true;
|
||||
stageHasContent = true;
|
||||
|
||||
// If this is the first content in the stage, add the stage heading
|
||||
if (!stageHasContent) {
|
||||
doc.setFontSize(16);
|
||||
doc.text(stageName, 14, stageStartYPos);
|
||||
}
|
||||
|
||||
// Add component heading
|
||||
doc.setFontSize(14);
|
||||
doc.text(componentName, 14, componentStartYPos);
|
||||
}
|
||||
|
||||
// Add field heading
|
||||
doc.setFontSize(12);
|
||||
doc.text(fieldLabel, 14, fieldYPos);
|
||||
fieldYPos += 6;
|
||||
|
||||
// Split the text into lines to handle wrapping
|
||||
const textLines = doc.splitTextToSize(fieldValue, 180);
|
||||
|
||||
// Add field content
|
||||
doc.setFontSize(10);
|
||||
doc.text(textLines, 14, fieldYPos);
|
||||
fieldYPos += textLines.length * 5 + 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Update current Y position if component had content
|
||||
if (componentHasContent) {
|
||||
currentYPos = fieldYPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the overall Y position if stage had content
|
||||
if (stageHasContent) {
|
||||
yPos = currentYPos;
|
||||
}
|
||||
});
|
||||
|
||||
// Save the PDF
|
||||
doc.save('community_dispute_protocol.pdf');
|
||||
});
|
||||
|
||||
// Export to JSON
|
||||
exportJsonBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
updateProtocolData();
|
||||
const jsonData = JSON.stringify(protocol, null, 2);
|
||||
downloadFile('community_dispute_protocol.json', jsonData);
|
||||
});
|
||||
|
||||
// Import from JSON
|
||||
importBtn.addEventListener('click', function() {
|
||||
importJsonInput.click();
|
||||
});
|
||||
|
||||
importJsonInput.addEventListener('change', function(event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
try {
|
||||
const importedProtocol = JSON.parse(e.target.result);
|
||||
protocol = importedProtocol;
|
||||
|
||||
// Populate metadata fields if present
|
||||
if (protocol.metadata) {
|
||||
if (protocol.metadata.communityName) {
|
||||
communityNameInput.value = protocol.metadata.communityName;
|
||||
}
|
||||
|
||||
if (protocol.metadata.summary) {
|
||||
protocolSummaryTextarea.value = protocol.metadata.summary;
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the component fields with the imported data
|
||||
for (const stageId in protocol.stages) {
|
||||
for (const componentId in protocol.stages[stageId]) {
|
||||
for (const fieldId in protocol.stages[stageId][componentId]) {
|
||||
const textarea = document.getElementById(fieldId);
|
||||
if (textarea) {
|
||||
textarea.value = protocol.stages[stageId][componentId][fieldId];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the imported protocol has template information, select that template
|
||||
if (protocol.templateId && protocolTemplateSelect) {
|
||||
protocolTemplateSelect.value = protocol.templateId;
|
||||
|
||||
// Update template description
|
||||
if (protocol.templateDescription && templateDescription) {
|
||||
templateDescription.textContent = protocol.templateDescription;
|
||||
templateDescription.style.display = 'block';
|
||||
}
|
||||
|
||||
// Expand all sections
|
||||
stageContents.forEach(content => {
|
||||
content.style.display = 'block';
|
||||
const toggleBtn = content.parentElement.querySelector('.toggle-btn');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.textContent = '-';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// If no template, reset the template selector
|
||||
if (protocolTemplateSelect) {
|
||||
protocolTemplateSelect.value = '';
|
||||
}
|
||||
if (templateDescription) {
|
||||
templateDescription.textContent = '';
|
||||
templateDescription.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Update preview mode if active
|
||||
if (previewModeActive) {
|
||||
markComponentsWithContent();
|
||||
}
|
||||
|
||||
alert('Protocol imported successfully!');
|
||||
} catch (error) {
|
||||
alert('Failed to import protocol. Invalid JSON format.');
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
});
|
||||
|
||||
// Helper function to download a file
|
||||
function downloadFile(filename, content) {
|
||||
const element = document.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content));
|
||||
element.setAttribute('download', filename);
|
||||
element.style.display = 'none';
|
||||
document.body.appendChild(element);
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
|
||||
// Save data when inputs change
|
||||
document.querySelectorAll('textarea').forEach(textarea => {
|
||||
textarea.addEventListener('input', function() {
|
||||
updateProtocolData();
|
||||
// Update preview mode if active
|
||||
if (previewModeActive) {
|
||||
markComponentsWithContent();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Function to update preview content
|
||||
function updatePreviewContent() {
|
||||
// First, clear any existing preview divs
|
||||
document.querySelectorAll('.preview-content').forEach(div => {
|
||||
div.parentNode.removeChild(div);
|
||||
});
|
||||
|
||||
// Show all textareas again
|
||||
document.querySelectorAll('textarea').forEach(textarea => {
|
||||
textarea.style.display = '';
|
||||
});
|
||||
|
||||
// Then create new preview divs for all textareas with content
|
||||
document.querySelectorAll('textarea').forEach(textarea => {
|
||||
if (textarea.value && textarea.value.trim()) {
|
||||
// Create a div to replace the textarea for preview
|
||||
const previewDiv = document.createElement('div');
|
||||
previewDiv.className = 'preview-content';
|
||||
previewDiv.textContent = textarea.value;
|
||||
previewDiv.dataset.forTextarea = textarea.id;
|
||||
|
||||
// Hide the textarea and insert the div
|
||||
textarea.style.display = 'none';
|
||||
textarea.parentNode.insertBefore(previewDiv, textarea.nextSibling);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Update preview content when preview mode is toggled
|
||||
document.getElementById('preview-toggle').addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
// Wait for the preview mode styles to apply, then update content
|
||||
setTimeout(updatePreviewContent, 100);
|
||||
}
|
||||
});
|
||||
|
||||
// Update preview content when module content changes
|
||||
document.querySelectorAll('.module-select').forEach(select => {
|
||||
select.addEventListener('change', function() {
|
||||
setTimeout(() => {
|
||||
if (document.getElementById('preview-toggle').checked) {
|
||||
updatePreviewContent();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
// Update preview content on window resize
|
||||
window.addEventListener('resize', function() {
|
||||
if (document.getElementById('preview-toggle').checked) {
|
||||
updatePreviewContent();
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Builder initialization complete');
|
||||
});
|
1997
static/js/data/modules.js
Normal file
1997
static/js/data/modules.js
Normal file
File diff suppressed because it is too large
Load Diff
274
static/js/data/template-mapper.js
Normal file
274
static/js/data/template-mapper.js
Normal file
@ -0,0 +1,274 @@
|
||||
// This file handles mapping raw template content to module IDs
|
||||
// It's used to convert templates that use raw content to use module references instead
|
||||
|
||||
// Helper function to find the best matching module for a given content
|
||||
function findBestMatchingModule(content, componentId, fieldId, modules) {
|
||||
// If content is empty, return null
|
||||
if (!content || !content.trim()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if there are modules for this component and field
|
||||
let matchingModules = [];
|
||||
|
||||
for (const category in modules) {
|
||||
const categoryModules = modules[category].filter(m =>
|
||||
m.componentId === componentId && m.fieldId === fieldId
|
||||
);
|
||||
|
||||
if (categoryModules.length > 0) {
|
||||
matchingModules = matchingModules.concat(categoryModules);
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingModules.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the most similar module based on content
|
||||
let bestMatch = null;
|
||||
let highestSimilarity = 0;
|
||||
|
||||
matchingModules.forEach(module => {
|
||||
// Simple similarity metric: count of matching words
|
||||
const contentWords = content.toLowerCase().split(/\s+/);
|
||||
const moduleWords = module.content.toLowerCase().split(/\s+/);
|
||||
|
||||
// Count matching words
|
||||
let matchCount = 0;
|
||||
contentWords.forEach(word => {
|
||||
if (moduleWords.includes(word)) {
|
||||
matchCount++;
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate similarity as percentage of matching words
|
||||
const similarity = matchCount / Math.max(contentWords.length, moduleWords.length);
|
||||
|
||||
if (similarity > highestSimilarity) {
|
||||
highestSimilarity = similarity;
|
||||
bestMatch = module;
|
||||
}
|
||||
});
|
||||
|
||||
// Only return a match if similarity is above threshold
|
||||
return highestSimilarity > 0.5 ? bestMatch : null;
|
||||
}
|
||||
|
||||
// Convert a raw template to use module references
|
||||
function convertTemplateToModules(template, modules) {
|
||||
const result = {
|
||||
id: template.id,
|
||||
title: template.title,
|
||||
description: template.description,
|
||||
moduleRefs: {}
|
||||
};
|
||||
|
||||
// Go through each stage, component, and field
|
||||
for (const stageId in template.data.stages) {
|
||||
if (!result.moduleRefs[stageId]) {
|
||||
result.moduleRefs[stageId] = {};
|
||||
}
|
||||
|
||||
for (const componentId in template.data.stages[stageId]) {
|
||||
if (!result.moduleRefs[stageId][componentId]) {
|
||||
result.moduleRefs[stageId][componentId] = {};
|
||||
}
|
||||
|
||||
for (const fieldId in template.data.stages[stageId][componentId]) {
|
||||
const content = template.data.stages[stageId][componentId][fieldId];
|
||||
|
||||
// Find best matching module
|
||||
const matchingModule = findBestMatchingModule(content, componentId, fieldId, modules);
|
||||
|
||||
if (matchingModule) {
|
||||
// Store module reference
|
||||
result.moduleRefs[stageId][componentId][fieldId] = matchingModule.id;
|
||||
} else {
|
||||
// If no matching module, create a custom one with this content
|
||||
const customId = `custom-${template.id}-${componentId}-${fieldId}`;
|
||||
|
||||
// Add to appropriate module category or create a new one
|
||||
const categoryKey = stageId; // Use stage ID as category
|
||||
|
||||
if (!modules[categoryKey]) {
|
||||
modules[categoryKey] = [];
|
||||
}
|
||||
|
||||
// Check if custom module already exists
|
||||
const existingModule = modules[categoryKey].find(m =>
|
||||
m.id === customId && m.componentId === componentId && m.fieldId === fieldId
|
||||
);
|
||||
|
||||
if (!existingModule) {
|
||||
// Create a concise but descriptive module title
|
||||
let moduleTitle = "";
|
||||
|
||||
// Helper function to create more meaningful component-based titles
|
||||
function getComponentBasedTitle() {
|
||||
// Get a human-readable form of the component and field IDs
|
||||
const componentName = componentId.split('_')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ');
|
||||
const fieldName = fieldId.replace(/([A-Z])/g, ' $1')
|
||||
.replace(/Text$/, '')
|
||||
.replace(/Id$/, '')
|
||||
.split(/[_\s]/)
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ')
|
||||
.trim();
|
||||
|
||||
// Find core theme from content
|
||||
const lines = content.split('\n').map(l => l.trim()).filter(l => l);
|
||||
|
||||
// Try to find a descriptive keyword from the first paragraph
|
||||
const firstPara = lines[0];
|
||||
const keywords = firstPara.match(/\b(restorative|collaborative|consensus|transformative|community|circle|mediation|third-party|written|verbal|facilitated|direct|multi-channel|needs|impact|harm|assessment|visual|phased|panel|independent|detailed|criteria|values|commitments|skills)\b/gi) || [];
|
||||
|
||||
if (keywords.length > 0) {
|
||||
const keywordTitle = keywords[0].charAt(0).toUpperCase() + keywords[0].slice(1).toLowerCase();
|
||||
return `${keywordTitle} ${fieldName || componentName}`;
|
||||
}
|
||||
|
||||
// Check for approach/model/process keywords
|
||||
const approachMatch = content.match(/\b(approach|model|process|method|system|framework|practice)\b/i);
|
||||
if (approachMatch) {
|
||||
// Get adjectives before the approach word
|
||||
const contentBefore = content.substring(0, approachMatch.index).trim();
|
||||
const lastWords = contentBefore.split(/\s+/).slice(-2);
|
||||
if (lastWords.length > 0 && lastWords[0].length > 3) {
|
||||
const adjective = lastWords.join(' ');
|
||||
return `${adjective.charAt(0).toUpperCase() + adjective.slice(1)} ${approachMatch[0]}`;
|
||||
}
|
||||
}
|
||||
|
||||
return `${componentName} ${fieldName}`.trim();
|
||||
}
|
||||
|
||||
// Analyze content structure
|
||||
const firstSentence = content.split(/[.!?:]\s+/)[0].trim().replace(/^[^a-zA-Z0-9]*/, '');
|
||||
const lines = content.split('\n').map(l => l.trim()).filter(l => l);
|
||||
const hasNumberedList = lines.some(line => line.match(/^[0-9]\.\s+/));
|
||||
|
||||
// Strategy 1: Look for purpose statements (often after "Our", "The", etc.)
|
||||
const purposeMatch = content.match(/\b(Our|The|This|A)\s+([^.!?:]+)(is|uses|follows|provides|ensures|helps)\s+/i);
|
||||
if (purposeMatch) {
|
||||
const purpose = purposeMatch[2].trim();
|
||||
if (purpose.length > 5 && purpose.length < 40) {
|
||||
moduleTitle = purpose.charAt(0).toUpperCase() + purpose.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 2: Check for clear format identifiers in first line
|
||||
if (!moduleTitle && lines.length > 0) {
|
||||
const firstLine = lines[0];
|
||||
if (firstLine.includes('approach') ||
|
||||
firstLine.includes('model') ||
|
||||
firstLine.includes('process') ||
|
||||
firstLine.includes('system')) {
|
||||
moduleTitle = firstLine;
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 3: Title with colon format
|
||||
if (!moduleTitle && firstSentence.includes(':')) {
|
||||
const beforeColon = firstSentence.split(':')[0].trim();
|
||||
if (beforeColon.length > 5 && beforeColon.length < 40) {
|
||||
moduleTitle = beforeColon.replace(/^(The|Our|This)\s+/i, '');
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 4: Numbered list with key concept
|
||||
if (!moduleTitle && hasNumberedList) {
|
||||
// Get the first numbered point - often a good summary
|
||||
for (let i = 0; i < lines.length && i < 5; i++) {
|
||||
const line = lines[i];
|
||||
if (line.match(/^[0-9]\.\s+/)) {
|
||||
let pointText = line.replace(/^[0-9]\.\s+/, '');
|
||||
|
||||
// Extract core concept (first 3-5 words)
|
||||
const words = pointText.split(/\s+/);
|
||||
if (words.length > 2) {
|
||||
pointText = words.slice(0, Math.min(5, words.length)).join(' ');
|
||||
}
|
||||
|
||||
if (pointText.length > 5 && pointText.length < 40) {
|
||||
moduleTitle = pointText;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 5: Extract key theme based on field purpose
|
||||
if (!moduleTitle) {
|
||||
// Use component and field context to generate meaningful title
|
||||
moduleTitle = getComponentBasedTitle();
|
||||
}
|
||||
|
||||
// Cleanup and formatting
|
||||
// Remove stopwords from beginning
|
||||
moduleTitle = moduleTitle.replace(/^(The|Our|This|An|A)\s+/i, '');
|
||||
|
||||
// Capitalize first letter
|
||||
moduleTitle = moduleTitle.charAt(0).toUpperCase() + moduleTitle.slice(1);
|
||||
|
||||
// Ensure reasonable length
|
||||
if (moduleTitle.length > 40) {
|
||||
const words = moduleTitle.split(/\s+/);
|
||||
moduleTitle = words.slice(0, 4).join(' ');
|
||||
}
|
||||
|
||||
// Remove any duplicate words
|
||||
const words = moduleTitle.split(/\s+/);
|
||||
const uniqueWords = [];
|
||||
for (const word of words) {
|
||||
if (!uniqueWords.includes(word)) {
|
||||
uniqueWords.push(word);
|
||||
}
|
||||
}
|
||||
moduleTitle = uniqueWords.join(' ');
|
||||
|
||||
// If all else fails, create a descriptive title based on component and content
|
||||
if (moduleTitle.length < 5) {
|
||||
const componentKey = componentId.split('_')[0];
|
||||
const componentName = componentKey.charAt(0).toUpperCase() + componentKey.slice(1);
|
||||
|
||||
// Find a distinctive word from content
|
||||
const contentWords = content.split(/\s+/)
|
||||
.filter(word =>
|
||||
word.length > 4 &&
|
||||
!['process', 'option', 'through', 'their', 'these', 'those', 'about', 'which', 'would', 'could', 'should'].includes(word.toLowerCase())
|
||||
);
|
||||
|
||||
const distinctiveWord = contentWords[0] || 'Standard';
|
||||
moduleTitle = distinctiveWord.charAt(0).toUpperCase() + distinctiveWord.slice(1) + " " + componentName;
|
||||
}
|
||||
|
||||
// Create new custom module with concise title
|
||||
modules[categoryKey].push({
|
||||
id: customId,
|
||||
title: moduleTitle,
|
||||
componentId: componentId,
|
||||
fieldId: fieldId,
|
||||
content: content
|
||||
});
|
||||
}
|
||||
|
||||
result.moduleRefs[stageId][componentId][fieldId] = customId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Export the mapper functions
|
||||
const templateMapper = {
|
||||
findBestMatchingModule,
|
||||
convertTemplateToModules
|
||||
};
|
||||
|
||||
// Make sure it's available globally
|
||||
window.templateMapper = templateMapper;
|
905
static/js/data/templates.js
Normal file
905
static/js/data/templates.js
Normal file
@ -0,0 +1,905 @@
|
||||
// Protocol templates
|
||||
// This file contains the raw template data
|
||||
// The builder.js code will convert these to use module references
|
||||
|
||||
const rawProtocolTemplates = [
|
||||
{
|
||||
id: "restorative-justice",
|
||||
title: "Restorative Justice",
|
||||
description: "A collaborative process that focuses on healing relationships and repairing harm rather than punitive measures",
|
||||
data: {
|
||||
stages: {
|
||||
intake: {
|
||||
process_start: {
|
||||
processStartText: "The restorative justice process begins when anyone in the community submits a request form indicating harm that needs to be addressed. This form asks for a brief description of what happened, who was involved, and what the person hopes might come from the process. A restorative justice coordinator acknowledges receipt within 24 hours and begins initial conversations with the person who submitted the request."
|
||||
},
|
||||
rules_access: {
|
||||
rulesAccessText: "Our community principles and restorative process guidelines are publicly available in multiple formats: a printed handbook in common spaces, an accessible online document, and visual displays in community gathering areas. New members receive an orientation to these principles when they join the community."
|
||||
},
|
||||
information_access: {
|
||||
informationAccessText: "Information about specific restorative processes is shared only with those directly involved. Statistical information about types of harm addressed (without identifying details) is shared annually to help the community learn and grow. The circle keeper maintains confidential records that are accessible only to them and the participants in each case."
|
||||
},
|
||||
participant_inclusion: {
|
||||
participantInclusionText: "Other participants are brought into the process through thoughtful invitation rather than formal notification. The restorative coordinator reaches out personally to each identified participant, explains the process, answers questions, and extends an invitation to participate. They emphasize that the goal is healing rather than blame."
|
||||
},
|
||||
participation_requirement: {
|
||||
participationRequirementText: "Participation in restorative justice processes is entirely voluntary. We believe that genuine healing and transformation can only come from willing engagement. If someone chooses not to participate, we respect that decision and explore other paths forward with the person who initiated the request."
|
||||
},
|
||||
participation_commitments: {
|
||||
participationCommitmentsText: "Participants in restorative processes commit to: 1) Speaking honestly from their own experience, 2) Listening deeply to others without interruption, 3) Maintaining confidentiality about what is shared, 4) Working toward understanding before solutions, 5) Following through on agreements they make, and 6) Engaging with respect and care for themselves and others throughout the process."
|
||||
}
|
||||
},
|
||||
process: {
|
||||
preparation: {
|
||||
preparationText: "Before any circle gathering, the circle keeper meets individually with each participant to build relationship, explain the process in detail, answer questions, address concerns, and help the person prepare what they might want to share. These preparation meetings help establish trust and safety for the full circle process."
|
||||
},
|
||||
place: {
|
||||
placeText: "Restorative circles take place in a neutral, comfortable space with natural light and privacy. Chairs are arranged in a perfect circle with no tables or barriers. A centerpiece with meaningful objects (plants, stones, candles, etc.) creates a focal point. The space is prepared thoughtfully to create a sense of safety and importance."
|
||||
},
|
||||
facilitation: {
|
||||
facilitationText: "The dispute process uses a restorative circle approach:\n\n1. A trained circle keeper facilitates but does not control the process\n2. All participants sit in a circle with no tables or barriers between them\n3. A talking piece is passed around the circle to ensure each person can speak without interruption\n4. Multiple rounds allow for deepening the conversation and moving toward resolution\n5. The circle process follows indigenous wisdom traditions adapted for contemporary contexts\n6. The circle keeper prepares participants individually before the full circle gathering"
|
||||
},
|
||||
communication: {
|
||||
communicationText: "Communication in restorative circles follows these guidelines: 1) Speak from the heart about your own experience, 2) Listen from the heart without planning your response, 3) Speak with respect and without blame, 4) Share what's true for you in the moment, 5) Be mindful of time so everyone can share, 6) Honor the talking piece - only the person holding it may speak, 7) Respect the confidentiality of what is shared."
|
||||
},
|
||||
participation: {
|
||||
participationText: "A restorative circle typically includes: 1) The person who experienced harm, 2) The person who caused harm, 3) Community members or loved ones who support each primary participant, 4) Community members affected by the situation, and 5) The circle keeper. Everyone participates as an equal in the circle, though the needs of those most affected guide the process."
|
||||
},
|
||||
documentation: {
|
||||
documentationText: "The circle keeper takes minimal notes during the process to maintain presence. The agreements reached are documented clearly in a format agreed upon by all participants. These written agreements are shared only with participants and include specific actions, timelines, and follow-up plans."
|
||||
}
|
||||
},
|
||||
assessment: {
|
||||
situation: {
|
||||
situationText: "The situation is assessed through a harm and needs framework:\n\n1. Each participant describes what happened from their perspective\n2. Participants identify how they have been affected or harmed\n3. Underlying needs that weren't met are identified\n4. The impact on relationships and the wider community is explored\n5. The assessment focuses on understanding rather than blame\n6. This approach creates a foundation for addressing specific harms"
|
||||
},
|
||||
stage_of_conflict: {
|
||||
stageOfConflictText: "The circle keeper assesses the readiness of all parties for a restorative process. They consider: 1) Whether those who caused harm acknowledge their responsibility, 2) The emotional state and safety needs of those who experienced harm, 3) The willingness of all parties to work toward repair, and 4) Any power dynamics that might affect the process. This assessment helps determine timing and structure."
|
||||
},
|
||||
needs: {
|
||||
needsText: "During preparation and circle meetings, participants identify their underlying needs related to the situation. These might include needs for safety, acknowledgment, understanding, accountability, belonging, repair, or healing. The circle process helps surface these needs and explore how they might be met through the restorative process."
|
||||
},
|
||||
evidence: {
|
||||
evidenceText: "Restorative processes focus more on impact and experience than evidence in a traditional sense. Participants share their direct experiences and how they were affected. When factual disagreements arise, the circle keeper helps the group find shared understanding without determining absolute truth. The focus remains on healing rather than proof."
|
||||
},
|
||||
jurisdiction: {
|
||||
jurisdictionText: "Our restorative justice process is appropriate for most interpersonal harms and conflicts within our community. For situations involving ongoing safety risks, legal violations that require reporting, or when participants are unwilling to acknowledge basic responsibility for harm, the process may be adapted or alternative resources recommended."
|
||||
}
|
||||
},
|
||||
deliberation: {
|
||||
information_gathering: {
|
||||
informationGatheringText: "Information emerges organically through circle sharing. The process begins with establishing relationships and context before directly addressing the harm. Multiple rounds of the talking piece allow deeper layers of the situation to surface. As understanding develops, the circle considers what needs to happen to make things right."
|
||||
},
|
||||
brainstorming: {
|
||||
brainstormingText: "Once the impact of the situation is well understood, the circle moves into generating ideas for repair and moving forward. Everyone contributes possibilities without immediate evaluation. The keeper encourages creative thinking that addresses the specific harms and needs identified earlier in the process."
|
||||
},
|
||||
discussion: {
|
||||
discussionText: "The circle discusses potential solutions through a structured process: 1) Each idea is considered in terms of how it addresses identified harms and needs, 2) Those most affected by the situation speak to what would help them move forward, 3) The group refines ideas based on what's practical and meaningful, 4) The keeper helps the group move toward consensus on actions for repair and healing."
|
||||
},
|
||||
deliberation_format: {
|
||||
deliberationFormatText: "Deliberation happens within the circle format, guided by a series of thoughtful questions from the keeper. The talking piece continues to structure the conversation. The process may include multiple circle sessions with time for reflection between meetings. Deliberation concludes when the group reaches shared agreements about how to move forward."
|
||||
}
|
||||
},
|
||||
resolution: {
|
||||
decision_making: {
|
||||
decisionMakingText: "Decisions in restorative processes are made by consensus of all participants. The circle keeper helps test potential agreements to ensure everyone can support them. If perfect agreement isn't possible, the keeper helps craft a solution that addresses core needs while respecting individual boundaries about what people are willing to do."
|
||||
},
|
||||
outcomes: {
|
||||
outcomesText: "Restorative outcomes typically include: 1) Acknowledgment of the harm that occurred, 2) Specific actions to repair damage or address impacts, 3) Commitments to changed behavior in the future, 4) Healing rituals or symbolic acts, 5) Plans for rebuilding trust and relationships over time, and 6) Community support mechanisms to help implement agreements."
|
||||
},
|
||||
agreement: {
|
||||
agreementText: "All resolutions result in a collaborative responsibility plan:\n\n1. The plan details specific actions to repair harm\n2. Each participant has clear responsibilities for making things right\n3. The plan includes timeline commitments for implementation\n4. Support mechanisms are built in to help participants fulfill their commitments\n5. The plan may include ongoing relationship-building activities\n6. All participants sign the agreement and receive a copy\n7. The agreement focuses on healing and moving forward rather than punishment"
|
||||
},
|
||||
follow_up: {
|
||||
followUpText: "The circle keeper schedules a follow-up circle 3-4 weeks after agreements are made to check on progress, celebrate steps taken, and address any challenges. Additional follow-up may happen at 3 months and 6 months depending on the situation. These follow-ups provide accountability and ongoing support for the healing process."
|
||||
},
|
||||
announcement: {
|
||||
announcementText: "The outcomes of restorative processes remain confidential to the participants unless they specifically agree to share information with the broader community. When information is shared, it focuses on lessons learned and community needs rather than personal details."
|
||||
}
|
||||
},
|
||||
appeal: {
|
||||
criteria: {
|
||||
criteriaText: "Restorative processes can be reopened if: 1) Agreements aren't being fulfilled despite good faith efforts, 2) New information emerges that significantly changes understanding of the situation, 3) Additional harms occur related to the original situation, or 4) The process was completed but healing remains incomplete."
|
||||
},
|
||||
appeal_process: {
|
||||
appealProcessText: "To revisit a completed process, any participant can contact the circle keeper to request a follow-up circle. The keeper reaches out to all original participants to check willingness to reconvene. If everyone agrees, a new circle is scheduled focusing specifically on the issues that need further attention."
|
||||
},
|
||||
appeal_deliberation: {
|
||||
appealDeliberationText: "The reconvened circle follows the same structured format as the original process but with focused attention on the specific concerns that led to reopening the case. The circle acknowledges progress already made while addressing outstanding issues or new insights."
|
||||
},
|
||||
appeal_resolution: {
|
||||
appealResolutionText: "The follow-up circle develops revised or additional agreements addressing the newly identified needs. These amendments are added to the original agreement with clear timelines for implementation and additional follow-up as needed."
|
||||
}
|
||||
},
|
||||
delegation: {
|
||||
criteria: {
|
||||
criteriaText: "The restorative process may be inappropriate when: 1) There are immediate safety concerns that need addressing first, 2) One or more key participants are unwilling to engage, 3) The harm involves legal violations requiring formal intervention, 4) The situation involves complex systems beyond interpersonal harm, or 5) Previous restorative attempts have not led to meaningful change."
|
||||
},
|
||||
delegation_process: {
|
||||
delegationProcessText: "If restorative justice isn't the right fit, the circle keeper works with participants to identify more appropriate resources. They provide warm referrals to other services like mediation, therapy, organizational change processes, or when necessary, formal authorities. The transition includes clear communication about why delegation is recommended."
|
||||
},
|
||||
delegation_authority: {
|
||||
delegationAuthorityText: "Our community maintains relationships with professional mediators, conflict coaches, mental health providers, social workers, and when needed, legal professionals. We have established referral protocols with each of these resources and provide financial assistance when cost would be a barrier to accessing needed support."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "transformative-justice",
|
||||
title: "Transformative Justice",
|
||||
description: "A process that addresses immediate harm while working to transform the conditions that allowed harm to occur",
|
||||
data: {
|
||||
stages: {
|
||||
intake: {
|
||||
process_start: {
|
||||
processStartText: "The transformative justice process begins when a community member reaches out to the transformative justice collective with a concern about harm. This initial contact can be through a secure online form, a phone line, or direct conversation with a collective member. Within 48 hours, two collective members are assigned to do an initial assessment and begin conversations with the person who raised the concern."
|
||||
},
|
||||
rules_access: {
|
||||
rulesAccessText: "Our community agreements, values, and transformative justice framework are documented in accessible formats including a community handbook (print and digital), visual materials, audio resources, and multilingual versions. These resources clearly distinguish between aspirational values and concrete practices. All members participate in regular workshops to review and update these materials."
|
||||
},
|
||||
information_access: {
|
||||
informationAccessText: "Information is shared based on a consent-based model. Those directly involved determine what information is shared beyond the immediate process. The transformative justice collective maintains secure records that include agreements made and lessons learned, but not sensitive personal details. Pattern-level information about types of harm addressed informs community education while protecting confidentiality."
|
||||
},
|
||||
participant_inclusion: {
|
||||
participantInclusionText: "People are brought into the process through intentional outreach by the facilitators, who explain the transformative approach and how it differs from punitive models. Key stakeholders include those directly harmed, those who caused harm, support people for both parties, and community members affected by or contributing to the situation. Each person receives individual preparation before group sessions."
|
||||
},
|
||||
participation_requirement: {
|
||||
participationRequirementText: "Participation is voluntary but strongly encouraged as part of our community commitments. We recognize that meaningful accountability cannot be forced. However, if someone chooses not to participate directly, the process may continue with those who are willing, focusing on community support for those harmed and addressing systemic factors that contributed to the harm."
|
||||
},
|
||||
participation_commitments: {
|
||||
participationCommitmentsText: "Participants commit to: 1) Engaging honestly in examining harm and its impacts, 2) Considering both individual and collective dimensions of accountability, 3) Respecting confidentiality boundaries established by the group, 4) Working to understand systemic factors beyond individual actions, 5) Contributing to implementation of agreements, and 6) Participating in follow-up and ongoing learning."
|
||||
}
|
||||
},
|
||||
prepare: {
|
||||
principles: {
|
||||
principlesText: "Our dispute resolution process is guided by these transformative justice principles:\n\n1. Address immediate harm between individuals\n2. Connect individual instances of harm to broader social patterns\n3. Transform the conditions that allowed harm to occur\n4. Build community accountability systems without relying on punitive measures\n5. Center the needs of those most impacted while inviting those who caused harm into accountability\n6. Develop collective strategies for healing, resilience, and safety\n7. Work toward long-term cultural and structural change"
|
||||
},
|
||||
values: {
|
||||
valuesText: "Our transformative justice work is rooted in these core values: 1) Liberation - working toward freedom from all forms of oppression, 2) Accountability without punishment, 3) Collective responsibility for community well-being, 4) Radical honesty about impacts and conditions, 5) Compassion for all involved, including those who have caused harm, 6) Faith in people's capacity to transform, 7) Commitment to sustainable, long-term change."
|
||||
},
|
||||
agreements: {
|
||||
agreementsText: "Participants in the transformative justice process agree to: 1) Approach the process with a willingness to examine personal and collective relationships to systems of power, 2) Listen to understand rather than defend, 3) Be open to feedback about impact regardless of intent, 4) Recognize that transformative work takes time and commitment, 5) Balance accountability with care for self and others."
|
||||
}
|
||||
},
|
||||
process: {
|
||||
preparation: {
|
||||
preparationText: "Preparation includes multiple one-on-one conversations with each participant before any group sessions. During these meetings, facilitators build relationship, explain the process, address concerns, provide educational resources about transformative justice, and help participants identify their needs and capacities. Support people are oriented to their role in the process."
|
||||
},
|
||||
place: {
|
||||
placeText: "Meetings take place in spaces that feel safe, accessible, and comfortable for all participants. The environment is checked for potential triggers or barriers. Sessions may move between private and community spaces depending on the phase of work. Sometimes neutral territory outside the community is used to provide perspective."
|
||||
},
|
||||
facilitation: {
|
||||
facilitationText: "The dispute process uses a community accountability approach:\n\n1. A facilitation team of 2-3 trained community members guides the process\n2. Both the person harmed and the person who caused harm have support teams\n3. The wider community is represented by stakeholders affected by the issues\n4. The process begins with individual preparation sessions before group meetings\n5. Facilitation focuses on transforming harmful patterns, not just individual incidents\n6. Multiple sessions allow for deep exploration of systemic factors\n7. The process builds community capacity to address similar issues in the future"
|
||||
},
|
||||
communication: {
|
||||
communicationText: "Communication follows these agreements: 1) Speak from personal experience using 'I' statements, 2) Acknowledge the difference between intent and impact, 3) Use language that recognizes both individual and systemic dimensions, 4) Name patterns and power dynamics when relevant, 5) Practice active listening, 6) Honor silence and processing time, 7) Express needs directly rather than through criticism."
|
||||
},
|
||||
participation: {
|
||||
participationText: "The process includes a constellation of participants depending on the situation: 1) Core participants directly involved in the harm, 2) Support people chosen by core participants, 3) Facilitators from the transformative justice collective, 4) Community stakeholders who represent affected groups or have relevant expertise, 5) Witnesses who help document and hold the process. Each participant has a specific role with clear responsibilities."
|
||||
},
|
||||
documentation: {
|
||||
documentationText: "Documentation includes: 1) Meeting summaries shared with all participants, 2) Agreements and action plans with assigned responsibilities, 3) Feedback collected after each major session, 4) Analysis of structural and cultural factors identified, 5) Resources shared during the process. Personal information is documented only as necessary and with consent."
|
||||
}
|
||||
},
|
||||
assessment: {
|
||||
situation: {
|
||||
situationText: "The situation is assessed through a systemic analysis framework:\n\n1. Individual experiences and harms are documented\n2. Patterns of behavior and power dynamics are identified\n3. Structural factors that contributed to the harm are analyzed\n4. Community norms and cultural assumptions are examined\n5. The assessment connects individual incidents to broader social contexts\n6. This approach identifies intervention points at multiple levels, from individual to systemic"
|
||||
},
|
||||
stage_of_conflict: {
|
||||
stageOfConflictText: "The facilitation team assesses: 1) The history and timeline of the harm, 2) Whether this is an isolated incident or part of a pattern, 3) The presence of immediate safety concerns, 4) The current capacity of all involved to engage in the process, 5) Community readiness to address potential systemic changes, and 6) Power dynamics that might impact the process."
|
||||
},
|
||||
needs: {
|
||||
needsText: "The assessment identifies needs at multiple levels: 1) Immediate needs for safety, support, and stabilization, 2) Individual healing needs for those directly impacted, 3) Accountability needs to address the harm, 4) Community needs for understanding and prevention, 5) Systemic needs for policy or cultural change, and 6) Learning needs to build capacity for addressing similar situations."
|
||||
},
|
||||
evidence: {
|
||||
evidenceText: "Information is gathered through multiple perspectives rather than a singular evidence-based approach. This includes: 1) First-person accounts of experiences, 2) Documentation of impacts, 3) Contextual information about the environment in which harm occurred, 4) Historical patterns within the community, 5) Analysis of how power operates in the situation, and 6) Relevant community agreements or expectations."
|
||||
},
|
||||
jurisdiction: {
|
||||
jurisdictionText: "Transformative justice processes are most appropriate for situations where: 1) The harm is connected to broader social patterns, 2) Community-based intervention is possible and desired, 3) There is willingness to address both immediate harm and root causes, and 4) Public systems (legal, etc.) would likely cause additional harm. The process may be adapted based on safety needs and legal requirements."
|
||||
}
|
||||
},
|
||||
deliberation: {
|
||||
information_gathering: {
|
||||
informationGatheringText: "Information is gathered through a trauma-informed approach that centers those most impacted. Multiple sessions allow time for reflection and integration. The facilitation team helps contextualize individual experiences within systemic patterns, gathering information about both the specific harm and the conditions that enabled it."
|
||||
},
|
||||
brainstorming: {
|
||||
brainstormingText: "Solution-building happens through structured brainstorming processes that include: 1) Small group work to generate ideas addressing different levels of change, 2) Research into approaches used by other communities, 3) Consultation with relevant experts or elders, 4) Creative visioning exercises that imagine new possibilities, and 5) Reality testing of proposals against available resources and capacities."
|
||||
},
|
||||
discussion: {
|
||||
discussionText: "Facilitated discussions focus on building shared understanding of how change can happen at multiple levels. Participants examine proposed solutions in terms of how they address immediate needs, build accountability, heal relationships, transform conditions, and prevent future harm. Special attention is paid to sustainability and community capacity."
|
||||
},
|
||||
deliberation_format: {
|
||||
deliberationFormatText: "The deliberation process includes multiple formats: 1) Structured dialogue sessions with all participants, 2) Caucus meetings with specific stakeholder groups, 3) One-on-one conversations for sensitive topics, 4) Community forums for systemic issues, and 5) Reflection periods between sessions. The process typically unfolds over 2-3 months, adapting to the specific situation."
|
||||
}
|
||||
},
|
||||
resolution: {
|
||||
decision_making: {
|
||||
decisionMakingText: "Decisions are made through a consensus process that prioritizes the needs of those most impacted while engaging everyone in finding solutions. The facilitation team helps test proposals against transformative justice principles. When full consensus isn't possible, the group identifies which elements have universal support and which need further development."
|
||||
},
|
||||
outcomes: {
|
||||
outcomesText: "Outcomes address multiple dimensions: 1) Survivor-centered responses to address immediate harm, 2) Accountability processes for those who caused harm, 3) Community support mechanisms to enable healing and accountability, 4) Education initiatives to build awareness, 5) Policy or structural changes to transform conditions, and 6) Community capacity-building to sustain changes over time."
|
||||
},
|
||||
agreement: {
|
||||
agreementText: "All resolutions result in a multi-level transformative action plan:\n\n1. Individual actions to address immediate harm and accountability\n2. Relationship-building commitments between affected parties\n3. Community-level interventions to address cultural factors\n4. Structural changes to prevent similar harms in the future\n5. Education and awareness components to share learning\n6. The plan includes both short-term and long-term actions\n7. Regular review points are scheduled to assess progress and adjust strategies"
|
||||
},
|
||||
follow_up: {
|
||||
followUpText: "Follow-up includes: 1) Regular check-ins on agreement implementation, 2) Support for those taking on accountability, 3) Ongoing resources for those who were harmed, 4) Community updates on systemic changes, 5) Periodic reassessment of whether the approach is effective, and 6) Documentation of lessons learned to inform future processes."
|
||||
},
|
||||
announcement: {
|
||||
announcementText: "Communication about outcomes follows consent-based protocols established during the process. Typically, information is shared at different levels: 1) Detailed information with direct participants, 2) General progress reports with the broader community, 3) Pattern-level insights for community education, and 4) Specific policy or structural changes implemented as a result of the process."
|
||||
}
|
||||
},
|
||||
appeal: {
|
||||
criteria: {
|
||||
criteriaText: "The process can be revisited if: 1) Agreements aren't being implemented as planned, 2) Implementation reveals unforeseen challenges, 3) New information emerges about the situation, 4) The harm continues or recurs, 5) Systemic changes aren't effectively addressing root causes, or 6) Additional affected parties come forward."
|
||||
},
|
||||
appeal_process: {
|
||||
appealProcessText: "Any participant can request reassessment by contacting the transformative justice collective. Two members review the request and consult with key stakeholders to determine next steps. This may lead to reconvening the original group, forming a new group, or taking targeted action on specific unaddressed issues."
|
||||
},
|
||||
appeal_deliberation: {
|
||||
appealDeliberationText: "Reassessment follows a structured format: 1) Review of original agreements and implementation status, 2) Identification of gaps or new issues, 3) Analysis of why certain aspects haven't been effective, 4) Development of refined or additional responses, with emphasis on systematic factors that may have been overlooked."
|
||||
},
|
||||
appeal_resolution: {
|
||||
appealResolutionText: "The renewed process produces an updated action plan that builds on previous work while addressing newly identified needs. This updated plan includes specific metrics for success and may assign new roles or resources to overcome previous implementation barriers."
|
||||
}
|
||||
},
|
||||
delegation: {
|
||||
criteria: {
|
||||
criteriaText: "Delegation to other resources may be appropriate when: 1) Immediate safety requires formal intervention, 2) The situation involves legal requirements beyond community capacity, 3) Specialized expertise is needed, 4) The community lacks resources to address the scale of harm, or 5) The transformative justice approach has been attempted without success."
|
||||
},
|
||||
delegation_process: {
|
||||
delegationProcessText: "When delegation is needed, the facilitation team: 1) Clearly explains why additional resources are recommended, 2) Helps participants understand options and potential impacts, 3) Supports access to appropriate services, 4) Continues to provide community support even when formal systems are involved, and 5) Documents learnings to strengthen future community capacity."
|
||||
},
|
||||
delegation_authority: {
|
||||
delegationAuthorityText: "Our community maintains relationships with a network of resources including: 1) Specialized transformative justice practitioners for complex cases, 2) Mental health providers with trauma expertise, 3) Legal advocates who understand transformative approaches, 4) Cultural workers who can support healing processes, and 5) Organizations working on systemic change in relevant areas."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "jury-protocol",
|
||||
title: "Community Jury",
|
||||
description: "A process where a randomly selected jury of community members hears evidence and makes decisions on disputes",
|
||||
data: {
|
||||
stages: {
|
||||
intake: {
|
||||
process_start: {
|
||||
processStartText: "The community jury process begins when a community member submits a case request form. This form requires a description of the dispute, parties involved, attempts at resolution so far, and desired outcome. The Jury Administrator reviews all submissions within 3 business days to determine if the case meets basic criteria for the jury process. If accepted, the case is assigned a number and scheduled for an initial hearing date."
|
||||
},
|
||||
rules_access: {
|
||||
rulesAccessText: "Community standards and jury procedures are publicly available through multiple channels: 1) A comprehensive online handbook with searchable content, 2) Print copies in the community center, 3) Audio recordings for accessibility, and 4) Regular community education sessions. New residents receive an orientation to these standards during their welcome process. The Jury Administrator is available to answer questions about procedures."
|
||||
},
|
||||
information_access: {
|
||||
informationAccessText: "Information about specific cases follows tiered access protocols: 1) Case parties receive all documentation relevant to their case, 2) Jury members receive case materials with sensitive personal information redacted, 3) The wider community receives notification of cases accepted and decisions made without identifying details, 4) Case summaries with key learnings are published annually for community education. Records are maintained securely by the Jury Administrator."
|
||||
},
|
||||
participant_inclusion: {
|
||||
participantInclusionText: "When a case is accepted, all named parties receive formal notification through both email and paper letter. This notification includes the initial claim, information about the jury process, their rights and responsibilities, important dates, and a response form to be returned within 10 days. The Jury Administrator follows up by phone if no response is received within 5 days."
|
||||
},
|
||||
participation_requirement: {
|
||||
participationRequirementText: "For community members, participation in the jury process is required as specified in the community agreement signed upon joining. For non-members or external entities, participation is voluntary. If a respondent declines to participate, the jury may still hear the case and reach a decision based on available information, but will note the limited nature of the proceedings."
|
||||
},
|
||||
participation_commitments: {
|
||||
participationCommitmentsText: "All participants in the jury process commit to: 1) Providing truthful information and evidence, 2) Adhering to scheduled deadlines and hearing dates, 3) Treating all participants with respect regardless of disagreements, 4) Preparing materials as requested by the jury, 5) Accepting the jury's decision as binding within community governance, and 6) Implementing agreed-upon actions or decisions within specified timeframes."
|
||||
}
|
||||
},
|
||||
prepare: {
|
||||
principles: {
|
||||
principlesText: "Our dispute resolution process is guided by these community jury principles:\n\n1. Fair representation through random selection of community members\n2. Impartiality through screening for conflicts of interest\n3. Informed deliberation based on evidence and testimony\n4. Collective wisdom through diverse perspectives\n5. Transparency in process while maintaining appropriate confidentiality\n6. Community standards as the basis for decision-making\n7. Balance between structure and flexibility to ensure fairness"
|
||||
},
|
||||
values: {
|
||||
valuesText: "Our community jury system is grounded in these core values: 1) Procedural fairness - ensuring consistent, transparent processes, 2) Collective wisdom - trusting in the reasoned judgment of peers, 3) Community ownership - placing decision-making authority within the community, 4) Balanced perspective - bringing diverse viewpoints to each case, 5) Reasoned judgment - basing decisions on evidence and community standards, and 6) Restorative outcomes - seeking decisions that repair harm and rebuild relationships."
|
||||
},
|
||||
agreements: {
|
||||
agreementsText: "All participants in the jury process agree to: 1) Accept the authority of the randomly selected jury to make decisions, 2) Present information honestly and completely, 3) Respect the confidentiality of sensitive information shared during the process, 4) Abide by the procedural rules established for hearings and deliberations, 5) Implement jury decisions in good faith, and 6) Use the appeals process rather than undermining decisions publicly."
|
||||
}
|
||||
},
|
||||
process: {
|
||||
preparation: {
|
||||
preparationText: "Case preparation includes several key steps: 1) The Jury Administrator creates a case file containing all initial submissions, 2) Both parties receive a preparation packet with instructions for submitting evidence and witness statements, 3) Parties have 14 days to submit all materials, which are then organized and distributed to jury members, 4) Jurors review all materials individually before the hearing, 5) Pre-hearing conferences address procedural questions and establish time allocations, 6) The facilitator ensures all parties understand the process and their roles."
|
||||
},
|
||||
place: {
|
||||
placeText: "Jury hearings take place in the community's designated hearing room, which features: 1) A formal arrangement with tables for parties and jury members, 2) Audio recording equipment to document proceedings, 3) Presentation technology for displaying evidence, 4) Good acoustics and appropriate lighting, 5) Accessibility features for all participants, and 6) A separate deliberation room for jury discussions. For sensitive cases, alternative venues can be arranged to ensure privacy and comfort for all participants."
|
||||
},
|
||||
facilitation: {
|
||||
facilitationText: "The dispute process is facilitated through a structured jury format:\n\n1. A trained process facilitator guides the proceedings but does not participate in decision-making\n2. The process follows clear phases: opening statements, evidence presentation, questions, deliberation, and decision\n3. All parties have equal time to present their perspectives and evidence\n4. Jurors may ask clarifying questions through the facilitator\n5. The facilitator ensures adherence to community standards and procedural fairness\n6. Deliberations are conducted by jurors alone, with the facilitator available for procedural questions"
|
||||
},
|
||||
communication: {
|
||||
communicationText: "Communication during jury proceedings follows formal protocols: 1) Opening and closing statements are uninterrupted and time-limited, 2) Evidence presentation follows a structured format with visual aids as needed, 3) Questions from jurors are submitted to the facilitator, who may rephrase for clarity, 4) Cross-examination is limited and focused on fact clarification rather than confrontation, 5) The facilitator moderates all exchanges to maintain respectful discourse, 6) Emotional expression is allowed but must remain appropriate to the setting."
|
||||
},
|
||||
participation: {
|
||||
participationText: "Jury proceedings involve the following participants: 1) The 5-7 community members selected as jurors, 2) The case parties (initiator and respondent), 3) A trained facilitator who guides the process, 4) Witnesses called by either party or the jury itself, 5) The Jury Administrator who manages logistics and record-keeping, and 6) Community observers who may attend open portions of the hearings. Each role has clear responsibilities and boundaries established in the process guidelines."
|
||||
},
|
||||
documentation: {
|
||||
documentationText: "Comprehensive documentation is maintained throughout the jury process: 1) Audio recordings of all open proceedings, 2) Written transcripts produced from these recordings, 3) A case file containing all submitted evidence and statements, 4) Jury deliberation worksheets (without attribution to specific jurors), 5) The final written decision with its rationale, and 6) Implementation and follow-up records. All documentation is maintained securely by the Jury Administrator for a minimum of five years."
|
||||
}
|
||||
},
|
||||
assessment: {
|
||||
situation: {
|
||||
situationText: "The jury assesses each case through a structured framework: 1) Establishing agreed-upon facts versus disputed elements, 2) Identifying relevant community standards or agreements that apply, 3) Evaluating the credibility and completeness of evidence presented, 4) Considering context and mitigating circumstances, 5) Assessing impacts on individuals and the community, and 6) Determining responsibility based on the preponderance of evidence. This assessment is documented as part of their deliberation process."
|
||||
},
|
||||
stage_of_conflict: {
|
||||
stageOfConflictText: "The jury considers the stage and history of the conflict, including: 1) Whether this is a first-time issue or recurring pattern, 2) Previous attempts at resolution and why they were unsuccessful, 3) Whether the situation is escalating or de-escalating, 4) The current relationship between the parties, 5) Potential impacts of various decision options on the conflict trajectory, and 6) How the timing of intervention might affect outcomes. This contextual understanding informs both their decision and implementation recommendations."
|
||||
},
|
||||
needs: {
|
||||
needsText: "The jury identifies the fundamental needs of all involved parties: 1) Each party's stated desired outcome, 2) Underlying needs for recognition, restoration, safety, or clarity, 3) Community needs for precedent, standard-setting, or harm prevention, 4) Practical needs related to resources, access, or accommodations, 5) Relationship needs between the parties and with the broader community, and 6) Systemic needs that might require policy changes beyond the specific case. This needs assessment guides the development of comprehensive solutions."
|
||||
},
|
||||
evidence: {
|
||||
evidenceText: "Evidence is evaluated through a structured process: 1) Written statements from all parties and witnesses, 2) Documentary evidence such as communications, records, or other relevant materials, 3) Visual evidence including photos, videos, or site documentation, 4) Community standards and agreements that establish expectations, 5) Expert testimony when specialized knowledge is required, and 6) Impact statements describing effects on involved parties. The jury weighs evidence based on relevance, credibility, and consistency rather than technical rules of admissibility."
|
||||
},
|
||||
jurisdiction: {
|
||||
jurisdictionText: "The community jury has jurisdiction over: 1) Disputes between community members regarding shared resources or spaces, 2) Alleged violations of community agreements or standards, 3) Conflicts affecting community function or wellbeing, 4) Requests for clarification of policies or practices, and 5) Appeals of decisions made by community committees. The jury does not have jurisdiction over legal matters requiring formal court proceedings, situations presenting immediate safety risks, or disputes that have been explicitly excluded in the community charter."
|
||||
}
|
||||
},
|
||||
deliberation: {
|
||||
information_gathering: {
|
||||
informationGatheringText: "Jury information gathering continues during deliberation: 1) Jurors identify information gaps that emerged during the hearing, 2) They may request clarification from parties through written questions, 3) They review all submitted evidence methodically, creating an evidence summary, 4) They consult community standards and precedents from previous similar cases, 5) If needed, they may request additional expert input on technical matters, and 6) They document key findings of fact that will form the basis for their decision."
|
||||
},
|
||||
brainstorming: {
|
||||
brainstormingText: "The jury uses a structured brainstorming process: 1) Individual jurors first write down potential solutions independently, 2) Each juror shares their ideas without criticism or evaluation, 3) Ideas are recorded visibly for all jurors to consider, 4) Building on initial ideas, jurors suggest modifications and combinations, 5) The full range of possibilities is organized into categories, and 6) The jury identifies underlying principles that might guide an effective resolution. This approach ensures all perspectives are considered before evaluation begins."
|
||||
},
|
||||
discussion: {
|
||||
discussionText: "Jury deliberation discussions follow a structured format: 1) The jury first clarifies the key questions that must be answered, 2) They review evidence related to each question, 3) Each juror shares their perspective on how the evidence answers these questions, 4) Areas of agreement and disagreement are explicitly identified, 5) For disagreements, jurors explore underlying reasoning and concerns, 6) The facilitator helps maintain focus and ensures all voices are heard, and 7) The jury works toward finding areas of consensus before moving to formal decision-making."
|
||||
},
|
||||
finding_solutions: {
|
||||
findingSolutionsText: "Solutions are developed through structured jury deliberation:\n\n1. Jurors first identify key issues requiring resolution\n2. Each juror shares their initial perspective without interruption\n3. The jury works to develop a shared understanding of the situation\n4. Multiple solution options are generated and evaluated\n5. Decisions require a supermajority (typically 2/3) agreement\n6. When consensus isn't possible on specific points, the jury may offer multiple options\n7. The jury documents their reasoning along with their final decision"
|
||||
},
|
||||
deliberation_format: {
|
||||
deliberationFormatText: "Jury deliberations follow a clear format: 1) Initial deliberations occur immediately following the hearing while information is fresh, 2) If needed, additional sessions are scheduled within 7 days, 3) A designated jury foreperson facilitates the discussion with assistance from the process facilitator as requested, 4) Deliberations are private, with only jury members present unless procedural assistance is needed, 5) Deliberations continue until a decision is reached or the maximum time (typically 10 hours total) has been used, 6) The jury takes structured breaks to prevent fatigue and allow reflection."
|
||||
}
|
||||
},
|
||||
resolution: {
|
||||
decision_making: {
|
||||
decisionMakingText: "Decisions are made through a structured jury voting process:\n\n1. After thorough deliberation, the jury votes on proposed resolutions\n2. A 2/3 majority is required for decisions to be adopted\n3. If the first vote doesn't reach the threshold, further discussion occurs\n4. Up to three voting rounds may take place to reach the required majority\n5. If consensus cannot be reached after three rounds, the most supported option with at least 60% support is adopted\n6. The jury provides written rationale for their decision based on community standards\n7. Jury decisions are binding within the scope of community governance"
|
||||
},
|
||||
outcomes: {
|
||||
outcomesText: "Jury decisions may include multiple outcome elements: 1) Determination of whether community standards were violated, 2) Specific actions required to address harm or restore conditions, 3) Clarification of rights and responsibilities going forward, 4) Resource allocations or adjustments to shared arrangements, 5) Monitoring provisions to ensure implementation, 6) Preventative measures to avoid similar issues, and 7) Recommendations for community policy or practice changes. Outcomes are designed to be specific, measurable, achievable, relevant, and time-bound."
|
||||
},
|
||||
agreement: {
|
||||
agreementText: "The jury decision is documented in a formal written determination that includes: 1) A summary of the case and key facts established, 2) The specific questions the jury was asked to resolve, 3) The jury's findings on each question with supporting rationale, 4) Specific actions required of each party with deadlines, 5) Consequences for non-compliance if applicable, 6) Monitoring and verification procedures, and 7) Signatures of all jury members. This document is provided to all parties and becomes part of community records."
|
||||
},
|
||||
follow_up: {
|
||||
followUpText: "Implementation of jury decisions is tracked through a structured follow-up process: 1) The Jury Administrator monitors compliance with required actions, 2) Parties submit documentation of completed items by established deadlines, 3) A 30-day check-in assesses initial progress, 4) A final implementation review occurs after all deadlines have passed, 5) The original jury foreperson is consulted if clarification is needed, and 6) Successful implementation is documented and the case is formally closed. If implementation issues arise, the Administrator may reconvene the jury or initiate the non-compliance process."
|
||||
},
|
||||
announcement: {
|
||||
announcementText: "Jury decisions are announced according to established protocols: 1) Parties receive the full written determination within 3 days of the decision, 2) A brief announcement that a decision has been reached is posted to community channels, 3) A redacted version removing sensitive information may be shared if the case involves community-wide issues, 4) Any policy implications or precedents are highlighted for community governance, 5) The jury may recommend specific educational communications if the case reveals common misunderstandings of community standards."
|
||||
}
|
||||
},
|
||||
appeal: {
|
||||
criteria: {
|
||||
criteriaText: "Appeals of jury decisions may be filed based on specific criteria: 1) Significant new evidence that wasn't available during the original hearing, 2) Procedural errors that materially affected the outcome, 3) Clear misapplication of community standards by the jury, 4) Jury bias or misconduct that affected the decision, or 5) Implementation difficulties that make the decision unworkable. Appeals must be filed within 14 days of the decision and must specifically identify which criteria apply."
|
||||
},
|
||||
appeal_process: {
|
||||
appealProcessText: "The appeal process follows these steps: 1) The appellant submits a written appeal stating the grounds and desired outcome, 2) The Appeal Committee (three community members not involved in the original case) reviews the appeal to determine if it meets criteria, 3) If accepted, a new jury is selected, larger than the original, 4) The new jury reviews all original materials plus the appeal documentation, 5) A limited appeal hearing is held focusing only on the specific grounds for appeal, 6) The appeal jury deliberates and issues a new decision that either confirms, modifies, or overturns the original decision."
|
||||
},
|
||||
appeal_deliberation: {
|
||||
appealDeliberationText: "Appeal deliberations focus specifically on the grounds presented: 1) For new evidence appeals, the jury assesses whether the evidence is truly new and would likely have changed the outcome, 2) For procedural error appeals, they determine if errors occurred and materially affected the result, 3) For misapplication of standards, they review the standards and their application, 4) For bias claims, they examine the conduct and decision patterns, 5) For implementation issues, they assess practicality and alternatives. Their deliberation is limited to the specific appeal grounds rather than rehearing the entire case."
|
||||
},
|
||||
appeal_resolution: {
|
||||
appealResolutionText: "The appeal jury has three possible resolution options: 1) Confirm the original decision if the appeal grounds are not substantiated, 2) Modify specific aspects of the decision while maintaining the core findings, or 3) Overturn the decision completely and issue a new determination. The appeal resolution includes specific reasoning addressing each appeal ground raised. Appeal decisions are final and not subject to further community appeal, though legal rights remain unaffected."
|
||||
}
|
||||
},
|
||||
delegation: {
|
||||
criteria: {
|
||||
criteriaText: "Cases may be delegated from the jury process when: 1) The matter involves legal issues beyond community governance, 2) Specialized expertise is required for proper resolution, 3) Immediate intervention is needed for safety concerns, 4) The case complexity exceeds what volunteer jurors can reasonably handle, 5) Multiple previous attempts through the jury process have failed to resolve the issue, or 6) The case would create significant conflicts of interest within the available jury pool. Delegation decisions are made by the Jury Administrator in consultation with community leadership."
|
||||
},
|
||||
delegation_process: {
|
||||
delegationProcessText: "When delegation is appropriate, the process includes: 1) The Jury Administrator documents the reason for delegation, 2) Parties are notified of the delegation decision and rationale, 3) They are provided with information about the alternative process and next steps, 4) Relevant case information is transferred to the appropriate body (with party consent), 5) The Jury Administrator remains available as a resource during the transition, and 6) The community record notes the delegation and eventual outcome for future reference and learning."
|
||||
},
|
||||
selection: {
|
||||
selectionText: "Jurors are selected through a structured random process:\n\n1. A pool of 15-20 community members is randomly selected from the membership roster\n2. Potential jurors complete a screening questionnaire to identify conflicts of interest\n3. Both parties in the dispute may exclude up to 3 potential jurors without stating a reason\n4. A final panel of 5-7 jurors is confirmed from the remaining pool\n5. Selected jurors receive orientation materials and basic conflict resolution training\n6. The process ensures diversity of perspectives while maintaining impartiality"
|
||||
},
|
||||
delegation_authority: {
|
||||
delegationAuthorityText: "Our community maintains relationships with several delegation authorities: 1) A panel of professional mediators for complex relationship conflicts, 2) Legal advisors for matters with potential legal implications, 3) Subject matter experts in areas like construction, finance, and technology, 4) Restorative justice practitioners for cases involving harm repair, 5) Mental health professionals for situations involving psychological wellbeing, and 6) External facilitation teams for conflicts involving governance leadership. These resources receive training on our community values and approaches."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "referee-protocol",
|
||||
title: "Community Referee",
|
||||
description: "A streamlined process where a single trained referee facilitates and decides on dispute resolution",
|
||||
data: {
|
||||
stages: {
|
||||
intake: {
|
||||
process_start: {
|
||||
processStartText: "The referee process begins when a community member submits a dispute resolution request form. This form includes a description of the issue, parties involved, desired outcome, and relevant documentation. Within 2 business days, the Dispute Coordinator reviews the form and determines if the referee process is appropriate. If so, the referee selection process begins immediately, with a goal of assigning a referee within 5 days of the initial submission."
|
||||
},
|
||||
rules_access: {
|
||||
rulesAccessText: "Community standards and the referee process guidelines are made accessible through: 1) A comprehensive digital handbook available on the community website, 2) Print copies in the community office, 3) Periodic community workshops explaining the process, and 4) A quick-reference guide that summarizes key points. New community members receive orientation to these materials when they join. The Dispute Coordinator is available to answer questions about the process."
|
||||
},
|
||||
information_access: {
|
||||
informationAccessText: "Information management follows clear confidentiality protocols: 1) Case information is shared only with the assigned referee and parties directly involved, 2) Documentation is stored securely in both digital and physical formats, 3) Anonymized statistical information is compiled quarterly for process improvements, 4) Final determinations may be used as precedent for future cases with identifying details removed, and 5) Parties may agree to share specific outcomes with the wider community when relevant to community functioning."
|
||||
},
|
||||
participant_inclusion: {
|
||||
participantInclusionText: "When a case is accepted, the Dispute Coordinator contacts all identified parties via email and phone within 48 hours. They receive an explanation of the process, a copy of the initial dispute form, information about referee selection, and a response form to be completed within 3 days. The coordinator answers questions and addresses concerns about the process to ensure informed participation. If a party is unresponsive, a secondary contact method is attempted."
|
||||
},
|
||||
participation_requirement: {
|
||||
participationRequirementText: "Participation in the referee process is a condition of community membership as outlined in our community agreement. Members are expected to engage in good faith when named in a dispute. However, the process may proceed even if a party declines to participate actively. In such cases, the referee will consider available information and note the limited participation in their determination. External parties not bound by community agreements may voluntarily opt in to the process."
|
||||
},
|
||||
participation_commitments: {
|
||||
participationCommitmentsText: "Parties in the referee process commit to: 1) Providing accurate and complete information, 2) Responding to referee requests within specified timeframes, 3) Participating in scheduled meetings prepared and on time, 4) Engaging respectfully even during disagreement, 5) Considering resolution options with an open mind, 6) Abiding by the referee's determination, and 7) Implementing required actions within established deadlines. These commitments are acknowledged in writing at the process start."
|
||||
}
|
||||
},
|
||||
prepare: {
|
||||
principles: {
|
||||
principlesText: "Our dispute resolution process is guided by these referee principles:\n\n1. Expertise-based facilitation by a qualified individual\n2. Fairness through clear procedures and balanced participation\n3. Efficiency through streamlined process with a single decision-maker\n4. Consistency in applying community standards\n5. Practicality in developing workable solutions\n6. Transparency in reasoning while maintaining confidentiality\n7. Authority balanced with participant input and feedback"
|
||||
},
|
||||
values: {
|
||||
valuesText: "The referee process embodies these essential values: 1) Efficiency - streamlining resolution to minimize time and resources, 2) Fairness - ensuring balanced consideration and equal opportunity to be heard, 3) Expertise - bringing relevant knowledge and skills to complex situations, 4) Practicality - focusing on workable solutions that can be implemented, 5) Consistency - applying community standards evenly across similar cases, and 6) Respect - maintaining dignity for all participants throughout the process."
|
||||
},
|
||||
agreements: {
|
||||
agreementsText: "All parties in the referee process agree to: 1) Recognize the authority of the referee to make binding determinations, 2) Provide information honestly and completely when requested, 3) Meet deadlines for submissions and responses, 4) Participate in good faith in all scheduled sessions, 5) Treat the referee and other participants with respect, 6) Maintain confidentiality about process details, and 7) Implement the referee's determination promptly once issued."
|
||||
}
|
||||
},
|
||||
process: {
|
||||
preparation: {
|
||||
preparationText: "Case preparation follows a streamlined sequence: 1) The assigned referee reviews the initial submission within 24 hours, 2) A case management plan with clear timeline is created and shared with all parties, 3) Parties submit position statements and supporting documentation within 5 days, 4) The referee identifies key issues and information gaps, 5) Individual pre-meeting calls are conducted with each party, and 6) The referee prepares a structured agenda for the joint session, focusing discussion on the most relevant issues."
|
||||
},
|
||||
place: {
|
||||
placeText: "Referee sessions typically take place in a neutral meeting room at the community center, featuring: 1) A conference table with equal seating for all parties, 2) Presentation equipment for sharing relevant information, 3) Soundproofing to ensure privacy, 4) Comfortable seating for sessions that may last 2-3 hours, 5) Good lighting and ventilation, and 6) Water and basic refreshments. Virtual participation options are available when necessary, using secure video conferencing technology with screen sharing capabilities."
|
||||
},
|
||||
facilitation: {
|
||||
facilitationText: "The dispute process is led by a single referee who:\n\n1. Reviews all submitted materials before the first meeting\n2. Conducts individual intake interviews with each party\n3. Structures a joint session with clear speaking times and guidelines\n4. Asks clarifying questions to develop a complete understanding\n5. May request additional information or witnesses as needed\n6. Maintains control of the process while ensuring all voices are heard\n7. Provides guidance on realistic options based on community standards"
|
||||
},
|
||||
communication: {
|
||||
communicationText: "Communication in referee sessions follows structured guidelines: 1) The referee establishes clear speaking protocols at the start, 2) Each party has equal opportunity to present their perspective without interruption, 3) Questions are directed through the referee to maintain order, 4) Time limits ensure balanced participation, 5) The referee may caucus with parties separately when needed, 6) Communication focuses on facts and interests rather than accusations, and 7) The referee summarizes key points to ensure shared understanding."
|
||||
},
|
||||
participation: {
|
||||
participationText: "Participation typically includes: 1) The primary parties directly involved in the dispute, 2) The referee who facilitates and ultimately decides the case, 3) One support person per party (non-speaking unless invited), 4) Witnesses with relevant information (for specific portions only), 5) The Dispute Coordinator who handles logistics and record-keeping, and 6) Occasional observers for training purposes (with party consent). All participants receive clear information about their role and expectations in advance."
|
||||
},
|
||||
documentation: {
|
||||
documentationText: "Documentation is maintained throughout the process: 1) All written submissions are compiled in a case file, 2) The referee takes structured notes during all meetings and calls, 3) Audio recording may be used with party consent for accuracy, 4) The referee documents key findings of fact and policy interpretations, 5) A written summary is provided to parties after each significant meeting, and 6) The final determination serves as the official record of the process outcome. All documentation is maintained confidentially in accordance with community record-keeping policies."
|
||||
}
|
||||
},
|
||||
assessment: {
|
||||
situation: {
|
||||
situationText: "The referee conducts a thorough situation assessment: 1) Identifying agreed-upon facts versus disputed facts, 2) Clarifying which community standards or agreements apply to the situation, 3) Determining the chronology of relevant events, 4) Assessing the impact on involved parties and the community, 5) Evaluating the credibility of conflicting accounts when necessary, and 6) Distinguishing between primary issues that require resolution and secondary factors. This assessment provides the foundation for a fair determination."
|
||||
},
|
||||
stage_of_conflict: {
|
||||
stageOfConflictText: "The referee evaluates the stage and dynamics of the conflict: 1) Whether this is a new issue or part of an ongoing pattern, 2) The level of escalation and emotional intensity, 3) Current communication patterns between the parties, 4) Power dynamics that may influence resolution options, 5) Previous attempts at resolution and why they were unsuccessful, and 6) The potential for cooperative versus imposed solutions based on relationship factors. This assessment helps the referee tailor the process appropriately."
|
||||
},
|
||||
needs: {
|
||||
needsText: "The referee identifies the underlying needs of all parties: 1) Stated desires and positions as expressed by each party, 2) Deeper interests that may not be explicitly articulated, 3) Practical needs related to resources, timing, or implementation capacity, 4) Relationship needs between the parties, 5) Community needs for precedent and standard enforcement, and 6) Procedural needs for clarity and closure. Understanding these needs helps the referee craft solutions that address core concerns rather than just surface positions."
|
||||
},
|
||||
evidence: {
|
||||
evidenceText: "Evidence evaluation follows a practical approach: 1) Written statements from all involved parties, 2) Supporting documentation such as communications, photos, or records, 3) Witness accounts from those with direct knowledge, 4) Site visits or inspections when relevant to physical disputes, 5) Community guidelines and precedents from similar cases, and 6) Expert input when specialized knowledge is required. The referee weighs evidence based on relevance, credibility, and consistency, focusing on information that directly impacts the key issues."
|
||||
},
|
||||
jurisdiction: {
|
||||
jurisdictionText: "The referee process has jurisdiction over: 1) Interpretation and application of community agreements and policies, 2) Allocation of shared resources and spaces, 3) Interpersonal conflicts affecting community functioning, 4) Minor property disputes between community members, and 5) Compliance with previous community decisions. The process does not have jurisdiction over legal matters outside community governance, criminal activities, or disputes explicitly excluded in the community charter. Complex cases may be referred to specialized authorities when appropriate."
|
||||
}
|
||||
},
|
||||
deliberation: {
|
||||
information_gathering: {
|
||||
informationGatheringText: "The referee gathers information through a structured approach: 1) Initial submissions from all parties, 2) Clarification questions to fill information gaps, 3) Targeted witness statements on specific disputed facts, 4) Review of community standards and precedents, 5) Site visits or physical inspections when relevant, and 6) Expert consultation on technical matters if needed. The process is designed to be thorough but efficient, gathering essential information without unnecessary delay."
|
||||
},
|
||||
brainstorming: {
|
||||
brainstormingText: "Solution development occurs through guided brainstorming: 1) The referee first asks parties to suggest potential solutions, 2) Each suggestion is noted without immediate evaluation, 3) The referee may offer additional options based on experience with similar cases, 4) Benefits and challenges of each option are identified, 5) Parties discuss which elements of various options might be combined, and 6) The referee helps refine promising approaches into workable solutions. This collaborative phase occurs before the referee makes a final determination."
|
||||
},
|
||||
discussion: {
|
||||
discussionText: "Discussion in referee sessions is highly structured: 1) The referee identifies specific topics for focused conversation, 2) Each party has equal opportunity to address each topic, 3) Direct questions between parties are moderated by the referee, 4) The referee summarizes points of agreement and disagreement, 5) When positions differ, the referee explores underlying interests and concerns, and 6) The discussion concludes with a summary of key findings and possible resolution paths. This structure ensures efficient use of time while covering all relevant issues."
|
||||
},
|
||||
deliberation_format: {
|
||||
deliberationFormatText: "The referee's deliberation typically includes: 1) A structured review of all gathered information, 2) Analysis of which community standards apply to the situation, 3) Assessment of the credibility and weight of conflicting evidence, 4) Consideration of precedent from similar cases, 5) Evaluation of proposed solutions against practical implementation criteria, and 6) Drafting of a determination that addresses all key issues. The referee may consult with other referees on complex matters while maintaining case confidentiality. Deliberation occurs within 3 days of the final information gathering."
|
||||
}
|
||||
},
|
||||
resolution: {
|
||||
decision_making: {
|
||||
decisionMakingText: "Decisions are made through a referee determination process:\n\n1. The referee first encourages participants to reach their own agreement\n2. If parties cannot agree, the referee considers all presented information\n3. The decision is based on community standards, precedent, and fairness\n4. The referee provides a written determination with clear reasoning\n5. Parties may ask clarifying questions about the decision\n6. The referee has authority to make binding decisions within community governance\n7. Decisions are delivered within one week of the final session"
|
||||
},
|
||||
outcomes: {
|
||||
outcomesText: "Referee determinations may include multiple elements: 1) Findings on disputed facts based on the preponderance of evidence, 2) Interpretation of how community standards apply to the situation, 3) Specific actions required of each party with deadlines, 4) Allocation of costs or resources if relevant, 5) Preventive measures to avoid similar disputes in the future, 6) Monitoring protocols to verify implementation, and 7) Recommendations for community policy clarification if gaps are identified. Outcomes balance fairness with practicality, focusing on clear, implementable solutions."
|
||||
},
|
||||
agreement: {
|
||||
agreementText: "All resolutions result in a clear written determination:\n\n1. The document summarizes the dispute and process\n2. Key findings on factual and policy matters are stated clearly\n3. Specific required actions are detailed with deadlines\n4. Rationale for the decision is provided with reference to community standards\n5. Implementation responsibilities are assigned to specific parties\n6. Follow-up and verification methods are specified\n7. The referee signs the determination, and parties acknowledge receipt"
|
||||
},
|
||||
follow_up: {
|
||||
followUpText: "Implementation is supported through structured follow-up: 1) The referee schedules check-in points based on action deadlines, 2) Parties submit verification of completed items, 3) The Dispute Coordinator tracks overall implementation progress, 4) Brief follow-up calls address any clarification needs or implementation challenges, 5) If implementation problems arise, the referee may reconvene the parties for problem-solving, and 6) When all requirements are complete, the case is formally closed with documentation of successful implementation. This accountability system ensures determinations are put into practice."
|
||||
},
|
||||
announcement: {
|
||||
announcementText: "Communication about referee determinations follows a tiered approach: 1) Parties receive the complete determination document, 2) The Dispute Coordinator records the outcome in the confidential case tracking system, 3) If the case involves community-wide issues, a general announcement noting that a determination has been made may be shared without personal details, 4) Policy implications or clarifications may be communicated to relevant community committees, and 5) Anonymized case summaries may be used for referee training and process improvement."
|
||||
}
|
||||
},
|
||||
appeal: {
|
||||
criteria: {
|
||||
criteriaText: "Appeals of referee determinations may be filed based on limited criteria: 1) Significant new information that wasn't available during the original process, 2) Clear misapplication of community standards, 3) Procedural errors that materially affected the outcome, 4) Bias or conflict of interest that wasn't previously disclosed, or 5) Implementation impossibility due to factors outside the party's control. Appeals must be filed within 10 days of the determination and must specifically identify which criterion applies and provide supporting evidence."
|
||||
},
|
||||
appeal_process: {
|
||||
appealProcessText: "The appeal process follows these steps: 1) The appealing party submits a written appeal form with supporting documentation, 2) The Appeals Committee (consisting of three experienced referees not involved in the original case) reviews the appeal to determine if it meets criteria, 3) If accepted, a senior referee not involved in the original case is assigned, 4) The senior referee reviews all materials from the original case plus the appeal documentation, 5) A limited appeal hearing may be held to address specific issues, and 6) The senior referee issues a final determination that confirms, modifies, or replaces the original decision."
|
||||
},
|
||||
appeal_deliberation: {
|
||||
appealDeliberationText: "Appeal deliberation is tightly focused on the specific grounds raised: 1) For new information appeals, the senior referee assesses whether the information is truly new and substantial enough to affect the outcome, 2) For misapplication appeals, they review the relevant standards and their application, 3) For procedural error appeals, they determine if the alleged errors occurred and materially impacted the result, 4) For bias appeals, they evaluate the evidence of partiality, and 5) For implementation appeals, they assess the practical constraints. The deliberation is completed within 5 days of receiving all appeal materials."
|
||||
},
|
||||
appeal_resolution: {
|
||||
appealResolutionText: "The appeal resolution is documented in a written determination that: 1) Addresses each appeal ground specifically, 2) Explains the rationale for upholding or modifying the original determination, 3) Provides any revised directives or timelines, 4) Clarifies implementation requirements, 5) Notes that this decision is final within the community process, and 6) Is delivered to all parties within 48 hours of the decision. The Appeals Committee records the outcome for tracking and quality improvement purposes."
|
||||
}
|
||||
},
|
||||
delegation: {
|
||||
criteria: {
|
||||
criteriaText: "Cases may be delegated from the referee process when: 1) Legal issues beyond community governance are central to the dispute, 2) The complexity requires specialized expertise beyond the referees' training, 3) Safety concerns require immediate professional intervention, 4) The scope affects multiple community systems or external entities, 5) Significant conflicts of interest exist with all available referees, or 6) The case involves policy creation rather than policy application. The Dispute Coordinator makes initial delegation recommendations, which are reviewed by the Referee Oversight Committee."
|
||||
},
|
||||
delegation_process: {
|
||||
delegationProcessText: "The delegation process includes: 1) Documentation of why the referee process is not appropriate, 2) Consultation with parties about alternative options, 3) Formal referral to the appropriate resource with relevant background information, 4) Assistance with transition to ensure parties understand the new process, 5) The Dispute Coordinator remains available as a resource during the transition, and 6) The outcome is recorded for community learning and process improvement. This approach ensures no dispute falls through the cracks due to jurisdictional limitations."
|
||||
},
|
||||
selection: {
|
||||
selectionText: "The referee is selected through a structured process:\n\n1. The community maintains a roster of 5-7 trained referees with diverse expertise\n2. For each dispute, 3 available referees are presented to the parties\n3. Parties rank their preferences, with the highest mutual ranking selected\n4. If parties cannot agree, a random selection from the three options is made\n5. Selected referees must disclose any potential conflicts of interest\n6. Parties may challenge the selection based on demonstrated bias or conflict\n7. Referees receive ongoing training and peer review to maintain quality"
|
||||
},
|
||||
delegation_authority: {
|
||||
delegationAuthorityText: "Our community maintains relationships with several authorities for delegation: 1) A network of professional mediators with various specializations, 2) Legal services for matters requiring formal legal intervention, 3) Subject matter experts in areas like construction, finance, technology, and health, 4) Conflict coaching services for high-emotion situations, 5) Therapeutic resources for conflicts with significant relational components, and 6) Regulatory agencies when disputes involve compliance with external requirements. The community budget includes funds to support access to these resources when needed."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "peer-to-peer",
|
||||
title: "Peer-to-Peer",
|
||||
description: "A self-facilitated process where participants work together directly to resolve disputes",
|
||||
data: {
|
||||
stages: {
|
||||
intake: {
|
||||
process_start: {
|
||||
processStartText: "The process begins when any community member fills out a dispute form, which is available on the community website or as paper copies in common areas. The form asks for a description of the issue, who is involved, and what resolution they're seeking."
|
||||
},
|
||||
rules_access: {
|
||||
rulesAccessText: "Community rules are kept in a shared digital repository accessible to all members, with physical copies posted in community spaces. Rules are reviewed annually in a community-wide meeting."
|
||||
},
|
||||
information_access: {
|
||||
informationAccessText: "Information about disputes is shared only with those directly involved in the process. A summary of resolved disputes (with identifying details removed) is shared quarterly to help the community learn and improve processes."
|
||||
},
|
||||
participant_inclusion: {
|
||||
participantInclusionText: "When a dispute is filed, all identified parties are contacted via their preferred communication method within 48 hours. They receive a copy of the dispute form and information about the peer-to-peer resolution process."
|
||||
},
|
||||
participation_requirement: {
|
||||
participationRequirementText: "Participation is voluntary but strongly encouraged. Community members have agreed in advance that the peer resolution process is the first step before escalating disputes to other forums."
|
||||
},
|
||||
participation_commitments: {
|
||||
participationCommitmentsText: "Participants commit to: 1) Communicating honestly and respectfully, 2) Listening to understand rather than to respond, 3) Working toward a mutually beneficial resolution, 4) Respecting confidentiality, and 5) Following through on any agreed-upon actions."
|
||||
}
|
||||
},
|
||||
process: {
|
||||
preparation: {
|
||||
preparationText: "Both parties have 3-5 days to prepare for the conversation. During this time, they reflect on the issue, their needs, and possible solutions. A preparation worksheet is provided to help structure their thoughts. Participants may seek advice from trusted friends but are asked to keep details confidential."
|
||||
},
|
||||
place: {
|
||||
placeText: "Participants choose a neutral location that feels comfortable for both parties. This could be a community meeting room, quiet outdoor space, or online video call if necessary. The space should be private, quiet, and free from interruptions."
|
||||
},
|
||||
facilitation: {
|
||||
facilitationText: "This process is self-facilitated by the participants. Both parties review a shared guidance document on productive communication before meeting. This document includes suggested time frames, communication techniques, and a basic structure for the conversation."
|
||||
},
|
||||
communication: {
|
||||
communicationText: "Participants follow these guidelines: 1) Take turns speaking without interruption, 2) Use 'I' statements to express feelings and needs, 3) Ask clarifying questions, 4) Summarize what you've heard to ensure understanding, 5) Focus on the present issue and future solutions rather than past grievances."
|
||||
},
|
||||
participation: {
|
||||
participationText: "Only the directly involved parties participate in the initial conversation. If they reach an impasse, they may jointly decide to invite a mutual trusted friend to help facilitate a follow-up conversation."
|
||||
},
|
||||
documentation: {
|
||||
documentationText: "Participants take collaborative notes during the meeting, focusing on agreements made and next steps. Both parties review these notes at the end of the meeting and receive a copy. These notes remain confidential to the participants."
|
||||
}
|
||||
},
|
||||
assessment: {
|
||||
situation: {
|
||||
situationText: "Participants assess the situation together by identifying: 1) The specific issue or behavior causing concern, 2) The impact on each person and the community, 3) Related community values or agreements, and 4) What needs to happen for resolution."
|
||||
},
|
||||
stage_of_conflict: {
|
||||
stageOfConflictText: "Participants jointly determine whether the dispute is: 1) Early stage (single incident or misunderstanding), 2) Developing (pattern forming but communication still possible), or 3) Escalated (significant breakdown in communication or trust). This helps determine appropriate next steps."
|
||||
},
|
||||
needs: {
|
||||
needsText: "Each participant identifies and shares their underlying needs, such as respect, clarity, security, fairness, autonomy, or community connection. They discuss how these needs can be addressed while honoring the needs of others."
|
||||
},
|
||||
evidence: {
|
||||
evidenceText: "Participants share relevant information with each other directly. This may include communications, photos, witness accounts, or other documentation. Both parties agree to honestly present all relevant information."
|
||||
},
|
||||
jurisdiction: {
|
||||
jurisdictionText: "The peer-to-peer process is appropriate for most interpersonal conflicts and minor disagreements. If the dispute involves illegal activity, poses safety risks, or requires specialized expertise, participants should refer to the delegation process."
|
||||
}
|
||||
},
|
||||
deliberation: {
|
||||
information_gathering: {
|
||||
informationGatheringText: "Participants ask each other clarifying questions to ensure they fully understand the situation. They may take a break to gather more information if needed before continuing the conversation."
|
||||
},
|
||||
brainstorming: {
|
||||
brainstormingText: "Participants jointly brainstorm potential solutions without immediately evaluating them. All ideas are recorded. After generating options, they discuss the advantages and challenges of each approach."
|
||||
},
|
||||
discussion: {
|
||||
discussionText: "Discussion follows the format of: 1) Each person shares their perspective uninterrupted, 2) Clarifying questions are asked, 3) Areas of agreement and difference are identified, 4) Participants work to find solutions that address core needs of all involved."
|
||||
},
|
||||
deliberation_format: {
|
||||
deliberationFormatText: "The deliberation is a face-to-face conversation (or video call if necessary) that typically lasts 60-90 minutes. If more time is needed, participants may schedule follow-up conversations rather than rushing to resolution."
|
||||
}
|
||||
},
|
||||
resolution: {
|
||||
decision_making: {
|
||||
decisionMakingText: "Decisions are made through mutual agreement. Both participants must consent to the resolution, meaning they can live with the decision even if it isn't their ideal outcome."
|
||||
},
|
||||
outcomes: {
|
||||
outcomesText: "Possible outcomes include: 1) Clarification of misunderstandings, 2) Apologies and acknowledgment of impact, 3) Agreements about future behavior, 4) Specific actions to restore harm, 5) Plans for ongoing communication, or 6) Agreement to disagree respectfully on certain matters."
|
||||
},
|
||||
agreement: {
|
||||
agreementText: "Agreements are documented in writing, with copies provided to both participants. They include specific, measurable actions with timelines and how progress will be reviewed. Both participants sign the agreement."
|
||||
},
|
||||
follow_up: {
|
||||
followUpText: "Participants schedule a follow-up check-in 2-4 weeks after the agreement to discuss progress and any adjustments needed. This can be a brief meeting or exchange of messages."
|
||||
},
|
||||
announcement: {
|
||||
announcementText: "The resolution remains confidential between the participants unless they jointly agree to share specific information with the wider community."
|
||||
}
|
||||
},
|
||||
appeal: {
|
||||
criteria: {
|
||||
criteriaText: "If either participant feels the agreement isn't working or circumstances have changed significantly, they can request a follow-up conversation using the same peer-to-peer process."
|
||||
},
|
||||
appeal_process: {
|
||||
appealProcessText: "To revisit the agreement, the participant sends a written request to the other party explaining why they believe the agreement needs adjustment. They then schedule a new conversation following the same format as the original process."
|
||||
},
|
||||
appeal_deliberation: {
|
||||
appealDeliberationText: "The follow-up conversation focuses specifically on the aspects of the agreement that aren't working, rather than reopening the entire dispute. Both parties discuss changes that could make the agreement more effective."
|
||||
},
|
||||
appeal_resolution: {
|
||||
appealResolutionText: "The participants revise their written agreement based on the follow-up conversation, with both signing the updated document."
|
||||
}
|
||||
},
|
||||
delegation: {
|
||||
criteria: {
|
||||
criteriaText: "Delegation to a different process is appropriate if: 1) The peer-to-peer process has been attempted without resolution, 2) The dispute involves serious safety concerns, 3) There is a significant power imbalance between participants, 4) The issue affects the broader community, or 5) Specialized expertise is needed."
|
||||
},
|
||||
delegation_process: {
|
||||
delegationProcessText: "If delegation is needed, participants document what has been tried and what issues remain unresolved. They then request assistance from the community mediator pool, a group of trained volunteer mediators."
|
||||
},
|
||||
delegation_authority: {
|
||||
delegationAuthorityText: "The community mediator pool maintains a roster of trained mediators who can facilitate a more structured process. They also maintain referral relationships with professional mediators, counselors, and legal services as needed."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "chosen-facilitator",
|
||||
title: "Chosen Facilitator",
|
||||
description: "A process where participants mutually select a facilitator to help guide their dispute resolution",
|
||||
data: {
|
||||
stages: {
|
||||
intake: {
|
||||
process_start: {
|
||||
processStartText: "The process begins when a community member submits a dispute form to the Community Relations Committee. The form includes details about the issue, parties involved, and previous attempts at resolution. The committee acknowledges receipt within 24 hours."
|
||||
},
|
||||
rules_access: {
|
||||
rulesAccessText: "Community rules and the dispute resolution protocol are available on the community website and in a physical binder kept in the community center. New members receive an orientation to these guidelines when they join."
|
||||
},
|
||||
information_access: {
|
||||
informationAccessText: "Information is shared on a need-to-know basis. The Community Relations Committee keeps records of disputes, and the parties involved have access to all documentation related to their case. Annual anonymous statistics about disputes are shared with the community."
|
||||
},
|
||||
participant_inclusion: {
|
||||
participantInclusionText: "Within 48 hours of receiving a dispute form, the committee contacts all named parties and provides them with a copy of the form and information about the process. Each person confirms their willingness to participate and receives information about selecting a facilitator."
|
||||
},
|
||||
participation_requirement: {
|
||||
participationRequirementText: "Participation is voluntary, though all community members have agreed as part of their membership that they will make a good faith effort to resolve conflicts through the community process before pursuing outside remedies."
|
||||
},
|
||||
participation_commitments: {
|
||||
participationCommitmentsText: "Participants commit to: 1) Engaging honestly and respectfully, 2) Selecting a mutually acceptable facilitator, 3) Attending all scheduled sessions, 4) Respecting confidentiality, 5) Working toward resolution in good faith, and 6) Abiding by any agreements reached."
|
||||
}
|
||||
},
|
||||
process: {
|
||||
preparation: {
|
||||
preparationText: "Before the first facilitated session, each participant completes a preparation form describing their perspective on the issue, their needs, and possible solutions. They submit this to the facilitator at least 48 hours before the first meeting. The facilitator may have individual pre-meetings with participants."
|
||||
},
|
||||
place: {
|
||||
placeText: "Meetings take place in a neutral community space, typically a designated meeting room in the community center. The facilitator ensures the space is set up appropriately with comfortable seating, water, and any needed materials like whiteboard or flipchart."
|
||||
},
|
||||
facilitation: {
|
||||
facilitationText: "The process is guided by a facilitator chosen jointly by all participants from a list of community members who have expressed willingness to serve in this role. The facilitator has basic training in conflict resolution but is not a professional mediator. They help guide the conversation, ensure all voices are heard, and maintain focus on resolution."
|
||||
},
|
||||
communication: {
|
||||
communicationText: "The facilitator establishes ground rules at the beginning of the first session, such as: 1) One person speaks at a time, 2) Focus on issues rather than personal attacks, 3) Use respectful language, 4) Actively listen to understand, 5) Take breaks when needed, and 6) Maintain confidentiality."
|
||||
},
|
||||
participation: {
|
||||
participationText: "The primary participants and the facilitator attend all sessions. With agreement from all parties, participants may bring one support person to sessions. Support people may speak when invited but primarily provide emotional support and perspective between sessions."
|
||||
},
|
||||
documentation: {
|
||||
documentationText: "The facilitator takes notes capturing main discussion points and any agreements reached. These notes are shared with participants after each session for review and correction. Final agreements are documented in writing and signed by all participants."
|
||||
}
|
||||
},
|
||||
assessment: {
|
||||
situation: {
|
||||
situationText: "In the first session, the facilitator helps participants create a shared understanding of the situation by: 1) Having each person share their perspective without interruption, 2) Identifying areas of agreement and disagreement, 3) Clarifying facts versus interpretations, and 4) Establishing what resolution would look like."
|
||||
},
|
||||
stage_of_conflict: {
|
||||
stageOfConflictText: "The facilitator helps assess whether the conflict is: 1) A misunderstanding that can be clarified, 2) A disagreement about resources or procedures, 3) A values-based conflict, or 4) A relationship conflict with a history of tension. This assessment helps determine appropriate resolution approaches."
|
||||
},
|
||||
needs: {
|
||||
needsText: "The facilitator guides participants in identifying their underlying needs and interests beyond their stated positions. These might include needs for respect, autonomy, fairness, safety, belonging, or understanding. The facilitator helps frame the dispute in terms of compatible needs rather than opposing positions."
|
||||
},
|
||||
evidence: {
|
||||
evidenceText: "Relevant information is shared through the facilitator, who ensures all participants have access to the same information. The facilitator may request additional documentation or clarification as needed. Information is presented factually without accusatory language."
|
||||
},
|
||||
jurisdiction: {
|
||||
jurisdictionText: "The facilitator helps determine if the chosen facilitator process is appropriate for the dispute. If the issue involves serious safety concerns, legal violations, or requires specialized expertise, the facilitator will recommend delegation to a more appropriate resource."
|
||||
}
|
||||
},
|
||||
deliberation: {
|
||||
information_gathering: {
|
||||
informationGatheringText: "After initial perspectives are shared, the facilitator identifies information gaps and helps participants determine what additional information might be needed. They may assign 'homework' to gather specific information before the next session."
|
||||
},
|
||||
brainstorming: {
|
||||
brainstormingText: "The facilitator leads a structured brainstorming session where all possible solutions are recorded without criticism. They may use techniques such as round-robin contribution or written idea submission to ensure everyone's ideas are included."
|
||||
},
|
||||
discussion: {
|
||||
discussionText: "After brainstorming, the facilitator helps participants evaluate options based on previously identified needs and interests. They guide the discussion to focus on finding solutions that address the core concerns of all parties rather than positional bargaining."
|
||||
},
|
||||
deliberation_format: {
|
||||
deliberationFormatText: "Deliberation typically involves 1-3 sessions of 90-120 minutes each, scheduled about a week apart. This provides time for reflection between sessions. The facilitator sets a clear agenda for each session and manages time to ensure productive discussion."
|
||||
}
|
||||
},
|
||||
resolution: {
|
||||
decision_making: {
|
||||
decisionMakingText: "Decisions are made by consensus of the participants, with the facilitator helping to test whether proposed solutions are acceptable to everyone. The facilitator may use techniques like fist-to-five voting to gauge levels of support for proposals."
|
||||
},
|
||||
outcomes: {
|
||||
outcomesText: "Typical outcomes include: 1) Mutual understanding and clarified expectations, 2) Specific action agreements with timelines, 3) Changes to procedures or resources, 4) Commitments to specific communication practices, 5) Relationship-rebuilding activities, or 6) Agreements about future conflict resolution if issues arise again."
|
||||
},
|
||||
agreement: {
|
||||
agreementText: "The facilitator drafts a written agreement based on the decisions reached. The agreement includes specific, actionable items with timelines, how implementation will be verified, and a plan for addressing any future issues. All participants review, possibly revise, and sign the agreement."
|
||||
},
|
||||
follow_up: {
|
||||
followUpText: "The facilitator schedules a follow-up check-in 3-4 weeks after the agreement is reached. This may be a meeting or individual check-ins to assess whether the agreement is working and address any implementation challenges."
|
||||
},
|
||||
announcement: {
|
||||
announcementText: "The fact that a resolution has been reached may be shared with the Community Relations Committee, but the details remain confidential unless all participants agree to share specific information more widely."
|
||||
}
|
||||
},
|
||||
appeal: {
|
||||
criteria: {
|
||||
criteriaText: "Appeals may be initiated if: 1) New information emerges that could significantly affect the agreement, 2) Circumstances change making the agreement unworkable, 3) There are persistent challenges implementing the agreement, or 4) One or more participants feel the process was unfair."
|
||||
},
|
||||
appeal_process: {
|
||||
appealProcessText: "To appeal, a participant submits a written request to the Community Relations Committee explaining why they believe the agreement needs reconsideration. The committee reviews the request and contacts all original participants to determine next steps."
|
||||
},
|
||||
appeal_deliberation: {
|
||||
appealDeliberationText: "If an appeal proceeds, a new facilitator is selected from the community to provide fresh perspective. This facilitator reviews documentation from the original process and conducts a new series of facilitated sessions focusing on the specific issues raised in the appeal."
|
||||
},
|
||||
appeal_resolution: {
|
||||
appealResolutionText: "The appeal process results in either a confirmation of the original agreement, modifications to address specific concerns, or in some cases, a completely new agreement. The new or modified agreement is documented and signed by all participants."
|
||||
}
|
||||
},
|
||||
delegation: {
|
||||
criteria: {
|
||||
criteriaText: "Delegation to a different process is appropriate when: 1) The facilitated process has been attempted without success, 2) The issue requires specialized expertise (legal, financial, therapeutic, etc.), 3) There are significant power imbalances that can't be addressed by a peer facilitator, 4) Safety concerns exist, or 5) The dispute has community-wide implications."
|
||||
},
|
||||
delegation_process: {
|
||||
delegationProcessText: "The facilitator or Community Relations Committee may recommend delegation at any point in the process. They document the reason for delegation and what has been attempted so far. They then connect participants with appropriate resources, which may be within or outside the community."
|
||||
},
|
||||
delegation_authority: {
|
||||
delegationAuthorityText: "The Community Relations Committee maintains a resource list of professional mediators, counselors, restorative justice practitioners, and legal resources. They have established relationships with these providers and can make direct referrals when needed. The community has a small fund to assist with costs if financial barriers exist."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "facilitation-council",
|
||||
title: "Facilitation Council",
|
||||
description: "A structured process with a trained council of facilitators who manage the dispute resolution process",
|
||||
data: {
|
||||
stages: {
|
||||
intake: {
|
||||
process_start: {
|
||||
processStartText: "The dispute resolution process begins when an individual submits a formal request using the council's intake form. This form is available online and in hard copy at the community office. The form requires details about the nature of the dispute, parties involved, and previous resolution attempts. A member of the Facilitation Council acknowledges receipt within 24 hours and assigns an intake coordinator."
|
||||
},
|
||||
rules_access: {
|
||||
rulesAccessText: "Community rules, bylaws, and the detailed dispute resolution protocol are maintained in a searchable online database with version history. Physical copies are available in the community center library. The Facilitation Council conducts quarterly workshops to educate community members about the rules and processes."
|
||||
},
|
||||
information_access: {
|
||||
informationAccessText: "Information access follows a tiered model: 1) The involved parties and council members have full access to case documentation, 2) Council administrators track anonymized case data for process improvement, 3) Quarterly reports with statistical information and lessons learned (without identifying details) are shared with the community."
|
||||
},
|
||||
participant_inclusion: {
|
||||
participantInclusionText: "The intake coordinator contacts all named parties within 48 hours via email and phone. They receive an explanation of the process, a copy of the initial request, information about their rights and responsibilities, and a response form to complete within 5 days. The coordinator offers to meet with each party individually to answer questions about the process."
|
||||
},
|
||||
participation_requirement: {
|
||||
participationRequirementText: "Participation in the facilitation council process is required for active community members as specified in the community membership agreement. For non-members or in cases where mandatory participation would be inappropriate, the council works with willing participants and documents non-participation of others."
|
||||
},
|
||||
participation_commitments: {
|
||||
participationCommitmentsText: "Participants commit to: 1) Providing complete and truthful information, 2) Respecting confidentiality, 3) Attending all scheduled meetings, 4) Engaging respectfully with all parties and council members, 5) Following the structured process, 6) Implementing agreed-upon resolutions, and 7) Participating in scheduled follow-up. These commitments are formalized in writing at the start of the process."
|
||||
}
|
||||
},
|
||||
process: {
|
||||
preparation: {
|
||||
preparationText: "After intake, each party receives a preparation packet with: 1) A detailed statement form to document their perspective, 2) Instructions for gathering and submitting relevant evidence, 3) A guide for identifying potential witnesses, and 4) Reflection questions about desired outcomes. Parties have one week to complete these materials. Council members then review all materials before the first session and may request additional information."
|
||||
},
|
||||
place: {
|
||||
placeText: "The council maintains a dedicated dispute resolution room in the community center, designed specifically for these processes. The room features a round table, comfortable seating, good acoustics, privacy screens, and necessary technology for sharing information. For complex cases with many participants, larger spaces can be reserved. Virtual participation options are available when in-person attendance is impossible."
|
||||
},
|
||||
facilitation: {
|
||||
facilitationText: "Disputes are facilitated by a panel of 2-3 council members who have completed a comprehensive training program in conflict resolution, mediation, and restorative practices. The panel always includes diversity of perspectives and backgrounds. One member serves as the lead facilitator, while others may focus on documentation, process management, or emotional support. The council operates according to established procedures with flexibility to adapt to specific needs of each case."
|
||||
},
|
||||
communication: {
|
||||
communicationText: "The council establishes and enforces clear communication protocols: 1) A talking piece indicates who has the floor, 2) Structured speaking order ensures equal voice, 3) Time limits for presentations may be used, 4) Direct communication between parties is facilitated when productive, 5) Council members summarize and reframe statements to ensure understanding, 6) Caucus sessions (private meetings) are available when needed, and 7) Written communication supplements verbal discussion for complex topics."
|
||||
},
|
||||
participation: {
|
||||
participationText: "The process includes: 1) Primary parties to the dispute, 2) Council panel members, 3) Witnesses invited by either party or the council (for specific sessions only), 4) Support persons (one per participant, non-speaking unless invited), and 5) In cases affecting community standards, a community representative. For disputes involving allegations of harm, the council uses practices that prevent re-traumatization while ensuring fair process."
|
||||
},
|
||||
documentation: {
|
||||
documentationText: "A designated council member maintains detailed documentation including: 1) Written submissions from all parties, 2) Minutes of all meetings with key points and decisions, 3) Supporting evidence and witness statements, 4) Audio recordings of sessions (with permission), 5) Written agreements, and 6) Follow-up reports. Parties receive copies of all non-confidential documentation. Records are securely stored according to the council's data retention policy."
|
||||
}
|
||||
},
|
||||
assessment: {
|
||||
situation: {
|
||||
situationText: "The council conducts a structured assessment through: 1) Individual interviews with each party, 2) Review of written statements and evidence, 3) Consultation with relevant witnesses, 4) Consideration of applicable community agreements or policies, and 5) Discussion with the full council to identify the nature and scope of the dispute. The assessment is documented in a preliminary findings report shared with all parties."
|
||||
},
|
||||
stage_of_conflict: {
|
||||
stageOfConflictText: "The council uses a formal assessment framework to determine: 1) The history and duration of the conflict, 2) The level of emotion and polarization between parties, 3) Whether communication between parties is still functional, 4) If the dispute is escalating or de-escalating, 5) The underlying causes (structural, relational, value-based, etc.), and 6) The potential community impact. This assessment determines the appropriate intervention approach and timeline."
|
||||
},
|
||||
needs: {
|
||||
needsText: "The council works with each party to identify needs using a structured needs assessment tool that covers: 1) Physical needs (safety, resources, space), 2) Emotional needs (recognition, respect, belonging), 3) Procedural needs (voice, fairness, clarity), and 4) Identity needs (role, values, reputation). The council maps these needs to identify commonalities and differences, using this as a foundation for resolution options."
|
||||
},
|
||||
evidence: {
|
||||
evidenceText: "The council has established procedures for evidence collection and evaluation: 1) Parties submit evidence following standardized guidelines, 2) A designated council member reviews all submissions for relevance and completeness, 3) Evidence is categorized and indexed, 4) All parties have equal access to non-confidential evidence, 5) The council may request additional evidence or clarification, and 6) When factual disputes persist, the council may consult appropriate experts or additional witnesses."
|
||||
},
|
||||
jurisdiction: {
|
||||
jurisdictionText: "The council follows a jurisdictional assessment checklist to determine if the case is appropriate for their process. Cases involving serious legal violations, safety threats, or requiring specialized expertise beyond the council's capacity are referred to appropriate authorities. For complex cases, the council may establish jurisdiction over certain aspects while referring others. The assessment considers legal requirements, community capacity, and the nature of the dispute."
|
||||
}
|
||||
},
|
||||
deliberation: {
|
||||
information_gathering: {
|
||||
informationGatheringText: "The council uses a structured information gathering process: 1) Initial statements from all parties, 2) Clarifying questions from council members, 3) Testimony from relevant witnesses, 4) Review of documentary evidence, 5) Expert input if needed for technical matters, and 6) Community standard review when applicable. Information gathering follows a predetermined schedule with deadlines for submissions and specific session agendas."
|
||||
},
|
||||
brainstorming: {
|
||||
brainstormingText: "Facilitated brainstorming sessions use specific methodologies including: 1) Individual brainstorming where each party independently generates solutions, 2) Council-moderated joint sessions using visual mapping tools, 3) Structured brainstorming techniques such as nominal group process or rounds, and 4) Consideration of precedents from similar cases. All options are documented without evaluation during the brainstorming phase."
|
||||
},
|
||||
discussion: {
|
||||
discussionText: "Discussion follows a structured format: 1) Review of brainstormed options, 2) Evaluation against previously identified needs and community values, 3) Consideration of implementation feasibility, 4) Discussion of modifications to promising options, 5) Council-facilitated negotiations on specific details, and 6) Caucus sessions when needed for private discussion. The council maintains focus on interests rather than positions and ensures balanced participation."
|
||||
},
|
||||
deliberation_format: {
|
||||
deliberationFormatText: "The council uses a multi-stage deliberation format: 1) Preliminary council-only meeting to review all materials and plan the process, 2) Joint sessions with all parties following a structured agenda, 3) Separate sessions with individual parties as needed, 4) Council executive sessions to assess progress and adjust process, 5) Final resolution session(s). Most cases involve 3-5 sessions of 2-3 hours each over a 2-4 week period, with a detailed schedule provided at the outset."
|
||||
}
|
||||
},
|
||||
resolution: {
|
||||
decision_making: {
|
||||
decisionMakingText: "The council uses a tiered decision-making approach: 1) Facilitated consensus among parties is the preferred method, with the council helping parties reach mutually acceptable agreements, 2) If consensus cannot be reached on all issues after good faith efforts, parties may authorize the council to make recommendations on specific points, 3) In cases involving community standards or policies, the council may make binding decisions following established criteria. The basis for all decisions is documented."
|
||||
},
|
||||
outcomes: {
|
||||
outcomesText: "Resolution outcomes may include: 1) Written agreements between parties with specific commitments, 2) Action plans with timelines and accountability measures, 3) Restorative agreements to address harm, 4) Resource allocation decisions, 5) Clarification of policies or expectations, 6) Structural changes to prevent future conflicts, 7) Educational or training requirements, and 8) Recommendations to community governance bodies for policy changes. All outcomes include clear implementation plans."
|
||||
},
|
||||
agreement: {
|
||||
agreementText: "Agreements are documented using a standard format that includes: 1) Names and roles of all parties, 2) Summary of the dispute and process, 3) Specific agreements with detailed action items, 4) Timelines for implementation, 5) Verification methods, 6) Consequences for non-compliance if applicable, 7) Privacy and communication guidelines, 8) Follow-up schedule, 9) Process for addressing future disputes or agreement modifications, and 10) Signatures of all parties and facilitating council members."
|
||||
},
|
||||
follow_up: {
|
||||
followUpText: "The council implements a multi-stage follow-up process: 1) Initial check-in 2 weeks after agreement, 2) Formal review meeting at 1-3 months, 3) Final assessment at 6 months, 4) Additional check-ins as specified in the agreement. A designated council member serves as agreement monitor, collecting implementation evidence and facilitating resolution of any implementation challenges."
|
||||
},
|
||||
announcement: {
|
||||
announcementText: "The council follows structured guidelines for announcements: 1) Parties and council members agree on what information will be shared, 2) A brief, factual summary is prepared noting that a resolution has been reached (without private details), 3) Any community-wide implications or policy changes are communicated through established channels, 4) In cases of broad community impact, educational sessions may be held to share lessons learned while respecting confidentiality, 5) Statistical information is included in quarterly council reports."
|
||||
}
|
||||
},
|
||||
appeal: {
|
||||
criteria: {
|
||||
criteriaText: "Appeals may be filed when: 1) New, significant evidence emerges that was not available during the original process, 2) There was a substantial procedural error that may have affected the outcome, 3) The agreement has proven unworkable despite good faith implementation efforts, or 4) There has been a significant change in circumstances that renders the agreement ineffective. Appeals must be filed within 30 days of discovering the grounds for appeal."
|
||||
},
|
||||
appeal_process: {
|
||||
appealProcessText: "The appeal process includes: 1) Submission of a formal appeal request specifying grounds for appeal and desired outcome, 2) Review by council members not involved in the original case to determine if appeal criteria are met, 3) Notification to all original parties, 4) If accepted, assignment of a new council panel, 5) Structured review of original documentation and new evidence, 6) Limited-scope hearings focused on appeal issues, 7) Decision rendered within 30 days of appeal acceptance."
|
||||
},
|
||||
appeal_deliberation: {
|
||||
appealDeliberationText: "Appeal deliberations follow a specialized process: 1) The appeal panel first reviews all documentation from the original process, 2) New evidence or procedural concerns are examined in detail, 3) Limited testimony may be heard specifically related to appeal grounds, 4) The panel deliberates using a structured framework for evaluating whether the original outcome should stand, be modified, or be replaced, 5) Deliberations are documented with specific reasoning for decisions."
|
||||
},
|
||||
appeal_resolution: {
|
||||
appealResolutionText: "Appeal resolutions are documented in a formal decision that includes: 1) Summary of the original case and resolution, 2) Grounds for appeal and additional evidence considered, 3) Analysis of how the appeal criteria were or were not met, 4) Specific modifications to the original agreement if applicable, 5) Implementation plan for any changes, 6) Statement of finality indicating whether further appeals are possible, and 7) Signatures of appeal panel members. All parties receive this document and acknowledge receipt."
|
||||
}
|
||||
},
|
||||
delegation: {
|
||||
criteria: {
|
||||
criteriaText: "Cases are delegated when: 1) They involve legal issues beyond the council's authority, 2) Specialized expertise is required (legal, psychological, financial, etc.), 3) Safety concerns exceed the council's capacity to address, 4) Conflicts of interest make impartial council deliberation impossible, 5) The case has implications beyond the immediate community requiring broader involvement, or 6) Multiple attempts at resolution through the council process have failed."
|
||||
},
|
||||
delegation_process: {
|
||||
delegationProcessText: "The delegation process involves: 1) Identification of delegation need either at intake or during the process, 2) Council deliberation and formal vote on delegation recommendation, 3) Documentation of reasons for delegation and process to date, 4) Consultation with parties about appropriate external resources, 5) Formal referral including transfer of relevant documentation (with permission), 6) Assignment of a council liaison to support transition and maintain communication, 7) Closure of the council process with clear communication about next steps."
|
||||
},
|
||||
delegation_authority: {
|
||||
delegationAuthorityText: "The council maintains formal relationships with: 1) A panel of professional mediators with different specializations, 2) Legal resources including community legal aid, 3) Mental health professionals for cases involving trauma or psychological concerns, 4) Restorative justice practitioners for cases involving harm, 5) Subject matter experts in relevant fields, and 6) Regional conflict resolution centers. Annual budget is allocated for professional services when needed, and financial assistance is available to ensure access regardless of ability to pay."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// Make sure rawProtocolTemplates is available globally
|
||||
window.rawProtocolTemplates = rawProtocolTemplates;
|
26
static/js/debug.js
Normal file
26
static/js/debug.js
Normal file
@ -0,0 +1,26 @@
|
||||
console.log('Testing toggle button functionality');
|
||||
|
||||
// Debug script to inspect template loading
|
||||
console.log("Debug script loaded");
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log("DOM loaded in debug script");
|
||||
|
||||
// Log raw templates
|
||||
console.log("Raw Protocol Templates:", typeof rawProtocolTemplates !== 'undefined' ? rawProtocolTemplates.length : "undefined");
|
||||
if (typeof rawProtocolTemplates !== 'undefined') {
|
||||
console.log("Template titles:", rawProtocolTemplates.map(t => t.title));
|
||||
}
|
||||
|
||||
// Log processed templates
|
||||
setTimeout(() => {
|
||||
const templateSelect = document.getElementById('protocol-template');
|
||||
if (templateSelect) {
|
||||
console.log("Template options:", templateSelect.options.length);
|
||||
const options = Array.from(templateSelect.options).map(o => o.textContent);
|
||||
console.log("Option texts:", options);
|
||||
} else {
|
||||
console.log("Template select element not found");
|
||||
}
|
||||
}, 1000);
|
||||
});
|
25
static/js/fix-dropdown.js
Normal file
25
static/js/fix-dropdown.js
Normal file
@ -0,0 +1,25 @@
|
||||
// Make sure the dropdown works correctly
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const exportBtn = document.getElementById('export-btn');
|
||||
const dropdownMenu = document.querySelector('.dropdown-menu');
|
||||
|
||||
if (exportBtn && dropdownMenu) {
|
||||
// Force clear any previous event listeners
|
||||
const newExportBtn = exportBtn.cloneNode(true);
|
||||
exportBtn.parentNode.replaceChild(newExportBtn, exportBtn);
|
||||
|
||||
// Add event listener to the new button
|
||||
newExportBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
|
||||
});
|
||||
|
||||
// Close dropdown when clicking elsewhere
|
||||
document.addEventListener('click', function(e) {
|
||||
if (newExportBtn && \!newExportBtn.contains(e.target) && dropdownMenu && \!dropdownMenu.contains(e.target)) {
|
||||
dropdownMenu.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
695
static/js/modules-page.js
Normal file
695
static/js/modules-page.js
Normal file
@ -0,0 +1,695 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('Modules page initializing...');
|
||||
|
||||
// Reference to container and filters
|
||||
const modulesContainer = document.getElementById('modules-container');
|
||||
const moduleSearch = document.getElementById('module-search');
|
||||
const stageFilter = document.getElementById('stage-filter');
|
||||
const componentFilter = document.getElementById('component-filter');
|
||||
const templateFilter = document.getElementById('template-filter');
|
||||
|
||||
// Data structures
|
||||
let allModules = [];
|
||||
let stageNames = {};
|
||||
let componentNames = {};
|
||||
let templateUsage = {};
|
||||
let processedTemplates = [];
|
||||
|
||||
// Functions
|
||||
function initializeData() {
|
||||
console.log('Initializing data...');
|
||||
|
||||
// Check if data is available
|
||||
if (typeof moduleData === 'undefined') {
|
||||
console.error('Error: moduleData is undefined');
|
||||
modulesContainer.innerHTML = '<div class="error">Error: Module data not available</div>';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof rawProtocolTemplates === 'undefined' || typeof templateMapper === 'undefined') {
|
||||
console.error('Error: Template data or mapper not available');
|
||||
modulesContainer.innerHTML = '<div class="error">Error: Template data not available</div>';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log what we're working with
|
||||
console.log('Module categories:', Object.keys(moduleData));
|
||||
console.log('Templates count:', rawProtocolTemplates.length);
|
||||
|
||||
try {
|
||||
// Process templates
|
||||
rawProtocolTemplates.forEach(template => {
|
||||
const processedTemplate = templateMapper.convertTemplateToModules(template, moduleData);
|
||||
processedTemplates.push(processedTemplate);
|
||||
});
|
||||
|
||||
// Collect all modules into a flat array
|
||||
for (const category in moduleData) {
|
||||
moduleData[category].forEach(module => {
|
||||
// Add category to module
|
||||
module.category = category;
|
||||
|
||||
// Initialize template usage
|
||||
module.usedInTemplates = [];
|
||||
|
||||
// Ensure all modules have a componentId - no uncategorized modules allowed
|
||||
if (!module.componentId) {
|
||||
// Try to infer from category first
|
||||
if (category !== 'uncategorized') {
|
||||
console.log(`Module ${module.id} missing componentId, using category: ${category}`);
|
||||
module.componentId = category;
|
||||
}
|
||||
// If that doesn't work, infer from title or content
|
||||
else {
|
||||
// First, try to find clues in the title
|
||||
if (module.title) {
|
||||
const titleLower = module.title.toLowerCase();
|
||||
// Check for key component names in the title
|
||||
if (titleLower.includes('principle')) module.componentId = 'principles';
|
||||
else if (titleLower.includes('process')) module.componentId = 'process';
|
||||
else if (titleLower.includes('assessment')) module.componentId = 'assessment';
|
||||
else if (titleLower.includes('intake')) module.componentId = 'intake';
|
||||
else if (titleLower.includes('appeal')) module.componentId = 'appeal';
|
||||
else if (titleLower.includes('deliberat')) module.componentId = 'deliberation';
|
||||
else if (titleLower.includes('resolut')) module.componentId = 'resolution';
|
||||
else if (titleLower.includes('facilit')) module.componentId = 'facilitation';
|
||||
else if (titleLower.includes('particip')) module.componentId = 'participants';
|
||||
else if (titleLower.includes('file') || titleLower.includes('submit')) module.componentId = 'filing';
|
||||
else if (titleLower.includes('notif') || titleLower.includes('inform')) module.componentId = 'notification';
|
||||
else if (titleLower.includes('delegat')) module.componentId = 'delegation';
|
||||
else module.componentId = 'process'; // Default to process
|
||||
}
|
||||
// If no title clues, check content
|
||||
else if (module.content) {
|
||||
const contentLower = module.content.toLowerCase();
|
||||
// Same checks in content
|
||||
if (contentLower.includes('principle')) module.componentId = 'principles';
|
||||
else if (contentLower.includes('process')) module.componentId = 'process';
|
||||
else if (contentLower.includes('assessment')) module.componentId = 'assessment';
|
||||
else if (contentLower.includes('intake')) module.componentId = 'intake';
|
||||
else if (contentLower.includes('appeal')) module.componentId = 'appeal';
|
||||
else if (contentLower.includes('deliberat')) module.componentId = 'deliberation';
|
||||
else if (contentLower.includes('resolut')) module.componentId = 'resolution';
|
||||
else if (contentLower.includes('facilit')) module.componentId = 'facilitation';
|
||||
else if (contentLower.includes('particip')) module.componentId = 'participants';
|
||||
else if (contentLower.includes('file') || contentLower.includes('submit')) module.componentId = 'filing';
|
||||
else if (contentLower.includes('notif') || contentLower.includes('inform')) module.componentId = 'notification';
|
||||
else if (contentLower.includes('delegat')) module.componentId = 'delegation';
|
||||
else module.componentId = 'process'; // Default to process
|
||||
}
|
||||
// Last resort default
|
||||
else {
|
||||
module.componentId = 'process';
|
||||
}
|
||||
|
||||
console.log(`Module ${module.id} had no componentId, assigned to: ${module.componentId}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Add to all modules array
|
||||
allModules.push(module);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Total modules collected:', allModules.length);
|
||||
|
||||
// Track which templates use each module
|
||||
processedTemplates.forEach(template => {
|
||||
for (const stageId in template.moduleRefs) {
|
||||
if (!stageNames[stageId]) {
|
||||
// Create a readable stage name
|
||||
stageNames[stageId] = stageId.charAt(0).toUpperCase() + stageId.slice(1).replace(/_/g, ' ');
|
||||
}
|
||||
|
||||
for (const componentId in template.moduleRefs[stageId]) {
|
||||
if (!componentNames[componentId]) {
|
||||
// Create a readable component name
|
||||
componentNames[componentId] = componentId.charAt(0).toUpperCase() + componentId.slice(1).replace(/_/g, ' ');
|
||||
}
|
||||
|
||||
for (const fieldId in template.moduleRefs[stageId][componentId]) {
|
||||
const moduleId = template.moduleRefs[stageId][componentId][fieldId];
|
||||
|
||||
// Find the module with this id
|
||||
const matchingModule = allModules.find(m => m.id === moduleId);
|
||||
if (matchingModule) {
|
||||
// Add template to module's usage
|
||||
if (!matchingModule.usedInTemplates.includes(template.title)) {
|
||||
matchingModule.usedInTemplates.push(template.title);
|
||||
}
|
||||
|
||||
// Set stage and component for the module if not already set
|
||||
if (!matchingModule.stageId) {
|
||||
matchingModule.stageId = stageId;
|
||||
}
|
||||
|
||||
// Track template usage
|
||||
if (!templateUsage[template.title]) {
|
||||
templateUsage[template.title] = [];
|
||||
}
|
||||
if (!templateUsage[template.title].includes(moduleId)) {
|
||||
templateUsage[template.title].push(moduleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Define official stages from YAML file
|
||||
const officialStages = {
|
||||
'intake': 'Intake',
|
||||
'process': 'Process',
|
||||
'assessment': 'Assessment',
|
||||
'deliberation': 'Deliberation',
|
||||
'resolution': 'Resolution',
|
||||
'appeal': 'Appeal',
|
||||
'delegation': 'Delegation'
|
||||
};
|
||||
|
||||
// Define official components with standardized display names
|
||||
const officialComponents = {
|
||||
// Process stage components
|
||||
'principles': 'Principles',
|
||||
'community_values': 'Values',
|
||||
'participants': 'Participants',
|
||||
'facilitation': 'Facilitation',
|
||||
'ground_rules': 'Ground Rules',
|
||||
'skills': 'Skills',
|
||||
|
||||
// Intake stage components
|
||||
'process_start': 'Process Start',
|
||||
'filing': 'Filing',
|
||||
'notification': 'Notification',
|
||||
'rules_access': 'Rules Access',
|
||||
'information_access': 'Information Access',
|
||||
'participant_inclusion': 'Participant Inclusion',
|
||||
|
||||
// Assessment stage components
|
||||
'dispute_assessment': 'Assessment',
|
||||
'values_adherence': 'Values Adherence',
|
||||
'jurisdiction': 'Jurisdiction',
|
||||
|
||||
// Deliberation stage components
|
||||
'deliberation_process': 'Deliberation Process',
|
||||
'additional_voices': 'Additional Voices',
|
||||
'deliberation_conclusion': 'Deliberation Conclusion',
|
||||
|
||||
// Resolution stage components
|
||||
'resolution_process': 'Resolution Process',
|
||||
'resolution_failure': 'Resolution Failure',
|
||||
|
||||
// Appeal stage components
|
||||
'appeal_criteria': 'Appeal Criteria',
|
||||
'appeal_process': 'Appeal Process',
|
||||
|
||||
// Delegation stage components
|
||||
'delegation_options': 'Delegation Options'
|
||||
};
|
||||
|
||||
// Map all component IDs (including custom ones) to official stages
|
||||
const componentToStageMap = {
|
||||
// Process stage components
|
||||
'principles': 'process',
|
||||
'community_values': 'process',
|
||||
'participants': 'process',
|
||||
'facilitation': 'process',
|
||||
'ground_rules': 'process',
|
||||
'skills': 'process',
|
||||
'values': 'process',
|
||||
'agreements': 'process',
|
||||
'participation_commitments': 'process',
|
||||
|
||||
// Intake stage components
|
||||
'process_start': 'intake',
|
||||
'filing': 'intake',
|
||||
'notification': 'intake',
|
||||
'rules_access': 'intake',
|
||||
'information_access': 'intake',
|
||||
'participant_inclusion': 'intake',
|
||||
'reporting': 'intake',
|
||||
|
||||
// Assessment stage components
|
||||
'dispute_assessment': 'assessment',
|
||||
'values_adherence': 'assessment',
|
||||
'jurisdiction': 'assessment',
|
||||
'non_participation': 'assessment',
|
||||
|
||||
// Deliberation stage components
|
||||
'deliberation_process': 'deliberation',
|
||||
'additional_voices': 'deliberation',
|
||||
'deliberation_conclusion': 'deliberation',
|
||||
'decision_making': 'deliberation',
|
||||
'discussion': 'deliberation',
|
||||
|
||||
// Resolution stage components
|
||||
'resolution_process': 'resolution',
|
||||
'resolution_failure': 'resolution',
|
||||
|
||||
// Appeal stage components
|
||||
'appeal_criteria': 'appeal',
|
||||
'appeal_process': 'appeal',
|
||||
'appeal_deliberation': 'appeal',
|
||||
'appeal_resolution': 'appeal',
|
||||
|
||||
// Delegation stage components
|
||||
'delegation_options': 'delegation'
|
||||
};
|
||||
|
||||
// Map non-standard components to official ones
|
||||
const componentMapping = {
|
||||
'direct_conversation': 'deliberation_process',
|
||||
'conflict_awareness': 'dispute_assessment',
|
||||
'accessing_help': 'process_start',
|
||||
'preparation': 'principles',
|
||||
'selection': 'participant_inclusion',
|
||||
'criteria': 'appeal_criteria',
|
||||
'agreement': 'resolution_process',
|
||||
'process': 'principles',
|
||||
'process_change': 'resolution_failure',
|
||||
'assessment': 'dispute_assessment',
|
||||
'situation': 'dispute_assessment',
|
||||
'reflection': 'deliberation_conclusion',
|
||||
'monitoring': 'dispute_assessment',
|
||||
'participation_requirement': 'participant_inclusion'
|
||||
};
|
||||
|
||||
allModules.forEach(module => {
|
||||
// If module has no stageId, try to infer from category
|
||||
if (!module.stageId && module.category) {
|
||||
// Check if category matches a known stage
|
||||
if (stageNames[module.category]) {
|
||||
module.stageId = module.category;
|
||||
} else {
|
||||
// Use category as stageId if not already recognized
|
||||
module.stageId = module.category;
|
||||
// Create a readable stage name from category
|
||||
stageNames[module.category] = module.category.charAt(0).toUpperCase() +
|
||||
module.category.slice(1).replace(/_/g, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
// If still no stageId, try to infer from componentId using the mapping
|
||||
if (!module.stageId && module.componentId) {
|
||||
const mappedStage = componentToStageMap[module.componentId];
|
||||
if (mappedStage) {
|
||||
module.stageId = mappedStage;
|
||||
console.log(`Module ${module.id} missing stageId, inferred from component: ${mappedStage}`);
|
||||
} else {
|
||||
// Default stage if no mapping exists
|
||||
module.stageId = 'process';
|
||||
console.log(`Module ${module.id} missing stageId, defaulting to: process`);
|
||||
}
|
||||
}
|
||||
|
||||
// If STILL no stageId (somehow), assign to process
|
||||
if (!module.stageId) {
|
||||
module.stageId = 'process';
|
||||
console.log(`Module ${module.id} had no stageId, assigned to: process`);
|
||||
}
|
||||
|
||||
// Force module to use only official stages
|
||||
if (officialStages[module.stageId]) {
|
||||
// Use official stage name
|
||||
module.stageName = officialStages[module.stageId];
|
||||
} else {
|
||||
// Map to closest official stage
|
||||
const mappedStage = componentToStageMap[module.componentId];
|
||||
if (mappedStage && officialStages[mappedStage]) {
|
||||
module.stageId = mappedStage;
|
||||
module.stageName = officialStages[mappedStage];
|
||||
console.log(`Module ${module.id} had invalid stage "${module.stageId}", remapped to: ${mappedStage}`);
|
||||
} else {
|
||||
// Default to Process stage if can't map anywhere else
|
||||
module.stageId = 'process';
|
||||
module.stageName = officialStages['process'];
|
||||
console.log(`Module ${module.id} had invalid stage "${module.stageId}", defaulting to: Process`);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle component mapping for non-standard components
|
||||
if (componentMapping[module.componentId]) {
|
||||
const originalComponentId = module.componentId;
|
||||
module.componentId = componentMapping[originalComponentId];
|
||||
console.log(`Module ${module.id} had non-standard component "${originalComponentId}", mapped to: ${module.componentId}`);
|
||||
}
|
||||
|
||||
// Set a readable component name using official list
|
||||
if (officialComponents[module.componentId]) {
|
||||
module.componentName = officialComponents[module.componentId];
|
||||
} else {
|
||||
// Generate a readable name for custom components
|
||||
module.componentName = module.componentId.charAt(0).toUpperCase() +
|
||||
module.componentId.slice(1).replace(/_/g, ' ');
|
||||
|
||||
// Log any component not in the official list
|
||||
console.log(`Module ${module.id} uses custom component: ${module.componentId}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Log the distribution of modules by stage
|
||||
const stageDistribution = {};
|
||||
allModules.forEach(module => {
|
||||
stageDistribution[module.stageName] = (stageDistribution[module.stageName] || 0) + 1;
|
||||
});
|
||||
console.log('Module distribution by stage:', stageDistribution);
|
||||
|
||||
console.log('Data initialization complete');
|
||||
console.log('Stages:', Object.keys(stageNames));
|
||||
console.log('Components:', Object.keys(componentNames));
|
||||
console.log('Templates:', Object.keys(templateUsage));
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error initializing data:', error);
|
||||
modulesContainer.innerHTML = `<div class="error">Error initializing data: ${error.message}</div>`;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function populateFilters() {
|
||||
console.log('Populating filters...');
|
||||
|
||||
// Clear existing options
|
||||
stageFilter.innerHTML = '<option value="">All Stages</option>';
|
||||
componentFilter.innerHTML = '<option value="">All Components</option>';
|
||||
templateFilter.innerHTML = '<option value="">All Templates</option>';
|
||||
|
||||
// Get unique stages and components
|
||||
const stages = [...new Set(allModules.map(m => m.stageName))].sort();
|
||||
const components = [...new Set(allModules.map(m => m.componentName))].sort();
|
||||
const templates = Object.keys(templateUsage).sort();
|
||||
|
||||
console.log('Filter options - Stages:', stages);
|
||||
console.log('Filter options - Components:', components);
|
||||
console.log('Filter options - Templates:', templates);
|
||||
|
||||
// Add options to filters
|
||||
stages.forEach(stage => {
|
||||
const option = document.createElement('option');
|
||||
option.value = stage;
|
||||
option.textContent = stage;
|
||||
stageFilter.appendChild(option);
|
||||
});
|
||||
|
||||
components.forEach(component => {
|
||||
const option = document.createElement('option');
|
||||
option.value = component;
|
||||
option.textContent = component;
|
||||
componentFilter.appendChild(option);
|
||||
});
|
||||
|
||||
templates.forEach(template => {
|
||||
const option = document.createElement('option');
|
||||
option.value = template;
|
||||
option.textContent = template;
|
||||
templateFilter.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
function renderModules() {
|
||||
console.log('Rendering modules...');
|
||||
|
||||
// Clear container
|
||||
modulesContainer.innerHTML = '';
|
||||
|
||||
// Get filter values
|
||||
const searchText = moduleSearch.value.toLowerCase();
|
||||
const stageValue = stageFilter.value;
|
||||
const componentValue = componentFilter.value;
|
||||
const templateValue = templateFilter.value;
|
||||
|
||||
console.log('Filter values:', {
|
||||
search: searchText,
|
||||
stage: stageValue,
|
||||
component: componentValue,
|
||||
template: templateValue
|
||||
});
|
||||
|
||||
// Create a stage-based organization of modules
|
||||
const modulesByStage = {};
|
||||
|
||||
// Filter modules based on search and filter criteria
|
||||
allModules.forEach(module => {
|
||||
// Check if module matches search text
|
||||
const matchesSearch = searchText === '' ||
|
||||
module.title.toLowerCase().includes(searchText) ||
|
||||
(module.content && module.content.toLowerCase().includes(searchText));
|
||||
|
||||
// Check if module matches stage filter
|
||||
const matchesStage = stageValue === '' || module.stageName === stageValue;
|
||||
|
||||
// Check if module matches component filter
|
||||
const matchesComponent = componentValue === '' || module.componentName === componentValue;
|
||||
|
||||
// Check if module matches template filter
|
||||
const matchesTemplate = templateValue === '' ||
|
||||
module.usedInTemplates.includes(templateValue);
|
||||
|
||||
// Include module if it matches all criteria
|
||||
if (matchesSearch && matchesStage && matchesComponent && matchesTemplate) {
|
||||
// Initialize stage object if not exists
|
||||
if (!modulesByStage[module.stageName]) {
|
||||
modulesByStage[module.stageName] = [];
|
||||
}
|
||||
|
||||
// Add module to its stage
|
||||
modulesByStage[module.stageName].push(module);
|
||||
}
|
||||
});
|
||||
|
||||
// Sort stages according to the official order from the YAML file
|
||||
const stageOrder = [
|
||||
'Intake', 'Process', 'Assessment',
|
||||
'Deliberation', 'Resolution', 'Appeal', 'Delegation'
|
||||
];
|
||||
|
||||
// Get all stages from the data
|
||||
const availableStages = Object.keys(modulesByStage);
|
||||
|
||||
// Sort stages according to the defined order, with any others at the end
|
||||
const sortedStages = [];
|
||||
|
||||
// First add stages in the predefined order (if they exist in the data)
|
||||
stageOrder.forEach(stage => {
|
||||
if (availableStages.includes(stage)) {
|
||||
sortedStages.push(stage);
|
||||
}
|
||||
});
|
||||
|
||||
// Then add any other stages not in the predefined order (sorted alphabetically)
|
||||
availableStages
|
||||
.filter(stage => !stageOrder.includes(stage))
|
||||
.sort()
|
||||
.forEach(stage => sortedStages.push(stage));
|
||||
|
||||
// If no modules match, show message
|
||||
if (sortedStages.length === 0) {
|
||||
modulesContainer.innerHTML = '<div class="no-results">No modules match your search criteria</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Create HTML for each stage and its modules
|
||||
sortedStages.forEach(stageName => {
|
||||
const stageModules = modulesByStage[stageName];
|
||||
|
||||
// Create stage section using similar structure to builder
|
||||
const stageSection = document.createElement('div');
|
||||
stageSection.className = 'stage-section';
|
||||
|
||||
// Create stage header
|
||||
const stageHeader = document.createElement('div');
|
||||
stageHeader.className = 'stage-header';
|
||||
|
||||
const stageHeaderContent = document.createElement('div');
|
||||
stageHeaderContent.className = 'stage-header-content';
|
||||
stageHeaderContent.innerHTML = `
|
||||
<h2>${stageName}</h2>
|
||||
<div class="stage-brief">
|
||||
Contains ${stageModules.length} module${stageModules.length !== 1 ? 's' : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Create toggle button
|
||||
const toggleBtn = document.createElement('button');
|
||||
toggleBtn.className = 'toggle-btn';
|
||||
toggleBtn.innerHTML = '+';
|
||||
toggleBtn.setAttribute('aria-label', 'Toggle stage content');
|
||||
|
||||
stageHeader.appendChild(stageHeaderContent);
|
||||
stageHeader.appendChild(toggleBtn);
|
||||
stageSection.appendChild(stageHeader);
|
||||
|
||||
// Create stage body
|
||||
const stageBody = document.createElement('div');
|
||||
stageBody.className = 'stage-body';
|
||||
stageBody.style.display = 'none';
|
||||
|
||||
// Group modules by component
|
||||
const modulesByComponent = {};
|
||||
stageModules.forEach(module => {
|
||||
// Use just the component name without duplicating stage info
|
||||
const cleanComponentName = module.componentName.replace(module.stageName, '').trim();
|
||||
const displayComponentName = cleanComponentName || module.componentName;
|
||||
|
||||
if (!modulesByComponent[displayComponentName]) {
|
||||
modulesByComponent[displayComponentName] = [];
|
||||
}
|
||||
modulesByComponent[displayComponentName].push(module);
|
||||
});
|
||||
|
||||
// Sort components
|
||||
const sortedComponents = Object.keys(modulesByComponent).sort();
|
||||
|
||||
// Create components container
|
||||
const componentsContainer = document.createElement('div');
|
||||
componentsContainer.className = 'components';
|
||||
|
||||
// Create component sections
|
||||
sortedComponents.forEach(componentName => {
|
||||
const componentModules = modulesByComponent[componentName];
|
||||
|
||||
// Create a component group heading with count
|
||||
const componentHeading = document.createElement('h3');
|
||||
componentHeading.className = 'component-group-heading';
|
||||
|
||||
// Create main text
|
||||
const headingText = document.createTextNode(componentName);
|
||||
componentHeading.appendChild(headingText);
|
||||
|
||||
// Add count in parentheses
|
||||
const moduleCount = componentModules.length;
|
||||
const countSpan = document.createElement('span');
|
||||
countSpan.className = 'component-module-count';
|
||||
countSpan.textContent = ` (${moduleCount} module${moduleCount !== 1 ? 's' : ''})`;
|
||||
componentHeading.appendChild(countSpan);
|
||||
|
||||
componentsContainer.appendChild(componentHeading);
|
||||
|
||||
// Add modules to component section
|
||||
componentModules.forEach(module => {
|
||||
const moduleCard = createModuleCard(module);
|
||||
componentsContainer.appendChild(moduleCard);
|
||||
});
|
||||
});
|
||||
|
||||
stageBody.appendChild(componentsContainer);
|
||||
stageSection.appendChild(stageBody);
|
||||
|
||||
// Add toggle functionality
|
||||
stageHeaderContent.addEventListener('click', function() {
|
||||
if (stageBody.style.display === 'none') {
|
||||
stageBody.style.display = 'block';
|
||||
toggleBtn.innerHTML = '−';
|
||||
} else {
|
||||
stageBody.style.display = 'none';
|
||||
toggleBtn.innerHTML = '+';
|
||||
}
|
||||
});
|
||||
|
||||
toggleBtn.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
if (stageBody.style.display === 'none') {
|
||||
stageBody.style.display = 'block';
|
||||
toggleBtn.innerHTML = '−';
|
||||
} else {
|
||||
stageBody.style.display = 'none';
|
||||
toggleBtn.innerHTML = '+';
|
||||
}
|
||||
});
|
||||
|
||||
modulesContainer.appendChild(stageSection);
|
||||
});
|
||||
|
||||
console.log('Modules rendering complete');
|
||||
}
|
||||
|
||||
function createModuleCard(module) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'component-card';
|
||||
card.dataset.id = module.id;
|
||||
|
||||
// Format templates list
|
||||
const templatesList = module.usedInTemplates.length > 0
|
||||
? module.usedInTemplates.join(', ')
|
||||
: 'Not used in any template';
|
||||
|
||||
// Create card content with structure similar to builder component
|
||||
card.innerHTML = `
|
||||
<div class="component-header">
|
||||
<h3>${module.title}</h3>
|
||||
</div>
|
||||
<div class="component-body">
|
||||
<div class="module-meta">
|
||||
<span class="tag stage-tag">${module.stageName}</span>
|
||||
<span class="tag component-tag">${module.componentName}</span>
|
||||
</div>
|
||||
<div class="module-content">
|
||||
<textarea readonly>${module.content}</textarea>
|
||||
</div>
|
||||
<div class="module-templates">
|
||||
<strong>Used in templates:</strong> ${templatesList}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Make the header clickable to toggle content visibility
|
||||
const header = card.querySelector('.component-header');
|
||||
const body = card.querySelector('.component-body');
|
||||
|
||||
// Add toggle button to the header (already positioned by CSS flexbox)
|
||||
const toggleBtn = document.createElement('button');
|
||||
toggleBtn.className = 'toggle-btn';
|
||||
toggleBtn.innerHTML = '+';
|
||||
toggleBtn.setAttribute('aria-label', 'Toggle module content');
|
||||
header.appendChild(toggleBtn);
|
||||
|
||||
// Start with content hidden
|
||||
body.style.display = 'none';
|
||||
|
||||
// Toggle functionality
|
||||
function toggleContent() {
|
||||
if (body.style.display === 'none') {
|
||||
body.style.display = 'block';
|
||||
toggleBtn.innerHTML = '−';
|
||||
card.classList.add('expanded');
|
||||
} else {
|
||||
body.style.display = 'none';
|
||||
toggleBtn.innerHTML = '+';
|
||||
card.classList.remove('expanded');
|
||||
}
|
||||
}
|
||||
|
||||
header.addEventListener('click', toggleContent);
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
// Initialize page
|
||||
function init() {
|
||||
console.log('Initializing modules page...');
|
||||
|
||||
// Load data
|
||||
if (!initializeData()) {
|
||||
console.error('Failed to initialize data');
|
||||
return;
|
||||
}
|
||||
|
||||
// Populate filters
|
||||
populateFilters();
|
||||
|
||||
// Render modules
|
||||
renderModules();
|
||||
|
||||
// Add event listeners to filters
|
||||
moduleSearch.addEventListener('input', renderModules);
|
||||
stageFilter.addEventListener('change', renderModules);
|
||||
componentFilter.addEventListener('change', renderModules);
|
||||
templateFilter.addEventListener('change', renderModules);
|
||||
|
||||
console.log('Modules page initialized with', allModules.length, 'modules');
|
||||
}
|
||||
|
||||
// Start initialization
|
||||
init();
|
||||
});
|
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 }}
|
0
themes/dispute-protocol-theme/layouts/_default/list.html
Normal file
0
themes/dispute-protocol-theme/layouts/_default/list.html
Normal file
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