39145-vm/update_html.py
2026-03-13 11:47:52 +00:00

107 lines
3.9 KiB
Python

import os
path = "core/templates/core/project_detail.html"
with open(path, "r") as f:
html = f.read()
# 1. Add top bar buttons (Layout, Zoom, etc)
buttons_to_add = """
<select id="layout-select" class="form-select form-select-sm d-inline-block w-auto me-2" onchange="changeLayout(this.value)">
<option value="organic">Organic Layout</option>
<option value="hierarchical">Hierarchical Layout</option>
</select>
<div class="btn-group btn-group-sm me-2" role="group">
<button type="button" class="btn btn-outline-secondary" onclick="zoomIn()" title="Zoom In">+</button>
<button type="button" class="btn btn-outline-secondary" onclick="zoomOut()" title="Zoom Out">-</button>
</div>"""
html = html.replace('<button class="btn btn-sm btn-outline-primary" onclick="fitNetwork()">Reset View</button>',
buttons_to_add + '\n <button class="btn btn-sm btn-outline-primary" onclick="fitNetwork()">Reset View</button>')
# 2. Add emoji logic
emoji_script = """
const categoryEmojis = {
'Strategy': '🎯',
'Product': '📦',
'Market': '🌍',
'Operations': '⚙️',
'Finance': '💰',
'General': '💡'
};
function getNodeEmoji(category) {
let cat = category || 'General';
for (let key in categoryEmojis) {
if (cat.toLowerCase().includes(key.toLowerCase())) {
return categoryEmojis[key];
}
}
return '💡'; // default emoji
}
"""
html = html.replace('function getNodeColor(category) {', emoji_script + '\n function getNodeColor(category) {')
# update node array to include emoji
html = html.replace('label: "{{ node.title|escapejs }}",', 'label: getNodeEmoji("{{ node.category|escapejs }}") + " " + "{{ node.title|escapejs }}",')
# 3. Add script functions for zoom and layout
scripts_to_add = """
function zoomIn() {
if (network) {
const scale = network.getScale() * 1.5;
network.moveTo({ scale: scale, animation: { duration: 300, easingFunction: 'easeInOutQuad' } });
}
}
function zoomOut() {
if (network) {
const scale = network.getScale() / 1.5;
network.moveTo({ scale: scale, animation: { duration: 300, easingFunction: 'easeInOutQuad' } });
}
}
function changeLayout(layoutType) {
if (layoutType === 'hierarchical') {
network.setOptions({
layout: {
hierarchical: {
enabled: true,
direction: 'UD',
sortMethod: 'directed',
nodeSpacing: 200,
levelSeparation: 150
}
},
physics: {
hierarchicalRepulsion: {
nodeDistance: 200
}
}
});
} else {
network.setOptions({
layout: { hierarchical: { enabled: false } },
physics: {
solver: 'forceAtlas2Based',
forceAtlas2Based: {
gravitationalConstant: -100,
centralGravity: 0.01,
springLength: 150,
springConstant: 0.08
},
maxVelocity: 50,
minVelocity: 0.1,
timestep: 0.5,
stabilization: { iterations: 150 }
}
});
}
}
"""
hTml = html.replace('// Export Map function', scripts_to_add + '\n // Export Map function')
with open(path, "w") as f:
f.write(html)
print("Updated HTML!")