JourneyMaterials: Difference between revisions
From Dune Awakening DB
mNo edit summary |
mNo edit summary |
||
| Line 1: | Line 1: | ||
<includeonly><!-- Template:JourneyMaterials - Enhanced Interactive Version --> | |||
{{#get_external_data: | {{#get_external_data: | ||
source = externaldb | source = externaldb | ||
| | |query = CALL sp_journey_components_bom({{{id|{{{1|}}}}}}) | ||
|data = Level = level, | |||
ItemLabel = item_label, | |||
| | TotalQty = total_qty | ||
|cache seconds = 3600 | |||
}} | }} | ||
<div class="journey-materials-wrapper" data-journey-id="{{{id|{{{1|}}}}}}"> | |||
<!-- Level 1 Materials (Left Column) --> | |||
<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) --> | |||
<div class="materials-column components-column"> | |||
<div class="column-header"> | |||
<span class="header-icon">🔧</span> | |||
Components Needed | |||
</div> | |||
<div class="materials-list"> | |||
{{#vardefine:current_level|2}} | |||
{{#for_external_table:|{{#ifexpr:{{{Level}}} >= 2| | |||
{{#ifeq:{{{Level}}}|{{#var:current_level}}|| | |||
<div class="level-separator">Level {{{Level}}} Components</div> | |||
{{#vardefine:current_level|{{{Level}}}}} | |||
}} | |||
<div class="material-item level-{{{Level}}}" data-level="{{{Level}}}" data-item="{{{ItemLabel}}}"> | |||
<input type="checkbox" class="material-checkbox component-checkbox" | |||
id="comp-{{{id|{{{1|}}}}}}-{{#replace:{{{ItemLabel}}}| |-}}-{{{Level}}}" /> | |||
<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> | |||
<!-- 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> | ||
</includeonly><noinclude>{{Documentation}}</noinclude> | (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> | |||
