feat: implement WYSIWYG markdown editor
Add complete markdown editor with Go backend and React/TypeScript frontend. Backend: - Cobra CLI with configurable host, port, data-dir, static-dir flags - REST API for CRUD operations on markdown files (GET, POST, PUT, DELETE) - File storage with flat .md structure - Comprehensive Logrus logging for all operations - Static asset serving for frontend Frontend: - React 18 + TypeScript + Tailwind CSS - Live markdown editor with GFM preview (react-markdown) - File management UI (list, create, open, save, delete) - Theme system (Light/Dark/System) with localStorage persistence - Responsive design (320px - 1920px+) Testing: - 6 backend tests covering CRUD round-trip, validation, error handling - 19 frontend tests covering API, theme system, and UI components - All tests passing with single 'make test' command Build: - Frontend compiles to optimized assets in dist/ - Backend can serve frontend via --static-dir flag
This commit is contained in:
80
backend/cmd/server/root.go
Normal file
80
backend/cmd/server/root.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/evanreichard/markdown-editor/internal/api"
|
||||
"github.com/evanreichard/markdown-editor/internal/config"
|
||||
"github.com/evanreichard/markdown-editor/internal/logging"
|
||||
"github.com/evanreichard/markdown-editor/internal/router"
|
||||
"github.com/evanreichard/markdown-editor/internal/storage"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
dataDir string
|
||||
port string
|
||||
host string
|
||||
staticDir string
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "Markdown editor server",
|
||||
Long: "A markdown editor server with REST API and frontend support",
|
||||
Run: runServer,
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.Flags().StringVar(&dataDir, "data-dir", "./data", "Storage path for markdown files")
|
||||
rootCmd.Flags().StringVar(&port, "port", "8080", "Server port")
|
||||
rootCmd.Flags().StringVar(&host, "host", "127.0.0.1", "Bind address")
|
||||
rootCmd.Flags().StringVar(&staticDir, "static-dir", "./frontend/dist", "Path to static assets")
|
||||
}
|
||||
|
||||
func runServer(cmd *cobra.Command, args []string) {
|
||||
cfg := &config.Config{
|
||||
DataDir: dataDir,
|
||||
Port: port,
|
||||
Host: host,
|
||||
}
|
||||
|
||||
logging.Init()
|
||||
logging.Logger.WithFields(map[string]interface{}{
|
||||
"data_dir": cfg.DataDir,
|
||||
"host": cfg.Host,
|
||||
"port": cfg.Port,
|
||||
"static_dir": staticDir,
|
||||
}).Info("Starting markdown editor server")
|
||||
|
||||
// Initialize storage
|
||||
store, err := storage.New(cfg.DataDir)
|
||||
if err != nil {
|
||||
logging.Logger.WithError(err).Fatal("Failed to initialize storage")
|
||||
}
|
||||
|
||||
// Initialize handlers
|
||||
handlers := api.New(store)
|
||||
|
||||
// Create router
|
||||
mux := router.New(handlers, staticDir)
|
||||
|
||||
// Wrap with logging middleware
|
||||
handler := logging.RequestMiddleware(mux)
|
||||
|
||||
// Start server
|
||||
addr := cfg.Addr()
|
||||
logging.Logger.WithField("addr", addr).Info("Server listening")
|
||||
if err := http.ListenAndServe(addr, handler); err != nil {
|
||||
logging.Logger.WithError(err).Fatal("Server error")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user