返回 presentation-ai
1 "use client";
2
3 import { useState } from "react";
4 import { useWatch } from "react-hook-form";
5
6 import { CurrentFontDisplay } from "./CurrentFontDisplay";
7 import { CustomFontCreator } from "./CustomFontCreator";
8 import { FontCombinationsList } from "./FontCombinationsList";
9 import { FontStepHeader } from "./FontStepHeader";
10 import { type FontStepProps } from "./types";
11 import { useFontUpload } from "./useFontUpload";
12 import { UserFontPairs } from "./UserFontPairs";
13 import { useSaveFontPair } from "./useSaveFontPair";
14
15 export function FontStep({ control, setValue }: FontStepProps) {
16 const [showCustom, setShowCustom] = useState(false);
17
18 // Use useWatch to properly subscribe to form changes
19 const currentHeadingFont = useWatch({ control, name: "fonts.heading" });
20 const currentBodyFont = useWatch({ control, name: "fonts.body" });
21 const currentHeadingUrl = useWatch({ control, name: "fonts.headingUrl" });
22 const currentBodyUrl = useWatch({ control, name: "fonts.bodyUrl" });
23
24 const {
25 isUploadingHeading,
26 isUploadingBody,
27 handleFontUpload,
28 getLocalCustomFonts,
29 } = useFontUpload({ setValue, control });
30
31 const { isSaving, saveFontPair } = useSaveFontPair(() => {
32 setShowCustom(false);
33 });
34
35 const handleSaveFontPair = () => {
36 saveFontPair({
37 heading: currentHeadingFont,
38 body: currentBodyFont,
39 headingUrl: currentHeadingUrl,
40 bodyUrl: currentBodyUrl,
41 });
42 };
43
44 const handleSelectFontPair = (heading: string, body: string) => {
45 const options = { shouldDirty: true };
46 setValue("fonts.heading", heading, options);
47 setValue("fonts.body", body, options);
48 setValue("fonts.headingUrl", undefined, options);
49 setValue("fonts.bodyUrl", undefined, options);
50 };
51
52 const handleSelectUserFontPair = (
53 heading: string,
54 body: string,
55 headingUrl?: string,
56 bodyUrl?: string,
57 ) => {
58 const options = { shouldDirty: true };
59 setValue("fonts.heading", heading, options);
60 setValue("fonts.body", body, options);
61 setValue("fonts.headingUrl", headingUrl, options);
62 setValue("fonts.bodyUrl", bodyUrl, options);
63 };
64
65 return (
66 <div className="flex h-full flex-col">
67 <FontStepHeader />
68
69 <div className="flex-1 space-y-4 overflow-y-auto p-6">
70 <CurrentFontDisplay
71 headingFont={currentHeadingFont}
72 bodyFont={currentBodyFont}
73 showCustom={showCustom}
74 onToggleCustom={() => setShowCustom(!showCustom)}
75 />
76
77 {showCustom && (
78 <CustomFontCreator
79 control={control}
80 setValue={setValue}
81 isUploadingHeading={isUploadingHeading}
82 isUploadingBody={isUploadingBody}
83 isSaving={isSaving}
84 onUploadHeading={() => handleFontUpload("heading")}
85 onUploadBody={() => handleFontUpload("body")}
86 onSave={handleSaveFontPair}
87 onCancel={() => setShowCustom(false)}
88 getLocalCustomFonts={getLocalCustomFonts}
89 currentHeadingFont={currentHeadingFont}
90 currentBodyFont={currentBodyFont}
91 />
92 )}
93
94 <UserFontPairs
95 currentHeading={currentHeadingFont}
96 currentBody={currentBodyFont}
97 onSelect={handleSelectUserFontPair}
98 />
99
100 <FontCombinationsList
101 currentHeading={currentHeadingFont}
102 currentBody={currentBodyFont}
103 onSelect={handleSelectFontPair}
104 />
105 </div>
106 </div>
107 );
108 }
109
109 lines Plain Text