diff --git a/content/modules.md b/content/modules.md deleted file mode 100644 index d136deb..0000000 --- a/content/modules.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -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. \ No newline at end of file diff --git a/data/modules/assessment.yaml b/data/modules/assessment.yaml deleted file mode 100644 index be779cf..0000000 --- a/data/modules/assessment.yaml +++ /dev/null @@ -1,27 +0,0 @@ -- 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 \ No newline at end of file diff --git a/data/modules/delegation.yaml b/data/modules/delegation.yaml deleted file mode 100644 index 3cba09e..0000000 --- a/data/modules/delegation.yaml +++ /dev/null @@ -1,41 +0,0 @@ -- 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 \ No newline at end of file diff --git a/data/modules/filing.yaml b/data/modules/filing.yaml deleted file mode 100644 index 147028f..0000000 --- a/data/modules/filing.yaml +++ /dev/null @@ -1,21 +0,0 @@ -- 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 \ No newline at end of file diff --git a/data/modules/intake.yaml b/data/modules/intake.yaml deleted file mode 100644 index 96dd9c9..0000000 --- a/data/modules/intake.yaml +++ /dev/null @@ -1,104 +0,0 @@ -- 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 \ No newline at end of file diff --git a/data/modules/notification.yaml b/data/modules/notification.yaml deleted file mode 100644 index ff3c52f..0000000 --- a/data/modules/notification.yaml +++ /dev/null @@ -1,21 +0,0 @@ -- 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 \ No newline at end of file diff --git a/data/modules/participants.yaml b/data/modules/participants.yaml deleted file mode 100644 index fdd0dd2..0000000 --- a/data/modules/participants.yaml +++ /dev/null @@ -1,33 +0,0 @@ -- 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 \ No newline at end of file diff --git a/data/modules/principles.yaml b/data/modules/principles.yaml deleted file mode 100644 index c1ff1d1..0000000 --- a/data/modules/principles.yaml +++ /dev/null @@ -1,32 +0,0 @@ -- 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 \ No newline at end of file diff --git a/data/modules/process.yaml b/data/modules/process.yaml deleted file mode 100644 index c0056e3..0000000 --- a/data/modules/process.yaml +++ /dev/null @@ -1,65 +0,0 @@ -- 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 \ No newline at end of file diff --git a/data/modules/resolution.yaml b/data/modules/resolution.yaml deleted file mode 100644 index 669a488..0000000 --- a/data/modules/resolution.yaml +++ /dev/null @@ -1,41 +0,0 @@ -- 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 \ No newline at end of file diff --git a/static/css/main.css b/static/css/main.css index 8cd40c2..b553f58 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -74,139 +74,7 @@ nav ul li a:hover { border-bottom: 1px solid var(--dark-color); } -/* Modules Page Styles */ -.search-filter { - margin-bottom: 2rem; - padding: 1.5rem; - background-color: #f5f5f5; - border: 1px solid var(--border-color); - display: flex; - flex-wrap: wrap; - gap: 1rem; - box-shadow: 0 2px 4px rgba(0,0,0,0.05); - border-radius: 4px; -} - -.search-filter input, -.search-filter select { - padding: 0.8rem; - border: 1px solid var(--border-color); - border-radius: 4px; - font-size: 1rem; - transition: all 0.2s ease; - box-shadow: inset 0 1px 3px rgba(0,0,0,0.05); -} - -.search-filter input:focus, -.search-filter select:focus { - outline: none; - border-color: #000; - box-shadow: 0 0 0 2px rgba(0,0,0,0.1); -} - -.search-filter input { - flex-grow: 1; - min-width: 200px; -} - -.search-filter select { - min-width: 150px; - background-color: white; - cursor: pointer; - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23333' d='M10.3 3.3L6 7.6 1.7 3.3c-.4-.4-1-.4-1.4 0s-.4 1 0 1.4l5 5c.2.2.4.3.7.3s.5-.1.7-.3l5-5c.4-.4.4-1 0-1.4s-1-.4-1.4 0z'/%3E%3C/svg%3E"); - background-position: calc(100% - 10px) center; - background-repeat: no-repeat; - padding-right: 30px; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -.modules-container { - margin-top: 2rem; -} - -.module-stage { - margin-bottom: 3rem; -} - -.module-stage h2 { - border-bottom: 2px solid var(--primary-color); - padding-bottom: 0.5rem; - margin-bottom: 1.5rem; - font-size: 1.75rem; -} - -.module-component { - margin-bottom: 2rem; - padding-left: 1.5rem; -} - -.module-component h3 { - color: var(--secondary-color); - margin-bottom: 1rem; - font-size: 1.4rem; -} - -.module-card { - border: 1px solid var(--border-color); - margin-bottom: 1.5rem; - border-radius: 4px; - overflow: hidden; - background-color: var(--light-color); - box-shadow: 0 1px 3px rgba(0,0,0,0.1); - transition: box-shadow 0.3s ease; -} - -.module-card.expanded { - box-shadow: 0 3px 6px rgba(0,0,0,0.16); -} - -.module-header { - padding: 1rem 1.5rem; - background-color: #f5f5f5; - cursor: pointer; - display: flex; - justify-content: space-between; - align-items: flex-start; - flex-wrap: wrap; - transition: background-color 0.2s ease; - position: relative; -} - -.module-header:hover { - background-color: #e9e9e9; -} - -.module-header:after { - content: "▼"; - position: absolute; - right: 1rem; - top: 1rem; - font-size: 0.8rem; - color: var(--secondary-color); - transition: transform 0.3s ease; -} - -.expanded .module-header:after { - transform: rotate(180deg); -} - -.module-header h4 { - margin: 0; - font-size: 1.1rem; - color: var(--primary-color); - flex-grow: 1; - padding-right: 2rem; -} - -.module-tags { - display: flex; - gap: 0.5rem; - flex-wrap: wrap; - margin-top: 0.8rem; -} - +/* Tag styles for components */ .tag { display: inline-block; padding: 0.3rem 0.6rem; @@ -234,68 +102,6 @@ nav ul li a:hover { color: #6600cc; border: 1px solid rgba(102, 0, 204, 0.2); } - -/* Module Library specific styles */ -.modules-container .component-card { - margin-bottom: 1rem; - animation: fadeIn 0.3s ease; -} - -@keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } -} - -.modules-container .component-body { - padding: 1.5rem 2rem; - animation: slideDown 0.3s ease; -} - -@keyframes slideDown { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.module-meta { - display: flex; - flex-wrap: wrap; - gap: 0.5rem; - margin-bottom: 1.5rem; -} - -.module-content { - margin: 1.5rem 0; -} - -.module-content textarea { - width: 100%; - min-height: 180px; - padding: 1rem; - border: 1px solid var(--border-color); - font-family: inherit; - resize: vertical; - background-color: var(--light-color); - font-size: 1.05rem; - line-height: 1.6; - color: var(--secondary-color); -} - -.module-templates { - margin-top: 1.5rem; - padding-top: 1rem; - border-top: 1px solid var(--border-color); - font-size: 0.9rem; - color: var(--accent-color); -} - -.module-templates strong { - color: var(--secondary-color); font-weight: 600; margin-right: 0.5rem; } @@ -1150,14 +956,21 @@ input:checked + .toggle-slider:before { textarea { width: 100%; - min-height: 250px; padding: 1rem; border: 1px solid var(--border-color); font-family: inherit; - resize: vertical; + resize: none; background-color: var(--light-color); font-size: 1.05rem; line-height: 1.5; + overflow: hidden; + transition: height 0.3s ease; + min-height: 60px; + box-sizing: border-box; + margin-bottom: 0.5rem; + display: block; + word-wrap: break-word; + white-space: pre-wrap; } .builder-actions { diff --git a/static/js/builder.js b/static/js/builder.js index 410400b..7f4efbd 100644 --- a/static/js/builder.js +++ b/static/js/builder.js @@ -436,6 +436,8 @@ document.addEventListener('DOMContentLoaded', function() { // Apply the content to the textarea textarea.value = content; + // Height adjustment is now handled by the global script + // Store in protocol data protocol.stages[stageId][componentId][fieldId] = content; fieldsPopulated++; @@ -467,6 +469,9 @@ document.addEventListener('DOMContentLoaded', function() { if (previewModeActive) { markComponentsWithContent(); } + + // Dispatch custom event for textarea auto-resize + document.dispatchEvent(new CustomEvent('templateApplied')); } // No helper functions needed anymore as we've simplified the approach diff --git a/static/js/modules-page.js b/static/js/modules-page.js deleted file mode 100644 index f8aa0ee..0000000 --- a/static/js/modules-page.js +++ /dev/null @@ -1,695 +0,0 @@ -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 = '
Error: Module data not available
'; - return false; - } - - if (typeof rawProtocolTemplates === 'undefined' || typeof templateMapper === 'undefined') { - console.error('Error: Template data or mapper not available'); - modulesContainer.innerHTML = '
Error: Template data not available
'; - 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 = `
Error initializing data: ${error.message}
`; - return false; - } - } - - function populateFilters() { - console.log('Populating filters...'); - - // Clear existing options - stageFilter.innerHTML = ''; - componentFilter.innerHTML = ''; - templateFilter.innerHTML = ''; - - // 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 = '
No modules match your search criteria
'; - 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 = ` -

${stageName}

-
- Contains ${stageModules.length} module${stageModules.length !== 1 ? 's' : ''} -
- `; - - // 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 = ` -
-

${module.title}

-
-
-
- ${module.stageName} - ${module.componentName} -
-
- -
-
- Used in templates: ${templatesList} -
-
- `; - - // 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(); -}); \ No newline at end of file diff --git a/themes/dispute-protocol-theme/layouts/_default/builder.html b/themes/dispute-protocol-theme/layouts/_default/builder.html index d142407..24d334a 100644 --- a/themes/dispute-protocol-theme/layouts/_default/builder.html +++ b/themes/dispute-protocol-theme/layouts/_default/builder.html @@ -58,7 +58,7 @@ - + {{ end }} @@ -165,6 +165,8 @@ document.addEventListener('DOMContentLoaded', function() { }); }); + // Textarea auto-resizing is now handled by the script in head.html + // Export dropdown removed (moved to sidebar) // Preview Mode Toggle diff --git a/themes/dispute-protocol-theme/layouts/_default/modules.html b/themes/dispute-protocol-theme/layouts/_default/modules.html deleted file mode 100644 index 60fe0e9..0000000 --- a/themes/dispute-protocol-theme/layouts/_default/modules.html +++ /dev/null @@ -1,36 +0,0 @@ -{{ define "main" }} -
- - -
- {{ .Content }} -
- -
- - - - -
- -
- -
Loading modules...
-
-
- - - - - - -{{ end }} \ No newline at end of file diff --git a/themes/dispute-protocol-theme/layouts/partials/head.html b/themes/dispute-protocol-theme/layouts/partials/head.html index 2490bdb..fce8839 100644 --- a/themes/dispute-protocol-theme/layouts/partials/head.html +++ b/themes/dispute-protocol-theme/layouts/partials/head.html @@ -18,6 +18,82 @@ + + + {{ end }} diff --git a/themes/dispute-protocol-theme/layouts/partials/header.html b/themes/dispute-protocol-theme/layouts/partials/header.html index f7716e0..cdb29a0 100644 --- a/themes/dispute-protocol-theme/layouts/partials/header.html +++ b/themes/dispute-protocol-theme/layouts/partials/header.html @@ -7,7 +7,6 @@