@@ -19,12 +19,14 @@ interface PreviewPanelProps {
19
19
const PageBreakLine = React . memo ( ( { pageNumber } : { pageNumber : number } ) => {
20
20
const { activeResume } = useResumeStore ( ) ;
21
21
const { globalSettings } = activeResume || { } ;
22
- if ( ! globalSettings ?. pagePadding ) return ;
22
+ if ( ! globalSettings ?. pagePadding ) return null ;
23
+
23
24
const A4_HEIGHT_MM = 297 ;
24
25
const MM_TO_PX = 3.78 ;
25
26
26
- const TOP_MARGIN_MM = globalSettings ?. pagePadding / MM_TO_PX ;
27
- const CONTENT_HEIGHT_MM = A4_HEIGHT_MM + TOP_MARGIN_MM + TOP_MARGIN_MM ;
27
+ const pagePaddingMM = globalSettings . pagePadding / MM_TO_PX ;
28
+
29
+ const CONTENT_HEIGHT_MM = A4_HEIGHT_MM + pagePaddingMM ;
28
30
const pageHeight = CONTENT_HEIGHT_MM * MM_TO_PX ;
29
31
30
32
return (
@@ -63,59 +65,80 @@ const PreviewPanel = ({
63
65
} , [ activeResume ?. templateId ] ) ;
64
66
65
67
const startRef = useRef < HTMLDivElement > ( null ) ;
66
- const previewRef = React . useRef < HTMLDivElement > ( null ) ;
67
- const resumeContentRef = React . useRef < HTMLDivElement > ( null ) ;
68
+ const previewRef = useRef < HTMLDivElement > ( null ) ;
69
+ const resumeContentRef = useRef < HTMLDivElement > ( null ) ;
68
70
const [ contentHeight , setContentHeight ] = useState ( 0 ) ;
69
71
70
72
const updateContentHeight = ( ) => {
71
73
if ( resumeContentRef . current ) {
72
- const height = resumeContentRef . current . scrollHeight ;
74
+ const height = resumeContentRef . current . clientHeight ;
73
75
if ( height > 0 ) {
74
- setContentHeight ( height ) ;
76
+ if ( height !== contentHeight ) {
77
+ setContentHeight ( height ) ;
78
+ }
75
79
}
76
80
}
77
81
} ;
78
82
79
83
useEffect ( ( ) => {
80
- const observer = new MutationObserver ( updateContentHeight ) ;
84
+ const debouncedUpdate = throttle ( ( ) => {
85
+ requestAnimationFrame ( ( ) => {
86
+ updateContentHeight ( ) ;
87
+ } ) ;
88
+ } , 100 ) ;
89
+
90
+ const observer = new MutationObserver ( debouncedUpdate ) ;
91
+
81
92
if ( resumeContentRef . current ) {
82
93
observer . observe ( resumeContentRef . current , {
83
94
childList : true ,
84
95
subtree : true ,
85
96
attributes : true ,
97
+ characterData : true ,
86
98
} ) ;
87
99
88
100
updateContentHeight ( ) ;
89
101
}
90
102
91
- const resizeObserver = new ResizeObserver (
92
- throttle ( updateContentHeight , 100 )
93
- ) ;
103
+ const resizeObserver = new ResizeObserver ( debouncedUpdate ) ;
104
+
94
105
if ( resumeContentRef . current ) {
95
106
resizeObserver . observe ( resumeContentRef . current ) ;
96
107
}
97
108
98
- const timeoutId = setTimeout ( updateContentHeight , 100 ) ;
99
-
100
109
return ( ) => {
101
110
observer . disconnect ( ) ;
102
111
resizeObserver . disconnect ( ) ;
103
- clearTimeout ( timeoutId ) ;
104
112
} ;
113
+ } , [ ] ) ;
114
+
115
+ useEffect ( ( ) => {
116
+ if ( activeResume ) {
117
+ const timer = setTimeout ( updateContentHeight , 300 ) ;
118
+ return ( ) => clearTimeout ( timer ) ;
119
+ }
105
120
} , [ activeResume ] ) ;
106
121
107
- const pageBreakCount = useMemo ( ( ) => {
108
- let TOP_MARGIN_MM ;
122
+ const { pageHeightPx, pageBreakCount } = useMemo ( ( ) => {
109
123
const MM_TO_PX = 3.78 ;
110
124
const A4_HEIGHT_MM = 297 ;
125
+
126
+ let pagePaddingMM = 0 ;
111
127
if ( activeResume ?. globalSettings ?. pagePadding ) {
112
- TOP_MARGIN_MM = activeResume . globalSettings . pagePadding / MM_TO_PX ;
113
- } else {
114
- TOP_MARGIN_MM = 0 ;
128
+ pagePaddingMM = activeResume . globalSettings . pagePadding / MM_TO_PX ;
115
129
}
116
- const CONTENT_HEIGHT_MM = A4_HEIGHT_MM - TOP_MARGIN_MM - TOP_MARGIN_MM ;
130
+
131
+ const CONTENT_HEIGHT_MM = A4_HEIGHT_MM - pagePaddingMM ;
117
132
const pageHeightPx = CONTENT_HEIGHT_MM * MM_TO_PX ;
118
- return Math . max ( 0 , Math . ceil ( contentHeight / pageHeightPx ) - 1 ) ;
133
+
134
+ if ( contentHeight <= 0 ) {
135
+ return { pageHeightPx, pageBreakCount : 0 } ;
136
+ }
137
+
138
+ const pageCount = Math . max ( 1 , Math . ceil ( contentHeight / pageHeightPx ) ) ;
139
+ const pageBreakCount = Math . max ( 0 , pageCount - 1 ) ;
140
+
141
+ return { pageHeightPx, pageBreakCount } ;
119
142
} , [ contentHeight , activeResume ?. globalSettings ?. pagePadding ] ) ;
120
143
121
144
if ( ! activeResume ) return null ;
@@ -128,7 +151,7 @@ const PreviewPanel = ({
128
151
fontFamily : "MiSans VF, sans-serif" ,
129
152
} }
130
153
>
131
- < div className = "py-4 ml-4 px-4 min-h-screen flex justify-center scale-[58%] origin-top md:scale-90 md:origin-top-left" >
154
+ < div className = "py-4 ml-4 px-4 min-h-screen flex justify-center scale-[58%] origin-top md:scale-90 md:origin-top-left" >
132
155
< div
133
156
ref = { startRef }
134
157
className = { cn (
@@ -186,9 +209,30 @@ const PreviewPanel = ({
186
209
}
187
210
` } </ style >
188
211
< ResumeTemplateComponent data = { activeResume } template = { template } />
189
- { Array . from ( { length : pageBreakCount } , ( _ , i ) => (
190
- < PageBreakLine key = { i } pageNumber = { i + 1 } />
191
- ) ) }
212
+ { contentHeight > 0 && (
213
+ < >
214
+ < div key = { `page-breaks-container-${ contentHeight } ` } >
215
+ { Array . from (
216
+ { length : Math . min ( pageBreakCount , 20 ) } ,
217
+ ( _ , i ) => {
218
+ const pageNumber = i + 1 ;
219
+
220
+ const pageLinePosition = pageHeightPx * pageNumber ;
221
+
222
+ if ( pageLinePosition <= contentHeight ) {
223
+ return (
224
+ < PageBreakLine
225
+ key = { `page-break-${ pageNumber } ` }
226
+ pageNumber = { pageNumber }
227
+ />
228
+ ) ;
229
+ }
230
+ return null ;
231
+ }
232
+ ) . filter ( Boolean ) }
233
+ </ div >
234
+ </ >
235
+ ) }
192
236
</ div >
193
237
</ div >
194
238
</ div >
0 commit comments