ShowerLoop-cc/docker/showerloop/public/themes/chocolate/layouts/partials/head.html

192 lines
7.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<title>{{.Title }} | ShowerLoop</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Meta description -->
{{ with .Description }}
<meta name="description" content="{{ . }}">
{{ else }}
<meta name="description" content="ShowerLoop - Real-time filtration, purification, recycling & heat recovery system for showers. Open source and sustainable water conservation technology.">
{{ end }}
<!-- Back/Forward Cache Fix for Hugo Development Server -->
{{ if eq hugo.Environment "development" }}
<script>
// Store WebSocket connections to properly handle back/forward navigation
let liveReloadSocket = null;
// Override the default WebSocket constructor to control the livereload connection
const OriginalWebSocket = window.WebSocket;
window.WebSocket = function(url, protocols) {
// If this is Hugo's livereload WebSocket
if (url.includes('/__livereload')) {
// Don't create the WebSocket immediately if document is still loading
// This allows the bfcache to work
if (document.readyState === 'complete') {
liveReloadSocket = new OriginalWebSocket(url, protocols);
// Store the original handlers
const originalHandlers = {
onmessage: null,
onclose: null
};
// Proxy the event handlers
Object.defineProperty(liveReloadSocket, 'onmessage', {
set: function(handler) {
originalHandlers.onmessage = handler;
},
get: function() {
return originalHandlers.onmessage;
}
});
Object.defineProperty(liveReloadSocket, 'onclose', {
set: function(handler) {
originalHandlers.onclose = handler;
},
get: function() {
return originalHandlers.onclose;
}
});
// Implement our own handlers
liveReloadSocket.addEventListener('message', function(e) {
if (originalHandlers.onmessage) originalHandlers.onmessage(e);
});
liveReloadSocket.addEventListener('close', function(e) {
liveReloadSocket = null;
if (originalHandlers.onclose) originalHandlers.onclose(e);
});
return liveReloadSocket;
}
// Return a fake WebSocket object that does nothing
// This allows the page to be cached
return {
send: function() {},
close: function() {},
addEventListener: function() {},
removeEventListener: function() {},
set onmessage(handler) {},
set onclose(handler) {}
};
}
// For all other WebSockets, use the original constructor
return new OriginalWebSocket(url, protocols);
};
// Copy properties from the original WebSocket
for (const prop in OriginalWebSocket) {
if (OriginalWebSocket.hasOwnProperty(prop)) {
window.WebSocket[prop] = OriginalWebSocket[prop];
}
}
window.WebSocket.prototype = OriginalWebSocket.prototype;
// When page is shown (including from bfcache)
document.addEventListener('pageshow', function(event) {
// Check if page is coming from bfcache
if (event.persisted) {
console.log('Page restored from bfcache');
// Reconnect WebSocket for live reload
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
liveReloadSocket = new OriginalWebSocket(`${protocol}//${window.location.host}/__livereload`);
liveReloadSocket.onmessage = function(e) {
if (e.data === 'reload') {
window.location.reload();
}
};
}
});
// Disconnect WebSocket before page unloads
window.addEventListener('pagehide', function() {
if (liveReloadSocket) {
liveReloadSocket.onclose = null; // Prevent auto-reconnect
liveReloadSocket.close();
liveReloadSocket = null;
}
});
</script>
{{ end }}
<!-- Critical CSS preloaded -->
<link rel="preload" href="/css/vendor/material-icons.css" as="style">
<!-- Removed VideoJS preload to reduce initial payload -->
<!-- Preload logo image -->
<link rel="preload" href="/images/logo2.webp" as="image">
<!-- Material Design -->
<link rel="stylesheet" href="/css/vendor/material-icons.css">
<link rel="stylesheet" href="/css/vendor/material.indigo-pink.min.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/css/vendor/material.indigo-pink.min.css"></noscript>
<!-- Font Awesome - deferred loading -->
<link rel="stylesheet" href="/css/vendor/fontawesome.min.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/css/vendor/fontawesome.min.css"></noscript>
<!-- Modern browsers - ES modules with efficient loading -->
{{ $hasVideo := or (eq .Layout "video") (isset .Params "hero_video_url") (findRE "<video.*class=\"video-js\".*>" .Content) }}
<!-- Essential utilities first - other scripts depend on this -->
<script type="module">
// Create a dynamic import that will resolve ./utils.js relative imports
import * as utils from '/js/utils.modern.min.js';
window.utilsModule = utils; // Make it globally available if needed
</script>
<!-- Core app script - always load this -->
<script type="module" src="/js/app.modern.min.js" defer></script>
<!-- Load only video initialization code (actual VideoJS loaded on demand) -->
{{ if $hasVideo }}
<script type="module" src="/js/videojs/video-init.min.js" defer></script>
<script type="module" src="/static/js/videojs/video-init.min.js" defer></script>
{{ end }}
<!-- Accessibility script -->
<script type="module" src="/js/skip-to-content.modern.min.js" defer></script>
<!-- Material Design loaded with defer for non-critical UI -->
<script type="module" src="/js/material.modern.min.js" defer></script>
<!-- Legacy browsers support - with polyfills -->
<script nomodule src="/js/app.min.js" defer></script>
{{ if $hasVideo }}
<script nomodule src="/js/videojs/video-init.min.js" defer></script>
<script nomodule src="/static/js/videojs/video-init.min.js" defer></script>
{{ end }}
<script nomodule src="/js/skip-to-content.min.js" defer></script>
<script nomodule src="/js/material.min.js" defer></script>
<!-- Custom CSS -->
<link rel="stylesheet" type="text/css" href="/css/app.min.css">
<link rel="stylesheet" type="text/css" href="/css/custom.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/css/custom.css"></noscript>
<!-- Favicon -->
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
<link rel="icon" href="/static/favicon.ico" type="image/x-icon">
<!-- VideoJS CSS -->
{{ if $hasVideo }}
<link rel="stylesheet" href="/css/vendor/video-js.min.css">
<link rel="stylesheet" href="/static/css/vendor/video-js.min.css">
<!-- VideoJS Core Libraries -->
<script src="/js/videojs/video.min.js"></script>
<script src="/static/js/videojs/video.min.js"></script>
<script src="/js/videojs/videojs-http-streaming.min.js"></script>
<script src="/static/js/videojs/videojs-http-streaming.min.js"></script>
{{ end }}
</head>