mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-05-01 04:53:00 +00:00
chore: merge main into feat/update-banner
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -786,56 +786,25 @@
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Alpine.js for reactive components -->
|
||||
<!-- Use local file when in AP mode (192.168.4.x) to avoid CDN dependency -->
|
||||
<!-- Alpine.js for reactive components.
|
||||
Load the local copy first (always works, no CDN round-trip, no AP-mode
|
||||
branch needed). `defer` on an HTML-parsed <script> is honored and runs
|
||||
after DOM parse but before DOMContentLoaded, which is exactly what
|
||||
Alpine wants — so no deferLoadingAlpine gymnastics are needed.
|
||||
The inline rescue below only fires if the local file is missing. -->
|
||||
<script defer src="{{ url_for('static', filename='v3/js/alpinejs.min.js') }}"></script>
|
||||
<script>
|
||||
(function() {
|
||||
// Prevent Alpine from auto-initializing by setting deferLoadingAlpine before it loads
|
||||
window.deferLoadingAlpine = function(callback) {
|
||||
// Wait for DOM to be ready
|
||||
function waitForReady() {
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', waitForReady);
|
||||
return;
|
||||
}
|
||||
|
||||
// app() is already defined in head, so we can initialize Alpine
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback();
|
||||
} else if (window.Alpine && typeof window.Alpine.start === 'function') {
|
||||
// If callback not provided but Alpine is available, start it
|
||||
try {
|
||||
window.Alpine.start();
|
||||
} catch (e) {
|
||||
// Alpine may already be initialized, ignore
|
||||
console.warn('Alpine start error (may already be initialized):', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
waitForReady();
|
||||
};
|
||||
|
||||
// Detect AP mode by IP address
|
||||
const isAPMode = window.location.hostname === '192.168.4.1' ||
|
||||
window.location.hostname.startsWith('192.168.4.');
|
||||
|
||||
const alpineSrc = isAPMode ? '/static/v3/js/alpinejs.min.js' : 'https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js';
|
||||
const alpineFallback = isAPMode ? 'https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js' : '/static/v3/js/alpinejs.min.js';
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.defer = true;
|
||||
script.src = alpineSrc;
|
||||
script.onerror = function() {
|
||||
if (alpineSrc !== alpineFallback) {
|
||||
const fallback = document.createElement('script');
|
||||
fallback.defer = true;
|
||||
fallback.src = alpineFallback;
|
||||
document.head.appendChild(fallback);
|
||||
}
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
// Rescue: if the local Alpine didn't load for any reason, pull the CDN
|
||||
// copy once on window load. This is a last-ditch fallback, not the
|
||||
// primary path.
|
||||
window.addEventListener('load', function() {
|
||||
if (typeof window.Alpine === 'undefined') {
|
||||
console.warn('[Alpine] Local file failed to load, falling back to CDN');
|
||||
const s = document.createElement('script');
|
||||
s.src = 'https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js';
|
||||
document.head.appendChild(s);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- CodeMirror for JSON editing - lazy loaded when needed -->
|
||||
@@ -995,6 +964,11 @@
|
||||
class="nav-tab">
|
||||
<i class="fas fa-file-code"></i>Config Editor
|
||||
</button>
|
||||
<button @click="activeTab = 'backup-restore'"
|
||||
:class="activeTab === 'backup-restore' ? 'nav-tab-active' : ''"
|
||||
class="nav-tab">
|
||||
<i class="fas fa-save"></i>Backup & Restore
|
||||
</button>
|
||||
<button @click="activeTab = 'fonts'"
|
||||
:class="activeTab === 'fonts' ? 'nav-tab-active' : ''"
|
||||
class="nav-tab">
|
||||
@@ -1197,6 +1171,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Backup & Restore tab -->
|
||||
<div x-show="activeTab === 'backup-restore'" x-transition>
|
||||
<div id="backup-restore-content" hx-get="/v3/partials/backup-restore" hx-trigger="revealed" hx-swap="innerHTML">
|
||||
<div class="animate-pulse">
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="h-4 bg-gray-200 rounded w-1/4 mb-4"></div>
|
||||
<div class="h-32 bg-gray-200 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Config Editor tab -->
|
||||
<div x-show="activeTab === 'config-editor'" x-transition>
|
||||
<div id="config-editor-content" hx-get="/v3/partials/raw-json" hx-trigger="revealed" hx-swap="innerHTML">
|
||||
|
||||
Reference in New Issue
Block a user