diff --git a/internal/idlewatcher/handle_http.go b/internal/idlewatcher/handle_http.go index 3d87067a..bc9773da 100644 --- a/internal/idlewatcher/handle_http.go +++ b/internal/idlewatcher/handle_http.go @@ -47,6 +47,10 @@ func isFaviconPath(path string) bool { return path == "/favicon.ico" } +func isLoadingPageCSSPath(path string) bool { + return path == "/style.css" +} + func (w *Watcher) redirectToStartEndpoint(rw http.ResponseWriter, r *http.Request) { uri := "/" if w.cfg.StartEndpoint != "" { @@ -96,6 +100,13 @@ func (w *Watcher) wakeFromHTTP(rw http.ResponseWriter, r *http.Request) (shouldN return false } + if isLoadingPageCSSPath(r.URL.Path) { + rw.Header().Set("Content-Type", "text/css") + rw.WriteHeader(http.StatusOK) + rw.Write(cssBytes) + return false + } + // Check if start endpoint is configured and request path matches if w.cfg.StartEndpoint != "" && r.URL.Path != w.cfg.StartEndpoint { http.Error(rw, "Forbidden: Container can only be started via configured start endpoint", http.StatusForbidden) diff --git a/internal/idlewatcher/html/loading_page.html b/internal/idlewatcher/html/loading_page.html index a1c891f7..104fa105 100644 --- a/internal/idlewatcher/html/loading_page.html +++ b/internal/idlewatcher/html/loading_page.html @@ -4,109 +4,8 @@ {{.Title}} - + +
diff --git a/internal/idlewatcher/html/style.css b/internal/idlewatcher/html/style.css new file mode 100644 index 00000000..5832276d --- /dev/null +++ b/internal/idlewatcher/html/style.css @@ -0,0 +1,91 @@ +/* size variables */ +:root { + --dot-size: 12px; + --logo-size: 100px; +} +/* Global Styles */ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} +body { + font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; + font-size: 16px; + line-height: 1.5; + color: #f8f9fa; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + gap: 32px; + background: linear-gradient(135deg, #121212 0%, #1e1e1e 100%); +} + +/* Container */ +.container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 48px; + border-radius: 16px; + background-color: rgba(30, 30, 30, 0.6); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(8px); + max-width: 90%; + transition: all 0.3s ease; +} + +/* Spinner Styles */ +.loading-dots { + display: flex; + justify-content: center; + align-items: center; + gap: 8px; + padding-top: 20px; + padding-bottom: 6px; +} +.dot { + width: var(--dot-size); + height: var(--dot-size); + background-color: #66d9ef; + border-radius: 50%; + animation: bounce 1.3s infinite ease-in-out; +} +.dot:nth-child(1) { + animation-delay: -0.32s; +} +.dot:nth-child(2) { + animation-delay: -0.16s; +} +@keyframes bounce { + 0%, + 80%, + 100% { + transform: translateY(0); + } + 40% { + transform: translateY(-10px); + } +} + +/* Message Styles */ +.message { + font-size: 20px; + font-weight: 500; + text-align: center; + color: #f8f9fa; + max-width: 500px; + letter-spacing: 0.3px; + white-space: nowrap; +} + +/* Logo */ +.logo { + width: var(--logo-size); + height: var(--logo-size); +} diff --git a/internal/idlewatcher/loading_page.go b/internal/idlewatcher/loading_page.go index 8407080e..6639d716 100644 --- a/internal/idlewatcher/loading_page.go +++ b/internal/idlewatcher/loading_page.go @@ -3,7 +3,7 @@ package idlewatcher import ( "bytes" _ "embed" - "text/template" + "html/template" "github.com/yusing/goutils/http/httpheaders" ) @@ -18,6 +18,9 @@ type templateData struct { var loadingPage []byte var loadingPageTmpl = template.Must(template.New("loading_page").Parse(string(loadingPage))) +//go:embed html/style.css +var cssBytes []byte + func (w *Watcher) makeLoadingPageBody() []byte { msg := w.cfg.ContainerName() + " is starting..."