Files
Maestro/src/renderer/index.html
Kayvan Sylvan 2667cbdd77 Developer Experience Improvements (multi-worktree simultaneous development) (#209)
* docs: add git hash display and configurable dev server port

## CHANGES

- Add `VITE_PORT` env variable to configure dev server port
- Display git commit hash in About modal next to version
- Add `__GIT_HASH__` build-time constant to both Vite configs
- Document running multiple Maestro instances with git worktrees
- Update CONTRIBUTING.md with parallel development instructions

* feat: add configurable ports for dev servers

- Allow VITE_PORT to configure main dev server port
- Update main window to load from configurable port
- Enable VITE_WEB_PORT for web interface dev server
- Add note in CONTRIBUTING.md about port configuration
- Log port usage in development mode

* docs: update CONTRIBUTING.md section and fix React DevTools script initialization

## CHANGES

- Rename "Linting" section to "Linting & Pre-commit Hooks" in table of contents
- Move script variable declaration outside conditional block
- Fix React DevTools script initialization order in index.html

* chore: update `.vscode/settings.json` with new markdownlint config

* fix: disable biome linting. Project uses ESLint

* chore: Update baseline-browser-mapping (>2 months old, warning message on "npm run build:web")

* chore: add .vscode/ to gitignore

* chore: fix gitignore to ignore .cscode/* files properly

* fix

* chore: stop tracking .vscode/ files, respect gitignore

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-01-22 12:14:48 -06:00

225 lines
7.1 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Maestro - Agent Orchestration Command Center</title>
<!-- Preload fonts to prevent FOUT (Flash of Unstyled Text) -->
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" as="style">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Critical CSS for splash screen - inline to prevent FOUC -->
<style>
/* Reset and base styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body, #root {
width: 100%;
height: 100%;
overflow: hidden;
}
body {
font-family: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #1a1a2e;
}
/* Initial splash screen styles */
#initial-splash {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
background-color: #1a1a2e;
transition: opacity 0.5s ease-out;
/* Account for 40px title bar (pt-10) so content aligns with app layout */
padding-top: 40px;
box-sizing: border-box;
}
#initial-splash.hidden {
opacity: 0;
pointer-events: none;
}
.splash-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 32px;
}
.splash-logo {
width: 180px;
height: 180px;
border-radius: 24px;
box-shadow: 0 25px 50px -12px rgba(139, 92, 246, 0.4);
overflow: hidden;
}
.splash-logo img {
width: 100%;
height: 100%;
object-fit: cover;
}
.splash-title {
font-family: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace;
font-weight: 700;
font-size: 36px;
letter-spacing: 0.25em;
color: #ffffff;
text-shadow: 0 2px 10px rgba(139, 92, 246, 0.3);
}
.splash-progress-container {
width: 280px;
height: 6px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 9999px;
overflow: hidden;
position: relative;
}
.splash-progress-bar {
position: absolute;
top: 0;
left: 0;
height: 100%;
border-radius: 9999px;
background: linear-gradient(90deg, #8b5cf6 0%, #a78bfa 50%, #c4b5fd 100%);
box-shadow: 0 0 10px rgba(139, 92, 246, 0.5);
transition: width 0.15s ease-out;
width: 0%;
}
.splash-text {
font-family: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace;
font-size: 14px;
letter-spacing: 0.05em;
color: rgba(255, 255, 255, 0.5);
}
</style>
</head>
<body>
<!-- Initial splash screen shown immediately while React loads -->
<div id="initial-splash">
<div class="splash-container">
<!-- Logo container with app icon -->
<div class="splash-logo">
<img src="/icon.png" alt="Maestro" />
</div>
<!-- Maestro title -->
<h1 class="splash-title">MAESTRO</h1>
<!-- Progress bar -->
<div class="splash-progress-container">
<div id="splash-progress" class="splash-progress-bar"></div>
</div>
<!-- Loading text -->
<p id="splash-text" class="splash-text">Loading...</p>
</div>
</div>
<div id="root"></div>
<!-- Splash screen progress animation -->
<script>
(function() {
var progress = 0;
var progressBar = document.getElementById('splash-progress');
var progressText = document.getElementById('splash-text');
// Capture any errors and display them on the splash screen
window.onerror = function(message, source, lineno, colno, error) {
if (progressText) {
progressText.style.color = '#ff6b6b';
progressText.textContent = 'Error: ' + (error?.message || message);
}
console.error('[Splash] Error:', message, source, lineno, colno, error);
return false;
};
window.onunhandledrejection = function(event) {
if (progressText) {
progressText.style.color = '#ff6b6b';
progressText.textContent = 'Error: ' + (event.reason?.message || String(event.reason));
}
console.error('[Splash] Unhandled rejection:', event.reason);
};
// Animate progress bar while waiting for React
var interval = setInterval(function() {
// Slow progress that caps at 70% until React takes over
progress += Math.random() * 3 + 1;
if (progress > 70) progress = 70;
if (progressBar) progressBar.style.width = progress + '%';
}, 100);
// Store interval ID so React can clear it
window.__splashInterval = interval;
window.__splashProgress = function() { return progress; };
// Function for React to call when ready
window.__hideSplash = function() {
clearInterval(interval);
// Complete the progress bar
if (progressBar) progressBar.style.width = '100%';
if (progressText) progressText.textContent = 'Ready';
// Helper to fade out the splash
function fadeOut() {
var splash = document.getElementById('initial-splash');
if (splash) {
splash.classList.add('hidden');
// Remove from DOM after animation
setTimeout(function() {
if (splash && splash.parentNode) {
splash.parentNode.removeChild(splash);
}
}, 500);
}
}
// Wait for fonts to be loaded to prevent layout shift from font swap
if (document.fonts && document.fonts.ready) {
document.fonts.ready.then(function() {
// Small delay after fonts ready for any final layout settling
setTimeout(fadeOut, 50);
});
} else {
// Fallback for browsers without Font Loading API
setTimeout(fadeOut, 200);
}
};
})();
</script>
<!-- React DevTools: connects to standalone react-devtools app (npm install -g react-devtools) -->
<!-- Only attempts connection in dev mode (Vite serves on localhost:5173) -->
<script>
var script = document.createElement('script');
if (window.location.hostname === 'localhost') {
script.src = 'http://localhost:8097';
script.async = false;
document.head.appendChild(script);
}
</script>
<script type="module" src="/main.tsx"></script>
</body>
</html>