diff --git a/Makefile b/Makefile index 9e6bcef..c10487d 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,13 @@ all: gen start open gen: @templ generate +build: + @go build -o nebula ./cmd/server + start: - @go run main.go + @go run ./cmd/server open: @open http://localhost:8080 -.PHONY: gen start +.PHONY: gen build start open all diff --git a/handlers/routes.go b/handlers/routes.go deleted file mode 100644 index 68b7f75..0000000 --- a/handlers/routes.go +++ /dev/null @@ -1,176 +0,0 @@ -package handlers - -import ( - "net/http" - "strconv" - - "nebula/models" - "nebula/views" -) - -func RegisterRoutes(mux *http.ServeMux) { - mux.HandleFunc("GET /", handleWelcome) - mux.HandleFunc("GET /welcome", handleWelcome) - mux.HandleFunc("GET /welcome/step/{step}", handleWelcomeStep) - - mux.HandleFunc("GET /register", handleRegister) - mux.HandleFunc("GET /register/step/{step}", handleRegisterStep) - mux.HandleFunc("GET /register/capabilities", handleRegisterCapabilities) - mux.HandleFunc("POST /register/verify-code", handleRegisterVerifyCode) - - mux.HandleFunc("GET /login", handleLogin) - mux.HandleFunc("GET /login/step/{step}", handleLoginStep) - mux.HandleFunc("GET /login/qr-status", handleLoginQRStatus) - - mux.HandleFunc("GET /authorize", handleAuthorize) - mux.HandleFunc("POST /authorize/approve", handleAuthorizeApprove) - mux.HandleFunc("POST /authorize/deny", handleAuthorizeDeny) - - mux.HandleFunc("GET /dashboard", handleDashboard) - - mux.HandleFunc("GET /settings", handleSettings) -} - -// handleWelcome renders the full welcome page at step 1 -func handleWelcome(w http.ResponseWriter, r *http.Request) { - views.WelcomePage(1).Render(r.Context(), w) -} - -// handleWelcomeStep handles HTMX partial updates for step navigation -func handleWelcomeStep(w http.ResponseWriter, r *http.Request) { - stepStr := r.PathValue("step") - step, err := strconv.Atoi(stepStr) - if err != nil || step < 1 || step > 3 { - step = 1 - } - - // Check if this is an HTMX request - if r.Header.Get("HX-Request") == "true" { - // Return step content with OOB stepper update (HTMX 4 pattern) - views.WelcomeStepWithStepper(step).Render(r.Context(), w) - return - } - - views.WelcomePage(step).Render(r.Context(), w) -} - -func handleRegister(w http.ResponseWriter, r *http.Request) { - state := models.RegisterState{Step: 1} - views.RegisterPage(state).Render(r.Context(), w) -} - -func handleRegisterStep(w http.ResponseWriter, r *http.Request) { - stepStr := r.PathValue("step") - step, err := strconv.Atoi(stepStr) - if err != nil || step < 1 || step > 3 { - step = 1 - } - - method := r.URL.Query().Get("method") - if method == "" { - method = "passkey" - } - - state := models.RegisterState{Step: step, Method: method} - - if r.Header.Get("HX-Request") == "true" { - views.RegisterStepWithStepper(state).Render(r.Context(), w) - return - } - - views.RegisterPage(state).Render(r.Context(), w) -} - -func handleRegisterCapabilities(w http.ResponseWriter, r *http.Request) { - caps := models.DeviceCapabilities{ - Platform: true, - CrossPlatform: true, - Conditional: true, - } - views.CapabilitiesResult(caps).Render(r.Context(), w) -} - -func handleRegisterVerifyCode(w http.ResponseWriter, r *http.Request) { - state := models.RegisterState{Step: 3} - if r.Header.Get("HX-Request") == "true" { - views.RegisterStepWithStepper(state).Render(r.Context(), w) - return - } - views.RegisterPage(state).Render(r.Context(), w) -} - -func handleLogin(w http.ResponseWriter, r *http.Request) { - state := models.LoginState{Step: "1"} - views.LoginPage(state).Render(r.Context(), w) -} - -func handleLoginStep(w http.ResponseWriter, r *http.Request) { - step := r.PathValue("step") - if step == "" { - step = "1" - } - - state := models.LoginState{Step: step} - - if r.Header.Get("HX-Request") == "true" { - views.LoginStepWithOOB(state).Render(r.Context(), w) - return - } - - views.LoginPage(state).Render(r.Context(), w) -} - -var qrPollCount = 0 - -func handleLoginQRStatus(w http.ResponseWriter, r *http.Request) { - qrPollCount++ - if qrPollCount >= 3 { - qrPollCount = 0 - views.QRStatusSuccess().Render(r.Context(), w) - return - } - views.QRStatusWaiting().Render(r.Context(), w) -} - -func handleAuthorize(w http.ResponseWriter, r *http.Request) { - reqType := r.URL.Query().Get("type") - req := models.DefaultAuthRequest(reqType) - views.AuthorizePage(req).Render(r.Context(), w) -} - -func handleAuthorizeApprove(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - actionType := r.FormValue("type") - if actionType == "" { - actionType = "connect" - } - views.AuthResultSuccess(actionType).Render(r.Context(), w) -} - -func handleAuthorizeDeny(w http.ResponseWriter, r *http.Request) { - views.AuthResultDenied().Render(r.Context(), w) -} - -func handleDashboard(w http.ResponseWriter, r *http.Request) { - tab := r.URL.Query().Get("tab") - if tab == "" { - tab = "overview" - } - data := models.DefaultDashboardData() - - if r.Header.Get("HX-Request") == "true" { - views.DashboardContent(data, tab).Render(r.Context(), w) - return - } - - views.DashboardPage(data, tab).Render(r.Context(), w) -} - -func handleSettings(w http.ResponseWriter, r *http.Request) { - tab := r.URL.Query().Get("tab") - if tab == "" { - tab = "profile" - } - data := models.DefaultSettingsData() - views.SettingsPage(data, tab).Render(r.Context(), w) -} diff --git a/layouts/base.templ b/layouts/base.templ index b72db92..439febb 100644 --- a/layouts/base.templ +++ b/layouts/base.templ @@ -1,36 +1,44 @@ package layouts -// Base provides the HTML document structure for all pages +import "nebula/pkg/config" + templ Base(title string) { - +
-