feat(web): scaffold React + Vite + TypeScript frontend
Phase 1 of frontend migration (epic #6, issue #7). Project setup (web/): - React 19, React Router 7, Vite 6, TypeScript 5.7 - Catppuccin Mocha theme CSS variables matching existing Go templates - Vite dev proxy to Go backend at :8080 for /api/*, /login, /logout, /auth/*, /health, /ready Shared infrastructure: - api/client.ts: typed fetch wrapper (get/post/put/del) with 401 redirect and credentials:include for session cookies - api/types.ts: TypeScript interfaces for all API response types (User, Item, Project, Schema, Revision, BOMEntry, Audit, Error) - context/AuthContext.tsx: AuthProvider calling GET /api/auth/me - hooks/useAuth.ts: useAuth() hook exposing user/loading/logout UI shell: - AppShell.tsx: header nav matching current Go template navbar (Items, Projects, Schemas, Audit, Settings) with role badges (admin=mauve, editor=blue, viewer=teal) and active tab highlighting - LoginPage: redirects to Go-served /login during transition - Placeholder pages: Items, Projects, Schemas fetch from API and display data in tables; Audit shows summary stats; Settings shows current user profile Go server changes: - routes.go: serve web/dist/ at /app/* with SPA index.html fallback (only activates when web/dist/ directory exists) - .gitignore: web/node_modules/, web/dist/ - Makefile: web-install, web-dev, web-build targets
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
@@ -198,5 +201,21 @@ func NewRouter(server *Server, logger zerolog.Logger) http.Handler {
|
||||
})
|
||||
})
|
||||
|
||||
// React SPA (transition period — served at /app/)
|
||||
if webDir, err := os.Stat("web/dist"); err == nil && webDir.IsDir() {
|
||||
webFS := os.DirFS("web/dist")
|
||||
r.Get("/app/*", func(w http.ResponseWriter, r *http.Request) {
|
||||
path := strings.TrimPrefix(r.URL.Path, "/app/")
|
||||
if path == "" {
|
||||
path = "index.html"
|
||||
}
|
||||
// Try to serve the requested file; fall back to index.html for SPA routing
|
||||
if _, err := fs.Stat(webFS, path); err != nil {
|
||||
path = "index.html"
|
||||
}
|
||||
http.ServeFileFS(w, r, webFS, path)
|
||||
})
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user