feat(server): add owner-tools injection and inline code theme CSS

- Add owner-tools serving and injection for blog owners
- Inline code theme CSS in templates for soft reload support
- Update import paths from github.com/writekitapp to writekit
- Add optional session middleware for owner detection
- Update platform index with improved UI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Josh 2026-01-12 02:02:13 +02:00
parent 771ff7615a
commit 119e3b7a6d
11 changed files with 838 additions and 483 deletions

View file

@ -15,11 +15,11 @@ import (
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
"github.com/gorilla/websocket"
"github.com/writekitapp/writekit/internal/config"
"github.com/writekitapp/writekit/internal/db"
"github.com/writekitapp/writekit/internal/imaginary"
"github.com/writekitapp/writekit/internal/markdown"
"github.com/writekitapp/writekit/internal/tenant"
"writekit/internal/config"
"writekit/internal/db"
"writekit/internal/imaginary"
"writekit/internal/markdown"
"writekit/internal/tenant"
)
func renderContent(q *tenant.Queries, r *http.Request, content string) string {
@ -52,6 +52,7 @@ func (s *Server) studioRoutes() chi.Router {
r.Get("/settings", s.getSettings)
r.Put("/settings", s.updateSettings)
r.Get("/settings/schema", s.getSettingsSchema)
r.Get("/interaction-config", s.getStudioInteractionConfig)
r.Put("/interaction-config", s.updateInteractionConfig)
@ -93,9 +94,8 @@ func (s *Server) studioRoutes() chi.Router {
r.Get("/sdk", s.getSDK)
r.Get("/lsp", s.proxyLSP)
// Code themes
// Code theme CSS
r.Get("/code-theme.css", s.codeThemeCSS)
r.Get("/code-themes", s.listCodeThemes)
// Plugin testing
r.Post("/plugins/test", s.testPlugin)
@ -818,6 +818,89 @@ func (s *Server) updateSettings(w http.ResponseWriter, r *http.Request) {
jsonResponse(w, http.StatusOK, map[string]bool{"success": true})
}
type settingOption struct {
Value string `json:"value"`
Label string `json:"label"`
}
type settingDefinition struct {
Key string `json:"key"`
Type string `json:"type"`
Label string `json:"label"`
Options []settingOption `json:"options,omitempty"`
Default string `json:"default,omitempty"`
}
func (s *Server) getSettingsSchema(w http.ResponseWriter, r *http.Request) {
schema := []settingDefinition{
{
Key: "accent_color",
Type: "color",
Label: "Accent Color",
Default: "#10b981",
},
{
Key: "font",
Type: "select",
Label: "Font",
Options: []settingOption{
{Value: "system", Label: "System Default"},
{Value: "inter", Label: "Inter"},
{Value: "georgia", Label: "Georgia"},
{Value: "merriweather", Label: "Merriweather"},
{Value: "source-serif", Label: "Source Serif"},
{Value: "jetbrains-mono", Label: "JetBrains Mono"},
},
Default: "system",
},
{
Key: "code_theme",
Type: "select",
Label: "Code Theme",
Options: []settingOption{
{Value: "github", Label: "GitHub Light"},
{Value: "github-dark", Label: "GitHub Dark"},
{Value: "vs", Label: "VS Light"},
{Value: "xcode", Label: "Xcode Light"},
{Value: "xcode-dark", Label: "Xcode Dark"},
{Value: "solarized-light", Label: "Solarized Light"},
{Value: "solarized-dark", Label: "Solarized Dark"},
{Value: "gruvbox-light", Label: "Gruvbox Light"},
{Value: "gruvbox", Label: "Gruvbox Dark"},
{Value: "nord", Label: "Nord"},
{Value: "onedark", Label: "One Dark"},
{Value: "dracula", Label: "Dracula"},
{Value: "monokai", Label: "Monokai"},
},
Default: "github",
},
{
Key: "layout",
Type: "select",
Label: "Layout",
Options: []settingOption{
{Value: "default", Label: "Classic"},
{Value: "minimal", Label: "Minimal"},
{Value: "magazine", Label: "Magazine"},
},
Default: "default",
},
{
Key: "compactness",
Type: "select",
Label: "Density",
Options: []settingOption{
{Value: "compact", Label: "Compact"},
{Value: "cozy", Label: "Cozy"},
{Value: "spacious", Label: "Spacious"},
},
Default: "cozy",
},
}
jsonResponse(w, http.StatusOK, schema)
}
func (s *Server) listAssets(w http.ResponseWriter, r *http.Request) {
tenantID := r.Context().Value(tenantIDKey).(string)
@ -1789,11 +1872,6 @@ func (s *Server) codeThemeCSS(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(css))
}
func (s *Server) listCodeThemes(w http.ResponseWriter, r *http.Request) {
themes := markdown.ListThemes()
jsonResponse(w, http.StatusOK, themes)
}
func contains(slice []string, item string) bool {
for _, s := range slice {
if s == item {