littlefs/src/components/ModulationPage.astro
2026-05-21 20:41:03 +02:00

505 lines
22 KiB
Text

---
// This is server-side - runs at build time
const pageTitle = "Modulation";
---
<div class="flex flex-col gap-4">
<h1 class="text-2xl font-bold">Laser Modulation</h1>
<!-- Modulation Mode Selection -->
<div class="card bg-base-200 shadow">
<div class="card-body bg-base-200 rounded-lg">
<h2 class="card-title">Modulation Mode</h2>
<!-- Main Mode Tabs - Keep horizontal even on mobile -->
<div class="tabs tabs-boxed mb-4">
<button class="tab tab-active flex-1" id="internal-tab" onclick="if('vibrate' in navigator) navigator.vibrate(15)">
<svg class="w-4 h-4 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M9 12l2 2 4-4"/>
<path d="M21 12c-1 0-3-1-3-3s2-3 3-3 3 1 3 3-2 3-3 3"/>
<path d="M3 12c1 0 3-1 3-3s-2-3-3-3-3 1-3 3 2 3 3 3"/>
<path d="M3 12h6m6 0h6"/>
</svg>
Internal
</button>
<button class="tab flex-1" id="external-tab" onclick="if('vibrate' in navigator) navigator.vibrate(15)">
<svg class="w-4 h-4 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M6 3v12"/>
<path d="M18 3v12"/>
<path d="M6 21l12-9-12-3z"/>
</svg>
External
</button>
</div>
<!-- Internal Modes - Stack on mobile -->
<div id="internal-modes" class="mb-4">
<h3 class="font-medium mb-3">Internal Modulation Modes</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-2">
<button class="btn btn-active" id="cc-tab" onclick="if('vibrate' in navigator) navigator.vibrate(15)">
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
</svg>
Constant Current
</button>
<button class="btn" id="cp-tab" onclick="if('vibrate' in navigator) navigator.vibrate(15)">
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="4"/>
<path d="M12 2v2"/>
<path d="M12 20v2"/>
<path d="m4.93 4.93 1.41 1.41"/>
<path d="m17.66 17.66 1.41 1.41"/>
<path d="M2 12h2"/>
<path d="M20 12h2"/>
<path d="m6.34 17.66-1.41 1.41"/>
<path d="m19.07 4.93-1.41 1.41"/>
</svg>
Constant Power
</button>
<button class="btn" id="pattern-continuous-tab" onclick="if('vibrate' in navigator) navigator.vibrate(15)">
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12h6l4 8 4-16 4 8h6"/>
</svg>
Pattern Continuous
</button>
<button class="btn" id="pattern-triggered-tab" onclick="if('vibrate' in navigator) navigator.vibrate(15)">
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M8 6l4-4 4 4"/>
<path d="M12 3v9"/>
<path d="M3 12h6l4 8 4-8h6"/>
</svg>
Pattern Triggered
</button>
</div>
</div>
<!-- External Modes - Stack on mobile -->
<div id="external-modes" class="mb-4 hidden">
<h3 class="font-medium mb-3">External Modulation Modes</h3>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-2">
<button class="btn btn-active" id="ttl-tab" onclick="if('vibrate' in navigator) navigator.vibrate(15)">
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M5 12h14"/>
<path d="M5 12v7"/>
<path d="M19 12v7"/>
<path d="M5 5v7"/>
<path d="M19 5v7"/>
</svg>
TTL
</button>
<button class="btn" id="mod2current-tab" onclick="if('vibrate' in navigator) navigator.vibrate(15)">
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 3v18h18"/>
<path d="M7 12l4-4 4 4 4-4"/>
</svg>
Mod2Current
</button>
<button class="btn" id="schmitt-trigger-tab" onclick="if('vibrate' in navigator) navigator.vibrate(15)">
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12h6l2-8 2 16 2-8h6"/>
</svg>
Schmitt Trigger
</button>
</div>
</div>
</div>
</div>
<!-- Mode Configuration Panels -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
<!-- Constant Current Panel -->
<div id="cc-panel" class="card bg-base-200 shadow">
<div class="card-body bg-base-200 rounded-lg">
<h2 class="card-title">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
</svg>
Constant Current Mode
</h2>
<div class="form-control">
<label class="label">
<span class="label-text">Current (A)</span>
<span class="label-text-alt">5.0A</span>
</label>
<input type="range" min="0" max="10" value="5" step="0.1" class="range range-primary" />
<div class="w-full flex justify-between text-xs px-2 mt-1">
<span>0A</span>
<span>2.5A</span>
<span>5.0A</span>
<span>7.5A</span>
<span>10.0A</span>
</div>
</div>
<div class="form-control mt-4">
<label class="cursor-pointer label justify-start gap-4">
<span class="label-text">Enable Soft Start</span>
<input type="checkbox" class="toggle toggle-success" checked onchange="updateToggleColor(this); if('vibrate' in navigator) navigator.vibrate(15)" />
</label>
</div>
<div class="alert alert-info mt-4">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="stroke-current shrink-0 w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span>Constant Current mode provides stable current output regardless of load changes.</span>
</div>
</div>
</div>
<!-- Constant Power Panel -->
<div id="cp-panel" class="card bg-base-200 shadow hidden">
<div class="card-body bg-base-200 rounded-lg">
<h2 class="card-title">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="4"/>
<path d="M12 2v2"/>
<path d="M12 20v2"/>
<path d="m4.93 4.93 1.41 1.41"/>
<path d="m17.66 17.66 1.41 1.41"/>
<path d="M2 12h2"/>
<path d="M20 12h2"/>
<path d="m6.34 17.66-1.41 1.41"/>
<path d="m19.07 4.93-1.41 1.41"/>
</svg>
Constant Power Mode
</h2>
<div class="form-control">
<label class="label">
<span class="label-text">Power (W)</span>
<span class="label-text-alt">5.0W</span>
</label>
<input type="range" min="0" max="10" value="5" step="0.1" class="range range-secondary" />
<div class="w-full flex justify-between text-xs px-2 mt-1">
<span>0W</span>
<span>2.5W</span>
<span>5.0W</span>
<span>7.5W</span>
<span>10.0W</span>
</div>
</div>
<div class="form-control mt-4">
<label class="cursor-pointer label justify-start gap-4">
<span class="label-text">Enable Feedback Control</span>
<input type="checkbox" class="toggle toggle-success" checked onchange="updateToggleColor(this); if('vibrate' in navigator) navigator.vibrate(15)" />
</label>
</div>
<div class="alert alert-info mt-4">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="stroke-current shrink-0 w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span>Constant Power mode uses feedback from the photodiode to maintain stable output power.</span>
</div>
</div>
</div>
<!-- Pattern Continuous Panel -->
<div id="pattern-continuous-panel" class="card bg-base-200 shadow hidden">
<div class="card-body bg-base-200 rounded-lg">
<h2 class="card-title">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12h6l4 8 4-16 4 8h6"/>
</svg>
Pattern Continuous Mode
</h2>
<div class="bg-base-200 rounded-lg p-6">
<div class="flex items-center justify-center h-40">
<div class="text-center">
<svg class="w-16 h-16 mx-auto mb-4 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2v20"/>
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
</svg>
<p class="text-lg font-bold">Coming Soon</p>
<p class="text-sm mt-2">Pattern configuration interface under development</p>
</div>
</div>
</div>
</div>
</div>
<!-- Pattern Triggered Panel -->
<div id="pattern-triggered-panel" class="card bg-base-200 shadow-xl border-l-4 border-l-warning hidden">
<div class="card-body bg-base-200 rounded-lg">
<h2 class="card-title text-warning">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M8 6l4-4 4 4"/>
<path d="M12 3v9"/>
<path d="M3 12h6l4 8 4-8h6"/>
</svg>
Pattern Triggered Mode
</h2>
<div class="bg-warning/5 border border-warning/20 rounded-lg p-6">
<div class="flex items-center justify-center h-40">
<div class="text-center">
<svg class="w-16 h-16 mx-auto mb-4 text-warning opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M8 6l4-4 4 4"/>
<path d="M12 3v9"/>
<path d="M3 12h6l4 8 4-8h6"/>
</svg>
<p class="text-lg font-bold">Coming Soon</p>
<p class="text-sm mt-2">Triggered pattern configuration interface under development</p>
</div>
</div>
</div>
</div>
</div>
<!-- TTL Panel -->
<div id="ttl-panel" class="card bg-base-200 shadow-xl border-l-4 border-l-info hidden">
<div class="card-body bg-base-200 rounded-lg">
<h2 class="card-title text-info">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M5 12h14"/>
<path d="M5 12v7"/>
<path d="M19 12v7"/>
<path d="M5 5v7"/>
<path d="M19 5v7"/>
</svg>
TTL Mode
</h2>
<div class="bg-info/5 border border-info/20 rounded-lg p-6">
<div class="flex items-center justify-center h-40">
<div class="text-center">
<svg class="w-16 h-16 mx-auto mb-4 text-info opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M5 12h14"/>
<path d="M5 12v7"/>
<path d="M19 12v7"/>
<path d="M5 5v7"/>
<path d="M19 5v7"/>
</svg>
<p class="text-lg font-bold">Coming Soon</p>
<p class="text-sm mt-2">TTL interface configuration under development</p>
</div>
</div>
</div>
</div>
</div>
<!-- Mod2Current Panel -->
<div id="mod2current-panel" class="card bg-base-200 shadow-xl border-l-4 border-l-success hidden">
<div class="card-body bg-base-200 rounded-lg">
<h2 class="card-title text-success">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 3v18h18"/>
<path d="M7 12l4-4 4 4 4-4"/>
</svg>
Mod2Current Mode
</h2>
<div class="bg-success/5 border border-success/20 rounded-lg p-4">
<div class="grid grid-cols-1 sm:grid-cols-3 gap-2 mb-4">
<button class="btn btn-active" onclick="if('vibrate' in navigator) navigator.vibrate(15)">0-5V</button>
<button class="btn" onclick="if('vibrate' in navigator) navigator.vibrate(15)">0-10V</button>
<button class="btn" onclick="if('vibrate' in navigator) navigator.vibrate(15)">Custom</button>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Current Limit (A)</span>
<span class="label-text-alt">7.5A</span>
</label>
<input type="range" min="0" max="10" value="7.5" step="0.1" class="range range-success" />
</div>
</div>
<div class="alert alert-info mt-4">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="stroke-current shrink-0 w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span>Mod2Current converts an analog input voltage to a proportional current output.</span>
</div>
</div>
</div>
<!-- Schmitt Trigger Panel -->
<div id="schmitt-trigger-panel" class="card bg-base-200 shadow-xl border-l-4 border-l-error hidden">
<div class="card-body bg-base-200 rounded-lg">
<h2 class="card-title text-error">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12h6l2-8 2 16 2-8h6"/>
</svg>
Schmitt Trigger Mode
</h2>
<div class="bg-error/5 border border-error/20 rounded-lg p-6">
<div class="flex items-center justify-center h-40">
<div class="text-center">
<svg class="w-16 h-16 mx-auto mb-4 text-error opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12h6l2-8 2 16 2-8h6"/>
</svg>
<p class="text-lg font-bold">Coming Soon</p>
<p class="text-sm mt-2">Schmitt Trigger configuration interface under development</p>
</div>
</div>
</div>
</div>
</div>
<!-- Advanced Parameters -->
<div class="card bg-base-200 shadow-xl border-l-4 border-l-primary">
<div class="card-body bg-base-200 rounded-lg">
<h2 class="card-title">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z"/>
<path d="M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z"/>
<path d="M12 2v2"/>
<path d="M12 22v-2"/>
<path d="m17 20.66-1-1.73"/>
<path d="M11 10.27 7 3.34"/>
<path d="m20.66 17-1.73-1"/>
<path d="m3.34 7 1.73 1"/>
<path d="M14 12h8"/>
<path d="M2 12h2"/>
<path d="m20.66 7-1.73 1"/>
<path d="m3.34 17 1.73-1"/>
<path d="m17 3.34-1 1.73"/>
<path d="m11 13.73-4 6.93"/>
</svg>
Advanced Parameters
</h2>
<div class="form-control">
<label class="label">
<span class="label-text">Response Time</span>
</label>
<label class="select select-bordered w-full flex items-center">
<svg class="w-4 h-4 opacity-70 absolute left-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<polyline points="12,6 12,12 16,14"/>
</svg>
<select class="pl-10">
<option>Fast (High Bandwidth)</option>
<option selected>Normal</option>
<option>Slow (Low Noise)</option>
</select>
</label>
</div>
<div class="form-control mt-4">
<label class="label">
<span class="label-text">Stability Mode</span>
</label>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-2">
<button class="btn btn-active" onclick="if('vibrate' in navigator) navigator.vibrate(15)">Normal</button>
<button class="btn" onclick="if('vibrate' in navigator) navigator.vibrate(15)">High Stability</button>
<button class="btn" onclick="if('vibrate' in navigator) navigator.vibrate(15)">Low Noise</button>
</div>
</div>
<div class="flex flex-col sm:flex-row justify-end mt-4 gap-2">
<button class="btn btn-outline" onclick="if('vibrate' in navigator) navigator.vibrate(15)">Save Preset</button>
<button class="btn btn-primary" onclick="if('vibrate' in navigator) navigator.vibrate([100, 200, 100])">Apply</button>
</div>
</div>
</div>
</div>
</div>
<script>
// Toggle color management function
function updateToggleColor(toggle: HTMLInputElement) {
if (toggle.checked) {
toggle.classList.remove('toggle-error');
toggle.classList.add('toggle-success');
} else {
toggle.classList.remove('toggle-success');
toggle.classList.add('toggle-error');
}
}
document.addEventListener('DOMContentLoaded', function() {
// Initialize toggle colors
const toggles = document.querySelectorAll('.toggle');
toggles.forEach(toggle => {
updateToggleColor(toggle as HTMLInputElement);
});
// Tab switching logic
const internalTab = document.getElementById('internal-tab');
const externalTab = document.getElementById('external-tab');
const internalModes = document.getElementById('internal-modes');
const externalModes = document.getElementById('external-modes');
// Mode panels
const panels = {
'cc': document.getElementById('cc-panel'),
'cp': document.getElementById('cp-panel'),
'pattern-continuous': document.getElementById('pattern-continuous-panel'),
'pattern-triggered': document.getElementById('pattern-triggered-panel'),
'ttl': document.getElementById('ttl-panel'),
'mod2current': document.getElementById('mod2current-panel'),
'schmitt-trigger': document.getElementById('schmitt-trigger-panel')
};
// Mode buttons
const modeButtons = {
'cc': document.getElementById('cc-tab'),
'cp': document.getElementById('cp-tab'),
'pattern-continuous': document.getElementById('pattern-continuous-tab'),
'pattern-triggered': document.getElementById('pattern-triggered-tab'),
'ttl': document.getElementById('ttl-tab'),
'mod2current': document.getElementById('mod2current-tab'),
'schmitt-trigger': document.getElementById('schmitt-trigger-tab')
};
// Show/hide panels
function showPanel(panelId: string) {
Object.values(panels).forEach(panel => panel?.classList.add('hidden'));
panels[panelId as keyof typeof panels]?.classList.remove('hidden');
// Update button states
Object.values(modeButtons).forEach(btn => btn?.classList.remove('btn-active'));
modeButtons[panelId as keyof typeof modeButtons]?.classList.add('btn-active');
}
// Tab switching
if (internalTab && externalTab && internalModes && externalModes) {
internalTab.addEventListener('click', function() {
internalTab.classList.add('tab-active');
externalTab.classList.remove('tab-active');
internalModes.classList.remove('hidden');
externalModes.classList.add('hidden');
showPanel('cc'); // Show default internal mode
});
externalTab.addEventListener('click', function() {
externalTab.classList.add('tab-active');
internalTab.classList.remove('tab-active');
externalModes.classList.remove('hidden');
internalModes.classList.add('hidden');
showPanel('ttl'); // Show default external mode
});
}
// Mode button event listeners
Object.entries(modeButtons).forEach(([mode, button]) => {
if (button) {
button.addEventListener('click', () => showPanel(mode));
}
});
// Stability mode buttons
const stabilityButtons = document.querySelectorAll('.grid .btn');
stabilityButtons.forEach(btn => {
btn.addEventListener('click', function(this: HTMLElement) {
// Only update buttons in the same grid
const grid = this.closest('.grid');
if (grid) {
grid.querySelectorAll('.btn').forEach(b => b.classList.remove('btn-active'));
this.classList.add('btn-active');
}
});
});
// Initialize with Constant Current mode
showPanel('cc');
});
</script>