Implement live collection preview system with contextual template selection

Replace isolated template previews with live collection reconstruction:
- Frontend now reconstructs collection container with all template variants
- Users click directly on rendered templates in proper CSS context
- Perfect preservation of grid/flex layouts and responsive behavior
- Simplified API: preview endpoint returns container_html + templates for frontend reconstruction
- Enhanced UX: WYSIWYG template selection shows exactly what will be added
- Removed redundant templates endpoint in favor of unified preview approach

Backend changes:
- Add GET /api/collections/{id}/preview endpoint
- Remove GET /api/collections/{id}/templates endpoint
- Return container HTML + templates for frontend reconstruction

Frontend changes:
- Replace isolated template modal with live collection preview
- Add generateLivePreview() method for container reconstruction
- Update CollectionManager to use preview API
- Add interactive CSS styling for template selection

This provides true contextual template selection where CSS inheritance,
grid layouts, and responsive design work perfectly in preview mode.
This commit is contained in:
2025-10-31 22:41:12 +01:00
parent 81ec8edf36
commit 163cbf7eea
4 changed files with 273 additions and 106 deletions

View File

@@ -405,8 +405,8 @@ func (h *ContentHandler) GetCollectionItems(w http.ResponseWriter, r *http.Reque
json.NewEncoder(w).Encode(items)
}
// GetCollectionTemplates handles GET /api/collections/{id}/templates
func (h *ContentHandler) GetCollectionTemplates(w http.ResponseWriter, r *http.Request) {
// GetCollectionPreview handles GET /api/collections/{id}/preview
func (h *ContentHandler) GetCollectionPreview(w http.ResponseWriter, r *http.Request) {
collectionID := chi.URLParam(r, "id")
siteID := r.URL.Query().Get("site_id")
@@ -415,14 +415,24 @@ func (h *ContentHandler) GetCollectionTemplates(w http.ResponseWriter, r *http.R
return
}
// Get collection container
collection, err := h.repository.GetCollection(context.Background(), siteID, collectionID)
if err != nil {
http.Error(w, fmt.Sprintf("Collection not found: %v", err), http.StatusNotFound)
return
}
// Get all templates for this collection
templates, err := h.repository.GetCollectionTemplates(context.Background(), siteID, collectionID)
if err != nil {
http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
http.Error(w, fmt.Sprintf("Templates not found: %v", err), http.StatusInternalServerError)
return
}
response := map[string]interface{}{
"templates": templates,
"collection_id": collectionID,
"container_html": collection.ContainerHTML,
"templates": templates,
}
w.Header().Set("Content-Type", "application/json")
@@ -525,10 +535,10 @@ func (h *ContentHandler) RegisterRoutes(r chi.Router) {
// COLLECTION MANAGEMENT - Groups of related content
// =============================================================================
r.Route("/collections", func(r chi.Router) {
r.Get("/", h.GetAllCollections) // GET /api/collections?site_id=X
r.Get("/{id}", h.GetCollection) // GET /api/collections/{id}?site_id=X
r.Get("/{id}/items", h.GetCollectionItems) // GET /api/collections/{id}/items?site_id=X
r.Get("/{id}/templates", h.GetCollectionTemplates) // GET /api/collections/{id}/templates?site_id=X
r.Get("/", h.GetAllCollections) // GET /api/collections?site_id=X
r.Get("/{id}", h.GetCollection) // GET /api/collections/{id}?site_id=X
r.Get("/{id}/items", h.GetCollectionItems) // GET /api/collections/{id}/items?site_id=X
r.Get("/{id}/preview", h.GetCollectionPreview) // GET /api/collections/{id}/preview?site_id=X
// Protected routes
r.Group(func(r chi.Router) {