Files
cairnquire/apps/server/internal/httpserver/app_files.go
Tim Bendt 780ff3a02c feat: miller column browser, offline cache, search, breadcrumbs
- Dynamic miller column sizing with flexbox layout
- Root column (160px), middle slices (48px), active column (flex)
- Auto-scroll browser to rightmost column on navigation
- Offline indicator UI and IndexedDB cache integration
- /api/documents endpoint for client-side document caching
- Breadcrumb navigation in document content area
- FTS5 search with SQLite virtual table
- Client-side Mermaid and KaTeX rendering via CDN
- Deep sample content (advanced-topics/raft-deep-dive)
- Border removal (only search button keeps radius)
- Full viewport layout with proper borders between sidebar/content
2026-04-30 11:55:03 -04:00

44 lines
1.1 KiB
Go

package httpserver
import (
"net/http"
"net/http/httputil"
"net/url"
"os"
"path/filepath"
"strings"
)
func (s *Server) appFileServer() http.Handler {
if s.config.Web.DevViteURL != "" {
viteURL, err := url.Parse(s.config.Web.DevViteURL)
if err == nil {
proxy := httputil.NewSingleHostReverseProxy(viteURL)
originalDirector := proxy.Director
proxy.Director = func(req *http.Request) {
originalDirector(req)
req.Host = viteURL.Host
// Add back the /app/ prefix that was stripped by http.StripPrefix
req.URL.Path = "/app" + req.URL.Path
}
return proxy
}
}
files := http.FileServer(http.Dir(s.config.Web.DistDir))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cleanPath := filepath.Clean(strings.TrimPrefix(r.URL.Path, "/"))
if cleanPath == "." {
cleanPath = "index.html"
}
target := filepath.Join(s.config.Web.DistDir, cleanPath)
if info, err := os.Stat(target); err == nil && !info.IsDir() {
files.ServeHTTP(w, r)
return
}
http.ServeFile(w, r, filepath.Join(s.config.Web.DistDir, "index.html"))
})
}