feat: upload fonts to slide and be able to retrieve deduplicated list for all in template
This commit is contained in:
parent
353f8e41d1
commit
2cd5eef92f
5 changed files with 40 additions and 12 deletions
|
|
@ -76,6 +76,7 @@ class GetLayoutsResponse(BaseModel):
|
|||
layouts: list[LayoutData]
|
||||
message: Optional[str] = None
|
||||
template: Optional[dict] = None
|
||||
fonts: Optional[List[str]] = None
|
||||
|
||||
|
||||
class PresentationSummary(BaseModel):
|
||||
|
|
@ -820,6 +821,13 @@ async def get_layouts(
|
|||
for layout in layouts_db
|
||||
]
|
||||
|
||||
# Aggregate unique fonts across all layouts
|
||||
aggregated_fonts: set[str] = set()
|
||||
for layout in layouts_db:
|
||||
if layout.fonts:
|
||||
aggregated_fonts.update([f for f in layout.fonts if isinstance(f, str)])
|
||||
fonts_list = sorted(list(aggregated_fonts)) if aggregated_fonts else None
|
||||
|
||||
# Fetch template meta
|
||||
template_meta = await session.get(TemplateModel, presentation_id)
|
||||
template = None
|
||||
|
|
@ -836,6 +844,7 @@ async def get_layouts(
|
|||
layouts=layouts,
|
||||
message=f"Retrieved {len(layouts)} layout(s) for presentation {presentation_id}",
|
||||
template=template,
|
||||
fonts=fonts_list,
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
|
|
|
|||
13
servers/fastapi/models/sql/template.py
Normal file
13
servers/fastapi/models/sql/template.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from sqlalchemy import Column, DateTime
|
||||
from sqlmodel import SQLModel, Field
|
||||
|
||||
|
||||
class TemplateModel(SQLModel, table=True):
|
||||
__tablename__ = "templates"
|
||||
|
||||
id: str = Field(primary_key=True, description="UUID for the template (matches presentation_id)")
|
||||
name: str = Field(description="Human friendly template name")
|
||||
description: Optional[str] = Field(default=None, description="Optional template description")
|
||||
created_at: datetime = Field(sa_column=Column(DateTime, default=datetime.now))
|
||||
|
|
@ -2,11 +2,12 @@ import { useState, useCallback } from "react";
|
|||
import { toast } from "sonner";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { ApiResponseHandler } from "@/app/(presentation-generator)/services/api/api-error-handler";
|
||||
import { ProcessedSlide, UploadedFont } from "../types";
|
||||
import { ProcessedSlide, UploadedFont, FontData } from "../types";
|
||||
|
||||
export const useLayoutSaving = (
|
||||
slides: ProcessedSlide[],
|
||||
UploadedFonts: UploadedFont[],
|
||||
fontsData: FontData | null,
|
||||
refetch: () => void,
|
||||
setSlides: React.Dispatch<React.SetStateAction<ProcessedSlide[]>>
|
||||
) => {
|
||||
|
|
@ -90,8 +91,10 @@ export const useLayoutSaving = (
|
|||
const reactComponents: any[] = [];
|
||||
const presentationId = uuidv4();
|
||||
|
||||
// Get all uploaded font URLs
|
||||
const FontUrls = UploadedFonts.map((font) => font.fontUrl);
|
||||
// Collect uploaded font URLs and Google Fonts CSS URLs
|
||||
const uploadedFontUrls = UploadedFonts.map((font) => font.fontUrl);
|
||||
const googleFontCssUrls = fontsData?.internally_supported_fonts?.map(f => f.google_fonts_url).filter(Boolean) || [];
|
||||
const FontUrls = Array.from(new Set([...(uploadedFontUrls || []), ...googleFontCssUrls]));
|
||||
console.log("FontUrls", FontUrls);
|
||||
|
||||
for (let i = 0; i < slides.length; i++) {
|
||||
|
|
@ -186,7 +189,7 @@ export const useLayoutSaving = (
|
|||
} finally {
|
||||
setIsSavingLayout(false);
|
||||
}
|
||||
}, [slides, UploadedFonts, refetch, closeSaveModal, setSlides]);
|
||||
}, [slides, UploadedFonts, fontsData, refetch, closeSaveModal, setSlides]);
|
||||
|
||||
return {
|
||||
isSavingLayout,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ const CustomTemplatePage = () => {
|
|||
const { isSavingLayout, isModalOpen, openSaveModal, closeSaveModal, saveLayout } = useLayoutSaving(
|
||||
slides,
|
||||
UploadedFonts,
|
||||
fontsData,
|
||||
refetch,
|
||||
setSlides
|
||||
);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ const GroupLayoutPreview = () => {
|
|||
const [currentFonts, setCurrentFonts] = useState<string[] | undefined>(undefined);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [layoutsMap, setLayoutsMap] = useState<Record<string, { layout_id: string; layout_name: string; layout_code: string; fonts?: string[] }>>({});
|
||||
const [templateMeta, setTemplateMeta] = useState<{ name?: string; description?: string } | null>(null);
|
||||
|
||||
const injectFonts = (fontUrls: string[]) => {
|
||||
fontUrls.forEach((fontUrl) => {
|
||||
|
|
@ -55,7 +56,7 @@ const GroupLayoutPreview = () => {
|
|||
const loadCustomLayouts = async () => {
|
||||
if (!isCustom) return;
|
||||
try {
|
||||
const res = await fetch(`/api/v1/ppt/layout-management/get-layouts/${presentationId}`);
|
||||
const res = await fetch(`/api/v1/ppt/template-management/get-templates/${presentationId}`);
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
const map: Record<string, { layout_id: string; layout_name: string; layout_code: string; fonts?: string[] }> = {};
|
||||
|
|
@ -68,12 +69,13 @@ const GroupLayoutPreview = () => {
|
|||
};
|
||||
}
|
||||
setLayoutsMap(map);
|
||||
// Inject all fonts used by this custom group's layouts
|
||||
// const allFonts: string[] = [];
|
||||
// Object.values(map).forEach((entry) => {
|
||||
// (entry.fonts || []).forEach((f) => allFonts.push(f));
|
||||
// });
|
||||
injectFonts(map[0].fonts || []);
|
||||
// Set template meta and inject aggregated fonts if provided
|
||||
if (data?.template) {
|
||||
setTemplateMeta({ name: data.template.name, description: data.template.description });
|
||||
}
|
||||
if (Array.isArray(data?.fonts) && data.fonts.length) {
|
||||
injectFonts(data.fonts);
|
||||
}
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
|
|
@ -157,7 +159,7 @@ const GroupLayoutPreview = () => {
|
|||
},
|
||||
],
|
||||
};
|
||||
const res = await fetch(`/api/v1/ppt/layout-management/save-layouts`, {
|
||||
const res = await fetch(`/api/v1/ppt/template-management/save-templates`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue