|
|
| Line 1: |
Line 1: |
| <includeonly><!-- Template:JourneyMaterials - Enhanced Interactive Version -->
| |
| {{#get_external_data: | | {{#get_external_data: |
| source = externaldb | | source = externaldb |
| Line 10: |
Line 9: |
|
| |
|
|
| |
|
| <div class="journey-materials-wrapper" data-journey-id="{{{id|{{{1|}}}}}}"> | | <div class="materials-container" style="max-height:600px;overflow-y:auto;"> |
| <!-- Level 1 Materials (Left Column) -->
| | {{#vardefine:current_level|0}}{{#vardefine:tier_open|false}} |
| <div class="materials-column level-1-column">
| |
| <div class="column-header">
| |
| <span class="header-icon">📦</span>
| |
| Direct Materials
| |
| </div>
| |
| <div class="materials-list">
| |
| {{#for_external_table:|{{#ifeq:{{{Level}}}|1|
| |
| <div class="material-item level-1" data-item="{{{ItemLabel}}}">
| |
| <input type="checkbox" class="material-checkbox" id="mat-{{{id|{{{1|}}}}}}-{{#replace:{{{ItemLabel}}}| |-}}" />
| |
| <label for="mat-{{{id|{{{1|}}}}}}-{{#replace:{{{ItemLabel}}}| |-}}">
| |
| <span class="material-icon">
| |
| {{#ifexist:File:{{#replace:{{{ItemLabel}}}| |_}}_-_Icon.png
| |
| |[[File:{{#replace:{{{ItemLabel}}}| |_}}_-_Icon.png|24px|link=]]
| |
| |<span class="icon-placeholder">●</span>
| |
| }}
| |
| </span>
| |
| <span class="material-name">{{{ItemLabel}}}</span>
| |
| <span class="material-qty">×{{{TotalQty}}}</span>
| |
| </label>
| |
| </div>
| |
| |}}}}
| |
| </div>
| |
| </div>
| |
|
| |
|
| <!-- Level 2+ Materials (Right Column) --> | | {{#for_external_table:| |
| <div class="materials-column components-column">
| | {{#ifeq:{{{Level}}}|{{#var:current_level}}|| |
| <div class="column-header">
| | {{#ifeq:{{#var:tier_open}}|true|</div>|}} |
| <span class="header-icon">🔧</span>
| | <div class="materials-tier level-{{{Level}}}"> |
| Components Needed
| | <div class="tier-header">{{#switch:{{{Level}}} |
| </div>
| | |1=Direct Materials Required |
| <div class="materials-list"> | | |2=Components for Level 1 Materials |
| {{#vardefine:current_level|2}} | | |3=Base Resources Needed |
| {{#for_external_table:|{{#ifexpr:{{{Level}}} >= 2| | | |#default=Level {{{Level}}} Materials |
| {{#ifeq:{{{Level}}}|{{#var:current_level}}|| | | }}</div> |
| <div class="level-separator">Level {{{Level}}} Components</div>
| | {{#vardefine:tier_open|true}} |
| {{#vardefine:current_level|{{{Level}}}}} | | {{#vardefine:current_level|{{{Level}}}}} |
| | }} |
| | <div class="material-item"> |
| | <span class="material-icon"> |
| | {{#ifexist:File:{{#replace:{{{ItemLabel}}}| |_}}_-_Icon.png |
| | |[[File:{{#replace:{{{ItemLabel}}}| |_}}_-_Icon.png|20px|link=]] |
| | | |
| }} | | }} |
| <div class="material-item level-{{{Level}}}" data-level="{{{Level}}}" data-item="{{{ItemLabel}}}">
| | </span> |
| <input type="checkbox" class="material-checkbox component-checkbox"
| | <span class="material-name">{{{ItemLabel}}}</span> |
| id="comp-{{{id|{{{1|}}}}}}-{{#replace:{{{ItemLabel}}}| |-}}-{{{Level}}}" />
| | <span class="material-qty">{{{TotalQty}}}</span> |
| <label for="comp-{{{id|{{{1|}}}}}}-{{#replace:{{{ItemLabel}}}| |-}}-{{{Level}}}">
| |
| <span class="material-icon">
| |
| {{#ifexist:File:{{#replace:{{{ItemLabel}}}| |_}}_-_Icon.png
| |
| |[[File:{{#replace:{{{ItemLabel}}}| |_}}_-_Icon.png|20px|link=]]
| |
| |<span class="icon-placeholder level-{{{Level}}}">○</span>
| |
| }}
| |
| </span>
| |
| <span class="material-name">{{{ItemLabel}}}</span>
| |
| <span class="material-qty">×{{{TotalQty}}}</span>
| |
| </label>
| |
| </div>
| |
| |}}}}
| |
| </div>
| |
| </div> | | </div> |
| | }} |
| | |
| | {{#ifeq:{{#var:tier_open}}|true|</div>|}} |
| </div> | | </div> |
| | | </includeonly><noinclude>{{Documentation}}</noinclude> |
| <!-- Add CSS -->
| |
| <style>
| |
| .journey-materials-wrapper {
| |
| display: flex;
| |
| gap: 20px;
| |
| max-height: 500px;
| |
| background: rgba(0, 0, 0, 0.9);
| |
| border: 1px solid #444;
| |
| border-radius: 8px;
| |
| padding: 15px;
| |
| }
| |
| | |
| .materials-column {
| |
| flex: 1;
| |
| display: flex;
| |
| flex-direction: column;
| |
| min-width: 250px;
| |
| }
| |
| | |
| .level-1-column {
| |
| border-right: 1px solid #333;
| |
| padding-right: 20px;
| |
| }
| |
| | |
| .column-header {
| |
| display: flex;
| |
| align-items: center;
| |
| gap: 8px;
| |
| padding: 10px 0;
| |
| margin-bottom: 10px;
| |
| border-bottom: 2px solid #555;
| |
| font-weight: bold;
| |
| font-size: 16px;
| |
| color: #fff;
| |
| }
| |
| | |
| .header-icon {
| |
| font-size: 20px;
| |
| }
| |
| | |
| .materials-list {
| |
| overflow-y: auto;
| |
| overflow-x: hidden;
| |
| flex: 1;
| |
| padding-right: 5px;
| |
| }
| |
| | |
| .material-item {
| |
| display: flex;
| |
| align-items: center;
| |
| padding: 6px 8px;
| |
| margin-bottom: 4px;
| |
| border-radius: 4px;
| |
| transition: all 0.2s;
| |
| background: rgba(255, 255, 255, 0.02);
| |
| }
| |
| | |
| .material-item:hover {
| |
| background: rgba(255, 255, 255, 0.08);
| |
| }
| |
| | |
| .material-item.checked {
| |
| background: rgba(76, 175, 80, 0.2);
| |
| opacity: 0.8;
| |
| }
| |
| | |
| .material-checkbox {
| |
| width: 18px;
| |
| height: 18px;
| |
| margin-right: 10px;
| |
| cursor: pointer;
| |
| accent-color: #4CAF50;
| |
| }
| |
| | |
| .material-item label {
| |
| display: flex;
| |
| align-items: center;
| |
| gap: 8px;
| |
| flex: 1;
| |
| cursor: pointer;
| |
| }
| |
| | |
| .material-icon {
| |
| width: 24px;
| |
| height: 24px;
| |
| display: flex;
| |
| align-items: center;
| |
| justify-content: center;
| |
| }
| |
| | |
| .icon-placeholder {
| |
| font-size: 16px;
| |
| color: #888;
| |
| }
| |
| | |
| .material-name {
| |
| flex: 1;
| |
| color: #ddd;
| |
| font-size: 14px;
| |
| }
| |
| | |
| .material-qty {
| |
| font-weight: bold;
| |
| color: #ffa500;
| |
| font-size: 14px;
| |
| margin-left: auto;
| |
| }
| |
| | |
| .level-separator {
| |
| font-size: 12px;
| |
| color: #888;
| |
| margin: 10px 0 5px;
| |
| padding: 5px 0;
| |
| border-top: 1px dashed #444;
| |
| }
| |
| | |
| /* Level-based styling */
| |
| .level-1 .material-name { color: #4CAF50; }
| |
| .level-2 .material-name { color: #2196F3; }
| |
| .level-3 .material-name { color: #FF9800; }
| |
| .level-4 .material-name { color: #9C27B0; }
| |
| | |
| /* Scrollbar styling */
| |
| .materials-list::-webkit-scrollbar {
| |
| width: 6px;
| |
| }
| |
| | |
| .materials-list::-webkit-scrollbar-track {
| |
| background: #222;
| |
| }
| |
| | |
| .materials-list::-webkit-scrollbar-thumb {
| |
| background: #555;
| |
| border-radius: 3px;
| |
| }
| |
| | |
| /* Responsive */
| |
| @media (max-width: 600px) {
| |
| .journey-materials-wrapper {
| |
| flex-direction: column;
| |
| max-height: 600px;
| |
| }
| |
|
| |
| .level-1-column {
| |
| border-right: none;
| |
| border-bottom: 1px solid #333;
| |
| padding-right: 0;
| |
| padding-bottom: 15px;
| |
| }
| |
| }
| |
| </style>
| |
| | |
| <!-- Add JavaScript for interactive checkboxes -->
| |
| <script>
| |
| (function() {
| |
| const wrapper = document.querySelector('.journey-materials-wrapper[data-journey-id="{{{id|{{{1|}}}}}}"]');
| |
| if (!wrapper) return;
| |
|
| |
| const checkboxes = wrapper.querySelectorAll('.material-checkbox');
| |
|
| |
| checkboxes.forEach(checkbox => {
| |
| checkbox.addEventListener('change', function() {
| |
| const item = this.closest('.material-item');
| |
| if (this.checked) {
| |
| item.classList.add('checked');
| |
| } else {
| |
| item.classList.remove('checked');
| |
| }
| |
|
| |
| // Save state to localStorage
| |
| const journeyId = wrapper.dataset.journeyId;
| |
| const itemId = this.id;
| |
| const checkedItems = JSON.parse(localStorage.getItem(`journey_${journeyId}_checked`) || '{}');
| |
| checkedItems[itemId] = this.checked;
| |
| localStorage.setItem(`journey_${journeyId}_checked`, JSON.stringify(checkedItems));
| |
|
| |
| // Check if all components are checked (for auto-checking direct materials)
| |
| checkDirectMaterialsCompletion();
| |
| });
| |
| });
| |
|
| |
| // Restore saved state
| |
| const journeyId = wrapper.dataset.journeyId;
| |
| const checkedItems = JSON.parse(localStorage.getItem(`journey_${journeyId}_checked`) || '{}');
| |
| Object.keys(checkedItems).forEach(itemId => {
| |
| const checkbox = document.getElementById(itemId);
| |
| if (checkbox && checkedItems[itemId]) {
| |
| checkbox.checked = true;
| |
| checkbox.closest('.material-item').classList.add('checked');
| |
| }
| |
| });
| |
|
| |
| // Function to check if all components for a material are complete
| |
| function checkDirectMaterialsCompletion() {
| |
| // This is a simplified version - you'd need to map which components
| |
| // belong to which direct materials based on your recipe data
| |
| const allComponentsChecked = wrapper.querySelectorAll('.component-checkbox:not(:checked)').length === 0;
| |
|
| |
| if (allComponentsChecked) {
| |
| // Visual indicator that all components are ready
| |
| wrapper.querySelector('.components-column').style.borderColor = '#4CAF50';
| |
| }
| |
| }
| |
|
| |
| // Add clear all button
| |
| const header = wrapper.querySelector('.column-header');
| |
| const clearBtn = document.createElement('button');
| |
| clearBtn.textContent = 'Clear All';
| |
| clearBtn.style.cssText = 'margin-left: auto; font-size: 12px; padding: 4px 8px; background: #666; border: none; border-radius: 4px; color: white; cursor: pointer;';
| |
| clearBtn.onclick = function() {
| |
| checkboxes.forEach(cb => {
| |
| cb.checked = false;
| |
| cb.closest('.material-item').classList.remove('checked');
| |
| });
| |
| localStorage.removeItem(`journey_${journeyId}_checked`);
| |
| };
| |
| header.appendChild(clearBtn);
| |
| })();
| |
| </script>
| |
| </includeonly><noinclude> | |
| {{Documentation}} | |
| </noinclude> | |
The query SELECT level,item_label,total_qty FROM `data_journey_materials` WHERE journey_id = ORDER BY level, item_label is invalid (Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'ORDER BY level, item_label' at line 1
Function: EDConnectorRdbms::fetch
Query: SELECT level,item_label,total_qty FROM `data_journey_materials` WHERE journey_id = ORDER BY level, item_label
).
</includeonly>Template:Documentation