@yamlresume/playground 0.13.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +19 -20
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { OnMount } from '@monaco-editor/react';
|
|
3
1
|
import * as react from 'react';
|
|
4
2
|
import { ReactNode, PropsWithChildren } from 'react';
|
|
3
|
+
import { OnMount } from '@monaco-editor/react';
|
|
5
4
|
import { Resume, LayoutEngine } from '@yamlresume/core';
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -30,7 +29,7 @@ interface EditorProps {
|
|
|
30
29
|
* @param props - The component props.
|
|
31
30
|
* @returns The rendered Editor component.
|
|
32
31
|
*/
|
|
33
|
-
declare function Editor({ value, onChange, language, readOnly, lineNumbers, minimap, onMount, }: EditorProps):
|
|
32
|
+
declare function Editor({ value, onChange, language, readOnly, lineNumbers, minimap, onMount, }: EditorProps): react.JSX.Element;
|
|
34
33
|
|
|
35
34
|
/**
|
|
36
35
|
* MIT License
|
|
@@ -105,7 +104,7 @@ interface EditorPanelProps {
|
|
|
105
104
|
* @param props - The component props.
|
|
106
105
|
* @returns The rendered editor panel.
|
|
107
106
|
*/
|
|
108
|
-
declare function EditorPanel({ value, onChange, filename, tooltips, }: EditorPanelProps):
|
|
107
|
+
declare function EditorPanel({ value, onChange, filename, tooltips, }: EditorPanelProps): react.JSX.Element;
|
|
109
108
|
|
|
110
109
|
/**
|
|
111
110
|
* Props for the ResumeEditor component.
|
|
@@ -134,7 +133,7 @@ interface ResumeEditorProps {
|
|
|
134
133
|
* @param props.onChange - Handler called when content is modified.
|
|
135
134
|
* @returns The rendered editor component.
|
|
136
135
|
*/
|
|
137
|
-
declare function ResumeEditor({ value, onChange, onMount }: ResumeEditorProps):
|
|
136
|
+
declare function ResumeEditor({ value, onChange, onMount }: ResumeEditorProps): react.JSX.Element;
|
|
138
137
|
|
|
139
138
|
/**
|
|
140
139
|
* Props for the Playground component.
|
|
@@ -159,7 +158,7 @@ interface PlaygroundProps {
|
|
|
159
158
|
* @param props - The component props.
|
|
160
159
|
* @returns The rendered Playground component.
|
|
161
160
|
*/
|
|
162
|
-
declare function Playground({ yaml: yamlStr, onChange, filename, messages, }: PlaygroundProps):
|
|
161
|
+
declare function Playground({ yaml: yamlStr, onChange, filename, messages, }: PlaygroundProps): react.JSX.Element;
|
|
163
162
|
|
|
164
163
|
/**
|
|
165
164
|
* Props for the PlaygroundDesktop component.
|
|
@@ -178,7 +177,7 @@ interface PlaygroundDesktopProps {
|
|
|
178
177
|
* @param props - The component props.
|
|
179
178
|
* @returns The rendered desktop layout.
|
|
180
179
|
*/
|
|
181
|
-
declare function PlaygroundDesktop({ editorPanel, previewPanel, }: PlaygroundDesktopProps):
|
|
180
|
+
declare function PlaygroundDesktop({ editorPanel, previewPanel, }: PlaygroundDesktopProps): react.JSX.Element;
|
|
182
181
|
|
|
183
182
|
/**
|
|
184
183
|
* Props for the PlaygroundMobile component.
|
|
@@ -197,7 +196,7 @@ interface PlaygroundMobileProps {
|
|
|
197
196
|
* @param props - The component props.
|
|
198
197
|
* @returns The rendered mobile layout.
|
|
199
198
|
*/
|
|
200
|
-
declare function PlaygroundMobile({ editorPanel, previewPanel, }: PlaygroundMobileProps):
|
|
199
|
+
declare function PlaygroundMobile({ editorPanel, previewPanel, }: PlaygroundMobileProps): react.JSX.Element;
|
|
201
200
|
|
|
202
201
|
/**
|
|
203
202
|
* MIT License
|
|
@@ -237,7 +236,7 @@ interface CodeViewerProps {
|
|
|
237
236
|
* @param props - The props for the CodePreview component.
|
|
238
237
|
* @returns The rendered Monaco Editor.
|
|
239
238
|
*/
|
|
240
|
-
declare function CodeViewer({ content, language }: CodeViewerProps):
|
|
239
|
+
declare function CodeViewer({ content, language }: CodeViewerProps): react.JSX.Element;
|
|
241
240
|
|
|
242
241
|
/**
|
|
243
242
|
* MIT License
|
|
@@ -275,7 +274,7 @@ interface DocxViewerProps {
|
|
|
275
274
|
* @param props - The props for the DocxViewer component.
|
|
276
275
|
* @returns The rendered DocxViewer component.
|
|
277
276
|
*/
|
|
278
|
-
declare function DocxViewer({ content }: DocxViewerProps):
|
|
277
|
+
declare function DocxViewer({ content }: DocxViewerProps): react.JSX.Element;
|
|
279
278
|
|
|
280
279
|
/**
|
|
281
280
|
* MIT License
|
|
@@ -313,7 +312,7 @@ interface HtmlViewerProps {
|
|
|
313
312
|
* @param props - The props for the HtmlPreview component.
|
|
314
313
|
* @returns The rendered iframe element.
|
|
315
314
|
*/
|
|
316
|
-
declare function HtmlViewer({ content }: HtmlViewerProps):
|
|
315
|
+
declare function HtmlViewer({ content }: HtmlViewerProps): react.JSX.Element;
|
|
317
316
|
|
|
318
317
|
/**
|
|
319
318
|
* Props for the PreviewPanel component.
|
|
@@ -336,7 +335,7 @@ interface PreviewPanelProps {
|
|
|
336
335
|
* @param props - The component props.
|
|
337
336
|
* @returns The rendered preview panel.
|
|
338
337
|
*/
|
|
339
|
-
declare function PreviewPanel({ activeLayoutIndex, filename, resume, setActiveLayoutIndex, tooltips, }: PreviewPanelProps):
|
|
338
|
+
declare function PreviewPanel({ activeLayoutIndex, filename, resume, setActiveLayoutIndex, tooltips, }: PreviewPanelProps): react.JSX.Element;
|
|
340
339
|
|
|
341
340
|
/**
|
|
342
341
|
* Props for the ResumeViewer component.
|
|
@@ -354,7 +353,7 @@ interface ResumeViewerProps {
|
|
|
354
353
|
* @param props - The props for the ResumeViewer component.
|
|
355
354
|
* @returns The rendered ResumeViewer component.
|
|
356
355
|
*/
|
|
357
|
-
declare function ResumeViewer({ resume, layoutIndex }: ResumeViewerProps):
|
|
356
|
+
declare function ResumeViewer({ resume, layoutIndex }: ResumeViewerProps): react.JSX.Element;
|
|
358
357
|
|
|
359
358
|
/**
|
|
360
359
|
* A styled panel container component for the Playground.
|
|
@@ -367,7 +366,7 @@ declare function ResumeViewer({ resume, layoutIndex }: ResumeViewerProps): react
|
|
|
367
366
|
* @param props - The component props.
|
|
368
367
|
* @returns The rendered panel container.
|
|
369
368
|
*/
|
|
370
|
-
declare function Panel({ children }: PropsWithChildren):
|
|
369
|
+
declare function Panel({ children }: PropsWithChildren): react.JSX.Element;
|
|
371
370
|
|
|
372
371
|
/**
|
|
373
372
|
* A shared container for panel content.
|
|
@@ -376,7 +375,7 @@ declare function Panel({ children }: PropsWithChildren): react_jsx_runtime.JSX.E
|
|
|
376
375
|
* @param props - The component props.
|
|
377
376
|
* @returns The rendered content container.
|
|
378
377
|
*/
|
|
379
|
-
declare function PanelContent({ children }: PropsWithChildren):
|
|
378
|
+
declare function PanelContent({ children }: PropsWithChildren): react.JSX.Element;
|
|
380
379
|
|
|
381
380
|
/**
|
|
382
381
|
* MIT License
|
|
@@ -406,7 +405,7 @@ declare function PanelContent({ children }: PropsWithChildren): react_jsx_runtim
|
|
|
406
405
|
*
|
|
407
406
|
* @returns The rendered separator.
|
|
408
407
|
*/
|
|
409
|
-
declare function PanelSeparator():
|
|
408
|
+
declare function PanelSeparator(): react.JSX.Element;
|
|
410
409
|
|
|
411
410
|
/**
|
|
412
411
|
* A shared toolbar component for panels.
|
|
@@ -414,7 +413,7 @@ declare function PanelSeparator(): react_jsx_runtime.JSX.Element;
|
|
|
414
413
|
* @param props - The component props.
|
|
415
414
|
* @returns The rendered toolbar.
|
|
416
415
|
*/
|
|
417
|
-
declare function PanelToolbar({ children }: PropsWithChildren):
|
|
416
|
+
declare function PanelToolbar({ children }: PropsWithChildren): react.JSX.Element;
|
|
418
417
|
|
|
419
418
|
/**
|
|
420
419
|
* Props for the ToolbarButton component.
|
|
@@ -435,7 +434,7 @@ interface ToolbarButtonProps {
|
|
|
435
434
|
* @param props - The component props.
|
|
436
435
|
* @returns The rendered toolbar button.
|
|
437
436
|
*/
|
|
438
|
-
declare function ToolbarButton({ onClick, children, title, }: ToolbarButtonProps):
|
|
437
|
+
declare function ToolbarButton({ onClick, children, title, }: ToolbarButtonProps): react.JSX.Element;
|
|
439
438
|
|
|
440
439
|
/**
|
|
441
440
|
* MIT License
|
|
@@ -476,7 +475,7 @@ interface ToolbarCopyButtonProps {
|
|
|
476
475
|
* @param props - The component props.
|
|
477
476
|
* @returns The rendered copy button.
|
|
478
477
|
*/
|
|
479
|
-
declare function ToolbarCopyButton({ onClick, title, }: ToolbarCopyButtonProps):
|
|
478
|
+
declare function ToolbarCopyButton({ onClick, title, }: ToolbarCopyButtonProps): react.JSX.Element;
|
|
480
479
|
|
|
481
480
|
/**
|
|
482
481
|
* MIT License
|
|
@@ -506,7 +505,7 @@ declare function ToolbarCopyButton({ onClick, title, }: ToolbarCopyButtonProps):
|
|
|
506
505
|
*
|
|
507
506
|
* @returns The rendered separator.
|
|
508
507
|
*/
|
|
509
|
-
declare function ToolbarSeparator():
|
|
508
|
+
declare function ToolbarSeparator(): react.JSX.Element;
|
|
510
509
|
|
|
511
510
|
/**
|
|
512
511
|
* MIT License
|
package/dist/index.js
CHANGED
|
@@ -273,6 +273,6 @@ layouts:
|
|
|
273
273
|
typography:
|
|
274
274
|
# LaTeX engine only supports 10pt, 11pt, and 12pt
|
|
275
275
|
fontSize: 11pt
|
|
276
|
-
`;function K({yaml:e=L,onChange:t}){let[o,r]=useState(0),n=i=>{t?.(i);},a=useMemo(()=>{try{return parse(e)}catch{return null}},[e]);return useEffect(()=>{let i=a?.layouts||[];o>=i.length&&i.length>0&&r(i.length-1);},[a?.layouts,o]),{yaml:e,handleYamlChange:n,activeLayoutIndex:o,setActiveLayoutIndex:r,resume:a}}var ce={tooltips:{copy:"Copy",undo:"Undo",redo:"Redo",clear:"Clear",print:"Print",openInNewTab:"Open in New Tab",download:"Download"}};function Ve({yaml:e=L,onChange:t,filename:o,messages:r}){let{yaml:n,handleYamlChange:a,activeLayoutIndex:i,setActiveLayoutIndex:s,resume:g}=K({yaml:e,onChange:t}),m={...ce.tooltips,...r?.tooltips},l=jsx(Z,{value:n,onChange:y=>a(y||""),filename:o,tooltips:m}),u=jsx(Y,{activeLayoutIndex:i,setActiveLayoutIndex:s,resume:g,filename:o,tooltips:m});return jsxs("div",{className:fe("flex flex-col h-full w-full gap-4","text-neutral-200"),style:{backgroundColor:w},children:[jsx(j,{editorPanel:l,previewPanel:u}),jsx(G,{editorPanel:l,previewPanel:u})]})}function G({editorPanel:e,previewPanel:t}){return jsx("div",{className:"hidden md:flex flex-1 overflow-hidden",children:jsxs(Group,{orientation:"horizontal",children:[jsx(Panel,{minSize:360,className:"flex flex-col",children:e}),jsx(Q,{}),jsx(Panel,{minSize:360,className:"flex flex-col",children:t})]})})}function q({label:e,active:t,onClick:o,icon:r}){return jsxs("button",{type:"button",onClick:o,className:fe("flex-1 flex items-center justify-center gap-2 h-10","text-sm","transition-colors",t&&"border-b-2 border-neutral-200 font-medium"),children:[jsx(r,{size:p.sm,stroke:c.sm}),e]})}function de({activeTab:e,onTabChange:t}){return jsxs("div",{className:"flex md:hidden border-b border-neutral-400",children:[jsx(q,{label:"Editor",icon:IconEdit,active:e==="editor",onClick:()=>t("editor")}),jsx(q,{label:"Preview",icon:IconEye,active:e==="preview",onClick:()=>t("preview")})]})}function j({editorPanel:e,previewPanel:t}){let[o,r]=useState("editor");return jsxs("div",{className:"flex-1 flex flex-col gap-2 overflow-hidden md:hidden",children:[jsx(de,{activeTab:o,onTabChange:r}),jsx("div",{className:fe("flex-1 flex-col min-h-0",o==="editor"?"flex":"hidden"),children:e}),jsx("div",{className:fe("flex-1 flex-col min-h-0",o==="preview"?"flex":"hidden"),children:t})]})}function oe({content:e,language:t}){return jsx(C,{language:t,value:e,readOnly:true,minimap:false,lineNumbers:false})}function te({content:e}){let t=useRef(null),[o,r]=useState(null),[n,a]=useState(false);return useEffect(()=>{if(!e||!t.current)return r(null),a(false),()=>{};a(true),r(null);let i=t.current;return renderAsync(e,i,void 0,{className:"docx",inWrapper:true}).then(()=>{a(false);}).catch(s=>{a(false),r(`DOCX Render Error: ${s instanceof Error?s.message:String(s)}`);}),()=>{i.innerHTML="";}},[e]),e?o?jsx("div",{role:"alert","aria-live":"polite",className:"h-full w-full p-4 font-mono text-red-500 bg-red-50 border border-red-200",children:o}):jsxs("div",{className:"h-full w-full overflow-auto bg-white relative",children:[n&&jsx("div",{className:"absolute inset-0 flex items-center justify-center bg-white/80 z-10",children:jsx("div",{className:"text-gray-500",children:"Loading DOCX preview\u2026"})}),jsx("div",{ref:t,className:"docx-preview-container"})]}):jsx("div",{className:"h-full w-full flex items-center justify-center text-gray-500 bg-gray-50",children:"No DOCX content to preview."})}function re({content:e}){return jsx("iframe",{title:"Resume HTML Preview",className:"w-full h-full border-none",srcDoc:e})}var he="data:image/png;base64,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";function ye(){return jsxs("div",{className:fe("h-full w-full","flex flex-col items-center justify-center gap-4","text-neutral-200"),children:[jsx("img",{src:he,alt:"YAML Resume Logo",className:"w-32 h-32 opacity-70 grayscale",draggable:false}),jsx("div",{className:"text-lg font-medium",children:"No Layouts Defined"}),jsx("p",{className:"max-w-xs text-center text-sm text-neutral-400",children:"Your resume appears to be empty or contains no layout definitions."})]})}function go(e){switch(e){case "html":return jsx(IconHtml,{size:p.sm,stroke:c.sm});case "markdown":return jsx(IconMarkdown,{size:p.sm,stroke:c.sm});case "latex":return jsx(IconTex,{size:p.sm,stroke:c.sm});default:return jsx(IconFileText,{size:p.sm,stroke:c.sm})}}function Pe({active:e,onClick:t,engine:o,index:r,filename:n}){return jsxs("button",{type:"button",onClick:t,className:fe("flex items-center gap-2 max-w-[200px]","h-full px-4","transition-colors border-r border-neutral-600 last:border-neutral-400"),title:`${n}.${r}${E(o)}`,role:"tab","aria-selected":e,style:{backgroundColor:e&&w},children:[go(o),jsxs("span",{className:"truncate",children:[n,".",r,E(o)]})]})}function we({children:e}){return jsx("div",{role:"tablist",className:fe("flex h-full overflow-x-auto"),children:e})}function ae({resume:e,layoutIndex:t}){let{renderedContent:o,binaryContent:r,engine:n,error:a}=J({resume:e,layoutIndex:t});return a?jsx("div",{role:"alert","aria-live":"polite",className:fe("h-full w-full p-4","font-mono text-red-500 bg-red-50","border border-red-200"),children:a}):n==="docx"?jsx(te,{content:r}):jsx("div",{className:"h-full w-full flex flex-col bg-white",children:n==="html"?jsx(re,{content:o}):jsx(oe,{content:o,language:n})})}function Y({activeLayoutIndex:e,filename:t,resume:o,setActiveLayoutIndex:r,tooltips:n}){let a=useMemo(()=>(o?.layouts||[]).map((u,y)=>({layout:u,originalIndex:y})).filter(u=>u.layout!==null&&u.layout!==void 0&&typeof u.layout.engine=="string"),[o?.layouts]),i=R(t,true)||"resume",s=useCallback(()=>{z(o,e);},[o,e]),g=useCallback(()=>{V(o,e);},[o,e]),m=useCallback(()=>{U(o,e);},[o,e]),l=useCallback(()=>{W(o,e);},[o,e]);return a.length===0?jsxs(x,{children:[jsx(v,{}),jsx(ye,{})]}):jsxs(x,{children:[jsxs(v,{children:[jsx(we,{children:a.map(({layout:u,originalIndex:y})=>jsx(Pe,{active:e===y,onClick:()=>r(y),engine:u.engine,index:y,filename:i},`${u.engine}-${y}`))}),jsx("div",{className:"flex-1"}),jsxs("div",{className:"flex items-center gap-0.5 pr-2",children:[jsx(N,{onClick:s,title:n.copy}),jsx(P,{}),o?.layouts?.[e]?.engine==="html"&&jsxs(Fragment,{children:[jsx(h,{onClick:g,title:n.print,children:jsx(IconPrinter,{size:p.sm,stroke:c.sm})}),jsx(h,{onClick:m,title:n.openInNewTab,children:jsx(IconExternalLink,{size:p.sm,stroke:c.sm})}),jsx(P,{})]}),jsx(h,{onClick:l,title:n.download,children:jsx(IconDownload,{size:p.sm,stroke:c.sm})})]})]}),jsx(k,{children:jsx(ae,{resume:o,layoutIndex:e})})]})}function x({children:e}){return jsx("div",{className:fe("flex-1 flex flex-col","border border-neutral-400 overflow-hidden"),children:e})}function k({children:e}){return jsx("div",{className:"flex-1 relative",children:e})}function Q(){return jsx(Separator,{className:fe("w-2","flex flex-col justify-center items-center group","transition-colors cursor-col-resize"),"data-testid":"separator",children:jsx("div",{className:fe("w-1 h-8","bg-neutral-400","group-hover:bg-neutral-300")})})}function v({children:e}){return jsx("div",{className:fe("flex items-center border-b border-neutral-400 h-10 text-sm","bg-neutral-800"),children:e})}function h({onClick:e,children:t,title:o}){return jsx("button",{type:"button",onClick:e,className:fe("flex items-center justify-center h-8 w-8","text-neutral-200 hover:text-neutral-700 hover:bg-neutral-200","transition-colors","focus:outline-none focus:ring-1 focus:ring-neutral-400"),title:o,children:t})}function N({onClick:e,title:t="Copy"}){let[o,r]=useState(false);return jsx(h,{onClick:async()=>{try{await e(),r(!0),setTimeout(()=>r(!1),2e3);}catch(a){console.error("Failed to copy",a);}},title:t,children:o?jsx(IconCheck,{size:p.sm,stroke:c.sm}):jsx(IconCopy,{size:p.sm,stroke:c.sm})})}function P(){return jsx("div",{className:"w-px h-4 bg-neutral-400 mx-1"})}
|
|
276
|
+
`;function K({yaml:e=L,onChange:t}){let[o,r]=useState(0),n=i=>{t?.(i);},a=useMemo(()=>{try{return parse(e)}catch{return null}},[e]);return useEffect(()=>{let i=a?.layouts||[];o>=i.length&&i.length>0&&r(i.length-1);},[a?.layouts,o]),{yaml:e,handleYamlChange:n,activeLayoutIndex:o,setActiveLayoutIndex:r,resume:a}}var ce={tooltips:{copy:"Copy",undo:"Undo",redo:"Redo",clear:"Clear",print:"Print",openInNewTab:"Open in New Tab",download:"Download"}};function Ve({yaml:e=L,onChange:t,filename:o,messages:r}){let{yaml:n,handleYamlChange:a,activeLayoutIndex:i,setActiveLayoutIndex:s,resume:g}=K({yaml:e,onChange:t}),m={...ce.tooltips,...r?.tooltips},l=jsx(Z,{value:n,onChange:y=>a(y||""),filename:o,tooltips:m}),u=jsx(Y,{activeLayoutIndex:i,setActiveLayoutIndex:s,resume:g,filename:o,tooltips:m});return jsxs("div",{className:fe("flex flex-col h-full w-full gap-4","text-neutral-200"),style:{backgroundColor:w},children:[jsx(j,{editorPanel:l,previewPanel:u}),jsx(G,{editorPanel:l,previewPanel:u})]})}function G({editorPanel:e,previewPanel:t}){return jsx("div",{className:"hidden md:flex flex-1 overflow-hidden",children:jsxs(Group,{orientation:"horizontal",children:[jsx(Panel,{minSize:360,className:"flex flex-col",children:e}),jsx(Q,{}),jsx(Panel,{minSize:360,className:"flex flex-col",children:t})]})})}function q({label:e,active:t,onClick:o,icon:r}){return jsxs("button",{type:"button",onClick:o,className:fe("flex-1 flex items-center justify-center gap-2 h-10","text-sm","transition-colors",t&&"border-b-2 border-neutral-200 font-medium"),children:[jsx(r,{size:p.sm,stroke:c.sm}),e]})}function de({activeTab:e,onTabChange:t}){return jsxs("div",{className:"flex md:hidden border-b border-neutral-400",children:[jsx(q,{label:"Editor",icon:IconEdit,active:e==="editor",onClick:()=>t("editor")}),jsx(q,{label:"Preview",icon:IconEye,active:e==="preview",onClick:()=>t("preview")})]})}function j({editorPanel:e,previewPanel:t}){let[o,r]=useState("editor");return jsxs("div",{className:"flex-1 flex flex-col gap-2 overflow-hidden md:hidden",children:[jsx(de,{activeTab:o,onTabChange:r}),jsx("div",{className:fe("flex-1 flex-col min-h-0",o==="editor"?"flex":"hidden"),children:e}),jsx("div",{className:fe("flex-1 flex-col min-h-0",o==="preview"?"flex":"hidden"),children:t})]})}function oe({content:e,language:t}){return jsx(C,{language:t,value:e,readOnly:true,minimap:false,lineNumbers:false})}function te({content:e}){let t=useRef(null),[o,r]=useState(null),[n,a]=useState(false);return useEffect(()=>{if(!e||!t.current)return r(null),a(false),()=>{};a(true),r(null);let i=t.current;return renderAsync(e,i,void 0,{className:"docx",inWrapper:true}).then(()=>{a(false);}).catch(s=>{a(false),r(`DOCX Render Error: ${s instanceof Error?s.message:String(s)}`);}),()=>{i.innerHTML="";}},[e]),e?o?jsx("div",{role:"alert","aria-live":"polite",className:"h-full w-full p-4 font-mono text-red-500 bg-red-50 border border-red-200",children:o}):jsxs("div",{className:"h-full w-full overflow-auto bg-white relative",children:[n&&jsx("div",{className:"absolute inset-0 flex items-center justify-center bg-white/80 z-10",children:jsx("div",{className:"text-gray-500",children:"Loading DOCX preview\u2026"})}),jsx("div",{ref:t,className:"docx-preview-container"})]}):jsx("div",{className:"h-full w-full flex items-center justify-center text-gray-500 bg-gray-50",children:"No DOCX content to preview."})}function re({content:e}){return jsx("iframe",{title:"Resume HTML Preview",className:"w-full h-full border-none",srcDoc:e})}var he="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAAAXNSR0IArs4c6QAAIABJREFUeF7tnQv0d1Od/1/FEE1p0vPkfim1pMGsoVW5DKmoqakhMkg3lFbppoZQUm5N6aaGQjdhRFRTU1RiXNKKWROTrCj3S480qYn4P+X/3T/nx+Pnd/leztlnX157rbN+5Tln78/ntT/7fN9nXx+FSQISSJ3AcsBiYBHwJOCJzfVXwBOAVYDHA48D/hJ4LLAysBLwGGBFYAXgL4DlgZDfo4FHNY7fD/wZ+BOwFPh/wH3AvcAfgXuAu4E/AP8H/B74HXAX8Fvgf4HfNNevgTuAJU1+qbPVPglUS2D6BVAtAB2XQM8Ewo/3usDazbUWsCawBrA6sFrzw9+zmWMVH4TA7cBtwK3ALcDNwE3NdUMjIsbK3IckIIHJCCgAJuPn0xIYhkD4EX86sEFzPRV4CrA+sOowGRR8z53AdcAvgV8A1zbXzxvxULDruiaBfgkoAPrlb+llEQhf738NbNRczwA2bLrry/I0jjdhWOFq4GfAVc31P00vQhwLLEUCBRNQABRcubrWKYGNgb9prk2BTTLuqu8UVAeZh6GFK4CfAP/dXFd2UI5ZSqBoAgqAoqtX51oiELrun9VcmwObNZPsWsrebFogECYpXg5cBvy4ucJwgkkCEpiDgALA0JDAwwmENrEl8Nzmek4zGU9O+REIkw8vBX7YXBcDYcWDSQISWGYZkDAkUCuBsCxuG2Dr5tqqWTJXK4+S/Q5LGy8CLmyuC5pljyX7rG8SmJOAPQAGR40Ewtf985pr22ZtfI0cavc57Hlw/kAA/qC5Qk+BSQLVEFAAVFPVVTu6DvDC5nqBS++qjoX5nA9LEr83GAL6bnPdKCkJlExAAVBy7dbtW+jKf1FzhUl7JgmMSiBMKvxOc4WhA5MEiiKgACiqOqt2Jmxv+9LmeokT96qOhS6cDxMKvwV8s7nCtskmCWRNQAGQdfVVb3zY7/7lzfWyZu/76qEIoHMC4WyEbwBfb66wBNEkgewIKACyq7LqDQ4H2+zUXDs2B9tUD0UAvREIPQFnDzaCOqu5wgFKJglkQUABkEU1aWTzlb8LsHNzup1QJJAagfDjf2ZzfS0147RHAjMJKACMiZQJhIl8uzZXOArXJIFcCITtik9vLicQ5lJrldmpAKiswjNwNyzZ2725wn77JgnkTiCcU3Bqc7m0MPfaLMh+BUBBlZm5K68YHAe7Z9PVn7krmi+BOQmEiYMnA1+VkQT6JqAA6LsG6i7/aYOz4F/TXOEoXZMEaiFwM/DF5rqmFqf1My0CCoC06qMWa8LSvdf5tV9LdevnAgRCr8DnmyWFwpJANAIKgGioqy9oFWDv5tqwehoCkMAjCVwNnNhcdwlIAl0TUAB0Tdj8w0S+NzTXCuKQgAQWJBBOLfxsc4UJhCYJdEJAAdAJVjMFtgf2BcJmPSYJSGA8AmGToeOBc8d73KckMDcBBYDR0TaB3YA3D05T27LtjM1PAhUTuBj4NHBaxQx0vWUCCoCWgVacXfja3w/YqGIGui6BrglcNTjO+timV6Drssy/cAIKgMIruGP3wgl8b2uusIGPSQISiEMgbCj0iebyZMI4zIsrRQFQXJVGcShM5ntHcz05SokWIgEJzEbgV8DHmitMHjRJYGgCCoChUXkjsDywf3O5N78hIYF0CISzB45prqXpmKUlKRNQAKRcO2nZ9k7g3YOxx9XSMktrJCCBZQjcDnwY+KhUJLAQAQXAQoT89zC57wBgPVFIQALZELge+JCTBbOpr14MVQD0gj2LQsNyvvcMDi3xRL4sqksjJTArgbCR0FEuHzQ6ZiOgADAuZhIIG/gcBGwjGglIoBgCFwBHuqFQMfXZiiMKgFYwFpFJ+NI/BHhlEd7ohAQkMBuBrwwm8x4OuMWw8YECwCAIh/S8DwiT/EwSkEAdBMIkwQ8MlvJ66FAd9T2rlwqAiisfeMvA/fcPdhZbtW4Mei+BKgnc2bT/T1XpvU7bA1BpDOwAHAY8u1L/dVsCEniIwI+AQ4FzhFIXAXsA6qrvtYAPAq+ty229lYAEhiDwBeC9wM1D3OstBRBQABRQiUO6ELbuPWKwNnilIe/3NglIoD4C9wAHN1sL1+d9ZR4rAMqv8LCcLyz/2aJ8V/VQAhJoicAlzXLgsHzQVCgBBUChFTvY/GNF4Gjg7eW6qGcSkEDHBD4OHDjYFOzejssx+x4IKAB6gB6hyF2abUDXj1CWRUhAAmUTuK7ZDvyMst2szzsFQFl1Hk7oCweBvKYst/RGAhJIgMAXmwPBwsmDpgIIKAAKqMTGhT2bo0A9precOtUTCaRGIPz4hyPBT07NMO0ZnYACYHRmqT2xuDn6c4/UDNMeCUigWAKnNLuHLinWwwocUwDkXcnhxL4wSSeIAJMEJCCBmATCj3+YZHxazEItqz0CCoD2WMbMaWXgE4MNO/aOWahlSUACEpiFwInA24C7pZMXAQVAXvUVrH0x8Elgg/xM12IJSKBQAtcCbx1sL/7tQv0r0i0FQF7VGnbyOygvk7VWAhKoiEDYdCzsJGjKgIACIINKAp4JfBoIu/qZJCABCaRMIOwe+GbgpykbqW14GmAGQfB64LjBdr4rZGCrJkpAAhIIBO4D3gR8ThzpErAHIN26CZYdD7wxbRO1TgISkMCcBD4D7CufNAkoANKsl82A0HDCX5MEJCCBnAlc3nzIhL+mhAgoABKqjMaUvYATcHgmvZrRIglIYFwC9wP7ACeNm4HPtU9AAdA+00lyDMv79pskA5+VgAQkkDCBY5vlggmbWI9pCoA06vopjTLeNg1ztEICEpBAZwTOB0JP5y87K8GMhyKgABgKU6c3vbSZKeshPp1iNnMJSCAhAuFQobDC6ZsJ2VSdKQqAfqs8nKr1kX5NsHQJSEACvRF4V3OKaW8G1FywAqC/2g+z/N/QX/GWLAEJSCAJAp91uXM/9aAAiM99TeBLwHbxi7ZECUhAAkkSOG8wJ+DVg5UCtyRpXaFGKQDiVuxWwMnAenGLtTQJSEACyRO4HtgTuCh5SwsxUAEQryJ3B06JV5wlSUACEsiSwB7AqVlanpnRCoA4FXYAcHScoixFAhKQQPYEDgQ+lL0XiTugAOi+gtzcp3vGliABCZRHwE2DOq5TBUB3gB8NnA7s3F0R5iwBCUigaAJnArsCfy7ay56cUwB0A34xEAJ3626yN1cJSEAC1RC4sPmQWlKNx5EcVQC0D3oj4KvAhu1nbY4SkIAEqiRwNfAK4Koqve/IaQVAu2DDMr+zALf1bZeruUlAAhII2wfv5DLB9gJBAdAey7Cn/9nA8u1laU4SkIAEJLAMgaXAjp4h0E5MKADa4bib61bbAWkuEpCABIYgEPZVOW2I+7xlHgIKgMnDYx8g7GVtkoAEJCCBeATCWSonxCuuvJIUAJPV6duAj0+WhU9LQAISkMCYBN4OfGLMZ6t/TAEwfgi4u9/47HxSAhKQQFsE3DVwTJIKgPHAvRf4wHiP+pQEJCABCbRM4H3AB1vOs/jsFACjV/Fhg12pQrCZJCABCUggHQLho+zQdMxJ3xIFwGh1FBTmIaM94t0SkIAEJBCJwOFA6KE1DUFAATAEpOYWf/yHZ+WdEpCABPoioAgYkrwCYDhQdvsPx8m7JCABCaRAwOGAIWpBAbAwJCf8LczIOyQgAQmkRsCJgQvUiAJgfkAu9UutSWuPBCQggeEJuERwHlYKgLnhuMnP8I3MOyUgAQmkSsDNguaoGQXA7GDc3jfVpqxdEpCABEYn4LbBszBTADwSigf7jN64fEICEpBA6gQ8QGhGDSkAHg4kHOn776lHsfZJQAISkMBYBP7Bo4Qf4qYAeIjFVsAPgOXHCisfkoAEJCCB1AksBZ4HXJS6oTHsUwA8QHkj4HxgUQzoliEBCUhAAr0RuGPwvt8WuKo3CxIpWAEAiweK8AJgw0TqRDMkIAEJSKBbAlcPeny3AZZ0W0zaudcuAB7dfPlvnXY1aZ0EJCABCbRM4MKmJ+DPLeebTXa1C4AzgJ2zqS0NlYAEJCCBNgmcCezSZoY55VWzAPgksF9OlaWtEpCABCTQOoFjgbe2nmsGGdYqANziN4Pg1EQJSEACkQhUuWVwjQIgbAZxSqSgshgJSEACEsiDwB7AqXmY2o6VtQmAsNY/TPwwSUACEpCABGYSCBPCq9kjoCYBsGZTsesZ8xKQgAQkIIFZCFwPhA/FW2qgU5MA+D6wXQ2Vqo8SkIAEJDA2gfMGPcXPH/vpjB6sRQB8BginQZkkIAEJSEACCxH4LPDGhW7K/d9rEAD7Ax/JvaK0XwISkIAEohJ4F3BM1BIjF1a6APB0v8gBZXESkIAECiJQ9OmBJQuApwCXesBPQU1RVyQgAQnEJRAODnoO8Mu4xcYprWQBEI72DSc+mSQgAQlIQALjEggnxYYjhItLpQoAt/ktLlR1SAISkEBvBIrcLrhEAbAXcGJvYWLBEpCABCRQIoG9gZNKcqw0AbAZ8GOgNL9Kijl9kYAEJJAjgfuBZwGX52j8bDaX9kN5GRBEgEkCEpCABCTQNoHw479525n2lV9JAuD4GjZu6CtQLFcCEpCABKYIhI3l9i2BRSkC4PWljc2UEFz6IAEJSKBQAmGu2edy960EAfBM4L+AFXKvDO2XgAQkIIEsCNwH/C3w0yysncPIEgRAWKO5Tc6VoO0SkIAEJJAdgQty32smdwFwBHBQdmGjwRKQgAQkUAKBI4GDc3UkZwHwYuA/cgWv3RKQgAQkUASBvwe+naMnuQqAlYGfABvkCF2bJSABCUigGALXApsCd+fmUa4C4AQg7MpkkoAEJCABCfRNIOw+u0/fRoxafo4CYDfg1FEd9X4JSEACEpBAhwR2B07rMP/Ws85NACwGrgTCX9Ng+cMPfvADtt223kMPn/e853H++WEhiEkCcQm8//3v59BDD41baEKlHXbYYQQGpgcJLAE2BsLfLFJuAuDLwB5ZkI1o5P33hy2q60zhxz+IAJMEYhOoud0F1o96VG4/H1Ei5BTgVVFKaqGQnGpwT+BLLfhcXBahByD0BNSa/BKpteb789uvf7/+54m+VwMn9xedw5eciwBY1Oy4FP6aZiHgUIBDATaMOAQU3P74LxBpdwBhh9rwN+mUiwD4AvCapEkmYFzNXZIOBSQQgJWYULvYtut/qED/IvDaoe7s8aYcBMAuwFd6ZJRN0X6Z+GWSTbBmaqhd/7axEUL3lYOegDNGuD/6rakLgBWBnwHrRyeTaYG1f524KiDTwM3E7Jp72ZxrM3KQXgc8A7h35CcjPZC6APgY8PZILIoppuaXlEMBxYRxco7U/vVv1/9YIflx4B1jPRnhoZQFQDjhzwXeYwRB7UMB9gKMETQ+Mi+B2n/8/fqfqIGEjVrCyYHJpZQFwMXAFskRy8SgmocC7AXIJEgzMrPmXjV//CcO1EuALSfOpYMMUhUAocvkox34W1WWvrTcpayqgO/I2dq//u36byWw3gmEIe2kUooCYC3g58BKSZHK0BiHAtwbIMOwTcrk2tuQX/+theM9gzNsnj44xO7m1nJsIaMUBcDnc1g/2QL7KFk4FOA2wVECrdBCam4//vi3HtRhP5vXtZ7rBBmmJgB2AL4zgT8+OgsBhwIcCrBhjE7Arv/Ufh5Gr8MEn3gRcE4qdqVWw5cCz04FTil21N6N6aqAUiI5rh8KZ4VzBxH3o8FH7nM6yHesLFMSAG8Bjh3LCx9akEDNXZmuClgwPLxhBoGav/7t+u+8OewHfKrzUoYoIBUBsArwi4EAWHUIm71lTAI1f9HYCzBm0FT4WM0//qG6nfXfedDfOTgt8KmDDYLu6rykBQpIRQAcA4RlEqYOCdQ8FGAvQIeBVVjWNQtlv/6jBXNY5r5/tNLmKCgFAbAxcEXfIGopv+ahAF9utUT5+H7W/PVv+xg/bsZ8chPgyjGfbeWxFATA6UA4NckUiUDNXzgOBUQKsgyLqbmHzK7/XgI2nHK7ay8lN4X2LQC2T2lJRJ8VEbPsml90DgXEjLS8yrJ3zFn/PURsWPp+bg/lThXZtwAIh/2EQ39MkQn4svNlFznkki7Orn/bQ08BGg4JCocF9ZL6FAC7DbZGPLUXry10ioBDAR42aVN4gEDNbcFZ/723gt2B0/qwok8BECb+hQmApp4IOBTgNsE9hV5Sxfr179d/zwEZJgKGCYHRU18CYF/guOjeWuAjCNQ8FOCEQBuEP/7++CfSCt4EHB/blr4EwHXAerGdtbzZCdTa/emEQFtErbEfat6u/6Ti/3pg/dgW9SEAwoY/YeMfUyIEah4KcO1zIkHYgxl+/fv130PYzVdk2BgobBAULcUWAMsDNw26OlaL5qEFDUXAoQAnBA4VKIXcpOj1xz/BUL4dWBtYGsu22ALgAODoWM5ZzmgEau0OdShgtDgp4e6aBa9d/0lH8IHAh2JZGFMArADcDCyK5ZzljEbAryK/ikaLmDzvtuvfOE84cu8A1gLui2FjTAHg13+MGp2wjJq/jFwVMGHwZPJ4rT1dznfJJEAhWi9ALAGwHHDLYOnfk7OpgooNrfUF6VBA+UFf89e/Xf/ZxPevgDWBP3VtcSwB4Mz/rmuyxfxrHgqwF6DFQEosq5p//P36TywYFzYnyoqAWALgBmCdhX32jlQI1DoUYC9AKhHYvh219mz5499+LEXI8UZg3a7LiSEA3PWv61rsKH9fmB2BNdvoBGr++rfrP3q4tVVg57sDxhAAPwU2aouI+cQj4FCAewPEi7buSqo5jv367y6uIuR8FfDMLsvpWgB44l+XtRchb4cCIkC2iE4J1BrD/vh3GlaxMu/0pMCuBcBFwJaxSFlONwQcCuiGq7l2T8Cu/+4ZW0KnBC4GtuqqhC4FwPbAOV0Zbr7xCNTcheqqgHhx1kVJitcuqJpnZAI7AOd2UWaXAuAsYMcujDbP+ARq7UZ1VUD8WGurxFq//u36byuCksnnbGCnLqzpSgBsPDD4ii4MNs/+CNT6NWUvQH8xN27Jtf74B17O+h83apJ+bhPgyrYt7EoAHAu8pW1jza9fArUOBdgL0G/cjVN6rWLVr/9xoiWLZz4F7Ne2pV0IgFWAJUA4/MdUGIFahwJ8seYTyLV+/Ruj+cToGJaGw4EWA3eN8eycj3QhAMIWhh9p00jzSotArV9XDgWkFYezWVNrL5Vd/+nHZgsWvgs4poV8HsyiCwHwM2DDNo00r7QI1PqSdSggrTiczRp7qNKvIy0cm8DVwDPGfnqWB9sWAC8HvtamgeaVJgFftGnWS81W2fVfc+1X4/s/Al9vy9u2BUD48Q8iwFQBAYcCKqjkjFysNR6d9Z9RkE5uavjxDyKgldSmAHga8PNWrDKTLAg4FJBFNVVhpF//VVSzTj5A4OnANW3AaFMAHA4c3IZR5pEPgVqHApwQmE6M+uOfTl1oSRQCRwCHtFFSmwLgJmCtNowyj7wI1Nj16oTAdGK0xvgL9O36TycGI1tyM7B2G2W2JQBeAZzZhkHmkR+BWocCXHfdf6z69d9/HWhBLwR2Br46acltCQAn/01aE5k/71BA5hWYofkKzwwrTZPbItDKZMA2BMA6wA1teWU++RKosSvWoYD+4rVW0WnXf38xl1jJ6wI3TmJTGwLgQOCoSYzw2TII+EVWRj3m4IVd/znUkjZ2TOA9wNGTlNGGAAin/oXT/0wSoNavMlcFxA3+GnubnHMSN8YyKC2cDhhOCRw7TSoAtgIuHLt0HyySQI0vZ4cC4oVyrV//dv3Hi7GMStoauGhceycVAB77Oy75gp+rdSjAXoDug7rWH3+//ruPrUxLmOiY4EkFQDj2d1Gm4DS7QwI1DgXYC9BhQDVZ19i75I9/93GVcQl3NMcEj+XCJAIg7Ed89lil+lAVBHxZV1HN0Zys9evfrv9oIZZrQWMfEDSJAPjyYD/iPXIlpt3dE3AooHvGtZRQayz59V9LhE/k5ynAq8bJYVwBsCJw12D5X/hrksCcBBwKMDjaIFBjHPnj30bkVJHHvcAqQPg7UhpXAOw2OJHo1JFK8uZqCTgUUG3Vt+K4Xf+tYDSTsgnsDpw2qovjCoAzgLAXsUkCCxKotfvWVQELhsZQNyggh8LkTXUTCGfx7DIqgnEEwMrA74DlRi3M++slUGMXrqsCJo/3Gr/+7fqfPG4qzOFPwOOBu0fxfRwBYPf/KIS990ECNX7J2QswfgOo8cc/0HLW//gxU/mTIw8DjCMA/g3YtXLQuj8GgRqHAuwFGCNQmkdqFIx+/Y8fLz7J6cA/jcJhVAEQuv1/D6w0SiHeK4FpAjUOBfhSHz3+a/z6N05GjxOfeBiBe4DHAWE4YKg0qgB4OfC1oXL2JgnMQaDGLzuHAoZvDjX2FNn1P3x8eOe8BEbaFGhUAXACsLcVIIFJCNT4gncoYPiIsZdoeFbeKYEZBE4E9hmWyqgC4FZg9WEz9z4JzEXAl7yxMRsBu/6NCwlMROA2YI1hcxhFAHj077BUvW8oAg4FDIWpqptqjAln/VcV4jGcHfqI4FEEwOHAwTGst4w6CDgUUEc9D+ulX//DkvI+CcxL4AjgkGEYjSIALgM2GyZT75HAsARqHApwQuAjo8Mf/2FbjPdJYEEClwObL3hX2HNimJuAdYAbhrzX2yQwEoHaun2dEPjI8KgtBgIBu/5Hek1482gE1gVuXOiRYQXAXkCYXWiSQOsEahwKcM33Q2Hk13/rTcoMJRBW6520EIZhBYC7/y1E0n+fiIBDARPhy/ZhxV+2VafhaRMYalfAYQXAr4FV0/ZX63InUFs3sEMBUKPws+s/9zdVFvbfCTxpIUuHEQDPBS5ZKCP/XQKTEvBrcFKCeT1v139e9aW12RHYAvjhfFYPIwAOAsKyApMEOidQ4xdhrasCauvxcd5H568PC3g4gbBs/8hJBcB3gRdIVgKxCNT2w1DjUECNX/92/cd6g1hOQ+B7wAsnEQDLA+GEofDXJIEoBGocCqipF6DGH3+//qO8Oizk4QSWNif3hr+zpoWGAJ4PBBVhkkBUArUNBdTUC1BbD48//lFfHRb2cAKh9/774wqA9wOHSlQCfRDwh6IP6t2WWePXv13/3caUuc9L4LDBv4bf8bF6AIJy2E7AEuiDgEMBfVDvrswa69Ov/+7iyZyHInAeEHryRxYAYXjgj4NZhCsMVYw3SaADAg4FdAC1pyxrq0t//HsKNItdlsB9wGMGPfn3z4ZlvjkAHv9rICVBwKGAJKphIiPs+p8Inw9LYBICcx4PPJ8AeDfwL5OU6rMSaINAjV3Hpa0KUMS10RLMQwJjEfhn4MOj9gCcBew4VnE+JIGWCdTWfVzSqoDavv7t+m+58ZvdpATOBnYaVQDcCqw+ack+L4G2CNT2FVlCL0BtP/4h1p3131aLN5+WCNwGrDGKANgAuKalws1GAq0QqG0ooIRegNpEm1//rTR1M2mfwNOAa2dmO9ccgN2AU9u3wRwlMBmB2oYCcv5Bqe3rP+e6mqxV+nQGBHYHThtWAHwUeEcGTmlihQRq+6rMcSigtt4au/4rfBHl5fLHgHcOKwD+c7B9YFg6YJJAcgRq+3HJcSjAnprkmo0G1U3gQuDvhhUAfxgsAVy5bl56nzIBf2DSrR27/tOtGy2rlsDdg6WAjx1GAGw8WDJwRbWYdDwbAg4FpFlVtdWLs/7TjEOtegSBTYArl/2vs00C3BP4kvAkkDoBhwLSqyG//tOrEy2SQEPg1cDJCwmAY2abLCBCCaRIoLahgJQnBPrjn2IL0SYJPEggTO7ffyEB8L35Tg8SpgRSI1BTl3PKEwJrqofQBuz6T+1NoD0LEAin+75gIQGwBFgkSgnkQqC2oYAU15v79Z9La9HOigncASyeTwCsBdxUMSBdz5SAQwH9VZwCrD/2liyBEQmsDdw8/czMSYAvAr49YobeLoEkCNTUBZ3SUEBt4suu/ySau0aMR+DFwHfmEgBhp6AwCdAkgewI+CUav8rs+o/P3BIlMAGBMAkwTAacSjN7AE4cDAHsNUHmPiqBXgnU9jXa96qAmnpdUpx70Wtjs/AcCZw0GALYey4BcDGwRY5eabMEpgnU9KPU51BAbV//dv37jimAwCXAlnMJgDuBJxbgpC5UTKC2oYA+egFq+/H367/iF0pZrv8GWHU2AbAacFtZvupNrQRqGgrooxegpl4Wf/xrfYsU6/fqwO0z5wCEk4IuKNZlHauOgD9S3VR5bV//dv13E0fm2huBbYBw4u/DJgG+HggTBEwSKIKAQwHtV2NtTP36bz+GzLF3AmGi/+dmCoAjgff0bpoGSKBFAg4FtAgTqImnP/7txo65JUPgKOCgmQLgdOCVyZioIRJoiYBDAe2AtOu/HY7mIoGeCXwF2HWmAPgxsHnPhlm8BFonUFu3dVerAhRSrYemGUqgDwKXAc+aKQB+vezygD6sskwJdEWgpq7rLlYF1PT1b9d/V63QfBMhEJb7P2lZAbAK8NtEjNMMCXRCoKYv2DZ7AWr68Z96KT5q5gapnYSjmUqgTwJPAO6ajvRNgJ/0aY1lS6BrAjUNBbTZC1CTcPLrv+tWaP6JENgUuGJaALxkMP7/zUQM0wwJdEagpqGANn7Mavr6b4NXZ4FrxhJol8BLB/MAvjUtAPYFjms3f3OTQJoEavqinWQooKYeE7v+02yrWtUZgTcBx08LgMOBgzsryowlkBCBmn7YJhkKsLckoaDVFAm0S+AI4JBpAfB54LXt5m9uEkiXgD9u89eNXf/pxq6WSaAFAl8AXjctAM4Btm8hU7OQQDYEHAqYu6pqYuOs/2yarIa2R+BcYIdpAXAFsHF7eZuTBNIn4FDA7HXk13/6sauFEpiQwJXAJtMCYAmwaMIMfVwC2RGoaShgmAmB/vhnF8IaLIFxCNwBLA4CYLnBZICl4+TgMxIogUAt3d3DTAishUWIW7v+S2i9+jABgeWDAFgduHWCTHxUAllxHvhNAAAgAElEQVQTqGkoYL617n79Zx3GGi+BUQmsEQSAuwCOis37iyNQ+1CAIqi4kNYhCSxEYNMgALYDvr/Qnf67BEonUEv392xDATUJILv+S2/J+jckgecHAbAzcMaQD3ibBIolUOtXsF3/xYa0jklgPgK7BAHwhsE8gM/ISQISgJq+hKdXBdTS8+Fe/7ZwCTyMwBuDADgAOFowEpDAAwRq+UEMQwEXXHABhx56aBVVb9d/FdWsk8MTODAIgKOAA4d/xjslUDaBmoYCyq7Jh7zz67+WmtbPEQgcHQTAvwLhZCCTBCTQEKhpKKD0SvfHv/Qa1r8xCRwXBMCXgT3GzMDHJFAsgVqGAoqtwMYxu/5Lr2H9G5PAKUEAfB142ZgZ+JgEiiXgUED+VevXf/51qAedEfhGEABhD4CwF4BJAhKYQcChgHxDwh//fOtOy6MQOC8IgEuBZ0cpzkIkkCEBhwIyrDT3+s+z0rQ6JoEfBQHgUcAxkVtWdgQcCsiuyvDrP7860+LoBK4MAuCawUTADaIXbYESyIiAQwH5VJY//vnUlZb2SuDaIABuAtbq1QwLl0AGBBwKyKCS7PrPo5K0MgUCNwcBsARYlII12iCBlAk4FJBy7Txgm1//6deRFiZD4I4gAH4LrJKMSRoigYQJOBSQbuX4459u3WhZkgTuCgLgD8DKSZqnURJIkIBDAQlWil3/aVaKVqVM4O4gAO4FVkjZSm2TQEoEHApIqTbs+k+vNrQoEwL3BQGwFFguE4M1UwJJEHAoIIlqmDLCrv906kJLsiLwpyAA/hx6z7IyW2MlkAABhwISqAS7/tOoBK3IkcD94Yf//hwt12YJ9E3AoYC+a8Cv//5rQAtyJqAAyLn2tL13Ag4F9FcFdv33x96SyyDgEEAZ9agXPRJwKKAf+B7z2w93Sy2GwNQQgJMAi6lPHemDgEMB8an79R+fuSUWR2BqEqDLAIurVx2KTcChgHjE/fGPx9qSiiYwtQzQjYCKrmOdi0XAoYA4pO36j8PZUoonMLURkFsBF1/POhiDgEMB3VP26797xpZQDYGprYA9DKia+tbRrgk4FNAdYX/8u2NrzlUSmDoMyOOAq6x7ne6KgEMB3ZC1678bruZaLYGp44CvATaoFoGOS6BlAg4FtAzU7X7bB2qOEoBrgwC4AthYGhKQQHsEHApoj6Vd/+2xNCcJLEPgyiAALgWeLRYJSKBdAg4FtMPTrv92OJqLBGYQ+FEQAN8HthONBCTQLgGHAibn6df/5AzNQQJzEDgvCICvAy8TkQQk0D4BhwLGZ+qP//jsfFICQxD4RhAAXx5MBNxjiJu9RQISGIOAQwFjQPOY3/Gg+ZQEhidwShAA/wq8afhnvFMCEhiFgEMBo9B64F6//kdn5hMSGJHAcUEAHAUcOOKD3i4BCYxAwKGA4WH54z88K++UwAQEjg4C4ADg6Aky8VEJSGAIAg4FDAHJrv/hIHmXBCYncGAQAG8APjN5XuYgAQnMR8ChgIXjw6//hRl5hwRaIvDGIAB2Bs5oKUOzkYAE5iHgUMDccPzxt+lIICqBXYIACHsAhL0ATBKQQAQCDgXMDtkNfyIEn0VI4CECzw8CYBPgJ1KRgATiEHAo4JGc/fqPE3uWIoFlCGwaBMDqg3kAt4pFAhKIR8ChgIdY++MfL+4sSQLLEFgjCIDlgKVikYAE4hJwKOAB3nb9x407S5NAQ2D5IABCWgIsEosEJBCPgEMBbvgTL9osSQIPI3DHYBPAxdMCwCOBjQ4J9ECg9l4Av/57CDqLlABcGeb/TQuAc4DtpSIBCcQloACYfgXF5W5pEqicwLnADtOt7/PAaysHovsSiE5AAaAAiB50FigB+ALwuunWdzhwsFQkIIG4BBQACoC4EWdpEpgicMRg8v8h061vX+A4wUhAAnEJKAAUAHEjztIkMEUgnAB8/HTrewnwTcFIQAJxCSgAFABxI87SJDBF4KXAt6Zbn7sBGhUS6IGAAkAB0EPYWaQENgWumG59qwC/lYkEJBCXgAJAARA34ixNAlMEngDctWzr+zWwqnAkIIF4BBQACoB40WZJEpgicCfwpPA/lm19Px7MA9hcQBKQQDwCCgAFQLxosyQJTBG4bDD+/6yZAuB04JUCkoAE4hFQACgA4kWbJUlgisBXgF1nCoAjgfcISAISiEdAAaAAiBdtliSBKQJHAQfNFACvB04SkAQkEI+AAkABEC/aLEkCUwT2Aj43UwD8HXCBgCQggXgEFAAKgHjRZkkSmCKwDfCfMwXAasBtApKABOIRUAAoAOJFmyVJYIrA6sDtMwVA+P9hecAThSQBCcQhoABQAMSJNEuRwBSB3yy73H9m67sY2EJQEpBAHAIKAAVAnEizFAlMEbgE2HKaxczWd2IzQUBWEpBABAIKAAVAhDCzCAlMEwgT/feeSwC8EzhGVhKQQBwCCgAFQJxIsxQJTBHYH/joXALgRcC3BSUBCcQhoABQAMSJNEuRwBSBFwPfmUsArDUYArhJUBKQQBwCCgAFQJxIsxQJTBFYezAEcPNcAiD89yXAImFJQALdE1AAKAC6jzJLkMAUgTuAxcuymK31fQ94vsAkIIHuCSgAFADdR5klSGCKwPeBFywkAMIkwDAZ0CQBCXRMQAGgAOg4xMxeAtMEwuS/MAnwwTRb69sT+JLMJCCB7gkoABQA3UeZJUhgisCrgZMXEgAbA1cITAIS6J6AAkAB0H2UWYIEpghsAly5kAAI//4HYGWhSUAC3RJQACgAuo0wc5fAFIG7gcfOZDFX6wsnBW0tOAlIoFsCCgAFQLcRZu4SmCJwIRBO/H1Ymqv1hckC7xCcBCTQLQEFgAKg2wgzdwlMEfjYbJP752p9uwGnCk4CEuiWgAJAAdBthJm7BKYI7A6cNmwPwAbANYKTgAS6JaAAUAB0G2HmLoEpAk8Drh1WAIT7bgVWF54EJNAdAQWAAqC76DJnCUwRuA1YYzYW87W+s4AdBSgBCXRHQAGgAOguusxZAlMEzh4s7d9pVAHw7sFSwH8RoAQk0B0BBYACoLvoMmcJTBH458ESwA+PKgC2apYOyFACEuiIgAJAAdBRaJmtBKYJhCX9F40qAELL/COwghwlIIFuCCgAFADdRJa5SmCKwH3AY4D7RxUA4f5wetB2gpSABLohoABQAHQTWeYqgSkC5813uu9Cre/9A+VwqCAlIIFuCCgAFnoFdcPdXCVQCYHDBn6G3/FZ00Kt7/nA9yoBpZsSiE5AAbDQKyh6lVigBEoi8IKmJ38sAbA8cA8Q/pokIIGWCSgAFAAth5TZSWCawFJgJSD8HUsAhIe+O5hBGFSESQISaJmAAkAB0HJImZ0EpgmE3vsXzodjmNZ3EHCETCUggfYJKACGeQW1z90cJVABgYMHq/iOnFQAPBe4pAJYuiiB6AQUAAqA6EFngbUQ2AL44aQCIDz/a2DVWqjppwRiEVAAKABixZrlVEXgTuBJC3k8bOv7N2DXhTLz3yUggdEIKACGfQWNxtW7JVA5gdOBf1qIwbCtby/gxIUy898lIIHRCCgAhn0FjcbVuyVQOYG9gZMWYjBs61sHuGGhzPx3CUhgNAIKgGFfQaNx9W4JVE5gXeDGhRiM0vouAzZbKEP/XQISGJ6AAmCUV9DwXL1TAhUTuBzYfBj/R2l9hwNhWYFJAhJoiYACYJRXUEvQzUYCZRMIy/YPGcbFUVqfxwMPQ9R7JDACAQXAKK+gEcB6qwTqJTDn8b8zkYza+m4FVq+Xq55LoF0CCoBRX0Ht8jc3CRRG4DZgjWF9GrX1nQCE2YUmCUigBQIKgFFfQS1ANwsJlEsgrNbbZ1j3Rm19Lwe+Nmzm3icBCcxPQAEw6ivIiJKABOYh8I/A14clNGrrWw74fXPC0LBleJ8EJDAHAQXAqK8gQ0kCEpiDQDi593HAn4YlNE7rc1fAYel6nwQWIKAAGOcVZFhJQAKzEBhq979lnxun9e0GnCp+CUhgcgIKgHFeQZNzNwcJFEhgd+C0Ufwap/WtDPwOCMMBJglIYAICCoBxXkETAPdRCZRJIHT7Px64exT3xm19ZwA7j1KQ90pAAo8koAAY9xVkNElAAssQOBPYZVQi47Y+hwFGJe39EpiFgAJg3FeQ4SQBCSxDYOTu//DsuK1vReAuIPw1SUACYxJQAIz7ChoTuI9JoDwC9wKrAOHvSGmS1vdlYI+RSvNmCUjgYQQUAJO8ggwmCUgAOAV41TgkJml9bgo0DnGfkcAyBBQAk7yCDCUJSAAYafOfZYlN2vqWAIusAglIYDwCCoBJX0HjcfcpCRRC4A5g8bi+TNr6jgXeMm7hPieB2gkoACZ9BdUeQfpfOYFPAfuNy2DS1ucRweOS9zkJAAqASV9BhpEEqiYw9NG/s1Fqo/VdAWxcdRXovATGJKAAaOMVNCZ8H5NA3gSuBDaZxIU2Wt+Bg+WAR01ihM9KoFYCCoA2XkG1Ro9+V07gPcDRkzBoo/WtA9wwiRE+K4FaCSgA2ngF1Ro9+l05gXWBGydh0Fbr+xoQlgWaJCCBEQgoANp6BY0A3VslkD+BrzfL/ybypK3W9wog7EVskoAERiCgAGjrFTQCdG+VQP4Ewlk8X53UjTZb303AWpMa5PMSqImAAqDNV1BNkaOvFRO4GVi7Df/bbH2HAwe3YZR5SKAWAgqANl9BtUSNflZO4AjgkDYYtNn6ngb8vA2jzEMCtRBQALT5CqolavSzcgJPH5zDc00bDNpufU4GbKNWzKMaAgqAtl9B1YSOjtZJoJXJf9Po2m59HhBUZ1Dq9ZgEFABtv4LGrAgfk0AeBMY++Gc297pofT8DNsyDpVZKoF8CCoAuXkH91qmlS6AjAlcDz2gz7y5a3/7AR9o00rwkUCoBBUAXr6BSo0W/KifwLuCYNhl00fpWAcIxwSu0aah5SaBEAgqALl5BJUaKPlVO4L7m2N+72uTQVevzmOA2a8m8iiWgAOjqFVRsyOhYnQQmOvZ3LmRdtb5wOmA4JdAkAQnMQ0AB0NUryLCTQFEEwql/4fS/VlOXre8sYMdWrTUzCRRGQAHQ5SuosGDRnVoJnD34oN6pC+e7bH3bA+d0YbR5SqAUAgqALl9BpUSJflROYAfg3C4YdN36LgK27MJw85RACQQUAF2/gkqIEn2omMDFwFZd+d9169sNOLUr481XArkTUAB0/QrKPUK0v3ICuwOndcUgRuv7KbBRVw6YrwRyJqAAiPEKyjlCtL1iAlcBz+zS/xitb1/guC6dMG8J5EpAARDjFZRrdGh35QTeBBzfJYNYre8GYJ0uHTFvCeRIQAEQ6xWUY3Roc8UEbgTW7dr/WK3vnW1vYdg1GPOXQAwCCoBYr6AYtWkZEmiNQNhS/6Ot5TZHRrFa33LALYOhgCd37ZD5SyAnAgqAWK+gnKJCWysn8CtgTeBPXXOI2foOAI7u2iHzl0BOBBQAMV9BOUWGtlZM4EDgQzH8j9n6wuFANwOLYjhmGRLIgYACIOYrKIeI0MbKCdwBrAWEw386T7Fbn70AnVepBeREQAEQ+xWUU3Roa4UEon39B7axW9/ywE2DpQ2rVVixuiyBRxBQAMR+BRmEEkiWwO3A2sDSWBb20fpcERCrdi0neQIKgD5eQcmHhQbWSSDKzP9l0fbV+q4D1quzjvVaAg8RUAD09QoyCiWQFIHrgfVjW9RX63N3wNg1bXlJElAA9PUKSjIcNKpeAp3v+jcb2j5b3xXAxvXWt55LABQAfb6CjEAJJEHgSmCTPizps/V5UmAfNW6ZSRFQAPT5CkoqFDSmXgKdnvg3H9a+W9/5wDb11rue105AAdD3K6j2CNT/nglcAGzblw19t77tgXP6ct5yJdA3AQVA36+gviPA8isnsANwbl8MUmh9pwOv7AuA5UqgTwIKgBReQX1GgGVXTOArwK59+p9C6wsTAcOEQJMEqiOgAEjhFVRd2OlwGgTCxL8wAbC3lErrOwYIGwSZJFAVAQVAKq+gqsJOZ/snEI76DRv/9JpSaX2rAL8AVu2VhoVLIDIBBUAqr6DIFW9xNRO4E3gqcFffEFJqfW8ZCIBj+wZi+RKISUABkNIrKGbNW1bFBPYDPpWC/6m1vkuBZ6cARhskEIOAAiC1V1CMWreMign8CHhOKv6n1vrCkojvpAJHOyTQNQEFQGqvoK5r3PwrJ/CilJa+p9j6Pg+8tvIg0f1KCCgAUnwFVRJ8uhmbwBeA18UudL7yUmx9awE/B1ZKCZS2SKALAgqAFF9BXdS0eVZO4B7g6cDNKXFItfW9AwjLJEwSKJqAAiDVV1DRYadz8QmEZe4fi1/s/CWm3PouHmyRuEVqwLRHAm0SUACk/Apqs6bNq2IClwBbpuh/yq0vHBIUDgsySaBYAgqAlF9BxYadjsUlEA77CYf+JJdSb32hy+TtyVHTIAm0REABkPorqKWKNptaCXx8sOFPGNJOMqXe+lYcHJbwM2D9JOlplAQmJKAASP0VNGEF+3jNBK4DngHcmyqEHFrfLkA4NckkgeIIKAByeAUVF3Y6FIdAOOX2jDhFjVdKLq0vrJ98zXgu+pQE0iWgAMjlFZRuDGlZkgS+mMN+Nrm0vkXAT4Hw1ySBYggoAHJ5BRUTcjrSPYE7Bl/+zwTC36RTTq1vT+BLSdPUOAmMSEABkNMraMTK9fZaCbx6cNrfyTk4n1vr+zKwRw5gtVECwxBQAOT2ChqmVr2nYgKnAK/Kxf/cWt9i4Eog/DVJIHsCCoDcXkHZh5wOdEdgCbAxEP5mkXJsfbsN9lQ+NQu6GimBBQgoAHJ8BRnWEpiVwO7AaTmxybX1nTA4VGHvnEBrqwRmI6AAyPUVZDxL4GEETgT2yY1Jrq1vZeAnwAa5AddeCSxLQAGQ6yvIOJbAgwSuBTYF7s6NSc6t78XAf+QGXHsloAB4iMCjHpXzK8hYlsAUgb8Hvp0ji9xb3xHAQTmC12YJBAL2AOT+CjKOKydwJHBwrgxKaH3hxMBwcqBJAtkRUACU8ArKLuw0uB0C4YS/cNJftqmE1hd2XPovYIVsa0HDqyWgACjhFVRt+Nbs+H3A3zY71GbLoZTW93rgpGxrQcOrJaAAKOUVVG0I1+r4XsDncne+pNZ3PPDG3CtE++sioAAo6RVUV+xW7O1ngH1L8L+01ncZsFkJFaMPdRBQAJT2Cqojbiv28nJg81L8L631hR//HwOl+VVKvOnHDAIKAJuqjSIbAvcDzwKCCCgildj6wthM2JXJJIHkCSgASnwFJR92GjgegbD7bFFzzUptfZ8E9huvjn1KAvEIKABKfQXFiyFLikLgWOCtUUqKWEjJre8Hua/RjBgHFtUTAQVAya+gnoLKYtsmEPaaeV7bmaaQX8mt7ynApcCiFEBrgwRmI6AAKPkVZMwXQOAO4DnALwvw5REulN76XjpYFfDvJVacPpVBQAFQ+iuojDit2It/GMz6/2ap/tfQ+vYHPlJqBeqXBCQgAQl0QuBdwDGd5JxIpjUIgIA6bNzwhkSYa4YEJCABCaRN4LM1bCxXiwAIofZ9YLu0Y07rJCABCUigZwLnAc/v2YYoxdckANYELgLWi0LWQiQgAQlIIDcC1wNbAbfkZvg49tYkAAKfULEXjgPKZyQgAQlIoHgCWzcfisU7GhysTQAEn3cHTqmidnVSAhKQgASGJbAHcOqwN5dwX40CINTbAcDRJVSgPkhAAhKQwMQEDgQ+NHEumWVQqwAI1eR2wZkFq+ZKQAIS6IBAkdv8DsOpZgEQ+JwB7DwMKO+RgAQkIIHiCJwJ7FKcV0M6VLsAePTgvICwz3OY+GGSgAQkIIF6CIQJ4dsCf67H5Yd7WrsACDQWDw56uADYsNYg0G8JSEAClRG4GtgGWFKZ3w9zVwHwAI6Nmp4ADw6quTXouwQkUAOBcMBP+PK/qgZn5/NRAfAQnbBHQDhCePnag0L/JSABCRRKYGlztG/YFK76pAB4eAh4emD1TUIAEpBAwQSKPt1v1HpTADyS2G61bQYxatB4vwQkIIEMCYRN4E7L0O7OTFYAzI52HyCcBmWSgAQkIIH8CYTTYE/I3412PVAAzM3zbcDH28VtbhKQgAQkEJnA24FPRC4zi+IUAPNXk1sGZxHGGikBCUhgVgJVbvE7bCwoABYm9V7gAwvf5h0SkIAEJJAQgfcBH0zInuRMUQAMVyWHDXaLCsFkkoAEJCCB9AmEj7ZD0zezXwsVAMPzD0rykOFv904JSEACEuiBwOFA6Lk1LUBAATBaiCgCRuPl3RKQgARiEvDHfwTaCoARYDW3OhwwOjOfkIAEJNA1Abv9RySsABgRWHO7EwPH4+ZTEpCABLog4IS/MagqAMaA1jziEsHx2fmkBCQggbYIuNRvTJIKgDHBNY+5WdBk/HxaAhKQwCQE3ORnAnoKgAngNY+6bfDkDM1BAhKQwKgE3N53VGIz7lcATAiwedwDhNrhaC4SkIAEhiHgwT7DUFrgHgVACxCbLMJRwmcDy7eXpTlJQAISkMAyBJYCOwLflMrkBBQAkzNcNoetgLOARe1ma24SkIAEqidwB7ATcFH1JFoCoABoCeQy2WwEfBXYsP2szVECEpBAlQSuBl4BXFWl9x05rQDoBuxi4Exg626yN1cJSEAC1RC4ENgZWFKNx5EcVQB0B/rRwOlN4HZXijlLQAISKJdA+JDadXAY25/LdbE/zxQA3bP/JLBf98VYggQkIIGiCBwLvLUojxJzRgEQp0LcNTAOZ0uRgATKIODufhHqUQEQAXJTRFi3ekq84ixJAhKQQJYE9gBOzdLyzIxWAMStsLBM8GRgvbjFWpoEJCCB5AlcD+zpMr949aQAiMd6uqQ1gS8B28Uv2hIlIAEJJEngPODVwC1JWleoUQqA/ir2M0DYy9okAQlIoGYCnwXeWDOAvnxXAPRF/oFy9wc+0q8Jli4BCUigNwLvAo7prfTKC1YA9B8A4QyBz7l9cP8VoQUSkEA0AmFb39e7p3803rMWpADol/906U8BTgK2TcMcrZCABCTQGYHzgb0GY/6/7KwEMx6KgAJgKEzRbnLToGioLUgCEuiBgJv79AB9riIVAAlVRmNKUMYnANZNenWjRRKQwHgE7h/M8N+n6ekcLwefap2APzKtI20lw82AsEog/DVJQAISyJnA5c0s//DXlBABBUBClTGLKce7PCbtCtI6CUhgXgLhQ2ZfGaVJQAGQZr0sa1WYKXscsEL6pmqhBCQggSkC9wFvalY4iSRRAgqARCtmhlnPHCwT/DSwTR7maqUEJFAxgQuANwM/rZhBFq4rALKopgeNPGKgrA/Ky2StlYAEKiJwJHBwRf5m7aoCIL/qezEQlgtukJ/pWiwBCRRK4FrgrcC3C/WvSLcUAHlW68rAJ4C98zRfqyUggYIInAi8Dbi7IJ+qcEUBkHc17wZ8HFictxtaLwEJZEhgCfB24LQMbddkN5spIgbCj/9HgT2K8EYnJCCBHAicArwTCCLAlCkBewAyrbhZzN6zOVVrUTku6YkEJJAYgXCITzjF9OTE7NKcMQgoAMaAlvAj4cf/w8BrErZR0yQggTwJfBF492CJXxABpgIIKAAKqMRZXNgF+BCwfpnu6ZUEJBCRwHXAAcAZEcu0qAgEFAARIPdUxIrA0c0knZ5MsFgJSCBzAmGS8YHAvZn7ofmzEFAAlB8WYffAsDnHFuW7qocSkEBLBC5pNh0Lu/qZCiWgACi0Ymdx6x1A2ElwpXpc1lMJSGBEAvc0O/l9bMTnvD1DAgqADCttApPXAj4IvHaCPHxUAhIok8AXgPcONhi7uUz39GomAQVAnTGxw2APiMMG23Y+u0739VoCEliGwI+AQ4FzpFIXAQVAXfU909u3DP7D+4FV68ag9xKoksCdTfv/VJXe6zQKAINgFeB9za5e0pCABOogEHYP/QBwVx3u6uVsBBQAxsU0gY2BQ4BXikQCEiiWwFeAw4Eri/VQx4YmoAAYGlU1N27fLP8JywdNEpBAGQTCcr6wHPjcMtzRizYIKADaoFhmHuGkwfcAoWfAJAEJ5EkgfOkf5Yl9eVZe11YrALomnH/++zbbgK6Xvyt6IIFqCFzfbAd+fDUe6+jIBBQAIyOr9oFw9Gc4CGS1agnouATSJ3B7cyBYmORnksC8BBQABsgoBJZvjgINx4F67PAo5LxXAt0SCCf0HdNcS7stytxLIaAAKKUm4/qxwmD5UNhaOFxPjlu0pUlAAssQ+BUQtu0N132SkcAoBBQAo9Dy3pkElgPe1lzriEcCEohG4EbgE831p2ilWlBRBBQARVVnr86EyYL7ARv1aoWFS6BsAlcNdu48djAXx8l9ZddzFO8UAFEwV1VIWD74ZmDLqrzWWQl0S+DiwbybT7ucr1vIteWuAKitxuP5GzYUCr0CO8Yr0pIkUByBs5uvfTfwKa5q+3dIAdB/HZRuQdhI6A3NFSYPmiQggfkJhMl8n20ut+w1WjojoADoDK0ZzyAQDh3au7k2lI4EJPAIAlcDJzaXh/QYIJ0TUAB0jtgCZiHwcuB1QPhrkkDtBL4OfB4If00SiEZAARANtQXNQuBpwGuaay0JSaAiAjcDX2yuayryW1cTIqAASKgyKjflFcCe9gpUHgXlux++8k8eHLL11fJd1cPUCSgAUq+h+uwLGwrt3lyeRFhf/ZfocZjId2pzhQ18TBJIgoACIIlq0Ig5CGwF7Npcnj1gmOREIOzNf3pzXZST4dpaDwEFQD11nbunYcLgLsDOg/PNV8zdGe0vksC9wJnAGU7oK7J+i3NKAVBclRbvUPjx36m5wiZD4TwCkwT6IhD24Q+b9ZzVXEEEmCSQBQEFQBbVpJFzEFi5mTQYegdeBqwkKQlEIHAP8I3mKz9M6rs7QpkWIYHWCSgAWkdqhj0RCD0BL22ulwCr92SHxZZJ4DbgW8A3m8sT+Mqs56q8UgBUVd1VOaZnh1wAAAJHSURBVBsmEL6ouTarynOdbYvA5cB3msuJfG1RNZ9kCCgAkqkKDemQQFha+MLmesHgONVVOyzLrPMlcCfwvcFJlt9tLpfs5VuXWj4EAQXAEJC8pTgCzwWe11zbAssX56EODUNgKXA+8IPm+uEwD3mPBEohoAAopSb1Y1wC4cd/G2Dr5gpDB55aOC7NtJ8Lp+yFrvwLm+sCIIgAkwSqJKAAqLLadXoeAqFNbAmEXoJwPccJhdnGS5i4dykQvuzDdTFwf7beaLgEWiagAGgZqNkVSWCDwQzwZzXX5kCYVBiWIJrSIRCW4oVJe5cBP26ua9MxT0skkB4BBUB6daJFeRAI5xT8TXNtOtgEZhPA7Yrj1F3YZvcK4CfAfzdX2G/fJAEJjEBAATACLG+VwAIEwpHGfw1s1FzPADYEnii5sQj8Brh6cBbEz4Crmut/gHCUrkkCEpiQgAJgQoA+LoEhCKw2OAnu6UAYSgjXU4GnDM6CX98liYSld9cBvxwcB/0LIHTbh+vnwO1DsPUWCUhgTAIKgDHB+ZgEWiKwCrAusHZzhV6ENYE1msmHQTzkOrQQuurDj3iYjHcrcEvz9X4TEK4bgLta4mg2EpDAiAQUACMC83YJ9EAgbHO8uBECT2qGFMKwwl8BTwCCiHg88DjgL4HHNpMUw9kIj2lOTwxLG/+i2fMg5PdoYLr9h5nxfwbC9rZhWdz/A8KSuXCwzR+BsPd9mGT3B+D/gN8Dv2t+vH8L/C8QuuvD9Wsg/PAvafLrAZdFSkACwxD4/181/r/aRhURAAAAAElFTkSuQmCC";function ye(){return jsxs("div",{className:fe("h-full w-full","flex flex-col items-center justify-center gap-4","text-neutral-200"),children:[jsx("img",{src:he,alt:"YAML Resume Logo",className:"w-32 h-32 opacity-70 grayscale",draggable:false}),jsx("div",{className:"text-lg font-medium",children:"No Layouts Defined"}),jsx("p",{className:"max-w-xs text-center text-sm text-neutral-400",children:"Your resume appears to be empty or contains no layout definitions."})]})}function go(e){switch(e){case "html":return jsx(IconHtml,{size:p.sm,stroke:c.sm});case "markdown":return jsx(IconMarkdown,{size:p.sm,stroke:c.sm});case "latex":return jsx(IconTex,{size:p.sm,stroke:c.sm});default:return jsx(IconFileText,{size:p.sm,stroke:c.sm})}}function Pe({active:e,onClick:t,engine:o,index:r,filename:n}){return jsxs("button",{type:"button",onClick:t,className:fe("flex items-center gap-2 max-w-[200px]","h-full px-4","transition-colors border-r border-neutral-600 last:border-neutral-400"),title:`${n}.${r}${E(o)}`,role:"tab","aria-selected":e,style:{backgroundColor:e&&w},children:[go(o),jsxs("span",{className:"truncate",children:[n,".",r,E(o)]})]})}function we({children:e}){return jsx("div",{role:"tablist",className:fe("flex h-full overflow-x-auto"),children:e})}function ae({resume:e,layoutIndex:t}){let{renderedContent:o,binaryContent:r,engine:n,error:a}=J({resume:e,layoutIndex:t});return a?jsx("div",{role:"alert","aria-live":"polite",className:fe("h-full w-full p-4","font-mono text-red-500 bg-red-50","border border-red-200"),children:a}):n==="docx"?jsx(te,{content:r}):jsx("div",{className:"h-full w-full flex flex-col bg-white",children:n==="html"?jsx(re,{content:o}):jsx(oe,{content:o,language:n})})}function Y({activeLayoutIndex:e,filename:t,resume:o,setActiveLayoutIndex:r,tooltips:n}){let a=useMemo(()=>(o?.layouts||[]).map((u,y)=>({layout:u,originalIndex:y})).filter(u=>u.layout!==null&&u.layout!==void 0&&typeof u.layout.engine=="string"),[o?.layouts]),i=R(t,true)||"resume",s=useCallback(()=>{z(o,e);},[o,e]),g=useCallback(()=>{V(o,e);},[o,e]),m=useCallback(()=>{U(o,e);},[o,e]),l=useCallback(()=>{W(o,e);},[o,e]);return a.length===0?jsxs(x,{children:[jsx(v,{}),jsx(ye,{})]}):jsxs(x,{children:[jsxs(v,{children:[jsx(we,{children:a.map(({layout:u,originalIndex:y})=>jsx(Pe,{active:e===y,onClick:()=>r(y),engine:u.engine,index:y,filename:i},`${u.engine}-${y}`))}),jsx("div",{className:"flex-1"}),jsxs("div",{className:"flex items-center gap-0.5 pr-2",children:[jsx(N,{onClick:s,title:n.copy}),jsx(P,{}),o?.layouts?.[e]?.engine==="html"&&jsxs(Fragment,{children:[jsx(h,{onClick:g,title:n.print,children:jsx(IconPrinter,{size:p.sm,stroke:c.sm})}),jsx(h,{onClick:m,title:n.openInNewTab,children:jsx(IconExternalLink,{size:p.sm,stroke:c.sm})}),jsx(P,{})]}),jsx(h,{onClick:l,title:n.download,children:jsx(IconDownload,{size:p.sm,stroke:c.sm})})]})]}),jsx(k,{children:jsx(ae,{resume:o,layoutIndex:e})})]})}function x({children:e}){return jsx("div",{className:fe("flex-1 flex flex-col","border border-neutral-400 overflow-hidden"),children:e})}function k({children:e}){return jsx("div",{className:"flex-1 relative min-h-0",children:e})}function Q(){return jsx(Separator,{className:fe("w-2","flex flex-col justify-center items-center group","transition-colors cursor-col-resize"),"data-testid":"separator",children:jsx("div",{className:fe("w-1 h-8","bg-neutral-400","group-hover:bg-neutral-300")})})}function v({children:e}){return jsx("div",{className:fe("flex items-center border-b border-neutral-400 h-10 text-sm shrink-0","bg-neutral-800"),children:e})}function h({onClick:e,children:t,title:o}){return jsx("button",{type:"button",onClick:e,className:fe("flex items-center justify-center h-8 w-8","text-neutral-200 hover:text-neutral-700 hover:bg-neutral-200","transition-colors","focus:outline-none focus:ring-1 focus:ring-neutral-400"),title:o,children:t})}function N({onClick:e,title:t="Copy"}){let[o,r]=useState(false);return jsx(h,{onClick:async()=>{try{await e(),r(!0),setTimeout(()=>r(!1),2e3);}catch(a){console.error("Failed to copy",a);}},title:t,children:o?jsx(IconCheck,{size:p.sm,stroke:c.sm}):jsx(IconCopy,{size:p.sm,stroke:c.sm})})}function P(){return jsx("div",{className:"w-px h-4 bg-neutral-400 mx-1"})}
|
|
277
277
|
export{oe as CodeViewer,ce as DEFAULT_PLAYGROUND_MESSAGES,te as DocxViewer,w as EDITOR_BG_COLOR,se as EDITOR_FONT_SIZE,C as Editor,Z as EditorPanel,re as HtmlViewer,p as ICON_SIZES,c as ICON_STROKES,x as Panel,k as PanelContent,Q as PanelSeparator,v as PanelToolbar,Ve as Playground,G as PlaygroundDesktop,j as PlaygroundMobile,Y as PreviewPanel,X as ResumeEditor,ae as ResumeViewer,h as ToolbarButton,N as ToolbarCopyButton,P as ToolbarSeparator,z as copyResumeToClipboard,W as downloadResume,R as getBasename,E as getExtension,U as openResumeInNewTab,V as printResume,J as useResumeRenderer,K as useResumeState};//# sourceMappingURL=index.js.map
|
|
278
278
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/components/editor/Editor.tsx","../src/utils/utils.ts","../src/components/editor/EditorTitle.tsx","../src/components/editor/ResumeEditor.tsx","../src/components/editor/EditorPanel.tsx","../src/hooks/useResumeRenderer.ts","../src/resources/default-resume.yml","../src/hooks/useResumeState.ts","../src/messages.ts","../src/components/layouts/Playground.tsx","../src/components/layouts/PlaygroundDesktop.tsx","../src/components/layouts/MobileTabButton.tsx","../src/components/layouts/MobileTabBar.tsx","../src/components/layouts/PlaygroundMobile.tsx","../src/components/preview/CodeViewer.tsx","../src/components/preview/DocxViewer.tsx","../src/components/preview/HtmlViewer.tsx","../src/components/preview/PreviewNoLayouts.tsx","../src/components/preview/PreviewTab.tsx","../src/components/preview/PreviewTabs.tsx","../src/components/preview/ResumeViewer.tsx","../src/components/preview/PreviewPanel.tsx","../src/components/ui/Panel.tsx","../src/components/ui/PanelContent.tsx","../src/components/ui/PanelSeparator.tsx","../src/components/ui/PanelToolbar.tsx","../src/components/ui/ToolbarButton.tsx","../src/components/ui/ToolbarCopyButton.tsx","../src/components/ui/ToolbarSeparator.tsx"],"names":["ICON_SIZES","ICON_STROKES","EDITOR_BG_COLOR","EDITOR_FONT_SIZE","registerLatexLanguage","monaco","latexLanguage","latexConf","l","Editor","value","onChange","language","readOnly","lineNumbers","minimap","onMount","jsx","MonacoEditor","getBasename","filepath","removeExtension","basename","getExtension","engine","downloadResume","resume","layoutIndex","layouts","renderResult","getResumeRenderer","layout","extension","filename","content","blob","url","a","e","copyResumeToClipboard","printResume","iframe","doc","openResumeInNewTab","EditorTitle","jsxs","clsx","IconFileCode","ResumeEditor","EditorPanel","tooltips","editorRef","useRef","handleEditorMount","editor","handleUndo","useCallback","handleRedo","handleCopy","handleClear","Panel","PanelToolbar","ToolbarCopyButton","ToolbarSeparator","ToolbarButton","IconArrowBackUp","IconArrowForwardUp","IconEraser","PanelContent","useResumeRenderer","renderedContent","setRenderedContent","useState","binaryContent","setBinaryContent","setEngine","error","setError","useEffect","currentEngine","result","default_resume_default","useResumeState","yaml","activeLayoutIndex","setActiveLayoutIndex","handleYamlChange","v","useMemo","parse","DEFAULT_PLAYGROUND_MESSAGES","Playground","yamlStr","messages","editorPanel","previewPanel","PreviewPanel","PlaygroundMobile","PlaygroundDesktop","Group","PanelSeparator","MobileTabButton","label","active","onClick","Icon","MobileTabBar","activeTab","onTabChange","IconEdit","IconEye","setActiveTab","CodeViewer","DocxViewer","containerRef","loading","setLoading","container","renderAsync","HtmlViewer","PreviewNoLayouts","logo_default","getTabIcon","IconHtml","IconMarkdown","IconTex","IconFileText","PreviewTab","index","PreviewTabs","children","ResumeViewer","validLayouts","originalIndex","item","handlePrint","handleOpenInNewTab","handleDownload","Fragment","IconPrinter","IconExternalLink","IconDownload","Separator","title","hasCopied","setHasCopied","IconCheck","IconCopy"],"mappings":"gjBAwBO,IAAMA,CAAAA,CAAa,CACxB,EAAA,CAAI,EAAA,CACJ,GAAI,EAAA,CACJ,EAAA,CAAI,GACJ,EAAA,CAAI,EAAA,CACJ,GAAI,EACN,CAAA,CAEaC,EAAe,CAC1B,EAAA,CAAI,EACJ,EAAA,CAAI,IAAA,CACJ,GAAI,GAAA,CACJ,EAAA,CAAI,KACJ,EAAA,CAAI,CACN,EAGaC,CAAAA,CAAkB,SAAA,CAGlBC,GAAmB,GCRhC,SAASC,GAAsBC,CAAAA,CAAgB,CAE7C,IAAMC,CAAAA,CAA4C,CAChD,YAAa,OAAA,CACb,IAAA,CAAM,QACN,SAAA,CAAW,CAAC,aAAc,UAAU,CAAA,CACpC,eAAgB,CAAC,KAAA,CAAO,MAAO,KAAK,CAAA,CAEpC,aAAc,QAAA,CACd,YAAA,CAAc,GAEd,QAAA,CAAU,CACR,kBACA,eAAA,CACA,cAAA,CACA,UACA,aAAA,CACA,WAAA,CACA,OACA,UAAA,CACA,QAAA,CACA,SACA,WAAA,CACA,cAAA,CACA,kBACA,IAAA,CACA,SAAA,CACA,gBACA,SAAA,CACA,UAAA,CACA,aACA,KAAA,CACA,SAAA,CACA,QACA,WAAA,CACA,SAAA,CACA,SACA,MAAA,CACA,iBAAA,CACA,WAAA,CACA,OAAA,CACA,SAAA,CACA,OAAA,CACA,YACA,SAAA,CACA,MAAA,CACA,QACA,eAAA,CACA,SAAA,CACA,KACA,MAAA,CACA,YAAA,CACA,WACA,MAAA,CACA,MAAA,CACA,cACA,UAAA,CACA,UAAA,CACA,eACA,cAAA,CACA,cAAA,CACA,OACA,OAAA,CACA,UAAA,CACA,gBACA,OAAA,CACA,OAAA,CACA,OACA,WAAA,CACA,QAAA,CACA,OACA,MAAA,CACA,aAAA,CACA,UACA,iBAAA,CACA,aAAA,CACA,SACA,OAAA,CACA,IAAA,CACA,OACA,MAAA,CACA,OAAA,CACA,QACA,OAAA,CACA,OAAA,CACA,QACA,QAAA,CACA,OAAA,CACA,MAAA,CACA,SAAA,CACA,MAAA,CACA,WAAA,CACA,gBACA,WAAA,CACA,eAAA,CACA,eACA,UAAA,CACA,SAAA,CACA,YACA,UAAA,CACA,SAAA,CACA,SACA,MAAA,CACA,SAAA,CACA,cACA,UAAA,CACA,YAAA,CACA,gBACA,YAAA,CACA,gBAAA,CACA,UACA,WAAA,CACA,SAAA,CACA,UACA,YAAA,CACA,YAAA,CACA,SACA,UAAA,CACA,aAAA,CACA,mBACA,YAAA,CACA,aAAA,CACA,MACA,WAAA,CACA,SAAA,CACA,OACA,WAAA,CACA,UAAA,CACA,YACA,eAAA,CACA,SAAA,CACA,YACA,KAAA,CACA,WAAA,CACA,SACA,WAAA,CACA,SAAA,CACA,MAAA,CACA,SAAA,CACA,gBAAA,CACA,KAAA,CACA,eACA,YAAA,CACA,aAAA,CACA,WACA,KAAA,CACA,cAAA,CACA,QACA,IAAA,CACA,OAAA,CACA,OACA,SAAA,CACA,MAAA,CACA,KACA,YAAA,CACA,SAAA,CACA,aACA,WAAA,CACA,YAAA,CACA,KACA,YAAA,CACA,WAAA,CACA,KACA,OAAA,CACA,OAAA,CACA,YACA,MAAA,CACA,OAAA,CACA,OACA,UAAA,CACA,aAAA,CACA,eACA,YAAA,CACA,eAAA,CACA,kBACA,WAAA,CACA,KAAA,CACA,SACA,WAAA,CACA,QAAA,CACA,SACA,YAAA,CACA,QAAA,CACA,SACA,QAAA,CACA,QAAA,CACA,QAAA,CACA,QAAA,CACA,WAAA,CACA,YAAA,CACA,SACA,eAAA,CACA,MAAA,CACA,QACA,OAAA,CACA,IAAA,CACA,YACA,SAAA,CACA,QAAA,CACA,QACA,YAAA,CACA,WAAA,CACA,aACA,QAAA,CACA,YAAA,CACA,QACA,OAAA,CACA,MAAA,CACA,UACA,OAAA,CACA,QAAA,CACA,OACA,OAAA,CACA,OAAA,CACA,WACA,QAAA,CAEA,gBAAA,CACA,iBACA,YAAA,CACA,OAAA,CACA,UACA,eAAA,CACA,eAAA,CACA,MACA,MAAA,CACA,YAAA,CACA,KACA,OAAA,CACA,OAAA,CACA,MACA,IAAA,CACA,MAAA,CACA,aACA,UAAA,CACA,aAAA,CACA,WAAA,CACA,OAAA,CACA,aAAA,CACA,cACF,EAE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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECyEO,SAASC,CAAAA,CAAe,CAC7B,IAAA,CAAAC,CAAAA,CAAOF,EACP,QAAA,CAAAtE,CACF,EAAwB,CACtB,GAAM,CAACyE,CAAAA,CAAmBC,CAAoB,EAAIb,QAAAA,CAAS,CAAC,EAEtDc,CAAAA,CAAoBC,CAAAA,EAAc,CACtC5E,CAAAA,GAAW4E,CAAC,EACd,CAAA,CAEM7D,CAAAA,CAAS8D,QAAQ,IAAM,CAC3B,GAAI,CACF,OAAOC,MAAMN,CAAI,CACnB,MAAa,CACX,OAAO,IACT,CACF,CAAA,CAAG,CAACA,CAAI,CAAC,EAGT,OAAAL,SAAAA,CAAU,IAAM,CACd,IAAMlD,EAAUF,CAAAA,EAAQ,OAAA,EAAW,EAAC,CAChC0D,CAAAA,EAAqBxD,EAAQ,MAAA,EAAUA,CAAAA,CAAQ,OAAS,CAAA,EAC1DyD,CAAAA,CAAqBzD,EAAQ,MAAA,CAAS,CAAC,EAE3C,CAAA,CAAG,CAACF,GAAQ,OAAA,CAAS0D,CAAiB,CAAC,CAAA,CAEhC,CACL,KAAAD,CAAAA,CACA,gBAAA,CAAAG,EACA,iBAAA,CAAAF,CAAAA,CACA,qBAAAC,CAAAA,CACA,MAAA,CAAA3D,CACF,CACF,KClDagE,EAAAA,CAAkD,CAC7D,SAAU,CACR,IAAA,CAAM,OACN,IAAA,CAAM,MAAA,CACN,KAAM,MAAA,CACN,KAAA,CAAO,QACP,KAAA,CAAO,OAAA,CACP,aAAc,iBAAA,CACd,QAAA,CAAU,UACZ,CACF,ECAO,SAASC,GAAW,CACzB,IAAA,CAAMC,EAAUX,CAAAA,CAChB,QAAA,CAAAtE,EACA,QAAA,CAAAsB,CAAAA,CACA,SAAA4D,CACF,CAAA,CAAoB,CAClB,GAAM,CACJ,KAAAV,CAAAA,CACA,gBAAA,CAAAG,EACA,iBAAA,CAAAF,CAAAA,CACA,qBAAAC,CAAAA,CACA,MAAA,CAAA3D,CACF,CAAA,CAAIwD,CAAAA,CAAe,CACjB,IAAA,CAAMU,CAAAA,CACN,SAAAjF,CACF,CAAC,EAEKuC,CAAAA,CAAW,CACf,GAAGwC,EAAAA,CAA4B,QAAA,CAC/B,GAAGG,CAAAA,EAAU,QACf,EAGMC,CAAAA,CACJ7E,GAAAA,CAACgC,EAAA,CACC,KAAA,CAAOkC,EACP,QAAA,CAAWI,CAAAA,EAAMD,EAAiBC,CAAAA,EAAK,EAAE,EACzC,QAAA,CAAUtD,CAAAA,CACV,SAAUiB,CAAAA,CACZ,CAAA,CAII6C,EACJ9E,GAAAA,CAAC+E,CAAAA,CAAA,CACC,iBAAA,CAAmBZ,CAAAA,CACnB,qBAAsBC,CAAAA,CACtB,MAAA,CAAQ3D,EACR,QAAA,CAAUO,CAAAA,CACV,SAAUiB,CAAAA,CACZ,CAAA,CAGF,OACEL,IAAAA,CAAC,KAAA,CAAA,CACC,SAAA,CAAWC,GAAK,mCAAA,CAAqC,kBAAkB,EACvE,KAAA,CAAO,CACL,gBAAiB5C,CACnB,CAAA,CAEA,UAAAe,GAAAA,CAACgF,CAAAA,CAAA,CAAiB,WAAA,CAAaH,CAAAA,CAAa,aAAcC,CAAAA,CAAc,CAAA,CACxE9E,IAACiF,CAAAA,CAAA,CACC,YAAaJ,CAAAA,CACb,YAAA,CAAcC,EAChB,CAAA,CAAA,CACF,CAEJ,CC7EO,SAASG,CAAAA,CAAkB,CAChC,WAAA,CAAAJ,CAAAA,CACA,aAAAC,CACF,CAAA,CAA2B,CAGzB,OACE9E,GAAAA,CAAC,OAAI,SAAA,CAAU,uCAAA,CACb,SAAA4B,IAAAA,CAACsD,KAAAA,CAAA,CAAM,WAAA,CAAY,YAAA,CACjB,UAAAlF,GAAAA,CAAC2C,KAAAA,CAAA,CAAM,OAAA,CAAS,GAAA,CAAc,UAAU,eAAA,CACrC,QAAA,CAAAkC,EACH,CAAA,CAEA7E,GAAAA,CAACmF,EAAA,EAAe,CAAA,CAEhBnF,IAAC2C,KAAAA,CAAA,CAAM,QAAS,GAAA,CAAc,SAAA,CAAU,gBACrC,QAAA,CAAAmC,CAAAA,CACH,GACF,CAAA,CACF,CAEJ,CClBO,SAASM,EAAgB,CAC9B,KAAA,CAAAC,EACA,MAAA,CAAAC,CAAAA,CACA,QAAAC,CAAAA,CACA,IAAA,CAAMC,CACR,CAAA,CAAyB,CACvB,OACE5D,IAAAA,CAAC,QAAA,CAAA,CACC,KAAK,QAAA,CACL,OAAA,CAAS2D,EACT,SAAA,CAAW1D,EAAAA,CACT,qDACA,SAAA,CACA,mBAAA,CACAyD,GAAU,2CACZ,CAAA,CAEA,UAAAtF,GAAAA,CAACwF,CAAAA,CAAA,CAAK,IAAA,CAAMzG,CAAAA,CAAW,GAAI,MAAA,CAAQC,CAAAA,CAAa,GAAI,CAAA,CACnDqG,CAAAA,CAAAA,CACH,CAEJ,CCrBO,SAASI,GAAa,CAAE,SAAA,CAAAC,EAAW,WAAA,CAAAC,CAAY,EAAsB,CAC1E,OACE/D,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,6CACb,QAAA,CAAA,CAAA5B,GAAAA,CAACoF,EAAA,CACC,KAAA,CAAM,SACN,IAAA,CAAMQ,QAAAA,CACN,OAAQF,CAAAA,GAAc,QAAA,CACtB,QAAS,IAAMC,CAAAA,CAAY,QAAQ,CAAA,CACrC,CAAA,CACA3F,GAAAA,CAACoF,CAAAA,CAAA,CACC,KAAA,CAAM,UACN,IAAA,CAAMS,OAAAA,CACN,OAAQH,CAAAA,GAAc,SAAA,CACtB,QAAS,IAAMC,CAAAA,CAAY,SAAS,CAAA,CACtC,CAAA,CAAA,CACF,CAEJ,CCpBO,SAASX,EAAiB,CAC/B,WAAA,CAAAH,EACA,YAAA,CAAAC,CACF,EAA0B,CACxB,GAAM,CAACY,CAAAA,CAAWI,CAAY,EAAIvC,QAAAA,CAAoB,QAAQ,EAE9D,OACE3B,IAAAA,CAAC,OAAI,SAAA,CAAU,sDAAA,CACb,UAAA5B,GAAAA,CAACyF,EAAAA,CAAA,CAAa,SAAA,CAAWC,CAAAA,CAAW,YAAaI,CAAAA,CAAc,CAAA,CAC/D9F,IAAC,KAAA,CAAA,CACC,SAAA,CAAW6B,GACT,yBAAA,CACA6D,CAAAA,GAAc,SAAW,MAAA,CAAS,QACpC,EAEC,QAAA,CAAAb,CAAAA,CACH,EACA7E,GAAAA,CAAC,KAAA,CAAA,CACC,UAAW6B,EAAAA,CACT,yBAAA,CACA6D,IAAc,SAAA,CAAY,MAAA,CAAS,QACrC,CAAA,CAEC,QAAA,CAAAZ,EACH,CAAA,CAAA,CACF,CAEJ,CC/BO,SAASiB,EAAAA,CAAW,CAAE,OAAA,CAAA9E,CAAAA,CAAS,SAAAtB,CAAS,CAAA,CAAoB,CACjE,OACEK,GAAAA,CAACR,EAAA,CACC,QAAA,CAAUG,EACV,KAAA,CAAOsB,CAAAA,CACP,SAAU,IAAA,CACV,OAAA,CAAS,MACT,WAAA,CAAa,KAAA,CACf,CAEJ,CCXO,SAAS+E,EAAAA,CAAW,CAAE,OAAA,CAAA/E,CAAQ,EAAoB,CACvD,IAAMgF,EAAe9D,MAAAA,CAAuB,IAAI,EAC1C,CAACwB,CAAAA,CAAOC,CAAQ,CAAA,CAAIL,QAAAA,CAAwB,IAAI,CAAA,CAChD,CAAC2C,EAASC,CAAU,CAAA,CAAI5C,SAAkB,KAAK,CAAA,CAiCrD,OA/BAM,SAAAA,CAAU,IAAM,CACd,GAAI,CAAC5C,GAAW,CAACgF,CAAAA,CAAa,QAC5B,OAAArC,CAAAA,CAAS,IAAI,CAAA,CACbuC,CAAAA,CAAW,KAAK,CAAA,CACT,IAAM,CAAC,CAAA,CAGhBA,CAAAA,CAAW,IAAI,CAAA,CACfvC,CAAAA,CAAS,IAAI,CAAA,CAEb,IAAMwC,EAAYH,CAAAA,CAAa,OAAA,CAE/B,OAAAI,WAAAA,CAAYpF,CAAAA,CAASmF,EAAW,MAAA,CAAW,CACzC,UAAW,MAAA,CACX,SAAA,CAAW,IACb,CAAC,CAAA,CACE,IAAA,CAAK,IAAM,CACVD,CAAAA,CAAW,KAAK,EAClB,CAAC,EACA,KAAA,CAAO9E,CAAAA,EAAM,CACZ8E,CAAAA,CAAW,KAAK,EAChBvC,CAAAA,CACE,CAAA,mBAAA,EAAsBvC,aAAa,KAAA,CAAQA,CAAAA,CAAE,QAAU,MAAA,CAAOA,CAAC,CAAC,CAAA,CAClE,EACF,CAAC,CAAA,CAEI,IAAM,CACX+E,CAAAA,CAAU,SAAA,CAAY,GACxB,CACF,CAAA,CAAG,CAACnF,CAAO,CAAC,EAEPA,CAAAA,CAQD0C,CAAAA,CAEA3D,IAAC,KAAA,CAAA,CACC,IAAA,CAAK,QACL,WAAA,CAAU,QAAA,CACV,UAAU,0EAAA,CAET,QAAA,CAAA2D,EACH,CAAA,CAKF/B,IAAAA,CAAC,OAAI,SAAA,CAAU,+CAAA,CACZ,UAAAsE,CAAAA,EACClG,GAAAA,CAAC,OAAI,SAAA,CAAU,oEAAA,CACb,SAAAA,GAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,eAAA,CAAgB,QAAA,CAAA,4BAAA,CAAqB,EACtD,CAAA,CAEFA,GAAAA,CAAC,OAAI,GAAA,CAAKiG,CAAAA,CAAc,UAAU,wBAAA,CAAyB,CAAA,CAAA,CAC7D,EA1BEjG,GAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,yEAAA,CAA0E,QAAA,CAAA,6BAAA,CAEzF,CA0BN,CCrEO,SAASsG,GAAW,CAAE,OAAA,CAAArF,CAAQ,CAAA,CAAoB,CACvD,OACEjB,GAAAA,CAAC,QAAA,CAAA,CACC,MAAM,qBAAA,CACN,SAAA,CAAU,4BACV,MAAA,CAAQiB,CAAAA,CACV,CAEJ,6vsBCZO,SAASsF,IAAmB,CACjC,OACE3E,KAAC,KAAA,CAAA,CACC,SAAA,CAAWC,GACT,eAAA,CACA,iDAAA,CACA,kBACF,CAAA,CAEA,QAAA,CAAA,CAAA7B,IAAC,KAAA,CAAA,CACC,GAAA,CAAKwG,GACL,GAAA,CAAI,kBAAA,CACJ,UAAU,gCAAA,CACV,SAAA,CAAW,MACb,CAAA,CACAxG,GAAAA,CAAC,OAAI,SAAA,CAAU,qBAAA,CAAsB,8BAAkB,CAAA,CACvDA,GAAAA,CAAC,KAAE,SAAA,CAAU,+CAAA,CAAgD,8EAE7D,CAAA,CAAA,CACF,CAEJ,CCIO,SAASyG,EAAAA,CAAWlG,EAAsB,CAC/C,OAAQA,CAAAA,EACN,KAAK,MAAA,CACH,OAAOP,GAAAA,CAAC0G,QAAAA,CAAA,CAAS,IAAA,CAAM3H,CAAAA,CAAW,GAAI,MAAA,CAAQC,CAAAA,CAAa,GAAI,CAAA,CACjE,KAAK,WACH,OAAOgB,GAAAA,CAAC2G,aAAA,CAAa,IAAA,CAAM5H,EAAW,EAAA,CAAI,MAAA,CAAQC,EAAa,EAAA,CAAI,CAAA,CACrE,KAAK,OAAA,CACH,OAAOgB,IAAC4G,OAAAA,CAAA,CAAQ,KAAM7H,CAAAA,CAAW,EAAA,CAAI,OAAQC,CAAAA,CAAa,EAAA,CAAI,EAChE,QACE,OAAOgB,IAAC6G,YAAAA,CAAA,CAAa,KAAM9H,CAAAA,CAAW,EAAA,CAAI,OAAQC,CAAAA,CAAa,EAAA,CAAI,CACvE,CACF,CAEO,SAAS8H,EAAAA,CAAW,CACzB,OAAAxB,CAAAA,CACA,OAAA,CAAAC,EACA,MAAA,CAAAhF,CAAAA,CACA,MAAAwG,CAAAA,CACA,QAAA,CAAA/F,CACF,CAAA,CAAoB,CAClB,OACEY,IAAAA,CAAC,QAAA,CAAA,CACC,KAAK,QAAA,CACL,OAAA,CAAS2D,EACT,SAAA,CAAW1D,EAAAA,CACT,wCACA,aAAA,CACA,uEACF,EACA,KAAA,CAAO,CAAA,EAAGb,CAAQ,CAAA,CAAA,EAAI+F,CAAK,GAAGzG,CAAAA,CAAaC,CAAM,CAAC,CAAA,CAAA,CAClD,IAAA,CAAK,MACL,eAAA,CAAe+E,CAAAA,CACf,MAAO,CACL,eAAA,CAAiBA,GAAUrG,CAC7B,CAAA,CAEC,UAAAwH,EAAAA,CAAWlG,CAAM,EAClBqB,IAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,UAAA,CACb,QAAA,CAAA,CAAAZ,EAAS,GAAA,CAAE+F,CAAAA,CACXzG,EAAaC,CAAM,CAAA,CAAA,CACtB,GACF,CAEJ,CCrEO,SAASyG,EAAAA,CAAY,CAAE,SAAAC,CAAS,CAAA,CAAsB,CAC3D,OACEjH,GAAAA,CAAC,OAAI,IAAA,CAAK,SAAA,CAAU,UAAW6B,EAAAA,CAAK,6BAA6B,EAC9D,QAAA,CAAAoF,CAAAA,CACH,CAEJ,CCSO,SAASC,GAAa,CAAE,MAAA,CAAAzG,EAAQ,WAAA,CAAAC,CAAY,EAAsB,CACvE,GAAM,CAAE,eAAA,CAAA2C,CAAAA,CAAiB,cAAAG,CAAAA,CAAe,MAAA,CAAAjD,EAAQ,KAAA,CAAAoD,CAAM,EAAIP,CAAAA,CAAkB,CAC1E,OAAA3C,CAAAA,CACA,WAAA,CAAAC,CACF,CAAC,CAAA,CAED,OAAIiD,CAAAA,CAEA3D,GAAAA,CAAC,OACC,IAAA,CAAK,OAAA,CACL,YAAU,QAAA,CACV,SAAA,CAAW6B,GACT,mBAAA,CACA,kCAAA,CACA,uBACF,CAAA,CAEC,QAAA,CAAA8B,CAAAA,CACH,EAIApD,CAAAA,GAAW,MAAA,CACNP,IAACgG,EAAAA,CAAA,CAAW,QAASxC,CAAAA,CAAe,CAAA,CAI3CxD,IAAC,KAAA,CAAA,CAAI,SAAA,CAAU,uCACZ,QAAA,CAAAO,CAAAA,GAAW,OACVP,GAAAA,CAACsG,EAAAA,CAAA,CAAW,OAAA,CAASjD,CAAAA,CAAiB,EAEtCrD,GAAAA,CAAC+F,EAAAA,CAAA,CAAW,OAAA,CAAS1C,CAAAA,CAAiB,SAAU9C,CAAAA,CAAQ,CAAA,CAE5D,CAEJ,CCHO,SAASwE,CAAAA,CAAa,CAC3B,iBAAA,CAAAZ,CAAAA,CACA,SAAAnD,CAAAA,CACA,MAAA,CAAAP,EACA,oBAAA,CAAA2D,CAAAA,CACA,SAAAnC,CACF,CAAA,CAAsB,CAGpB,IAAMkF,CAAAA,CAAe5C,QAAQ,IAAA,CACnB9D,CAAAA,EAAQ,SAAW,EAAC,EACzB,IAAI,CAACK,CAAAA,CAAQsG,KAAmB,CAAE,MAAA,CAAAtG,EAAQ,aAAA,CAAAsG,CAAc,EAAE,CAAA,CAC1D,MAAA,CACEC,GACCA,CAAAA,CAAK,MAAA,GAAW,MAChBA,CAAAA,CAAK,MAAA,GAAW,QAChB,OAAOA,CAAAA,CAAK,OAAO,MAAA,EAAW,QAClC,EACD,CAAC5G,CAAAA,EAAQ,OAAO,CAAC,CAAA,CAEdJ,EAAWH,CAAAA,CAAYc,CAAAA,CAAU,IAAI,CAAA,EAAK,QAAA,CAE1CyB,EAAaF,WAAAA,CAAY,IAAM,CACnCjB,CAAAA,CAAsBb,CAAAA,CAAQ0D,CAAiB,EACjD,CAAA,CAAG,CAAC1D,CAAAA,CAAQ0D,CAAiB,CAAC,CAAA,CAExBmD,CAAAA,CAAc/E,YAAY,IAAM,CACpChB,EAAYd,CAAAA,CAAQ0D,CAAiB,EACvC,CAAA,CAAG,CAAC1D,EAAQ0D,CAAiB,CAAC,EAExBoD,CAAAA,CAAqBhF,WAAAA,CAAY,IAAM,CAC3Cb,CAAAA,CAAmBjB,EAAQ0D,CAAiB,EAC9C,EAAG,CAAC1D,CAAAA,CAAQ0D,CAAiB,CAAC,CAAA,CAExBqD,EAAiBjF,WAAAA,CAAY,IAAM,CACvC/B,CAAAA,CAAeC,CAAAA,CAAQ0D,CAAiB,EAC1C,CAAA,CAAG,CAAC1D,CAAAA,CAAQ0D,CAAiB,CAAC,CAAA,CAE9B,OAAIgD,EAAa,MAAA,GAAW,CAAA,CAExBvF,KAACe,CAAAA,CAAA,CACC,UAAA3C,GAAAA,CAAC4C,CAAAA,CAAA,EAAa,CAAA,CACd5C,GAAAA,CAACuG,GAAA,EAAiB,CAAA,CAAA,CACpB,EAKF3E,IAAAA,CAACe,CAAAA,CAAA,CACC,QAAA,CAAA,CAAAf,IAAAA,CAACgB,EAAA,CACC,QAAA,CAAA,CAAA5C,IAACgH,EAAAA,CAAA,CACE,SAAAG,CAAAA,CAAa,GAAA,CAAI,CAAC,CAAE,MAAA,CAAArG,CAAAA,CAAQ,aAAA,CAAAsG,CAAc,CAAA,GACzCpH,IAAC8G,EAAAA,CAAA,CAEC,OAAQ3C,CAAAA,GAAsBiD,CAAAA,CAC9B,QAAS,IAAMhD,CAAAA,CAAqBgD,CAAa,CAAA,CACjD,MAAA,CAAQtG,EAAO,MAAA,CACf,KAAA,CAAOsG,EACP,QAAA,CAAU/G,CAAAA,CAAAA,CALL,GAAGS,CAAAA,CAAO,MAAM,IAAIsG,CAAa,CAAA,CAMxC,CACD,CAAA,CACH,CAAA,CACApH,IAAC,KAAA,CAAA,CAAI,SAAA,CAAU,SAAS,CAAA,CACxB4B,IAAAA,CAAC,OAAI,SAAA,CAAU,gCAAA,CACb,UAAA5B,GAAAA,CAAC6C,CAAAA,CAAA,CAAkB,OAAA,CAASJ,CAAAA,CAAY,MAAOR,CAAAA,CAAS,IAAA,CAAM,EAC9DjC,GAAAA,CAAC8C,CAAAA,CAAA,EAAiB,CAAA,CACjBrC,CAAAA,EAAQ,UAAU0D,CAAiB,CAAA,EAAG,SAAW,MAAA,EAChDvC,IAAAA,CAAA6F,SAAA,CACE,QAAA,CAAA,CAAAzH,IAAC+C,CAAAA,CAAA,CAAc,QAASuE,CAAAA,CAAa,KAAA,CAAOrF,EAAS,KAAA,CACnD,QAAA,CAAAjC,IAAC0H,WAAAA,CAAA,CAAY,KAAM3I,CAAAA,CAAW,EAAA,CAAI,OAAQC,CAAAA,CAAa,EAAA,CAAI,EAC7D,CAAA,CACAgB,GAAAA,CAAC+C,EAAA,CACC,OAAA,CAASwE,EACT,KAAA,CAAOtF,CAAAA,CAAS,aAEhB,QAAA,CAAAjC,GAAAA,CAAC2H,iBAAA,CACC,IAAA,CAAM5I,EAAW,EAAA,CACjB,MAAA,CAAQC,EAAa,EAAA,CACvB,CAAA,CACF,EACAgB,GAAAA,CAAC8C,CAAAA,CAAA,EAAiB,CAAA,CAAA,CACpB,CAAA,CAEF9C,IAAC+C,CAAAA,CAAA,CAAc,QAASyE,CAAAA,CAAgB,KAAA,CAAOvF,EAAS,QAAA,CACtD,QAAA,CAAAjC,IAAC4H,YAAAA,CAAA,CAAa,KAAM7I,CAAAA,CAAW,EAAA,CAAI,OAAQC,CAAAA,CAAa,EAAA,CAAI,EAC9D,CAAA,CAAA,CACF,CAAA,CAAA,CACF,EACAgB,GAAAA,CAACmD,CAAAA,CAAA,CACC,QAAA,CAAAnD,GAAAA,CAACkH,GAAA,CAAa,MAAA,CAAQzG,EAAQ,WAAA,CAAa0D,CAAAA,CAAmB,EAChE,CAAA,CAAA,CACF,CAEJ,CCvIO,SAASxB,CAAAA,CAAM,CAAE,QAAA,CAAAsE,CAAS,EAAsB,CACrD,OACEjH,IAAC,KAAA,CAAA,CACC,SAAA,CAAW6B,GACT,sBAAA,CACA,2CACF,EAEC,QAAA,CAAAoF,CAAAA,CACH,CAEJ,CChBO,SAAS9D,EAAa,CAAE,QAAA,CAAA8D,CAAS,CAAA,CAAsB,CAC5D,OAAOjH,GAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,iBAAA,CAAmB,QAAA,CAAAiH,EAAS,CACpD,CCHO,SAAS9B,CAAAA,EAAiB,CAC/B,OACEnF,GAAAA,CAAC6H,SAAAA,CAAA,CACC,SAAA,CAAWhG,EAAAA,CACT,MACA,iDAAA,CACA,qCACF,EACA,aAAA,CAAY,WAAA,CAEZ,SAAA7B,GAAAA,CAAC,KAAA,CAAA,CACC,UAAW6B,EAAAA,CACT,SAAA,CACA,iBACA,4BACF,CAAA,CACF,EACF,CAEJ,CClBO,SAASe,CAAAA,CAAa,CAAE,SAAAqE,CAAS,CAAA,CAAsB,CAC5D,OACEjH,GAAAA,CAAC,OACC,SAAA,CAAW6B,EAAAA,CACT,6DACA,gBACF,CAAA,CAEC,SAAAoF,CAAAA,CACH,CAEJ,CCGO,SAASlE,CAAAA,CAAc,CAC5B,OAAA,CAAAwC,CAAAA,CACA,SAAA0B,CAAAA,CACA,KAAA,CAAAa,CACF,CAAA,CAAuB,CACrB,OACE9H,GAAAA,CAAC,QAAA,CAAA,CACC,KAAK,QAAA,CACL,OAAA,CAASuF,EACT,SAAA,CAAW1D,EAAAA,CACT,2CACA,8DAAA,CACA,mBAAA,CACA,wDACF,CAAA,CACA,KAAA,CAAOiG,EAEN,QAAA,CAAAb,CAAAA,CACH,CAEJ,CCpBO,SAASpE,EAAkB,CAChC,OAAA,CAAA0C,EACA,KAAA,CAAAuC,CAAAA,CAAQ,MACV,CAAA,CAA2B,CACzB,GAAM,CAACC,CAAAA,CAAWC,CAAY,CAAA,CAAIzE,QAAAA,CAAS,KAAK,CAAA,CAYhD,OACEvD,IAAC+C,CAAAA,CAAA,CAAc,QAXE,SAAY,CAC7B,GAAI,CACF,MAAMwC,GAAQ,CACdyC,CAAAA,CAAa,EAAI,CAAA,CACjB,UAAA,CAAW,IAAMA,CAAAA,CAAa,CAAA,CAAK,EAAG,GAAI,EAC5C,OAAS3G,CAAAA,CAAG,CACV,QAAQ,KAAA,CAAM,gBAAA,CAAkBA,CAAC,EACnC,CACF,EAGsC,KAAA,CAAOyG,CAAAA,CACxC,SAAAC,CAAAA,CACC/H,GAAAA,CAACiI,UAAA,CAAU,IAAA,CAAMlJ,EAAW,EAAA,CAAI,MAAA,CAAQC,EAAa,EAAA,CAAI,CAAA,CAEzDgB,IAACkI,QAAAA,CAAA,CAAS,KAAMnJ,CAAAA,CAAW,EAAA,CAAI,OAAQC,CAAAA,CAAa,EAAA,CAAI,EAE5D,CAEJ,CC3CO,SAAS8D,CAAAA,EAAmB,CACjC,OAAO9C,GAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,8BAAA,CAA+B,CACvD","file":"index.js","sourcesContent":["/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nexport const ICON_SIZES = {\n xs: 12,\n sm: 16,\n md: 20,\n lg: 24,\n xl: 28,\n}\n\nexport const ICON_STROKES = {\n xs: 1,\n sm: 1.25,\n md: 1.5,\n lg: 1.75,\n xl: 2,\n}\n\n// Monaco's default dark theme (aka, the `vsdark` theme) background color\nexport const EDITOR_BG_COLOR = '#1e1e1e'\n\n// Monaco's default font size\nexport const EDITOR_FONT_SIZE = 14\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n'use client'\n\nimport MonacoEditor, { type Monaco, type OnMount } from '@monaco-editor/react'\nimport type { languages } from 'monaco-editor'\n\nimport { EDITOR_FONT_SIZE } from '@/constants'\n\n/**\n * Registers the LaTeX language support in Monaco.\n *\n * @param monaco - The Monaco instance.\n */\nfunction registerLatexLanguage(monaco: Monaco) {\n // ref issue: https://github.com/microsoft/monaco-editor/issues/3233\n const latexLanguage: languages.IMonarchLanguage = {\n displayName: 'LaTeX',\n name: 'latex',\n mimeTypes: ['text/latex', 'text/tex'],\n fileExtensions: ['tex', 'sty', 'cls'],\n\n tokenPostfix: '.latex',\n defaultToken: '',\n\n keywords: [\n 'addcontentsline',\n 'addtocontents',\n 'addtocounter',\n 'address',\n 'addtolength',\n 'addvspace',\n 'alph',\n 'appendix',\n 'arabic',\n 'author',\n 'backslash',\n 'baselineskip',\n 'baselinestretch',\n 'bf',\n 'bibitem',\n 'bigskipamount',\n 'bigskip',\n 'boldmath',\n 'boldsymbol',\n 'cal',\n 'caption',\n 'cdots',\n 'centering',\n 'chapter',\n 'circle',\n 'cite',\n 'cleardoublepage',\n 'clearpage',\n 'cline',\n 'closing',\n 'color',\n 'copyright',\n 'dashbox',\n 'date',\n 'ddots',\n 'documentclass',\n 'dotfill',\n 'em',\n 'emph',\n 'ensuremath',\n 'epigraph',\n 'euro',\n 'fbox',\n 'flushbottom',\n 'fnsymbol',\n 'footnote',\n 'footnotemark',\n 'footnotesize',\n 'footnotetext',\n 'frac',\n 'frame',\n 'framebox',\n 'frenchspacing',\n 'hfill',\n 'hline',\n 'href',\n 'hrulefill',\n 'hspace',\n 'huge',\n 'Huge',\n 'hyphenation',\n 'include',\n 'includegraphics',\n 'includeonly',\n 'indent',\n 'input',\n 'it',\n 'item',\n 'kill',\n 'label',\n 'large',\n 'Large',\n 'LARGE',\n 'LaTeX',\n 'LaTeXe',\n 'ldots',\n 'left',\n 'lefteqn',\n 'line',\n 'linebreak',\n 'linethickness',\n 'linewidth',\n 'listoffigures',\n 'listoftables',\n 'location',\n 'makebox',\n 'maketitle',\n 'markboth',\n 'mathcal',\n 'mathop',\n 'mbox',\n 'medskip',\n 'multicolumn',\n 'multiput',\n 'newcommand',\n 'newcolumntype',\n 'newcounter',\n 'newenvironment',\n 'newfont',\n 'newlength',\n 'newline',\n 'newpage',\n 'newsavebox',\n 'newtheorem',\n 'nocite',\n 'noindent',\n 'nolinebreak',\n 'nonfrenchspacing',\n 'normalsize',\n 'nopagebreak',\n 'not',\n 'onecolumn',\n 'opening',\n 'oval',\n 'overbrace',\n 'overline',\n 'pagebreak',\n 'pagenumbering',\n 'pageref',\n 'pagestyle',\n 'par',\n 'paragraph',\n 'parbox',\n 'parindent',\n 'parskip',\n 'part',\n 'protect',\n 'providecommand',\n 'put',\n 'raggedbottom',\n 'raggedleft',\n 'raggedright',\n 'raisebox',\n 'ref',\n 'renewcommand',\n 'right',\n 'rm',\n 'roman',\n 'rule',\n 'savebox',\n 'sbox',\n 'sc',\n 'scriptsize',\n 'section',\n 'setcounter',\n 'setlength',\n 'settowidth',\n 'sf',\n 'shortstack',\n 'signature',\n 'sl',\n 'slash',\n 'small',\n 'smallskip',\n 'sout',\n 'space',\n 'sqrt',\n 'stackrel',\n 'stepcounter',\n 'subparagraph',\n 'subsection',\n 'subsubsection',\n 'tableofcontents',\n 'telephone',\n 'TeX',\n 'textbf',\n 'textcolor',\n 'textit',\n 'textmd',\n 'textnormal',\n 'textrm',\n 'textsc',\n 'textsf',\n 'textsl',\n 'texttt',\n 'textup',\n 'textwidth',\n 'textheight',\n 'thanks',\n 'thispagestyle',\n 'tiny',\n 'title',\n 'today',\n 'tt',\n 'twocolumn',\n 'typeout',\n 'typein',\n 'uline',\n 'underbrace',\n 'underline',\n 'unitlength',\n 'usebox',\n 'usecounter',\n 'uwave',\n 'value',\n 'vbox',\n 'vcenter',\n 'vdots',\n 'vector',\n 'verb',\n 'vfill',\n 'vline',\n 'vphantom',\n 'vspace',\n\n 'RequirePackage',\n 'NeedsTeXFormat',\n 'usepackage',\n 'input',\n 'include',\n 'documentclass',\n 'documentstyle',\n 'def',\n 'edef',\n 'defcommand',\n 'if',\n 'ifdim',\n 'ifnum',\n 'ifx',\n 'fi',\n 'else',\n 'begingroup',\n 'endgroup',\n 'definecolor',\n 'textcolor',\n 'color',\n 'eifstrequal',\n 'eeifstrequal',\n ],\n\n tokenizer: {\n root: [\n [\n /(\\\\begin)(\\s*)(\\{)([\\w\\-*@]+)(\\})/,\n [\n 'keyword.predefined',\n 'white',\n '@brackets',\n { token: 'tag.env-$4', bracket: '@open' },\n '@brackets',\n ],\n ],\n [\n /(\\\\end)(\\s*)(\\{)([\\w\\-*@]+)(\\})/,\n [\n 'keyword.predefined',\n 'white',\n '@brackets',\n { token: 'tag.env-$4', bracket: '@close' },\n '@brackets',\n ],\n ],\n [/\\\\\\[a-zA-Z@]/, 'keyword'],\n [/\\\\\\\\[^a-zA-Z@]/, 'keyword'],\n [/\\\\@[a-zA-Z@]+/, 'keyword.at'],\n [\n /\\\\([a-zA-Z@]+)/,\n {\n cases: {\n '$1@keywords': 'keyword.predefined',\n '@default': 'keyword',\n },\n },\n ],\n { include: '@whitespace' },\n [/[{}()[\\]]/, '@brackets'],\n [/#+\\d/, 'number.arg'],\n [\n /\\\\-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)\\s*(?:em|ex|pt|pc|sp|cm|mm|in)/,\n 'number.len',\n ],\n ],\n\n whitespace: [\n [/[ \\t\\r\\n]+/, 'white'],\n ['%.*$', 'comment'],\n ],\n },\n }\n\n const latexConf: languages.LanguageConfiguration = {\n comments: {\n lineComment: '%',\n },\n brackets: [\n ['{', '}'],\n ['[', ']'],\n ['(', ')'],\n ],\n autoClosingPairs: [\n { open: '{', close: '}' },\n { open: '[', close: ']' },\n { open: '(', close: ')' },\n { open: '$', close: '$' },\n ],\n surroundingPairs: [\n { open: '{', close: '}' },\n { open: '[', close: ']' },\n { open: '(', close: ')' },\n { open: '$', close: '$' },\n ],\n }\n\n if (\n monaco.languages\n .getLanguages()\n .some((l: { id: string }) => l.id === 'latex')\n ) {\n return\n }\n\n monaco.languages.register({ id: 'latex' })\n monaco.languages.setMonarchTokensProvider('latex', latexLanguage)\n monaco.languages.setLanguageConfiguration('latex', latexConf)\n}\n\n/**\n * Props for the Editor component.\n */\nexport interface EditorProps {\n /** The content of the editor. */\n value: string\n /** Callback triggered when content changes. */\n onChange?: (value: string | undefined) => void\n /** The language of the content. */\n language: string\n /** Whether the editor is read-only. Defaults to false. */\n readOnly?: boolean\n /** Whether to show line numbers. Defaults to true. */\n lineNumbers?: boolean\n /** Whether to show the minimap. Defaults to true. */\n minimap?: boolean\n /** Callback triggered when the editor is mounted. */\n onMount?: OnMount\n}\n\n/**\n * A shared editor component based on Monaco Editor.\n * Encapsulates theme handling, common configuration, and LaTeX support.\n *\n * @param props - The component props.\n * @returns The rendered Editor component.\n */\nexport function Editor({\n value,\n onChange,\n language,\n readOnly = false,\n lineNumbers = true,\n minimap = true,\n onMount,\n}: EditorProps) {\n return (\n <MonacoEditor\n height=\"100%\"\n language={language}\n value={value}\n onChange={onChange}\n theme=\"vs-dark\"\n onMount={onMount}\n beforeMount={registerLatexLanguage}\n options={{\n readOnly,\n domReadOnly: readOnly,\n lineNumbers: lineNumbers ? 'on' : 'off',\n minimap: { enabled: minimap },\n fontSize: EDITOR_FONT_SIZE,\n lineNumbersMinChars: 4,\n padding: {\n top: 8,\n },\n automaticLayout: true,\n roundedSelection: false,\n smoothScrolling: true,\n scrollBeyondLastLine: false,\n }}\n />\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n getResumeRenderer,\n type LayoutEngine,\n type Resume,\n} from '@yamlresume/core'\n\n/**\n * Gets the basename from a filepath.\n *\n * @param filepath - The file path (e.g. \"path/to/resume.yaml\").\n * @param removeExtension - Whether to remove the file extension.\n * @returns The basename of the file.\n */\nexport const getBasename = (\n filepath = 'resume.yaml',\n removeExtension = false\n): string => {\n const basename = filepath.split(/[/\\\\]/).pop() || filepath\n if (removeExtension) {\n return basename.replace(/\\.(ya?ml|json)$/, '')\n }\n return basename\n}\n\n/**\n * Gets the file extension for a given rendering engine.\n *\n * @param engine - The rendering engine (html, latex, markdown).\n * @returns The associated file extension.\n */\nexport const getExtension = (engine: LayoutEngine): string => {\n switch (engine) {\n case 'html':\n return '.html'\n case 'latex':\n return '.tex'\n case 'markdown':\n return '.md'\n case 'docx':\n return '.docx'\n default:\n return ''\n }\n}\n\n/**\n * Downloads the resume for a specific layout index.\n *\n * @param resume - The resume object.\n * @param layoutIndex - The index of the layout to download.\n */\nexport const downloadResume = async (\n resume: Resume | null,\n layoutIndex: number\n) => {\n try {\n const layouts = resume?.layouts\n if (!resume || !layouts[layoutIndex]) {\n console.warn('No resume or layout found for download')\n return\n }\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const renderResult = renderer.render()\n const layout = layouts[layoutIndex]\n const extension = getExtension(layout.engine)\n const filename = `resume.${layoutIndex}${extension}`\n\n const content =\n renderResult instanceof Promise ? await renderResult : renderResult\n const blob =\n content instanceof Uint8Array\n ? new Blob([content.buffer as BlobPart], {\n type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n })\n : new Blob([content], { type: 'text/plain' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n URL.revokeObjectURL(url)\n } catch (e) {\n console.error('Failed to download resume:', e)\n }\n}\n\n/**\n * Copies the resume content to the clipboard for a specific layout index.\n *\n * @param resume - The resume object.\n * @param layoutIndex - The index of the layout to copy.\n */\nexport const copyResumeToClipboard = (\n resume: Resume | null,\n layoutIndex: number\n): Promise<void> => {\n try {\n const layouts = resume?.layouts\n if (!resume || !layouts[layoutIndex]) {\n console.warn('No resume or layout found for copy')\n return Promise.resolve()\n }\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const content = renderer.render()\n if (typeof content !== 'string') {\n console.warn('Copy to clipboard is not supported for binary layouts')\n return Promise.resolve()\n }\n\n return navigator.clipboard.writeText(content)\n } catch (e) {\n console.error('Failed to copy resume:', e)\n return Promise.resolve()\n }\n}\n\n/**\n * Prints the resume content (only for HTML layouts).\n *\n * @param resume - The resume object.\n * @param layoutIndex - The index of the layout to print.\n */\nexport const printResume = (resume: Resume | null, layoutIndex: number) => {\n try {\n const layouts = resume?.layouts\n if (!resume || !layouts[layoutIndex]) {\n console.warn('No resume or layout found for print')\n return\n }\n\n const layout = layouts[layoutIndex]\n if (layout.engine !== 'html') {\n console.warn('Printing is only supported for HTML layouts')\n return\n }\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const content = renderer.render()\n if (typeof content !== 'string') {\n console.warn('Printing is only supported for string-based layouts')\n return\n }\n\n const iframe = document.createElement('iframe')\n iframe.style.position = 'absolute'\n iframe.style.width = '0px'\n iframe.style.height = '0px'\n iframe.style.border = 'none'\n document.body.appendChild(iframe)\n\n const doc = iframe.contentWindow?.document\n if (doc) {\n doc.open()\n doc.write(content)\n doc.close()\n iframe.contentWindow?.focus()\n iframe.contentWindow?.print()\n }\n\n // Clean up after print dialog closes (or reasonably soon)\n setTimeout(() => {\n document.body.removeChild(iframe)\n }, 1000)\n } catch (e) {\n console.error('Failed to print resume:', e)\n }\n}\n\n/**\n * Opens the resume content in a new tab (only for HTML layouts).\n *\n * @param resume - The resume object.\n * @param layoutIndex - The index of the layout to open.\n */\nexport const openResumeInNewTab = (\n resume: Resume | null,\n layoutIndex: number\n) => {\n try {\n const layouts = resume?.layouts\n if (!resume || !layouts[layoutIndex]) {\n console.warn('No resume or layout found for new tab')\n return\n }\n\n const layout = layouts[layoutIndex]\n if (layout.engine !== 'html') {\n console.warn('Open in new tab is only supported for HTML layouts')\n return\n }\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const content = renderer.render()\n if (typeof content !== 'string') {\n console.warn('Open in new tab is only supported for string-based layouts')\n return\n }\n\n const blob = new Blob([content], { type: 'text/html' })\n const url = URL.createObjectURL(blob)\n window.open(url, '_blank')\n } catch (e) {\n console.error('Failed to open resume in new tab:', e)\n }\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { IconFileCode } from '@tabler/icons-react'\nimport clsx from 'clsx'\n\nimport { EDITOR_BG_COLOR, ICON_SIZES, ICON_STROKES } from '@/constants'\nimport { getBasename } from '@/utils'\n\n/**\n * The title component for the editor panel.\n * Displays as a tab with a YAML icon.\n *\n * @returns The rendered title element.\n */\ninterface EditorTitleProps {\n filename?: string\n}\n\nexport function EditorTitle({ filename = 'resume.yaml' }: EditorTitleProps) {\n // Extract basename if path is provided\n const basename = getBasename(filename)\n return (\n <div\n className={clsx(\n 'flex items-center gap-2',\n 'h-full px-4',\n 'border-r border-neutral-600'\n )}\n style={{ backgroundColor: EDITOR_BG_COLOR }}\n >\n <IconFileCode size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n <span>{basename}</span>\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { OnMount } from '@monaco-editor/react'\nimport { Editor } from './Editor'\n\n/**\n * Props for the ResumeEditor component.\n */\nexport interface ResumeEditorProps {\n /**\n * The current value of the YAML resume.\n */\n value: string\n /**\n * Callback triggered when the editor content changes.\n * @param value - The new value of the editor content.\n */\n onChange: (value: string | undefined) => void\n /** Callback triggered when the editor is mounted. */\n onMount?: OnMount\n}\n\n/**\n * A specialized editor component for editing the resume YAML content.\n *\n * This component wraps the shared {@link Editor} component, pre-configured\n * for YAML editing.\n *\n * @param props - The component props.\n * @param props.value - The string content to display in the editor.\n * @param props.onChange - Handler called when content is modified.\n * @returns The rendered editor component.\n */\nexport function ResumeEditor({ value, onChange, onMount }: ResumeEditorProps) {\n return (\n <Editor\n language=\"yaml\"\n value={value}\n onChange={onChange}\n onMount={onMount}\n />\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { OnMount } from '@monaco-editor/react'\nimport {\n IconArrowBackUp,\n IconArrowForwardUp,\n IconEraser,\n} from '@tabler/icons-react'\nimport { useCallback, useRef } from 'react'\n\nimport {\n Panel,\n PanelContent,\n PanelToolbar,\n ToolbarButton,\n ToolbarCopyButton,\n ToolbarSeparator,\n} from '@/components'\nimport { ICON_SIZES, ICON_STROKES } from '@/constants'\nimport type { PlaygroundTooltipMessages } from '@/messages'\n\nimport { EditorTitle } from './EditorTitle'\nimport { ResumeEditor } from './ResumeEditor'\n\n/**\n * Props for the EditorPanel component.\n */\nexport interface EditorPanelProps {\n /** The current YAML content of the editor. */\n value: string\n /** Callback triggered when the content changes. */\n onChange: (value: string) => void\n /** The name of the file being edited. */\n filename?: string\n /** Localized tooltip labels for editor actions. */\n tooltips: Pick<PlaygroundTooltipMessages, 'copy' | 'undo' | 'redo' | 'clear'>\n}\n\n/**\n * A panel component containing the resume editor.\n *\n * @param props - The component props.\n * @returns The rendered editor panel.\n */\nexport function EditorPanel({\n value,\n onChange,\n filename,\n tooltips,\n}: EditorPanelProps) {\n const editorRef = useRef<Parameters<OnMount>[0] | null>(null)\n\n const handleEditorMount: OnMount = (editor) => {\n editorRef.current = editor\n }\n\n const handleUndo = useCallback(() => {\n editorRef.current?.trigger('source', 'undo', null)\n }, [])\n\n const handleRedo = useCallback(() => {\n editorRef.current?.trigger('source', 'redo', null)\n }, [])\n\n const handleCopy = useCallback(() => {\n const content = editorRef.current?.getValue()\n if (content) {\n return navigator.clipboard.writeText(content)\n }\n return Promise.resolve()\n }, [])\n\n const handleClear = useCallback(() => {\n if (\n editorRef.current &&\n window.confirm('Are you sure you want to clear the editor?')\n ) {\n editorRef.current.setValue('')\n }\n }, [])\n\n return (\n <Panel>\n <PanelToolbar>\n <div className=\"flex h-full\">\n <EditorTitle filename={filename} />\n </div>\n <div className=\"flex-1\" />\n <div className=\"flex items-center gap-0.5 pr-2\">\n <ToolbarCopyButton onClick={handleCopy} title={tooltips.copy} />\n <ToolbarSeparator />\n <ToolbarButton onClick={handleUndo} title={tooltips.undo}>\n <IconArrowBackUp size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n <ToolbarButton onClick={handleRedo} title={tooltips.redo}>\n <IconArrowForwardUp size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n <ToolbarSeparator />\n <ToolbarButton onClick={handleClear} title={tooltips.clear}>\n <IconEraser size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n </div>\n </PanelToolbar>\n <PanelContent>\n <ResumeEditor\n value={value}\n onChange={onChange}\n onMount={handleEditorMount}\n />\n </PanelContent>\n </Panel>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n getResumeRenderer,\n type LayoutEngine,\n type Resume,\n} from '@yamlresume/core'\nimport { useEffect, useState } from 'react'\n\n/**\n * Props for the `useResumeRenderer` hook.\n *\n * @property {Resume | null} resume - The pre-parsed resume object to render.\n * Pass `null` when the resume is not yet available or parsing failed.\n * @property {number} layoutIndex - The index of the layout to use for rendering.\n * Must be a valid index within the `resume.layouts` array.\n */\nexport interface UseResumeRendererProps {\n resume: Resume | null\n layoutIndex: number\n}\n\n/**\n * A React hook for rendering a resume using a specified layout.\n *\n * @description\n * This hook encapsulates the logic for:\n * - Selecting the appropriate layout from the resume's layouts array\n * - Determining the rendering engine (html, markdown, or latex)\n * - Generating the rendered output content\n * - Handling errors gracefully during rendering\n *\n * The hook re-renders when either the `resume` object or `layoutIndex` changes.\n * If `resume` is `null`, no rendering is performed.\n *\n * @param {UseResumeRendererProps} props - Configuration options for the hook.\n * @returns An object containing:\n * - `renderedContent` - The rendered resume content as a string\n * - `engine` - The rendering engine used ('html', 'markdown', or 'latex')\n * - `error` - Error message if rendering failed, or `null` if successful\n *\n * @example\n * const { renderedContent, engine, error } = useResumeRenderer({\n * resume: parsedResume,\n * layoutIndex: 0,\n * })\n *\n * if (error) {\n * return <ErrorDisplay message={error} />\n * }\n *\n * return engine === 'html'\n * ? <HtmlViewer content={renderedContent} />\n * : <CodeViewer content={renderedContent} language={engine} />\n */\nexport function useResumeRenderer({\n resume,\n layoutIndex,\n}: UseResumeRendererProps) {\n const [renderedContent, setRenderedContent] = useState<string>('')\n const [binaryContent, setBinaryContent] = useState<Uint8Array | null>(null)\n const [engine, setEngine] = useState<LayoutEngine>('html')\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n if (!resume) return\n\n try {\n const layout = resume.layouts?.[layoutIndex]\n if (!layout) {\n setError(`Layout at index ${layoutIndex} not found.`)\n return\n }\n\n // Handle incomplete layout entries (e.g., when user is typing \"- \" in YAML)\n if (typeof layout.engine !== 'string') {\n setError('Layout is incomplete - missing engine property.')\n return\n }\n\n const currentEngine = layout.engine\n setEngine(currentEngine)\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const result = renderer.render()\n\n if (typeof result === 'string') {\n setRenderedContent(result)\n setBinaryContent(null)\n setError(null)\n } else if (result instanceof Uint8Array) {\n setRenderedContent('')\n setBinaryContent(result)\n setError(null)\n } else {\n result\n .then((content) => {\n if (typeof content === 'string') {\n setRenderedContent(content)\n setBinaryContent(null)\n } else if (content instanceof Uint8Array) {\n setRenderedContent('')\n setBinaryContent(content)\n }\n setError(null)\n })\n .catch((e) => {\n setError(\n `Render Error: ${e instanceof Error ? e.message : String(e)}`\n )\n })\n }\n } catch (e) {\n setError(`Render Error: ${e instanceof Error ? e.message : String(e)}`)\n }\n }, [resume, layoutIndex])\n\n return {\n renderedContent,\n binaryContent,\n engine,\n error,\n }\n}\n","# MIT License\n#\n# Copyright (c) 2023–Present PPResume (https://ppresume.com)\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to\n# deal in the Software without restriction, including without limitation the\n# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n# sell copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n# IN THE SOFTWARE.\n\n# yaml-language-server: $schema=https://yamlresume.dev/schema.json\n#\n# YAMLResume provides a builtin schema to validate resumes and help avoid lots\n# of low level mistakes.\n#\n# You need to install https://github.com/redhat-developer/yaml-language-server\n# in order to get the best editing experience in your choice of editor/IDE.\n#\n# ref:\n# - https://yamlresume.dev/docs/compiler/schema\n# - https://yamlresume.dev/docs/compiler/schema/json\n\n---\ncontent:\n basics:\n name: Andy Dufresne\n headline: Headed for the Pacific\n phone: \"(213) 555-9876\"\n email: hi@ppresume.com\n url: https://ppresume.com/gallery\n # All summary fields supports a limited rich text capabilities in markdown\n # syntax:\n #\n # - bold, (e.g, **bold**)\n # - italic, (e.g, *italic*)\n # - ordered list, unordored list and nested sub list\n # - links (e.g. [link](https://ppresume.com))\n summary: |\n - Computer Science major with strong foundation in data structures, algorithms, and software development\n - Pixel perfect full stack web developer, specialised in creating high-quality, visually appealing websites\n - Experiened in databases (SQL, NoSQL), familiar with server-side technologies (Node.js, Express, etc.)\n - Team player, with detail-oriented mindset and a keen eye for design and user experiences\n location:\n address: 123 Main Street\n city: Sacramento\n region: California\n country: United States\n postalCode: \"95814\"\n profiles:\n - network: Line\n url: https://line.com/PPResumeX\n username: PPResumeX\n - network: Twitter\n url: https://twitter.com/PPResumeX\n username: PPResumeX\n education:\n - institution: University of Southern California\n url: https://www.cs.usc.edu/\n # Valid degree options:\n #\n # - 'Middle School'\n # - 'High School'\n # - 'Diploma'\n # - 'Associate'\n # - 'Bachelor'\n # - 'Master'\n # - 'Doctor'\n degree: Bachelor\n area: Computer Engineering and Computer Science\n score: \"3.8\"\n # Should be a valid date string that can be parsed by \\`new Date(dateStr)\\`\n # in JavaScript, eg. '2020-01', '2020-02-03', 'Jul 1, 2023' etc.\n #\n # The date part would be removed in the final output as most of the time\n # people won't really care about the exact date for your working\n # experience or education background, etc.\n # ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date\n startDate: Sep 1, 2016\n # Leave endDate blank to indicate \"Present\"\n endDate: Jul 1, 2020\n courses:\n - Discrete Methods in Computer Science\n - Programming Language Concepts\n - Data Structures and Object-Oriented Design\n - Operating Systems\n - Computer Architecture\n - Database Systems\n - Computer Networking\n - Introduction to the Theory of Computing\n summary: |\n - Developed proficiency in programming languages such as Java, C++, and Python\n - Gained hands-on experience in software development through various projects and assignments\n - Strong communication and teamwork skills acquired through group projects and presentations\n work:\n - name: PPResume\n url: https://ppresume.com\n startDate: Dec 1, 2022\n endDate:\n position: Senior Software Engineer\n summary: |\n - Developed and implemented efficient and scalable code, ensuring high-quality and maintainable web applications\n - Collaborated with cross-functional teams to gather project requirements and translate them into technical solutions\n - Conducted thorough testing and debugging to identify and resolve any issues or bugs in the software\n - Actively participated in code reviews, providing valuable feedback to improve code quality and adherence to best practices\n - Mentored and guided junior developers, fostering a collaborative and growth-oriented team environment\n keywords:\n - Scalability\n - Growth\n - Quality\n - Mentorship\n - name: PPResume\n url: https://ppresume.com\n startDate: Sep 1, 2020\n endDate: Dec 1, 2022\n position: Software Engineer\n summary: |\n - Created reusable React components to ensure code efficiency and maintainability\n - Integrated with RESTful APIs to fetch and display dynamic data on the frontend\n - Implemented client-side routing using React Router for smooth navigation between pages\n - Actively participated in Agile development methodologies, attending daily stand-up meetings and sprint planning sessions\n keywords:\n - RESTful\n - React\n - Agile\n languages:\n # Valid language fluency options:\n #\n # - 'Elementary Proficiency'\n # - 'Limited Working Proficiency'\n # - 'Minimum Professional Proficiency'\n # - 'Full Professional Proficiency'\n # - 'Native or Bilingual Proficiency'\n - language: English\n fluency: Native or Bilingual Proficiency\n keywords:\n - TOEFL 110\n - IELTS 7.5\n - language: Chinese\n fluency: Elementary Proficiency\n keywords: []\n skills:\n # Valid level options:\n #\n # - 'Novice'\n # - 'Beginner'\n # - 'Intermediate'\n # - 'Advanced'\n # - 'Expert'\n # - 'Master'\n - name: Web Development\n level: Expert\n keywords:\n - Python\n - Ruby\n - CSS\n - React\n - JavaScript\n - name: DevOps\n level: Intermediate\n keywords:\n - Python\n - Kubernetes\n - Docker\n - Shell\n - Ansible\n - name: Design\n level: Intermediate\n keywords:\n - Sketch\n - Figma\n - Photoshop\n awards:\n - title: Dean's List\n awarder: University of Southern California\n date: Oct 2016\n summary: |\n Awarded to students who achieve a high academic standing by maintaining a specified grade point average (GPA) during a semester.\n certificates:\n - name: AWS Certified Developer - Associate\n url: https://aws.amazon.com/certification/\n issuer: AWS\n date: Mar 2021\n publications:\n - publisher: ACM Transactions on Interactive Intelligent Systems\n url: https://dl.acm.org/journal/tiis\n name: Enhancing Human-Computer Interaction through Augmented Reality\n releaseDate: Dec 2017\n summary: |\n - Explores the potential of augmented reality (AR) in improving interaction between humans and computers\n - Highlights benefits of AR in various areas such as gaming, education, healthcare, and design\n - Discusses challenges and future directions of AR technology in enhancing user experience\n references:\n - name: Dr. Amanda Reynolds\n phone: \"(555) 123-4567\"\n relationship: Computer Science Professor\n email: amanda.reynolds@usc.edu\n summary: |\n Andy Dufresne shows exceptional problem-solving skills and a solid understanding of programming concepts, he would bring immense value to any team or organization he becomes a part of.\n projects:\n - name: EduWeb\n url: https://www.eduweb.xyz/\n description: A web-based educational platform for interactive learning\n startDate: Sep 2016\n endDate: Dec 2016\n summary: |\n - Designed to enhance online learning experiences\n - Facilitates students' engagement and collaboration through interactive features and user-friendly interface\n - Offers a wide range of courses across various subjects\n - Aims to improve the way students learn through the power of the web\n keywords:\n - Education\n - Online Learning\n - HCI\n interests:\n - name: Sports\n keywords:\n - Soccer\n - Swimming\n - Bicycling\n - Hiking\n - name: Music\n keywords:\n - Piano\n - Guitar\n volunteer:\n - organization: USC Computer Science and Engineering Society\n url: https://www.usccsesociety.org/\n position: Tech Mentor\n startDate: Sep 2015\n endDate: Jul 2023\n summary: |\n - Volunteered as a Tech Mentor at USC Computer Science and Engineering Society\n - Provided guidance and assistance to fellow students in their technical projects and coursework\n - Assisted in organizing workshops, coding competitions, and networking events for the society members\n - Contributed to fostering a collaborative and supportive environment within the student community\n\n# Top-level locale setting\nlocale:\n # Use \\`yamlresume languages list\\` to get the list of supported languages\n language: en\n\n# Multiple output layouts configuration\nlayouts:\n - engine: html\n # Use \\`yamlresume templates list\\` to get the list of available templates\n template: calm\n typography:\n # HTML engine only supports font size in px unit, from 10px to 24px\n fontSize: 16px\n - engine: markdown\n - engine: latex\n page:\n margins:\n top: 2.5cm\n left: 1.5cm\n right: 1.5cm\n bottom: 2.5cm\n showPageNumbers: true\n # Use \\`yamlresume templates list\\` to get the list of available templates\n template: moderncv-banking\n typography:\n # LaTeX engine only supports 10pt, 11pt, and 12pt\n fontSize: 11pt\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { Resume } from '@yamlresume/core'\nimport { useEffect, useMemo, useState } from 'react'\nimport { parse } from 'yaml'\n\nimport DEFAULT_RESUME_YAML from '@/resources/default-resume.yml'\n\n/**\n * Props for the `useResumeState` hook.\n *\n * @property {string} [yaml] - The YAML content for the resume editor.\n * Defaults to `DEFAULT_YAML` if not provided. Parent component should\n * manage this state and update it via the `onChange` callback.\n * @property {(value: string) => void} [onChange] - Callback invoked when\n * the YAML content changes. The parent should update its state accordingly.\n */\nexport interface UseResumeStateProps {\n yaml?: string\n onChange?: (value: string) => void\n}\n\n/**\n * A React hook for managing resume state derived from YAML content.\n *\n * @description\n * This hook encapsulates the logic for:\n * - Parsing YAML into a `Resume` object with memoization\n * - Tracking the active layout index with bounds checking\n * - Providing a change handler that notifies the parent\n *\n * The parent component is responsible for managing the YAML state.\n * This hook simply derives state (parsed resume, layout index) from the\n * provided YAML and exposes utilities for updates.\n *\n * @param {UseResumeStateProps} props - Configuration options for the hook.\n * @returns An object containing:\n * - `yaml` - The current YAML string content\n * - `handleYamlChange` - Function to notify parent of YAML changes\n * - `activeLayoutIndex` - The currently selected layout index\n * - `setActiveLayoutIndex` - Function to change the active layout\n * - `resume` - The parsed `Resume` object (or `null` if parsing fails)\n *\n * @example\n * // Parent manages state, hook derives resume object\n * const [yaml, setYaml] = useState(defaultYaml)\n * const { resume, activeLayoutIndex } = useResumeState({\n * yaml,\n * onChange: setYaml,\n * })\n */\nexport function useResumeState({\n yaml = DEFAULT_RESUME_YAML,\n onChange,\n}: UseResumeStateProps) {\n const [activeLayoutIndex, setActiveLayoutIndex] = useState(0)\n\n const handleYamlChange = (v: string) => {\n onChange?.(v)\n }\n\n const resume = useMemo(() => {\n try {\n return parse(yaml) as Resume\n } catch (_e) {\n return null\n }\n }, [yaml])\n\n // Ensure activeLayoutIndex is always within bounds\n useEffect(() => {\n const layouts = resume?.layouts || []\n if (activeLayoutIndex >= layouts.length && layouts.length > 0) {\n setActiveLayoutIndex(layouts.length - 1)\n }\n }, [resume?.layouts, activeLayoutIndex])\n\n return {\n yaml,\n handleYamlChange,\n activeLayoutIndex,\n setActiveLayoutIndex,\n resume,\n }\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * Tooltip label strings for each action button in the playground toolbar.\n */\nexport interface PlaygroundTooltipMessages {\n copy: string\n undo: string\n redo: string\n clear: string\n print: string\n openInNewTab: string\n download: string\n}\n\n/**\n * All user-facing messages consumed by the playground component.\n */\nexport interface PlaygroundMessages {\n tooltips: PlaygroundTooltipMessages\n}\n\n/**\n * Partial overrides for {@link PlaygroundMessages}, allowing consumers to\n * customize individual strings without providing the full message object.\n */\nexport interface PlaygroundMessageOverrides {\n tooltips?: Partial<PlaygroundTooltipMessages>\n}\n\n/**\n * Default English messages used by the playground when no overrides are\n * provided.\n */\nexport const DEFAULT_PLAYGROUND_MESSAGES: PlaygroundMessages = {\n tooltips: {\n copy: 'Copy',\n undo: 'Undo',\n redo: 'Redo',\n clear: 'Clear',\n print: 'Print',\n openInNewTab: 'Open in New Tab',\n download: 'Download',\n },\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n'use client'\n\nimport clsx from 'clsx'\n\nimport {\n EditorPanel,\n PlaygroundDesktop,\n PlaygroundMobile,\n PreviewPanel,\n} from '@/components'\nimport { EDITOR_BG_COLOR } from '@/constants'\nimport { useResumeState } from '@/hooks'\nimport {\n DEFAULT_PLAYGROUND_MESSAGES,\n type PlaygroundMessageOverrides,\n} from '@/messages'\nimport DEFAULT_RESUME_YAML from '@/resources/default-resume.yml'\n\n/**\n * Props for the Playground component.\n */\nexport interface PlaygroundProps {\n /** YAML content for the playground editor. Defaults to DEFAULT_YAML. */\n yaml?: string\n /** Callback triggered when the content changes. */\n onChange?: (value: string) => void\n /** The name of the file being edited. */\n filename?: string\n /** Optional localized UI messages for tooltip labels. */\n messages?: PlaygroundMessageOverrides\n}\n\n/**\n * Main Playground component providing a split-view interface for editing and\n * previewing resumes.\n *\n * On desktop (md+), shows side-by-side resizable panels.\n * On mobile, shows a tab-based interface to switch between Editor and Preview.\n *\n * @param props - The component props.\n * @returns The rendered Playground component.\n */\nexport function Playground({\n yaml: yamlStr = DEFAULT_RESUME_YAML,\n onChange,\n filename,\n messages,\n}: PlaygroundProps) {\n const {\n yaml,\n handleYamlChange,\n activeLayoutIndex,\n setActiveLayoutIndex,\n resume,\n } = useResumeState({\n yaml: yamlStr,\n onChange,\n })\n\n const tooltips = {\n ...DEFAULT_PLAYGROUND_MESSAGES.tooltips,\n ...messages?.tooltips,\n }\n\n // Create editor panel element\n const editorPanel = (\n <EditorPanel\n value={yaml}\n onChange={(v) => handleYamlChange(v || '')}\n filename={filename}\n tooltips={tooltips}\n />\n )\n\n // Create preview panel element\n const previewPanel = (\n <PreviewPanel\n activeLayoutIndex={activeLayoutIndex}\n setActiveLayoutIndex={setActiveLayoutIndex}\n resume={resume}\n filename={filename}\n tooltips={tooltips}\n />\n )\n\n return (\n <div\n className={clsx('flex flex-col h-full w-full gap-4', 'text-neutral-200')}\n style={{\n backgroundColor: EDITOR_BG_COLOR,\n }}\n >\n <PlaygroundMobile editorPanel={editorPanel} previewPanel={previewPanel} />\n <PlaygroundDesktop\n editorPanel={editorPanel}\n previewPanel={previewPanel}\n />\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { ReactNode } from 'react'\nimport { Group, Panel } from 'react-resizable-panels'\nimport { PanelSeparator } from '@/components'\n\n/**\n * Props for the PlaygroundDesktop component.\n */\nexport interface PlaygroundDesktopProps {\n /** The editor panel content to render. */\n editorPanel: ReactNode\n /** The preview panel content to render. */\n previewPanel: ReactNode\n}\n\n/**\n * The desktop layout component for the playground.\n * Shows a side-by-side resizable panel layout.\n * This component is only visible on medium and larger screens (hidden on mobile).\n *\n * @param props - The component props.\n * @returns The rendered desktop layout.\n */\nexport function PlaygroundDesktop({\n editorPanel,\n previewPanel,\n}: PlaygroundDesktopProps) {\n const panelMinSize = 360\n\n return (\n <div className=\"hidden md:flex flex-1 overflow-hidden\">\n <Group orientation=\"horizontal\">\n <Panel minSize={panelMinSize} className=\"flex flex-col\">\n {editorPanel}\n </Panel>\n\n <PanelSeparator />\n\n <Panel minSize={panelMinSize} className=\"flex flex-col\">\n {previewPanel}\n </Panel>\n </Group>\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { ElementType } from 'react'\n\nimport { ICON_SIZES, ICON_STROKES } from '@/constants'\n\n/**\n * Props for the MobileTabButton component.\n */\ninterface MobileTabButtonProps {\n /** The label text to display on the tab. */\n label: string\n /** Whether this tab is currently active. */\n active: boolean\n /** Callback when the tab is clicked. */\n onClick: () => void\n /** The icon to display on the tab. */\n icon: ElementType\n}\n\n/**\n * A reusable tab button component for the mobile playground layout.\n *\n * @param props - The component props.\n * @returns The rendered tab button.\n */\nexport function MobileTabButton({\n label,\n active,\n onClick,\n icon: Icon,\n}: MobileTabButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={clsx(\n 'flex-1 flex items-center justify-center gap-2 h-10',\n 'text-sm',\n 'transition-colors',\n active && 'border-b-2 border-neutral-200 font-medium'\n )}\n >\n <Icon size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n {label}\n </button>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { IconEdit, IconEye } from '@tabler/icons-react'\nimport { MobileTabButton } from './MobileTabButton'\n\n/**\n * The available tab options for the mobile playground.\n */\nexport type MobileTab = 'editor' | 'preview'\n\n/**\n * Props for the MobileTabBar component.\n */\ninterface MobileTabBarProps {\n /** The currently active tab. */\n activeTab: MobileTab\n /** Callback when the active tab changes. */\n onTabChange: (tab: MobileTab) => void\n}\n\n/**\n * A tab bar component for switching between Editor and Preview on mobile devices.\n * This component is only visible on small screens (hidden on md+).\n *\n * @param props - The component props.\n * @returns The rendered tab bar.\n */\nexport function MobileTabBar({ activeTab, onTabChange }: MobileTabBarProps) {\n return (\n <div className=\"flex md:hidden border-b border-neutral-400\">\n <MobileTabButton\n label=\"Editor\"\n icon={IconEdit}\n active={activeTab === 'editor'}\n onClick={() => onTabChange('editor')}\n />\n <MobileTabButton\n label=\"Preview\"\n icon={IconEye}\n active={activeTab === 'preview'}\n onClick={() => onTabChange('preview')}\n />\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport { type ReactNode, useState } from 'react'\nimport { type MobileTab, MobileTabBar } from './MobileTabBar'\n\n/**\n * Props for the PlaygroundMobile component.\n */\nexport interface PlaygroundMobileProps {\n /** The editor panel content to render. */\n editorPanel: ReactNode\n /** The preview panel content to render. */\n previewPanel: ReactNode\n}\n\n/**\n * The mobile layout component for the playground.\n * Shows either the editor or preview panel based on the active tab.\n * This component is only visible on small screens (hidden on md+).\n *\n * @param props - The component props.\n * @returns The rendered mobile layout.\n */\nexport function PlaygroundMobile({\n editorPanel,\n previewPanel,\n}: PlaygroundMobileProps) {\n const [activeTab, setActiveTab] = useState<MobileTab>('editor')\n\n return (\n <div className=\"flex-1 flex flex-col gap-2 overflow-hidden md:hidden\">\n <MobileTabBar activeTab={activeTab} onTabChange={setActiveTab} />\n <div\n className={clsx(\n 'flex-1 flex-col min-h-0',\n activeTab === 'editor' ? 'flex' : 'hidden'\n )}\n >\n {editorPanel}\n </div>\n <div\n className={clsx(\n 'flex-1 flex-col min-h-0',\n activeTab === 'preview' ? 'flex' : 'hidden'\n )}\n >\n {previewPanel}\n </div>\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Editor } from '@/components'\n\n/**\n * Props for the CodeViewer component.\n */\nexport interface CodeViewerProps {\n /** The code content to display. */\n content: string\n /** The language of the code (markdown or latex). */\n language: 'markdown' | 'latex' | 'yaml'\n}\n\n/**\n * Component to preview code (Markdown or LaTeX) using Monaco Editor.\n *\n * @param props - The props for the CodePreview component.\n * @returns The rendered Monaco Editor.\n */\nexport function CodeViewer({ content, language }: CodeViewerProps) {\n return (\n <Editor\n language={language}\n value={content}\n readOnly={true}\n minimap={false}\n lineNumbers={false}\n />\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { renderAsync } from 'docx-preview'\nimport { useEffect, useRef, useState } from 'react'\n\n/**\n * Props for the DocxViewer component.\n */\nexport interface DocxViewerProps {\n /** The DOCX binary content to render. */\n content: Uint8Array | null\n}\n\n/**\n * Component to preview DOCX content by rendering it to HTML via docx-preview.\n *\n * @param props - The props for the DocxViewer component.\n * @returns The rendered DocxViewer component.\n */\nexport function DocxViewer({ content }: DocxViewerProps) {\n const containerRef = useRef<HTMLDivElement>(null)\n const [error, setError] = useState<string | null>(null)\n const [loading, setLoading] = useState<boolean>(false)\n\n useEffect(() => {\n if (!content || !containerRef.current) {\n setError(null)\n setLoading(false)\n return () => {}\n }\n\n setLoading(true)\n setError(null)\n\n const container = containerRef.current\n\n renderAsync(content, container, undefined, {\n className: 'docx',\n inWrapper: true,\n })\n .then(() => {\n setLoading(false)\n })\n .catch((e) => {\n setLoading(false)\n setError(\n `DOCX Render Error: ${e instanceof Error ? e.message : String(e)}`\n )\n })\n\n return () => {\n container.innerHTML = ''\n }\n }, [content])\n\n if (!content) {\n return (\n <div className=\"h-full w-full flex items-center justify-center text-gray-500 bg-gray-50\">\n No DOCX content to preview.\n </div>\n )\n }\n\n if (error) {\n return (\n <div\n role=\"alert\"\n aria-live=\"polite\"\n className=\"h-full w-full p-4 font-mono text-red-500 bg-red-50 border border-red-200\"\n >\n {error}\n </div>\n )\n }\n\n return (\n <div className=\"h-full w-full overflow-auto bg-white relative\">\n {loading && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-white/80 z-10\">\n <div className=\"text-gray-500\">Loading DOCX preview…</div>\n </div>\n )}\n <div ref={containerRef} className=\"docx-preview-container\" />\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * Props for the HtmlViewer component.\n */\nexport interface HtmlViewerProps {\n /** The HTML content to render. */\n content: string\n}\n\n/**\n * Component to preview HTML content in an iframe.\n *\n * @param props - The props for the HtmlPreview component.\n * @returns The rendered iframe element.\n */\nexport function HtmlViewer({ content }: HtmlViewerProps) {\n return (\n <iframe\n title=\"Resume HTML Preview\"\n className=\"w-full h-full border-none\"\n srcDoc={content}\n />\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\n\nimport logo from '@/resources/logo.png'\n\n/**\n * A placeholder component shown when no resume layouts are defined.\n * Displays a logo and a helpful message.\n *\n * @returns The rendered empty state component.\n */\nexport function PreviewNoLayouts() {\n return (\n <div\n className={clsx(\n 'h-full w-full',\n 'flex flex-col items-center justify-center gap-4',\n 'text-neutral-200'\n )}\n >\n <img\n src={logo}\n alt=\"YAML Resume Logo\"\n className=\"w-32 h-32 opacity-70 grayscale\"\n draggable={false}\n />\n <div className=\"text-lg font-medium\">No Layouts Defined</div>\n <p className=\"max-w-xs text-center text-sm text-neutral-400\">\n Your resume appears to be empty or contains no layout definitions.\n </p>\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n IconFileText,\n IconHtml,\n IconMarkdown,\n IconTex,\n} from '@tabler/icons-react'\nimport type { LayoutEngine } from '@yamlresume/core'\nimport clsx from 'clsx'\n\nimport { EDITOR_BG_COLOR, ICON_SIZES, ICON_STROKES } from '@/constants'\nimport { getExtension } from '@/utils'\n\n/**\n * Props for the PreviewTab component.\n */\ninterface PreviewTabProps {\n /** Whether this tab is currently active. */\n active: boolean\n /** Callback triggered when the tab is clicked. */\n onClick: () => void\n /** The layout engine (e.g., 'html', 'markdown') used for this tab. */\n engine: LayoutEngine\n /** The index of this layout in the resume configuration. */\n index: number\n /** The basename of the file (e.g., 'resume' from 'resume.yml'). */\n filename: string\n}\n\n/**\n * A tab button representing a specific resume layout.\n * Displays the engine icon and document name.\n *\n * @param props - The component props.\n * @returns The rendered tab button.\n */\nexport function getTabIcon(engine: LayoutEngine) {\n switch (engine) {\n case 'html':\n return <IconHtml size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n case 'markdown':\n return <IconMarkdown size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n case 'latex':\n return <IconTex size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n default:\n return <IconFileText size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n }\n}\n\nexport function PreviewTab({\n active,\n onClick,\n engine,\n index,\n filename,\n}: PreviewTabProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={clsx(\n 'flex items-center gap-2 max-w-[200px]',\n 'h-full px-4',\n 'transition-colors border-r border-neutral-600 last:border-neutral-400'\n )}\n title={`${filename}.${index}${getExtension(engine)}`}\n role=\"tab\"\n aria-selected={active}\n style={{\n backgroundColor: active && EDITOR_BG_COLOR,\n }}\n >\n {getTabIcon(engine)}\n <span className=\"truncate\">\n {filename}.{index}\n {getExtension(engine)}\n </span>\n </button>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { PropsWithChildren } from 'react'\n\n/**\n * A scrollable container for preview tabs.\n *\n * @param props - The component props.\n * @returns The rendered tabs container.\n */\nexport function PreviewTabs({ children }: PropsWithChildren) {\n return (\n <div role=\"tablist\" className={clsx('flex h-full overflow-x-auto')}>\n {children}\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { Resume } from '@yamlresume/core'\nimport clsx from 'clsx'\nimport { useResumeRenderer } from '../../hooks'\nimport { CodeViewer } from './CodeViewer'\nimport { DocxViewer } from './DocxViewer'\nimport { HtmlViewer } from './HtmlViewer'\n\n/**\n * Props for the ResumeViewer component.\n */\nexport interface ResumeViewerProps {\n /** The pre-parsed resume object. */\n resume: Resume | null\n /** The index of the layout to use for rendering. */\n layoutIndex: number\n}\n\n/**\n * ResumeViewer component responsible for rendering the appropriate preview\n * (HTML, Markdown, LaTeX, or DOCX) based on the selected layout.\n *\n * @param props - The props for the ResumeViewer component.\n * @returns The rendered ResumeViewer component.\n */\nexport function ResumeViewer({ resume, layoutIndex }: ResumeViewerProps) {\n const { renderedContent, binaryContent, engine, error } = useResumeRenderer({\n resume,\n layoutIndex,\n })\n\n if (error) {\n return (\n <div\n role=\"alert\"\n aria-live=\"polite\"\n className={clsx(\n 'h-full w-full p-4',\n 'font-mono text-red-500 bg-red-50',\n 'border border-red-200'\n )}\n >\n {error}\n </div>\n )\n }\n\n if (engine === 'docx') {\n return <DocxViewer content={binaryContent} />\n }\n\n return (\n <div className=\"h-full w-full flex flex-col bg-white\">\n {engine === 'html' ? (\n <HtmlViewer content={renderedContent} />\n ) : (\n <CodeViewer content={renderedContent} language={engine} />\n )}\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n IconDownload,\n IconExternalLink,\n IconPrinter,\n} from '@tabler/icons-react'\nimport type { Resume } from '@yamlresume/core'\nimport { useCallback, useMemo } from 'react'\n\nimport {\n Panel,\n PanelContent,\n PanelToolbar,\n ToolbarButton,\n ToolbarCopyButton,\n ToolbarSeparator,\n} from '@/components'\nimport { ICON_SIZES, ICON_STROKES } from '@/constants'\nimport type { PlaygroundTooltipMessages } from '@/messages'\nimport {\n copyResumeToClipboard,\n downloadResume,\n getBasename,\n openResumeInNewTab,\n printResume,\n} from '@/utils'\n\nimport { PreviewNoLayouts } from './PreviewNoLayouts'\nimport { PreviewTab } from './PreviewTab'\nimport { PreviewTabs } from './PreviewTabs'\nimport { ResumeViewer } from './ResumeViewer'\n\n/**\n * Props for the PreviewPanel component.\n */\nexport interface PreviewPanelProps {\n /** The index of the currently active layout. */\n activeLayoutIndex: number\n /** The name of the file being edited. */\n filename?: string\n /** The parsed resume object. */\n resume: Resume | null\n /** Callback to change the active layout index. */\n setActiveLayoutIndex: (index: number) => void\n /** Localized tooltip labels for preview actions. */\n tooltips: Pick<\n PlaygroundTooltipMessages,\n 'copy' | 'print' | 'openInNewTab' | 'download'\n >\n}\n\n/**\n * A panel component containing the resume preview, layout selector tabs, and actions.\n *\n * @param props - The component props.\n * @returns The rendered preview panel.\n */\nexport function PreviewPanel({\n activeLayoutIndex,\n filename,\n resume,\n setActiveLayoutIndex,\n tooltips,\n}: PreviewPanelProps) {\n // Filter out invalid layouts (null or missing engine property)\n // This can happen when user is typing incomplete YAML like \"- \" in layouts array\n const validLayouts = useMemo(() => {\n return (resume?.layouts || [])\n .map((layout, originalIndex) => ({ layout, originalIndex }))\n .filter(\n (item) =>\n item.layout !== null &&\n item.layout !== undefined &&\n typeof item.layout.engine === 'string'\n )\n }, [resume?.layouts])\n\n const basename = getBasename(filename, true) || 'resume'\n\n const handleCopy = useCallback(() => {\n copyResumeToClipboard(resume, activeLayoutIndex)\n }, [resume, activeLayoutIndex])\n\n const handlePrint = useCallback(() => {\n printResume(resume, activeLayoutIndex)\n }, [resume, activeLayoutIndex])\n\n const handleOpenInNewTab = useCallback(() => {\n openResumeInNewTab(resume, activeLayoutIndex)\n }, [resume, activeLayoutIndex])\n\n const handleDownload = useCallback(() => {\n downloadResume(resume, activeLayoutIndex)\n }, [resume, activeLayoutIndex])\n\n if (validLayouts.length === 0) {\n return (\n <Panel>\n <PanelToolbar />\n <PreviewNoLayouts />\n </Panel>\n )\n }\n\n return (\n <Panel>\n <PanelToolbar>\n <PreviewTabs>\n {validLayouts.map(({ layout, originalIndex }) => (\n <PreviewTab\n key={`${layout.engine}-${originalIndex}`}\n active={activeLayoutIndex === originalIndex}\n onClick={() => setActiveLayoutIndex(originalIndex)}\n engine={layout.engine}\n index={originalIndex}\n filename={basename}\n />\n ))}\n </PreviewTabs>\n <div className=\"flex-1\" />\n <div className=\"flex items-center gap-0.5 pr-2\">\n <ToolbarCopyButton onClick={handleCopy} title={tooltips.copy} />\n <ToolbarSeparator />\n {resume?.layouts?.[activeLayoutIndex]?.engine === 'html' && (\n <>\n <ToolbarButton onClick={handlePrint} title={tooltips.print}>\n <IconPrinter size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n <ToolbarButton\n onClick={handleOpenInNewTab}\n title={tooltips.openInNewTab}\n >\n <IconExternalLink\n size={ICON_SIZES.sm}\n stroke={ICON_STROKES.sm}\n />\n </ToolbarButton>\n <ToolbarSeparator />\n </>\n )}\n <ToolbarButton onClick={handleDownload} title={tooltips.download}>\n <IconDownload size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n </div>\n </PanelToolbar>\n <PanelContent>\n <ResumeViewer resume={resume} layoutIndex={activeLayoutIndex} />\n </PanelContent>\n </Panel>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { PropsWithChildren } from 'react'\n\n/**\n * A styled panel container component for the Playground.\n *\n * Provides consistent styling including:\n * - Flexbox layout for content organization\n * - Shadow effect for visual depth\n * - Border styling for clear boundaries\n *\n * @param props - The component props.\n * @returns The rendered panel container.\n */\nexport function Panel({ children }: PropsWithChildren) {\n return (\n <div\n className={clsx(\n 'flex-1 flex flex-col',\n 'border border-neutral-400 overflow-hidden'\n )}\n >\n {children}\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { PropsWithChildren } from 'react'\n\n/**\n * A shared container for panel content.\n * Provides a flexible layout for the main content area of a panel.\n *\n * @param props - The component props.\n * @returns The rendered content container.\n */\nexport function PanelContent({ children }: PropsWithChildren) {\n return <div className=\"flex-1 relative\">{children}</div>\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport { Separator } from 'react-resizable-panels'\n\n/**\n * A separator component for the Playground.\n *\n * @returns The rendered separator.\n */\nexport function PanelSeparator() {\n return (\n <Separator\n className={clsx(\n 'w-2',\n 'flex flex-col justify-center items-center group',\n 'transition-colors cursor-col-resize'\n )}\n data-testid=\"separator\"\n >\n <div\n className={clsx(\n 'w-1 h-8',\n 'bg-neutral-400',\n 'group-hover:bg-neutral-300'\n )}\n />\n </Separator>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { PropsWithChildren } from 'react'\n\n/**\n * A shared toolbar component for panels.\n *\n * @param props - The component props.\n * @returns The rendered toolbar.\n */\nexport function PanelToolbar({ children }: PropsWithChildren) {\n return (\n <div\n className={clsx(\n 'flex items-center border-b border-neutral-400 h-10 text-sm',\n 'bg-neutral-800'\n )}\n >\n {children}\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { ReactNode } from 'react'\n\n/**\n * Props for the ToolbarButton component.\n */\nexport interface ToolbarButtonProps {\n /** Callback triggered when the button is clicked. */\n onClick: () => void\n /** The content to be rendered inside the button, typically an icon. */\n children: ReactNode\n /** The tooltip text displayed when hovering over the button. */\n title: string\n}\n\n/**\n * A generic button component used in the playground toolbar.\n *\n * It provides consistent styling and behavior for all toolbar actions.\n *\n * @param props - The component props.\n * @returns The rendered toolbar button.\n */\nexport function ToolbarButton({\n onClick,\n children,\n title,\n}: ToolbarButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={clsx(\n 'flex items-center justify-center h-8 w-8',\n 'text-neutral-200 hover:text-neutral-700 hover:bg-neutral-200',\n 'transition-colors',\n 'focus:outline-none focus:ring-1 focus:ring-neutral-400'\n )}\n title={title}\n >\n {children}\n </button>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { IconCheck, IconCopy } from '@tabler/icons-react'\nimport { useState } from 'react'\n\nimport { ICON_SIZES, ICON_STROKES } from '@/constants'\nimport { ToolbarButton } from './ToolbarButton'\n\n/**\n * Props for the ToolbarCopyButton component.\n */\nexport interface ToolbarCopyButtonProps {\n /** Callback triggered to perform the copy action. Can be async. */\n onClick: () => Promise<void> | void\n /** The tooltip text. Defaults to 'Copy'. */\n title?: string\n}\n\n/**\n * A toolbar button for copying content to the clipboard.\n * It temporarily changes the icon to a checkmark upon successful copy.\n *\n * @param props - The component props.\n * @returns The rendered copy button.\n */\nexport function ToolbarCopyButton({\n onClick,\n title = 'Copy',\n}: ToolbarCopyButtonProps) {\n const [hasCopied, setHasCopied] = useState(false)\n\n const handleCopy = async () => {\n try {\n await onClick()\n setHasCopied(true)\n setTimeout(() => setHasCopied(false), 2000)\n } catch (e) {\n console.error('Failed to copy', e)\n }\n }\n\n return (\n <ToolbarButton onClick={handleCopy} title={title}>\n {hasCopied ? (\n <IconCheck size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n ) : (\n <IconCopy size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n )}\n </ToolbarButton>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * A toolbar separator component.\n *\n * @returns The rendered separator.\n */\nexport function ToolbarSeparator() {\n return <div className=\"w-px h-4 bg-neutral-400 mx-1\" />\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/components/editor/Editor.tsx","../src/utils/utils.ts","../src/components/editor/EditorTitle.tsx","../src/components/editor/ResumeEditor.tsx","../src/components/editor/EditorPanel.tsx","../src/hooks/useResumeRenderer.ts","../src/resources/default-resume.yml","../src/hooks/useResumeState.ts","../src/messages.ts","../src/components/layouts/Playground.tsx","../src/components/layouts/PlaygroundDesktop.tsx","../src/components/layouts/MobileTabButton.tsx","../src/components/layouts/MobileTabBar.tsx","../src/components/layouts/PlaygroundMobile.tsx","../src/components/preview/CodeViewer.tsx","../src/components/preview/DocxViewer.tsx","../src/components/preview/HtmlViewer.tsx","../src/components/preview/PreviewNoLayouts.tsx","../src/components/preview/PreviewTab.tsx","../src/components/preview/PreviewTabs.tsx","../src/components/preview/ResumeViewer.tsx","../src/components/preview/PreviewPanel.tsx","../src/components/ui/Panel.tsx","../src/components/ui/PanelContent.tsx","../src/components/ui/PanelSeparator.tsx","../src/components/ui/PanelToolbar.tsx","../src/components/ui/ToolbarButton.tsx","../src/components/ui/ToolbarCopyButton.tsx","../src/components/ui/ToolbarSeparator.tsx"],"names":["ICON_SIZES","ICON_STROKES","EDITOR_BG_COLOR","EDITOR_FONT_SIZE","registerLatexLanguage","monaco","latexLanguage","latexConf","l","Editor","value","onChange","language","readOnly","lineNumbers","minimap","onMount","jsx","MonacoEditor","getBasename","filepath","removeExtension","basename","getExtension","engine","downloadResume","resume","layoutIndex","layouts","renderResult","getResumeRenderer","layout","extension","filename","content","blob","url","a","e","copyResumeToClipboard","printResume","iframe","doc","openResumeInNewTab","EditorTitle","jsxs","clsx","IconFileCode","ResumeEditor","EditorPanel","tooltips","editorRef","useRef","handleEditorMount","editor","handleUndo","useCallback","handleRedo","handleCopy","handleClear","Panel","PanelToolbar","ToolbarCopyButton","ToolbarSeparator","ToolbarButton","IconArrowBackUp","IconArrowForwardUp","IconEraser","PanelContent","useResumeRenderer","renderedContent","setRenderedContent","useState","binaryContent","setBinaryContent","setEngine","error","setError","useEffect","currentEngine","result","default_resume_default","useResumeState","yaml","activeLayoutIndex","setActiveLayoutIndex","handleYamlChange","v","useMemo","parse","DEFAULT_PLAYGROUND_MESSAGES","Playground","yamlStr","messages","editorPanel","previewPanel","PreviewPanel","PlaygroundMobile","PlaygroundDesktop","Group","PanelSeparator","MobileTabButton","label","active","onClick","Icon","MobileTabBar","activeTab","onTabChange","IconEdit","IconEye","setActiveTab","CodeViewer","DocxViewer","containerRef","loading","setLoading","container","renderAsync","HtmlViewer","PreviewNoLayouts","logo_default","getTabIcon","IconHtml","IconMarkdown","IconTex","IconFileText","PreviewTab","index","PreviewTabs","children","ResumeViewer","validLayouts","originalIndex","item","handlePrint","handleOpenInNewTab","handleDownload","Fragment","IconPrinter","IconExternalLink","IconDownload","Separator","title","hasCopied","setHasCopied","IconCheck","IconCopy"],"mappings":"gjBAwBO,IAAMA,CAAAA,CAAa,CACxB,EAAA,CAAI,EAAA,CACJ,GAAI,EAAA,CACJ,EAAA,CAAI,GACJ,EAAA,CAAI,EAAA,CACJ,GAAI,EACN,CAAA,CAEaC,EAAe,CAC1B,EAAA,CAAI,EACJ,EAAA,CAAI,IAAA,CACJ,GAAI,GAAA,CACJ,EAAA,CAAI,KACJ,EAAA,CAAI,CACN,EAGaC,CAAAA,CAAkB,SAAA,CAGlBC,GAAmB,GCRhC,SAASC,GAAsBC,CAAAA,CAAgB,CAE7C,IAAMC,CAAAA,CAA4C,CAChD,YAAa,OAAA,CACb,IAAA,CAAM,QACN,SAAA,CAAW,CAAC,aAAc,UAAU,CAAA,CACpC,eAAgB,CAAC,KAAA,CAAO,MAAO,KAAK,CAAA,CAEpC,aAAc,QAAA,CACd,YAAA,CAAc,GAEd,QAAA,CAAU,CACR,kBACA,eAAA,CACA,cAAA,CACA,UACA,aAAA,CACA,WAAA,CACA,OACA,UAAA,CACA,QAAA,CACA,SACA,WAAA,CACA,cAAA,CACA,kBACA,IAAA,CACA,SAAA,CACA,gBACA,SAAA,CACA,UAAA,CACA,aACA,KAAA,CACA,SAAA,CACA,QACA,WAAA,CACA,SAAA,CACA,SACA,MAAA,CACA,iBAAA,CACA,WAAA,CACA,OAAA,CACA,SAAA,CACA,OAAA,CACA,YACA,SAAA,CACA,MAAA,CACA,QACA,eAAA,CACA,SAAA,CACA,KACA,MAAA,CACA,YAAA,CACA,WACA,MAAA,CACA,MAAA,CACA,cACA,UAAA,CACA,UAAA,CACA,eACA,cAAA,CACA,cAAA,CACA,OACA,OAAA,CACA,UAAA,CACA,gBACA,OAAA,CACA,OAAA,CACA,OACA,WAAA,CACA,QAAA,CACA,OACA,MAAA,CACA,aAAA,CACA,UACA,iBAAA,CACA,aAAA,CACA,SACA,OAAA,CACA,IAAA,CACA,OACA,MAAA,CACA,OAAA,CACA,QACA,OAAA,CACA,OAAA,CACA,QACA,QAAA,CACA,OAAA,CACA,MAAA,CACA,SAAA,CACA,MAAA,CACA,WAAA,CACA,gBACA,WAAA,CACA,eAAA,CACA,eACA,UAAA,CACA,SAAA,CACA,YACA,UAAA,CACA,SAAA,CACA,SACA,MAAA,CACA,SAAA,CACA,cACA,UAAA,CACA,YAAA,CACA,gBACA,YAAA,CACA,gBAAA,CACA,UACA,WAAA,CACA,SAAA,CACA,UACA,YAAA,CACA,YAAA,CACA,SACA,UAAA,CACA,aAAA,CACA,mBACA,YAAA,CACA,aAAA,CACA,MACA,WAAA,CACA,SAAA,CACA,OACA,WAAA,CACA,UAAA,CACA,YACA,eAAA,CACA,SAAA,CACA,YACA,KAAA,CACA,WAAA,CACA,SACA,WAAA,CACA,SAAA,CACA,MAAA,CACA,SAAA,CACA,gBAAA,CACA,KAAA,CACA,eACA,YAAA,CACA,aAAA,CACA,WACA,KAAA,CACA,cAAA,CACA,QACA,IAAA,CACA,OAAA,CACA,OACA,SAAA,CACA,MAAA,CACA,KACA,YAAA,CACA,SAAA,CACA,aACA,WAAA,CACA,YAAA,CACA,KACA,YAAA,CACA,WAAA,CACA,KACA,OAAA,CACA,OAAA,CACA,YACA,MAAA,CACA,OAAA,CACA,OACA,UAAA,CACA,aAAA,CACA,eACA,YAAA,CACA,eAAA,CACA,kBACA,WAAA,CACA,KAAA,CACA,SACA,WAAA,CACA,QAAA,CACA,SACA,YAAA,CACA,QAAA,CACA,SACA,QAAA,CACA,QAAA,CACA,QAAA,CACA,QAAA,CACA,WAAA,CACA,YAAA,CACA,SACA,eAAA,CACA,MAAA,CACA,QACA,OAAA,CACA,IAAA,CACA,YACA,SAAA,CACA,QAAA,CACA,QACA,YAAA,CACA,WAAA,CACA,aACA,QAAA,CACA,YAAA,CACA,QACA,OAAA,CACA,MAAA,CACA,UACA,OAAA,CACA,QAAA,CACA,OACA,OAAA,CACA,OAAA,CACA,WACA,QAAA,CAEA,gBAAA,CACA,iBACA,YAAA,CACA,OAAA,CACA,UACA,eAAA,CACA,eAAA,CACA,MACA,MAAA,CACA,YAAA,CACA,KACA,OAAA,CACA,OAAA,CACA,MACA,IAAA,CACA,MAAA,CACA,aACA,UAAA,CACA,aAAA,CACA,WAAA,CACA,OAAA,CACA,aAAA,CACA,cACF,EAEA,SAAA,CAAW,CACT,KAAM,CACJ,CACE,oCACA,CACE,oBAAA,CACA,QACA,WAAA,CACA,CAAE,MAAO,YAAA,CAAc,OAAA,CAAS,OAAQ,CAAA,CACxC,WACF,CACF,CAAA,CACA,CACE,kCACA,CACE,oBAAA,CACA,QACA,WAAA,CACA,CAAE,MAAO,YAAA,CAAc,OAAA,CAAS,QAAS,CAAA,CACzC,WACF,CACF,CAAA,CACA,CAAC,eAAgB,SAAS,CAAA,CAC1B,CAAC,gBAAA,CAAkB,SAAS,EAC5B,CAAC,eAAA,CAAiB,YAAY,CAAA,CAC9B,CACE,gBAAA,CACA,CACE,KAAA,CAAO,CACL,cAAe,oBAAA,CACf,UAAA,CAAY,SACd,CACF,CACF,EACA,CAAE,OAAA,CAAS,aAAc,CAAA,CACzB,CAAC,YAAa,WAAW,CAAA,CACzB,CAAC,MAAA,CAAQ,YAAY,EACrB,CACE,2DAAA,CACA,YACF,CACF,CAAA,CAEA,WAAY,CACV,CAAC,aAAc,OAAO,CAAA,CACtB,CAAC,MAAA,CAAQ,SAAS,CACpB,CACF,CACF,EAEMC,CAAAA,CAA6C,CACjD,SAAU,CACR,WAAA,CAAa,GACf,CAAA,CACA,QAAA,CAAU,CACR,CAAC,GAAA,CAAK,GAAG,EACT,CAAC,GAAA,CAAK,GAAG,CAAA,CACT,CAAC,IAAK,GAAG,CACX,EACA,gBAAA,CAAkB,CAChB,CAAE,IAAA,CAAM,GAAA,CAAK,MAAO,GAAI,CAAA,CACxB,CAAE,IAAA,CAAM,GAAA,CAAK,MAAO,GAAI,CAAA,CACxB,CAAE,IAAA,CAAM,GAAA,CAAK,MAAO,GAAI,CAAA,CACxB,CAAE,IAAA,CAAM,GAAA,CAAK,MAAO,GAAI,CAC1B,EACA,gBAAA,CAAkB,CAChB,CAAE,IAAA,CAAM,GAAA,CAAK,KAAA,CAAO,GAAI,CAAA,CACxB,CAAE,KAAM,GAAA,CAAK,KAAA,CAAO,GAAI,CAAA,CACxB,CAAE,KAAM,GAAA,CAAK,KAAA,CAAO,GAAI,CAAA,CACxB,CAAE,KAAM,GAAA,CAAK,KAAA,CAAO,GAAI,CAC1B,CACF,EAGEF,CAAAA,CAAO,SAAA,CACJ,cAAa,CACb,IAAA,CAAMG,GAAsBA,CAAAA,CAAE,EAAA,GAAO,OAAO,CAAA,GAKjDH,CAAAA,CAAO,UAAU,QAAA,CAAS,CAAE,GAAI,OAAQ,CAAC,EACzCA,CAAAA,CAAO,SAAA,CAAU,yBAAyB,OAAA,CAASC,CAAa,EAChED,CAAAA,CAAO,SAAA,CAAU,wBAAA,CAAyB,OAAA,CAASE,CAAS,CAAA,EAC9D,CA6BO,SAASE,CAAAA,CAAO,CACrB,KAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,QAAA,CAAAC,CAAAA,CAAW,MACX,WAAA,CAAAC,CAAAA,CAAc,KACd,OAAA,CAAAC,CAAAA,CAAU,KACV,OAAA,CAAAC,CACF,EAAgB,CACd,OACEC,IAACC,EAAAA,CAAA,CACC,OAAO,MAAA,CACP,QAAA,CAAUN,EACV,KAAA,CAAOF,CAAAA,CACP,SAAUC,CAAAA,CACV,KAAA,CAAM,UACN,OAAA,CAASK,CAAAA,CACT,YAAaZ,EAAAA,CACb,OAAA,CAAS,CACP,QAAA,CAAAS,CAAAA,CACA,WAAA,CAAaA,CAAAA,CACb,WAAA,CAAaC,CAAAA,CAAc,KAAO,KAAA,CAClC,OAAA,CAAS,CAAE,OAAA,CAASC,CAAQ,EAC5B,QAAA,CAAUZ,EAAAA,CACV,oBAAqB,CAAA,CACrB,OAAA,CAAS,CACP,GAAA,CAAK,CACP,EACA,eAAA,CAAiB,IAAA,CACjB,iBAAkB,KAAA,CAClB,eAAA,CAAiB,KACjB,oBAAA,CAAsB,KACxB,EACF,CAEJ,KCrYagB,CAAAA,CAAc,CACzBC,EAAW,aAAA,CACXC,CAAAA,CAAkB,QACP,CACX,IAAMC,EAAWF,CAAAA,CAAS,KAAA,CAAM,OAAO,CAAA,CAAE,GAAA,IAASA,CAAAA,CAClD,OAAIC,EACKC,CAAAA,CAAS,OAAA,CAAQ,kBAAmB,EAAE,CAAA,CAExCA,CACT,CAAA,CAQaC,CAAAA,CAAgBC,GAAiC,CAC5D,OAAQA,GACN,KAAK,OACH,OAAO,OAAA,CACT,KAAK,OAAA,CACH,OAAO,OACT,KAAK,UAAA,CACH,OAAO,KAAA,CACT,KAAK,MAAA,CACH,OAAO,OAAA,CACT,QACE,OAAO,EACX,CACF,EAQaC,CAAAA,CAAiB,MAC5BC,EACAC,CAAAA,GACG,CACH,GAAI,CACF,IAAMC,EAAUF,CAAAA,EAAQ,OAAA,CACxB,GAAI,CAACA,CAAAA,EAAU,CAACE,CAAAA,CAAQD,CAAW,EAAG,CACpC,OAAA,CAAQ,KAAK,wCAAwC,CAAA,CACrD,MACF,CAGA,IAAME,EADWC,iBAAAA,CAAkBJ,CAAAA,CAAQC,CAAW,CAAA,CACxB,MAAA,GACxBI,CAAAA,CAASH,CAAAA,CAAQD,CAAW,CAAA,CAC5BK,CAAAA,CAAYT,CAAAA,CAAaQ,CAAAA,CAAO,MAAM,CAAA,CACtCE,EAAW,CAAA,OAAA,EAAUN,CAAW,GAAGK,CAAS,CAAA,CAAA,CAE5CE,EACJL,CAAAA,YAAwB,OAAA,CAAU,MAAMA,CAAAA,CAAeA,CAAAA,CACnDM,EACJD,CAAAA,YAAmB,UAAA,CACf,IAAI,IAAA,CAAK,CAACA,EAAQ,MAAkB,CAAA,CAAG,CACrC,IAAA,CAAM,yEACR,CAAC,CAAA,CACD,IAAI,KAAK,CAACA,CAAO,EAAG,CAAE,IAAA,CAAM,YAAa,CAAC,CAAA,CAC1CE,EAAM,GAAA,CAAI,eAAA,CAAgBD,CAAI,CAAA,CAC9BE,CAAAA,CAAI,SAAS,aAAA,CAAc,GAAG,CAAA,CACpCA,CAAAA,CAAE,IAAA,CAAOD,CAAAA,CACTC,EAAE,QAAA,CAAWJ,CAAAA,CACb,SAAS,IAAA,CAAK,WAAA,CAAYI,CAAC,CAAA,CAC3BA,CAAAA,CAAE,OAAM,CACR,QAAA,CAAS,KAAK,WAAA,CAAYA,CAAC,EAC3B,GAAA,CAAI,eAAA,CAAgBD,CAAG,EACzB,CAAA,MAASE,EAAG,CACV,OAAA,CAAQ,MAAM,4BAAA,CAA8BA,CAAC,EAC/C,CACF,CAAA,CAQaC,EAAwB,CACnCb,CAAAA,CACAC,IACkB,CAClB,GAAI,CACF,IAAMC,CAAAA,CAAUF,GAAQ,OAAA,CACxB,GAAI,CAACA,CAAAA,EAAU,CAACE,CAAAA,CAAQD,CAAW,CAAA,CACjC,OAAA,OAAA,CAAQ,KAAK,oCAAoC,CAAA,CAC1C,QAAQ,OAAA,EAAQ,CAIzB,IAAMO,CAAAA,CADWJ,iBAAAA,CAAkBJ,EAAQC,CAAW,CAAA,CAC7B,QAAO,CAChC,OAAI,OAAOO,CAAAA,EAAY,QAAA,EACrB,QAAQ,IAAA,CAAK,uDAAuD,EAC7D,OAAA,CAAQ,OAAA,IAGV,SAAA,CAAU,SAAA,CAAU,UAAUA,CAAO,CAC9C,OAASI,CAAAA,CAAG,CACV,eAAQ,KAAA,CAAM,wBAAA,CAA0BA,CAAC,CAAA,CAClC,OAAA,CAAQ,SACjB,CACF,EAQaE,CAAAA,CAAc,CAACd,CAAAA,CAAuBC,CAAAA,GAAwB,CACzE,GAAI,CACF,IAAMC,CAAAA,CAAUF,GAAQ,OAAA,CACxB,GAAI,CAACA,CAAAA,EAAU,CAACE,EAAQD,CAAW,CAAA,CAAG,CACpC,OAAA,CAAQ,IAAA,CAAK,qCAAqC,CAAA,CAClD,MACF,CAGA,GADeC,CAAAA,CAAQD,CAAW,CAAA,CACvB,MAAA,GAAW,OAAQ,CAC5B,OAAA,CAAQ,KAAK,6CAA6C,CAAA,CAC1D,MACF,CAGA,IAAMO,EADWJ,iBAAAA,CAAkBJ,CAAAA,CAAQC,CAAW,CAAA,CAC7B,MAAA,GACzB,GAAI,OAAOO,GAAY,QAAA,CAAU,CAC/B,OAAA,CAAQ,IAAA,CAAK,qDAAqD,CAAA,CAClE,MACF,CAEA,IAAMO,EAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA,CAC9CA,CAAAA,CAAO,MAAM,QAAA,CAAW,UAAA,CACxBA,EAAO,KAAA,CAAM,KAAA,CAAQ,MACrBA,CAAAA,CAAO,KAAA,CAAM,OAAS,KAAA,CACtBA,CAAAA,CAAO,MAAM,MAAA,CAAS,MAAA,CACtB,SAAS,IAAA,CAAK,WAAA,CAAYA,CAAM,CAAA,CAEhC,IAAMC,EAAMD,CAAAA,CAAO,aAAA,EAAe,SAC9BC,CAAAA,GACFA,CAAAA,CAAI,MAAK,CACTA,CAAAA,CAAI,MAAMR,CAAO,CAAA,CACjBQ,EAAI,KAAA,EAAM,CACVD,CAAAA,CAAO,aAAA,EAAe,KAAA,EAAM,CAC5BA,EAAO,aAAA,EAAe,KAAA,IAIxB,UAAA,CAAW,IAAM,CACf,QAAA,CAAS,IAAA,CAAK,YAAYA,CAAM,EAClC,EAAG,GAAI,EACT,OAASH,CAAAA,CAAG,CACV,QAAQ,KAAA,CAAM,yBAAA,CAA2BA,CAAC,EAC5C,CACF,EAQaK,CAAAA,CAAqB,CAChCjB,EACAC,CAAAA,GACG,CACH,GAAI,CACF,IAAMC,EAAUF,CAAAA,EAAQ,OAAA,CACxB,GAAI,CAACA,CAAAA,EAAU,CAACE,CAAAA,CAAQD,CAAW,EAAG,CACpC,OAAA,CAAQ,IAAA,CAAK,uCAAuC,CAAA,CACpD,MACF,CAGA,GADeC,CAAAA,CAAQD,CAAW,CAAA,CACvB,MAAA,GAAW,OAAQ,CAC5B,OAAA,CAAQ,KAAK,oDAAoD,CAAA,CACjE,MACF,CAGA,IAAMO,EADWJ,iBAAAA,CAAkBJ,CAAAA,CAAQC,CAAW,CAAA,CAC7B,MAAA,GACzB,GAAI,OAAOO,GAAY,QAAA,CAAU,CAC/B,QAAQ,IAAA,CAAK,4DAA4D,EACzE,MACF,CAEA,IAAMC,CAAAA,CAAO,IAAI,KAAK,CAACD,CAAO,EAAG,CAAE,IAAA,CAAM,WAAY,CAAC,CAAA,CAChDE,CAAAA,CAAM,GAAA,CAAI,eAAA,CAAgBD,CAAI,EACpC,MAAA,CAAO,IAAA,CAAKC,EAAK,QAAQ,EAC3B,OAASE,CAAAA,CAAG,CACV,QAAQ,KAAA,CAAM,mCAAA,CAAqCA,CAAC,EACtD,CACF,EChMO,SAASM,EAAAA,CAAY,CAAE,QAAA,CAAAX,CAAAA,CAAW,aAAc,CAAA,CAAqB,CAE1E,IAAMX,CAAAA,CAAWH,CAAAA,CAAYc,CAAQ,CAAA,CACrC,OACEY,KAAC,KAAA,CAAA,CACC,SAAA,CAAWC,GACT,yBAAA,CACA,aAAA,CACA,6BACF,CAAA,CACA,KAAA,CAAO,CAAE,eAAA,CAAiB5C,CAAgB,CAAA,CAE1C,UAAAe,GAAAA,CAAC8B,YAAAA,CAAA,CAAa,IAAA,CAAM/C,CAAAA,CAAW,GAAI,MAAA,CAAQC,CAAAA,CAAa,GAAI,CAAA,CAC5DgB,GAAAA,CAAC,QAAM,QAAA,CAAAK,CAAAA,CAAS,GAClB,CAEJ,CCDO,SAAS0B,CAAAA,CAAa,CAAE,MAAAtC,CAAAA,CAAO,QAAA,CAAAC,EAAU,OAAA,CAAAK,CAAQ,EAAsB,CAC5E,OACEC,IAACR,CAAAA,CAAA,CACC,SAAS,MAAA,CACT,KAAA,CAAOC,EACP,QAAA,CAAUC,CAAAA,CACV,QAASK,CAAAA,CACX,CAEJ,CCEO,SAASiC,EAAY,CAC1B,KAAA,CAAAvC,EACA,QAAA,CAAAC,CAAAA,CACA,SAAAsB,CAAAA,CACA,QAAA,CAAAiB,CACF,CAAA,CAAqB,CACnB,IAAMC,CAAAA,CAAYC,MAAAA,CAAsC,IAAI,CAAA,CAEtDC,CAAAA,CAA8BC,GAAW,CAC7CH,CAAAA,CAAU,QAAUG,EACtB,CAAA,CAEMC,EAAaC,WAAAA,CAAY,IAAM,CACnCL,CAAAA,CAAU,OAAA,EAAS,QAAQ,QAAA,CAAU,MAAA,CAAQ,IAAI,EACnD,CAAA,CAAG,EAAE,CAAA,CAECM,EAAaD,WAAAA,CAAY,IAAM,CACnCL,CAAAA,CAAU,OAAA,EAAS,OAAA,CAAQ,SAAU,MAAA,CAAQ,IAAI,EACnD,CAAA,CAAG,EAAE,CAAA,CAECO,CAAAA,CAAaF,YAAY,IAAM,CACnC,IAAMtB,CAAAA,CAAUiB,CAAAA,CAAU,SAAS,QAAA,EAAS,CAC5C,OAAIjB,CAAAA,CACK,SAAA,CAAU,UAAU,SAAA,CAAUA,CAAO,EAEvC,OAAA,CAAQ,OAAA,EACjB,CAAA,CAAG,EAAE,CAAA,CAECyB,CAAAA,CAAcH,YAAY,IAAM,CAElCL,EAAU,OAAA,EACV,MAAA,CAAO,QAAQ,4CAA4C,CAAA,EAE3DA,EAAU,OAAA,CAAQ,QAAA,CAAS,EAAE,EAEjC,CAAA,CAAG,EAAE,CAAA,CAEL,OACEN,KAACe,CAAAA,CAAA,CACC,UAAAf,IAAAA,CAACgB,CAAAA,CAAA,CACC,QAAA,CAAA,CAAA5C,GAAAA,CAAC,OAAI,SAAA,CAAU,aAAA,CACb,SAAAA,GAAAA,CAAC2B,EAAAA,CAAA,CAAY,QAAA,CAAUX,CAAAA,CAAU,EACnC,CAAA,CACAhB,GAAAA,CAAC,OAAI,SAAA,CAAU,QAAA,CAAS,EACxB4B,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,gCAAA,CACb,QAAA,CAAA,CAAA5B,IAAC6C,CAAAA,CAAA,CAAkB,QAASJ,CAAAA,CAAY,KAAA,CAAOR,EAAS,IAAA,CAAM,CAAA,CAC9DjC,IAAC8C,CAAAA,CAAA,EAAiB,CAAA,CAClB9C,GAAAA,CAAC+C,CAAAA,CAAA,CAAc,QAAST,CAAAA,CAAY,KAAA,CAAOL,EAAS,IAAA,CAClD,QAAA,CAAAjC,IAACgD,eAAAA,CAAA,CAAgB,KAAMjE,CAAAA,CAAW,EAAA,CAAI,OAAQC,CAAAA,CAAa,EAAA,CAAI,EACjE,CAAA,CACAgB,GAAAA,CAAC+C,EAAA,CAAc,OAAA,CAASP,EAAY,KAAA,CAAOP,CAAAA,CAAS,KAClD,QAAA,CAAAjC,GAAAA,CAACiD,mBAAA,CAAmB,IAAA,CAAMlE,EAAW,EAAA,CAAI,MAAA,CAAQC,EAAa,EAAA,CAAI,CAAA,CACpE,EACAgB,GAAAA,CAAC8C,CAAAA,CAAA,EAAiB,CAAA,CAClB9C,GAAAA,CAAC+C,EAAA,CAAc,OAAA,CAASL,CAAAA,CAAa,KAAA,CAAOT,CAAAA,CAAS,KAAA,CACnD,SAAAjC,GAAAA,CAACkD,UAAAA,CAAA,CAAW,IAAA,CAAMnE,CAAAA,CAAW,GAAI,MAAA,CAAQC,CAAAA,CAAa,GAAI,CAAA,CAC5D,CAAA,CAAA,CACF,GACF,CAAA,CACAgB,GAAAA,CAACmD,EAAA,CACC,QAAA,CAAAnD,IAAC+B,CAAAA,CAAA,CACC,MAAOtC,CAAAA,CACP,QAAA,CAAUC,EACV,OAAA,CAAS0C,CAAAA,CACX,EACF,CAAA,CAAA,CACF,CAEJ,CCzDO,SAASgB,CAAAA,CAAkB,CAChC,MAAA,CAAA3C,CAAAA,CACA,YAAAC,CACF,CAAA,CAA2B,CACzB,GAAM,CAAC2C,EAAiBC,CAAkB,CAAA,CAAIC,SAAiB,EAAE,CAAA,CAC3D,CAACC,CAAAA,CAAeC,CAAgB,EAAIF,QAAAA,CAA4B,IAAI,EACpE,CAAChD,CAAAA,CAAQmD,CAAS,CAAA,CAAIH,QAAAA,CAAuB,MAAM,CAAA,CACnD,CAACI,EAAOC,CAAQ,CAAA,CAAIL,SAAwB,IAAI,CAAA,CAEtD,OAAAM,SAAAA,CAAU,IAAM,CACd,GAAKpD,CAAAA,CAEL,GAAI,CACF,IAAMK,EAASL,CAAAA,CAAO,OAAA,GAAUC,CAAW,CAAA,CAC3C,GAAI,CAACI,EAAQ,CACX8C,CAAAA,CAAS,mBAAmBlD,CAAW,CAAA,WAAA,CAAa,EACpD,MACF,CAGA,GAAI,OAAOI,CAAAA,CAAO,QAAW,QAAA,CAAU,CACrC8C,EAAS,iDAAiD,CAAA,CAC1D,MACF,CAEA,IAAME,EAAgBhD,CAAAA,CAAO,MAAA,CAC7B4C,EAAUI,CAAa,CAAA,CAGvB,IAAMC,CAAAA,CADWlD,iBAAAA,CAAkBJ,EAAQC,CAAW,CAAA,CAC9B,QAAO,CAE3B,OAAOqD,GAAW,QAAA,EACpBT,CAAAA,CAAmBS,CAAM,CAAA,CACzBN,CAAAA,CAAiB,IAAI,CAAA,CACrBG,CAAAA,CAAS,IAAI,CAAA,EACJG,CAAAA,YAAkB,UAAA,EAC3BT,EAAmB,EAAE,CAAA,CACrBG,EAAiBM,CAAM,CAAA,CACvBH,EAAS,IAAI,CAAA,EAEbG,EACG,IAAA,CAAM9C,CAAAA,EAAY,CACb,OAAOA,CAAAA,EAAY,UACrBqC,CAAAA,CAAmBrC,CAAO,EAC1BwC,CAAAA,CAAiB,IAAI,GACZxC,CAAAA,YAAmB,UAAA,GAC5BqC,EAAmB,EAAE,CAAA,CACrBG,EAAiBxC,CAAO,CAAA,CAAA,CAE1B2C,EAAS,IAAI,EACf,CAAC,CAAA,CACA,KAAA,CAAOvC,GAAM,CACZuC,CAAAA,CACE,iBAAiBvC,CAAAA,YAAa,KAAA,CAAQA,EAAE,OAAA,CAAU,MAAA,CAAOA,CAAC,CAAC,CAAA,CAC7D,EACF,CAAC,EAEP,CAAA,MAASA,EAAG,CACVuC,CAAAA,CAAS,iBAAiBvC,CAAAA,YAAa,KAAA,CAAQA,EAAE,OAAA,CAAU,MAAA,CAAOA,CAAC,CAAC,CAAA,CAAE,EACxE,CACF,CAAA,CAAG,CAACZ,CAAAA,CAAQC,CAAW,CAAC,CAAA,CAEjB,CACL,gBAAA2C,CAAAA,CACA,aAAA,CAAAG,EACA,MAAA,CAAAjD,CAAAA,CACA,MAAAoD,CACF,CACF,CCjJA,IAAAK,CAAAA,CAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","file":"index.js","sourcesContent":["/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nexport const ICON_SIZES = {\n xs: 12,\n sm: 16,\n md: 20,\n lg: 24,\n xl: 28,\n}\n\nexport const ICON_STROKES = {\n xs: 1,\n sm: 1.25,\n md: 1.5,\n lg: 1.75,\n xl: 2,\n}\n\n// Monaco's default dark theme (aka, the `vsdark` theme) background color\nexport const EDITOR_BG_COLOR = '#1e1e1e'\n\n// Monaco's default font size\nexport const EDITOR_FONT_SIZE = 14\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n'use client'\n\nimport MonacoEditor, { type Monaco, type OnMount } from '@monaco-editor/react'\nimport type { languages } from 'monaco-editor'\n\nimport { EDITOR_FONT_SIZE } from '@/constants'\n\n/**\n * Registers the LaTeX language support in Monaco.\n *\n * @param monaco - The Monaco instance.\n */\nfunction registerLatexLanguage(monaco: Monaco) {\n // ref issue: https://github.com/microsoft/monaco-editor/issues/3233\n const latexLanguage: languages.IMonarchLanguage = {\n displayName: 'LaTeX',\n name: 'latex',\n mimeTypes: ['text/latex', 'text/tex'],\n fileExtensions: ['tex', 'sty', 'cls'],\n\n tokenPostfix: '.latex',\n defaultToken: '',\n\n keywords: [\n 'addcontentsline',\n 'addtocontents',\n 'addtocounter',\n 'address',\n 'addtolength',\n 'addvspace',\n 'alph',\n 'appendix',\n 'arabic',\n 'author',\n 'backslash',\n 'baselineskip',\n 'baselinestretch',\n 'bf',\n 'bibitem',\n 'bigskipamount',\n 'bigskip',\n 'boldmath',\n 'boldsymbol',\n 'cal',\n 'caption',\n 'cdots',\n 'centering',\n 'chapter',\n 'circle',\n 'cite',\n 'cleardoublepage',\n 'clearpage',\n 'cline',\n 'closing',\n 'color',\n 'copyright',\n 'dashbox',\n 'date',\n 'ddots',\n 'documentclass',\n 'dotfill',\n 'em',\n 'emph',\n 'ensuremath',\n 'epigraph',\n 'euro',\n 'fbox',\n 'flushbottom',\n 'fnsymbol',\n 'footnote',\n 'footnotemark',\n 'footnotesize',\n 'footnotetext',\n 'frac',\n 'frame',\n 'framebox',\n 'frenchspacing',\n 'hfill',\n 'hline',\n 'href',\n 'hrulefill',\n 'hspace',\n 'huge',\n 'Huge',\n 'hyphenation',\n 'include',\n 'includegraphics',\n 'includeonly',\n 'indent',\n 'input',\n 'it',\n 'item',\n 'kill',\n 'label',\n 'large',\n 'Large',\n 'LARGE',\n 'LaTeX',\n 'LaTeXe',\n 'ldots',\n 'left',\n 'lefteqn',\n 'line',\n 'linebreak',\n 'linethickness',\n 'linewidth',\n 'listoffigures',\n 'listoftables',\n 'location',\n 'makebox',\n 'maketitle',\n 'markboth',\n 'mathcal',\n 'mathop',\n 'mbox',\n 'medskip',\n 'multicolumn',\n 'multiput',\n 'newcommand',\n 'newcolumntype',\n 'newcounter',\n 'newenvironment',\n 'newfont',\n 'newlength',\n 'newline',\n 'newpage',\n 'newsavebox',\n 'newtheorem',\n 'nocite',\n 'noindent',\n 'nolinebreak',\n 'nonfrenchspacing',\n 'normalsize',\n 'nopagebreak',\n 'not',\n 'onecolumn',\n 'opening',\n 'oval',\n 'overbrace',\n 'overline',\n 'pagebreak',\n 'pagenumbering',\n 'pageref',\n 'pagestyle',\n 'par',\n 'paragraph',\n 'parbox',\n 'parindent',\n 'parskip',\n 'part',\n 'protect',\n 'providecommand',\n 'put',\n 'raggedbottom',\n 'raggedleft',\n 'raggedright',\n 'raisebox',\n 'ref',\n 'renewcommand',\n 'right',\n 'rm',\n 'roman',\n 'rule',\n 'savebox',\n 'sbox',\n 'sc',\n 'scriptsize',\n 'section',\n 'setcounter',\n 'setlength',\n 'settowidth',\n 'sf',\n 'shortstack',\n 'signature',\n 'sl',\n 'slash',\n 'small',\n 'smallskip',\n 'sout',\n 'space',\n 'sqrt',\n 'stackrel',\n 'stepcounter',\n 'subparagraph',\n 'subsection',\n 'subsubsection',\n 'tableofcontents',\n 'telephone',\n 'TeX',\n 'textbf',\n 'textcolor',\n 'textit',\n 'textmd',\n 'textnormal',\n 'textrm',\n 'textsc',\n 'textsf',\n 'textsl',\n 'texttt',\n 'textup',\n 'textwidth',\n 'textheight',\n 'thanks',\n 'thispagestyle',\n 'tiny',\n 'title',\n 'today',\n 'tt',\n 'twocolumn',\n 'typeout',\n 'typein',\n 'uline',\n 'underbrace',\n 'underline',\n 'unitlength',\n 'usebox',\n 'usecounter',\n 'uwave',\n 'value',\n 'vbox',\n 'vcenter',\n 'vdots',\n 'vector',\n 'verb',\n 'vfill',\n 'vline',\n 'vphantom',\n 'vspace',\n\n 'RequirePackage',\n 'NeedsTeXFormat',\n 'usepackage',\n 'input',\n 'include',\n 'documentclass',\n 'documentstyle',\n 'def',\n 'edef',\n 'defcommand',\n 'if',\n 'ifdim',\n 'ifnum',\n 'ifx',\n 'fi',\n 'else',\n 'begingroup',\n 'endgroup',\n 'definecolor',\n 'textcolor',\n 'color',\n 'eifstrequal',\n 'eeifstrequal',\n ],\n\n tokenizer: {\n root: [\n [\n /(\\\\begin)(\\s*)(\\{)([\\w\\-*@]+)(\\})/,\n [\n 'keyword.predefined',\n 'white',\n '@brackets',\n { token: 'tag.env-$4', bracket: '@open' },\n '@brackets',\n ],\n ],\n [\n /(\\\\end)(\\s*)(\\{)([\\w\\-*@]+)(\\})/,\n [\n 'keyword.predefined',\n 'white',\n '@brackets',\n { token: 'tag.env-$4', bracket: '@close' },\n '@brackets',\n ],\n ],\n [/\\\\\\[a-zA-Z@]/, 'keyword'],\n [/\\\\\\\\[^a-zA-Z@]/, 'keyword'],\n [/\\\\@[a-zA-Z@]+/, 'keyword.at'],\n [\n /\\\\([a-zA-Z@]+)/,\n {\n cases: {\n '$1@keywords': 'keyword.predefined',\n '@default': 'keyword',\n },\n },\n ],\n { include: '@whitespace' },\n [/[{}()[\\]]/, '@brackets'],\n [/#+\\d/, 'number.arg'],\n [\n /\\\\-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)\\s*(?:em|ex|pt|pc|sp|cm|mm|in)/,\n 'number.len',\n ],\n ],\n\n whitespace: [\n [/[ \\t\\r\\n]+/, 'white'],\n ['%.*$', 'comment'],\n ],\n },\n }\n\n const latexConf: languages.LanguageConfiguration = {\n comments: {\n lineComment: '%',\n },\n brackets: [\n ['{', '}'],\n ['[', ']'],\n ['(', ')'],\n ],\n autoClosingPairs: [\n { open: '{', close: '}' },\n { open: '[', close: ']' },\n { open: '(', close: ')' },\n { open: '$', close: '$' },\n ],\n surroundingPairs: [\n { open: '{', close: '}' },\n { open: '[', close: ']' },\n { open: '(', close: ')' },\n { open: '$', close: '$' },\n ],\n }\n\n if (\n monaco.languages\n .getLanguages()\n .some((l: { id: string }) => l.id === 'latex')\n ) {\n return\n }\n\n monaco.languages.register({ id: 'latex' })\n monaco.languages.setMonarchTokensProvider('latex', latexLanguage)\n monaco.languages.setLanguageConfiguration('latex', latexConf)\n}\n\n/**\n * Props for the Editor component.\n */\nexport interface EditorProps {\n /** The content of the editor. */\n value: string\n /** Callback triggered when content changes. */\n onChange?: (value: string | undefined) => void\n /** The language of the content. */\n language: string\n /** Whether the editor is read-only. Defaults to false. */\n readOnly?: boolean\n /** Whether to show line numbers. Defaults to true. */\n lineNumbers?: boolean\n /** Whether to show the minimap. Defaults to true. */\n minimap?: boolean\n /** Callback triggered when the editor is mounted. */\n onMount?: OnMount\n}\n\n/**\n * A shared editor component based on Monaco Editor.\n * Encapsulates theme handling, common configuration, and LaTeX support.\n *\n * @param props - The component props.\n * @returns The rendered Editor component.\n */\nexport function Editor({\n value,\n onChange,\n language,\n readOnly = false,\n lineNumbers = true,\n minimap = true,\n onMount,\n}: EditorProps) {\n return (\n <MonacoEditor\n height=\"100%\"\n language={language}\n value={value}\n onChange={onChange}\n theme=\"vs-dark\"\n onMount={onMount}\n beforeMount={registerLatexLanguage}\n options={{\n readOnly,\n domReadOnly: readOnly,\n lineNumbers: lineNumbers ? 'on' : 'off',\n minimap: { enabled: minimap },\n fontSize: EDITOR_FONT_SIZE,\n lineNumbersMinChars: 4,\n padding: {\n top: 8,\n },\n automaticLayout: true,\n roundedSelection: false,\n smoothScrolling: true,\n scrollBeyondLastLine: false,\n }}\n />\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n getResumeRenderer,\n type LayoutEngine,\n type Resume,\n} from '@yamlresume/core'\n\n/**\n * Gets the basename from a filepath.\n *\n * @param filepath - The file path (e.g. \"path/to/resume.yaml\").\n * @param removeExtension - Whether to remove the file extension.\n * @returns The basename of the file.\n */\nexport const getBasename = (\n filepath = 'resume.yaml',\n removeExtension = false\n): string => {\n const basename = filepath.split(/[/\\\\]/).pop() || filepath\n if (removeExtension) {\n return basename.replace(/\\.(ya?ml|json)$/, '')\n }\n return basename\n}\n\n/**\n * Gets the file extension for a given rendering engine.\n *\n * @param engine - The rendering engine (html, latex, markdown).\n * @returns The associated file extension.\n */\nexport const getExtension = (engine: LayoutEngine): string => {\n switch (engine) {\n case 'html':\n return '.html'\n case 'latex':\n return '.tex'\n case 'markdown':\n return '.md'\n case 'docx':\n return '.docx'\n default:\n return ''\n }\n}\n\n/**\n * Downloads the resume for a specific layout index.\n *\n * @param resume - The resume object.\n * @param layoutIndex - The index of the layout to download.\n */\nexport const downloadResume = async (\n resume: Resume | null,\n layoutIndex: number\n) => {\n try {\n const layouts = resume?.layouts\n if (!resume || !layouts[layoutIndex]) {\n console.warn('No resume or layout found for download')\n return\n }\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const renderResult = renderer.render()\n const layout = layouts[layoutIndex]\n const extension = getExtension(layout.engine)\n const filename = `resume.${layoutIndex}${extension}`\n\n const content =\n renderResult instanceof Promise ? await renderResult : renderResult\n const blob =\n content instanceof Uint8Array\n ? new Blob([content.buffer as BlobPart], {\n type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n })\n : new Blob([content], { type: 'text/plain' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n URL.revokeObjectURL(url)\n } catch (e) {\n console.error('Failed to download resume:', e)\n }\n}\n\n/**\n * Copies the resume content to the clipboard for a specific layout index.\n *\n * @param resume - The resume object.\n * @param layoutIndex - The index of the layout to copy.\n */\nexport const copyResumeToClipboard = (\n resume: Resume | null,\n layoutIndex: number\n): Promise<void> => {\n try {\n const layouts = resume?.layouts\n if (!resume || !layouts[layoutIndex]) {\n console.warn('No resume or layout found for copy')\n return Promise.resolve()\n }\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const content = renderer.render()\n if (typeof content !== 'string') {\n console.warn('Copy to clipboard is not supported for binary layouts')\n return Promise.resolve()\n }\n\n return navigator.clipboard.writeText(content)\n } catch (e) {\n console.error('Failed to copy resume:', e)\n return Promise.resolve()\n }\n}\n\n/**\n * Prints the resume content (only for HTML layouts).\n *\n * @param resume - The resume object.\n * @param layoutIndex - The index of the layout to print.\n */\nexport const printResume = (resume: Resume | null, layoutIndex: number) => {\n try {\n const layouts = resume?.layouts\n if (!resume || !layouts[layoutIndex]) {\n console.warn('No resume or layout found for print')\n return\n }\n\n const layout = layouts[layoutIndex]\n if (layout.engine !== 'html') {\n console.warn('Printing is only supported for HTML layouts')\n return\n }\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const content = renderer.render()\n if (typeof content !== 'string') {\n console.warn('Printing is only supported for string-based layouts')\n return\n }\n\n const iframe = document.createElement('iframe')\n iframe.style.position = 'absolute'\n iframe.style.width = '0px'\n iframe.style.height = '0px'\n iframe.style.border = 'none'\n document.body.appendChild(iframe)\n\n const doc = iframe.contentWindow?.document\n if (doc) {\n doc.open()\n doc.write(content)\n doc.close()\n iframe.contentWindow?.focus()\n iframe.contentWindow?.print()\n }\n\n // Clean up after print dialog closes (or reasonably soon)\n setTimeout(() => {\n document.body.removeChild(iframe)\n }, 1000)\n } catch (e) {\n console.error('Failed to print resume:', e)\n }\n}\n\n/**\n * Opens the resume content in a new tab (only for HTML layouts).\n *\n * @param resume - The resume object.\n * @param layoutIndex - The index of the layout to open.\n */\nexport const openResumeInNewTab = (\n resume: Resume | null,\n layoutIndex: number\n) => {\n try {\n const layouts = resume?.layouts\n if (!resume || !layouts[layoutIndex]) {\n console.warn('No resume or layout found for new tab')\n return\n }\n\n const layout = layouts[layoutIndex]\n if (layout.engine !== 'html') {\n console.warn('Open in new tab is only supported for HTML layouts')\n return\n }\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const content = renderer.render()\n if (typeof content !== 'string') {\n console.warn('Open in new tab is only supported for string-based layouts')\n return\n }\n\n const blob = new Blob([content], { type: 'text/html' })\n const url = URL.createObjectURL(blob)\n window.open(url, '_blank')\n } catch (e) {\n console.error('Failed to open resume in new tab:', e)\n }\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { IconFileCode } from '@tabler/icons-react'\nimport clsx from 'clsx'\n\nimport { EDITOR_BG_COLOR, ICON_SIZES, ICON_STROKES } from '@/constants'\nimport { getBasename } from '@/utils'\n\n/**\n * The title component for the editor panel.\n * Displays as a tab with a YAML icon.\n *\n * @returns The rendered title element.\n */\ninterface EditorTitleProps {\n filename?: string\n}\n\nexport function EditorTitle({ filename = 'resume.yaml' }: EditorTitleProps) {\n // Extract basename if path is provided\n const basename = getBasename(filename)\n return (\n <div\n className={clsx(\n 'flex items-center gap-2',\n 'h-full px-4',\n 'border-r border-neutral-600'\n )}\n style={{ backgroundColor: EDITOR_BG_COLOR }}\n >\n <IconFileCode size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n <span>{basename}</span>\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { OnMount } from '@monaco-editor/react'\nimport { Editor } from './Editor'\n\n/**\n * Props for the ResumeEditor component.\n */\nexport interface ResumeEditorProps {\n /**\n * The current value of the YAML resume.\n */\n value: string\n /**\n * Callback triggered when the editor content changes.\n * @param value - The new value of the editor content.\n */\n onChange: (value: string | undefined) => void\n /** Callback triggered when the editor is mounted. */\n onMount?: OnMount\n}\n\n/**\n * A specialized editor component for editing the resume YAML content.\n *\n * This component wraps the shared {@link Editor} component, pre-configured\n * for YAML editing.\n *\n * @param props - The component props.\n * @param props.value - The string content to display in the editor.\n * @param props.onChange - Handler called when content is modified.\n * @returns The rendered editor component.\n */\nexport function ResumeEditor({ value, onChange, onMount }: ResumeEditorProps) {\n return (\n <Editor\n language=\"yaml\"\n value={value}\n onChange={onChange}\n onMount={onMount}\n />\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { OnMount } from '@monaco-editor/react'\nimport {\n IconArrowBackUp,\n IconArrowForwardUp,\n IconEraser,\n} from '@tabler/icons-react'\nimport { useCallback, useRef } from 'react'\n\nimport {\n Panel,\n PanelContent,\n PanelToolbar,\n ToolbarButton,\n ToolbarCopyButton,\n ToolbarSeparator,\n} from '@/components'\nimport { ICON_SIZES, ICON_STROKES } from '@/constants'\nimport type { PlaygroundTooltipMessages } from '@/messages'\n\nimport { EditorTitle } from './EditorTitle'\nimport { ResumeEditor } from './ResumeEditor'\n\n/**\n * Props for the EditorPanel component.\n */\nexport interface EditorPanelProps {\n /** The current YAML content of the editor. */\n value: string\n /** Callback triggered when the content changes. */\n onChange: (value: string) => void\n /** The name of the file being edited. */\n filename?: string\n /** Localized tooltip labels for editor actions. */\n tooltips: Pick<PlaygroundTooltipMessages, 'copy' | 'undo' | 'redo' | 'clear'>\n}\n\n/**\n * A panel component containing the resume editor.\n *\n * @param props - The component props.\n * @returns The rendered editor panel.\n */\nexport function EditorPanel({\n value,\n onChange,\n filename,\n tooltips,\n}: EditorPanelProps) {\n const editorRef = useRef<Parameters<OnMount>[0] | null>(null)\n\n const handleEditorMount: OnMount = (editor) => {\n editorRef.current = editor\n }\n\n const handleUndo = useCallback(() => {\n editorRef.current?.trigger('source', 'undo', null)\n }, [])\n\n const handleRedo = useCallback(() => {\n editorRef.current?.trigger('source', 'redo', null)\n }, [])\n\n const handleCopy = useCallback(() => {\n const content = editorRef.current?.getValue()\n if (content) {\n return navigator.clipboard.writeText(content)\n }\n return Promise.resolve()\n }, [])\n\n const handleClear = useCallback(() => {\n if (\n editorRef.current &&\n window.confirm('Are you sure you want to clear the editor?')\n ) {\n editorRef.current.setValue('')\n }\n }, [])\n\n return (\n <Panel>\n <PanelToolbar>\n <div className=\"flex h-full\">\n <EditorTitle filename={filename} />\n </div>\n <div className=\"flex-1\" />\n <div className=\"flex items-center gap-0.5 pr-2\">\n <ToolbarCopyButton onClick={handleCopy} title={tooltips.copy} />\n <ToolbarSeparator />\n <ToolbarButton onClick={handleUndo} title={tooltips.undo}>\n <IconArrowBackUp size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n <ToolbarButton onClick={handleRedo} title={tooltips.redo}>\n <IconArrowForwardUp size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n <ToolbarSeparator />\n <ToolbarButton onClick={handleClear} title={tooltips.clear}>\n <IconEraser size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n </div>\n </PanelToolbar>\n <PanelContent>\n <ResumeEditor\n value={value}\n onChange={onChange}\n onMount={handleEditorMount}\n />\n </PanelContent>\n </Panel>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n getResumeRenderer,\n type LayoutEngine,\n type Resume,\n} from '@yamlresume/core'\nimport { useEffect, useState } from 'react'\n\n/**\n * Props for the `useResumeRenderer` hook.\n *\n * @property {Resume | null} resume - The pre-parsed resume object to render.\n * Pass `null` when the resume is not yet available or parsing failed.\n * @property {number} layoutIndex - The index of the layout to use for rendering.\n * Must be a valid index within the `resume.layouts` array.\n */\nexport interface UseResumeRendererProps {\n resume: Resume | null\n layoutIndex: number\n}\n\n/**\n * A React hook for rendering a resume using a specified layout.\n *\n * @description\n * This hook encapsulates the logic for:\n * - Selecting the appropriate layout from the resume's layouts array\n * - Determining the rendering engine (html, markdown, or latex)\n * - Generating the rendered output content\n * - Handling errors gracefully during rendering\n *\n * The hook re-renders when either the `resume` object or `layoutIndex` changes.\n * If `resume` is `null`, no rendering is performed.\n *\n * @param {UseResumeRendererProps} props - Configuration options for the hook.\n * @returns An object containing:\n * - `renderedContent` - The rendered resume content as a string\n * - `engine` - The rendering engine used ('html', 'markdown', or 'latex')\n * - `error` - Error message if rendering failed, or `null` if successful\n *\n * @example\n * const { renderedContent, engine, error } = useResumeRenderer({\n * resume: parsedResume,\n * layoutIndex: 0,\n * })\n *\n * if (error) {\n * return <ErrorDisplay message={error} />\n * }\n *\n * return engine === 'html'\n * ? <HtmlViewer content={renderedContent} />\n * : <CodeViewer content={renderedContent} language={engine} />\n */\nexport function useResumeRenderer({\n resume,\n layoutIndex,\n}: UseResumeRendererProps) {\n const [renderedContent, setRenderedContent] = useState<string>('')\n const [binaryContent, setBinaryContent] = useState<Uint8Array | null>(null)\n const [engine, setEngine] = useState<LayoutEngine>('html')\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n if (!resume) return\n\n try {\n const layout = resume.layouts?.[layoutIndex]\n if (!layout) {\n setError(`Layout at index ${layoutIndex} not found.`)\n return\n }\n\n // Handle incomplete layout entries (e.g., when user is typing \"- \" in YAML)\n if (typeof layout.engine !== 'string') {\n setError('Layout is incomplete - missing engine property.')\n return\n }\n\n const currentEngine = layout.engine\n setEngine(currentEngine)\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const result = renderer.render()\n\n if (typeof result === 'string') {\n setRenderedContent(result)\n setBinaryContent(null)\n setError(null)\n } else if (result instanceof Uint8Array) {\n setRenderedContent('')\n setBinaryContent(result)\n setError(null)\n } else {\n result\n .then((content) => {\n if (typeof content === 'string') {\n setRenderedContent(content)\n setBinaryContent(null)\n } else if (content instanceof Uint8Array) {\n setRenderedContent('')\n setBinaryContent(content)\n }\n setError(null)\n })\n .catch((e) => {\n setError(\n `Render Error: ${e instanceof Error ? e.message : String(e)}`\n )\n })\n }\n } catch (e) {\n setError(`Render Error: ${e instanceof Error ? e.message : String(e)}`)\n }\n }, [resume, layoutIndex])\n\n return {\n renderedContent,\n binaryContent,\n engine,\n error,\n }\n}\n","# MIT License\n#\n# Copyright (c) 2023–Present PPResume (https://ppresume.com)\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to\n# deal in the Software without restriction, including without limitation the\n# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n# sell copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n# IN THE SOFTWARE.\n\n# yaml-language-server: $schema=https://yamlresume.dev/schema.json\n#\n# YAMLResume provides a builtin schema to validate resumes and help avoid lots\n# of low level mistakes.\n#\n# You need to install https://github.com/redhat-developer/yaml-language-server\n# in order to get the best editing experience in your choice of editor/IDE.\n#\n# ref:\n# - https://yamlresume.dev/docs/compiler/schema\n# - https://yamlresume.dev/docs/compiler/schema/json\n\n---\ncontent:\n basics:\n name: Andy Dufresne\n headline: Headed for the Pacific\n phone: \"(213) 555-9876\"\n email: hi@ppresume.com\n url: https://ppresume.com/gallery\n # All summary fields supports a limited rich text capabilities in markdown\n # syntax:\n #\n # - bold, (e.g, **bold**)\n # - italic, (e.g, *italic*)\n # - ordered list, unordored list and nested sub list\n # - links (e.g. [link](https://ppresume.com))\n summary: |\n - Computer Science major with strong foundation in data structures, algorithms, and software development\n - Pixel perfect full stack web developer, specialised in creating high-quality, visually appealing websites\n - Experiened in databases (SQL, NoSQL), familiar with server-side technologies (Node.js, Express, etc.)\n - Team player, with detail-oriented mindset and a keen eye for design and user experiences\n location:\n address: 123 Main Street\n city: Sacramento\n region: California\n country: United States\n postalCode: \"95814\"\n profiles:\n - network: Line\n url: https://line.com/PPResumeX\n username: PPResumeX\n - network: Twitter\n url: https://twitter.com/PPResumeX\n username: PPResumeX\n education:\n - institution: University of Southern California\n url: https://www.cs.usc.edu/\n # Valid degree options:\n #\n # - 'Middle School'\n # - 'High School'\n # - 'Diploma'\n # - 'Associate'\n # - 'Bachelor'\n # - 'Master'\n # - 'Doctor'\n degree: Bachelor\n area: Computer Engineering and Computer Science\n score: \"3.8\"\n # Should be a valid date string that can be parsed by \\`new Date(dateStr)\\`\n # in JavaScript, eg. '2020-01', '2020-02-03', 'Jul 1, 2023' etc.\n #\n # The date part would be removed in the final output as most of the time\n # people won't really care about the exact date for your working\n # experience or education background, etc.\n # ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date\n startDate: Sep 1, 2016\n # Leave endDate blank to indicate \"Present\"\n endDate: Jul 1, 2020\n courses:\n - Discrete Methods in Computer Science\n - Programming Language Concepts\n - Data Structures and Object-Oriented Design\n - Operating Systems\n - Computer Architecture\n - Database Systems\n - Computer Networking\n - Introduction to the Theory of Computing\n summary: |\n - Developed proficiency in programming languages such as Java, C++, and Python\n - Gained hands-on experience in software development through various projects and assignments\n - Strong communication and teamwork skills acquired through group projects and presentations\n work:\n - name: PPResume\n url: https://ppresume.com\n startDate: Dec 1, 2022\n endDate:\n position: Senior Software Engineer\n summary: |\n - Developed and implemented efficient and scalable code, ensuring high-quality and maintainable web applications\n - Collaborated with cross-functional teams to gather project requirements and translate them into technical solutions\n - Conducted thorough testing and debugging to identify and resolve any issues or bugs in the software\n - Actively participated in code reviews, providing valuable feedback to improve code quality and adherence to best practices\n - Mentored and guided junior developers, fostering a collaborative and growth-oriented team environment\n keywords:\n - Scalability\n - Growth\n - Quality\n - Mentorship\n - name: PPResume\n url: https://ppresume.com\n startDate: Sep 1, 2020\n endDate: Dec 1, 2022\n position: Software Engineer\n summary: |\n - Created reusable React components to ensure code efficiency and maintainability\n - Integrated with RESTful APIs to fetch and display dynamic data on the frontend\n - Implemented client-side routing using React Router for smooth navigation between pages\n - Actively participated in Agile development methodologies, attending daily stand-up meetings and sprint planning sessions\n keywords:\n - RESTful\n - React\n - Agile\n languages:\n # Valid language fluency options:\n #\n # - 'Elementary Proficiency'\n # - 'Limited Working Proficiency'\n # - 'Minimum Professional Proficiency'\n # - 'Full Professional Proficiency'\n # - 'Native or Bilingual Proficiency'\n - language: English\n fluency: Native or Bilingual Proficiency\n keywords:\n - TOEFL 110\n - IELTS 7.5\n - language: Chinese\n fluency: Elementary Proficiency\n keywords: []\n skills:\n # Valid level options:\n #\n # - 'Novice'\n # - 'Beginner'\n # - 'Intermediate'\n # - 'Advanced'\n # - 'Expert'\n # - 'Master'\n - name: Web Development\n level: Expert\n keywords:\n - Python\n - Ruby\n - CSS\n - React\n - JavaScript\n - name: DevOps\n level: Intermediate\n keywords:\n - Python\n - Kubernetes\n - Docker\n - Shell\n - Ansible\n - name: Design\n level: Intermediate\n keywords:\n - Sketch\n - Figma\n - Photoshop\n awards:\n - title: Dean's List\n awarder: University of Southern California\n date: Oct 2016\n summary: |\n Awarded to students who achieve a high academic standing by maintaining a specified grade point average (GPA) during a semester.\n certificates:\n - name: AWS Certified Developer - Associate\n url: https://aws.amazon.com/certification/\n issuer: AWS\n date: Mar 2021\n publications:\n - publisher: ACM Transactions on Interactive Intelligent Systems\n url: https://dl.acm.org/journal/tiis\n name: Enhancing Human-Computer Interaction through Augmented Reality\n releaseDate: Dec 2017\n summary: |\n - Explores the potential of augmented reality (AR) in improving interaction between humans and computers\n - Highlights benefits of AR in various areas such as gaming, education, healthcare, and design\n - Discusses challenges and future directions of AR technology in enhancing user experience\n references:\n - name: Dr. Amanda Reynolds\n phone: \"(555) 123-4567\"\n relationship: Computer Science Professor\n email: amanda.reynolds@usc.edu\n summary: |\n Andy Dufresne shows exceptional problem-solving skills and a solid understanding of programming concepts, he would bring immense value to any team or organization he becomes a part of.\n projects:\n - name: EduWeb\n url: https://www.eduweb.xyz/\n description: A web-based educational platform for interactive learning\n startDate: Sep 2016\n endDate: Dec 2016\n summary: |\n - Designed to enhance online learning experiences\n - Facilitates students' engagement and collaboration through interactive features and user-friendly interface\n - Offers a wide range of courses across various subjects\n - Aims to improve the way students learn through the power of the web\n keywords:\n - Education\n - Online Learning\n - HCI\n interests:\n - name: Sports\n keywords:\n - Soccer\n - Swimming\n - Bicycling\n - Hiking\n - name: Music\n keywords:\n - Piano\n - Guitar\n volunteer:\n - organization: USC Computer Science and Engineering Society\n url: https://www.usccsesociety.org/\n position: Tech Mentor\n startDate: Sep 2015\n endDate: Jul 2023\n summary: |\n - Volunteered as a Tech Mentor at USC Computer Science and Engineering Society\n - Provided guidance and assistance to fellow students in their technical projects and coursework\n - Assisted in organizing workshops, coding competitions, and networking events for the society members\n - Contributed to fostering a collaborative and supportive environment within the student community\n\n# Top-level locale setting\nlocale:\n # Use \\`yamlresume languages list\\` to get the list of supported languages\n language: en\n\n# Multiple output layouts configuration\nlayouts:\n - engine: html\n # Use \\`yamlresume templates list\\` to get the list of available templates\n template: calm\n typography:\n # HTML engine only supports font size in px unit, from 10px to 24px\n fontSize: 16px\n - engine: markdown\n - engine: latex\n page:\n margins:\n top: 2.5cm\n left: 1.5cm\n right: 1.5cm\n bottom: 2.5cm\n showPageNumbers: true\n # Use \\`yamlresume templates list\\` to get the list of available templates\n template: moderncv-banking\n typography:\n # LaTeX engine only supports 10pt, 11pt, and 12pt\n fontSize: 11pt\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { Resume } from '@yamlresume/core'\nimport { useEffect, useMemo, useState } from 'react'\nimport { parse } from 'yaml'\n\nimport DEFAULT_RESUME_YAML from '@/resources/default-resume.yml'\n\n/**\n * Props for the `useResumeState` hook.\n *\n * @property {string} [yaml] - The YAML content for the resume editor.\n * Defaults to `DEFAULT_YAML` if not provided. Parent component should\n * manage this state and update it via the `onChange` callback.\n * @property {(value: string) => void} [onChange] - Callback invoked when\n * the YAML content changes. The parent should update its state accordingly.\n */\nexport interface UseResumeStateProps {\n yaml?: string\n onChange?: (value: string) => void\n}\n\n/**\n * A React hook for managing resume state derived from YAML content.\n *\n * @description\n * This hook encapsulates the logic for:\n * - Parsing YAML into a `Resume` object with memoization\n * - Tracking the active layout index with bounds checking\n * - Providing a change handler that notifies the parent\n *\n * The parent component is responsible for managing the YAML state.\n * This hook simply derives state (parsed resume, layout index) from the\n * provided YAML and exposes utilities for updates.\n *\n * @param {UseResumeStateProps} props - Configuration options for the hook.\n * @returns An object containing:\n * - `yaml` - The current YAML string content\n * - `handleYamlChange` - Function to notify parent of YAML changes\n * - `activeLayoutIndex` - The currently selected layout index\n * - `setActiveLayoutIndex` - Function to change the active layout\n * - `resume` - The parsed `Resume` object (or `null` if parsing fails)\n *\n * @example\n * // Parent manages state, hook derives resume object\n * const [yaml, setYaml] = useState(defaultYaml)\n * const { resume, activeLayoutIndex } = useResumeState({\n * yaml,\n * onChange: setYaml,\n * })\n */\nexport function useResumeState({\n yaml = DEFAULT_RESUME_YAML,\n onChange,\n}: UseResumeStateProps) {\n const [activeLayoutIndex, setActiveLayoutIndex] = useState(0)\n\n const handleYamlChange = (v: string) => {\n onChange?.(v)\n }\n\n const resume = useMemo(() => {\n try {\n return parse(yaml) as Resume\n } catch (_e) {\n return null\n }\n }, [yaml])\n\n // Ensure activeLayoutIndex is always within bounds\n useEffect(() => {\n const layouts = resume?.layouts || []\n if (activeLayoutIndex >= layouts.length && layouts.length > 0) {\n setActiveLayoutIndex(layouts.length - 1)\n }\n }, [resume?.layouts, activeLayoutIndex])\n\n return {\n yaml,\n handleYamlChange,\n activeLayoutIndex,\n setActiveLayoutIndex,\n resume,\n }\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * Tooltip label strings for each action button in the playground toolbar.\n */\nexport interface PlaygroundTooltipMessages {\n copy: string\n undo: string\n redo: string\n clear: string\n print: string\n openInNewTab: string\n download: string\n}\n\n/**\n * All user-facing messages consumed by the playground component.\n */\nexport interface PlaygroundMessages {\n tooltips: PlaygroundTooltipMessages\n}\n\n/**\n * Partial overrides for {@link PlaygroundMessages}, allowing consumers to\n * customize individual strings without providing the full message object.\n */\nexport interface PlaygroundMessageOverrides {\n tooltips?: Partial<PlaygroundTooltipMessages>\n}\n\n/**\n * Default English messages used by the playground when no overrides are\n * provided.\n */\nexport const DEFAULT_PLAYGROUND_MESSAGES: PlaygroundMessages = {\n tooltips: {\n copy: 'Copy',\n undo: 'Undo',\n redo: 'Redo',\n clear: 'Clear',\n print: 'Print',\n openInNewTab: 'Open in New Tab',\n download: 'Download',\n },\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n'use client'\n\nimport clsx from 'clsx'\n\nimport {\n EditorPanel,\n PlaygroundDesktop,\n PlaygroundMobile,\n PreviewPanel,\n} from '@/components'\nimport { EDITOR_BG_COLOR } from '@/constants'\nimport { useResumeState } from '@/hooks'\nimport {\n DEFAULT_PLAYGROUND_MESSAGES,\n type PlaygroundMessageOverrides,\n} from '@/messages'\nimport DEFAULT_RESUME_YAML from '@/resources/default-resume.yml'\n\n/**\n * Props for the Playground component.\n */\nexport interface PlaygroundProps {\n /** YAML content for the playground editor. Defaults to DEFAULT_YAML. */\n yaml?: string\n /** Callback triggered when the content changes. */\n onChange?: (value: string) => void\n /** The name of the file being edited. */\n filename?: string\n /** Optional localized UI messages for tooltip labels. */\n messages?: PlaygroundMessageOverrides\n}\n\n/**\n * Main Playground component providing a split-view interface for editing and\n * previewing resumes.\n *\n * On desktop (md+), shows side-by-side resizable panels.\n * On mobile, shows a tab-based interface to switch between Editor and Preview.\n *\n * @param props - The component props.\n * @returns The rendered Playground component.\n */\nexport function Playground({\n yaml: yamlStr = DEFAULT_RESUME_YAML,\n onChange,\n filename,\n messages,\n}: PlaygroundProps) {\n const {\n yaml,\n handleYamlChange,\n activeLayoutIndex,\n setActiveLayoutIndex,\n resume,\n } = useResumeState({\n yaml: yamlStr,\n onChange,\n })\n\n const tooltips = {\n ...DEFAULT_PLAYGROUND_MESSAGES.tooltips,\n ...messages?.tooltips,\n }\n\n // Create editor panel element\n const editorPanel = (\n <EditorPanel\n value={yaml}\n onChange={(v) => handleYamlChange(v || '')}\n filename={filename}\n tooltips={tooltips}\n />\n )\n\n // Create preview panel element\n const previewPanel = (\n <PreviewPanel\n activeLayoutIndex={activeLayoutIndex}\n setActiveLayoutIndex={setActiveLayoutIndex}\n resume={resume}\n filename={filename}\n tooltips={tooltips}\n />\n )\n\n return (\n <div\n className={clsx('flex flex-col h-full w-full gap-4', 'text-neutral-200')}\n style={{\n backgroundColor: EDITOR_BG_COLOR,\n }}\n >\n <PlaygroundMobile editorPanel={editorPanel} previewPanel={previewPanel} />\n <PlaygroundDesktop\n editorPanel={editorPanel}\n previewPanel={previewPanel}\n />\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { ReactNode } from 'react'\nimport { Group, Panel } from 'react-resizable-panels'\nimport { PanelSeparator } from '@/components'\n\n/**\n * Props for the PlaygroundDesktop component.\n */\nexport interface PlaygroundDesktopProps {\n /** The editor panel content to render. */\n editorPanel: ReactNode\n /** The preview panel content to render. */\n previewPanel: ReactNode\n}\n\n/**\n * The desktop layout component for the playground.\n * Shows a side-by-side resizable panel layout.\n * This component is only visible on medium and larger screens (hidden on mobile).\n *\n * @param props - The component props.\n * @returns The rendered desktop layout.\n */\nexport function PlaygroundDesktop({\n editorPanel,\n previewPanel,\n}: PlaygroundDesktopProps) {\n const panelMinSize = 360\n\n return (\n <div className=\"hidden md:flex flex-1 overflow-hidden\">\n <Group orientation=\"horizontal\">\n <Panel minSize={panelMinSize} className=\"flex flex-col\">\n {editorPanel}\n </Panel>\n\n <PanelSeparator />\n\n <Panel minSize={panelMinSize} className=\"flex flex-col\">\n {previewPanel}\n </Panel>\n </Group>\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { ElementType } from 'react'\n\nimport { ICON_SIZES, ICON_STROKES } from '@/constants'\n\n/**\n * Props for the MobileTabButton component.\n */\ninterface MobileTabButtonProps {\n /** The label text to display on the tab. */\n label: string\n /** Whether this tab is currently active. */\n active: boolean\n /** Callback when the tab is clicked. */\n onClick: () => void\n /** The icon to display on the tab. */\n icon: ElementType\n}\n\n/**\n * A reusable tab button component for the mobile playground layout.\n *\n * @param props - The component props.\n * @returns The rendered tab button.\n */\nexport function MobileTabButton({\n label,\n active,\n onClick,\n icon: Icon,\n}: MobileTabButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={clsx(\n 'flex-1 flex items-center justify-center gap-2 h-10',\n 'text-sm',\n 'transition-colors',\n active && 'border-b-2 border-neutral-200 font-medium'\n )}\n >\n <Icon size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n {label}\n </button>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { IconEdit, IconEye } from '@tabler/icons-react'\nimport { MobileTabButton } from './MobileTabButton'\n\n/**\n * The available tab options for the mobile playground.\n */\nexport type MobileTab = 'editor' | 'preview'\n\n/**\n * Props for the MobileTabBar component.\n */\ninterface MobileTabBarProps {\n /** The currently active tab. */\n activeTab: MobileTab\n /** Callback when the active tab changes. */\n onTabChange: (tab: MobileTab) => void\n}\n\n/**\n * A tab bar component for switching between Editor and Preview on mobile devices.\n * This component is only visible on small screens (hidden on md+).\n *\n * @param props - The component props.\n * @returns The rendered tab bar.\n */\nexport function MobileTabBar({ activeTab, onTabChange }: MobileTabBarProps) {\n return (\n <div className=\"flex md:hidden border-b border-neutral-400\">\n <MobileTabButton\n label=\"Editor\"\n icon={IconEdit}\n active={activeTab === 'editor'}\n onClick={() => onTabChange('editor')}\n />\n <MobileTabButton\n label=\"Preview\"\n icon={IconEye}\n active={activeTab === 'preview'}\n onClick={() => onTabChange('preview')}\n />\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport { type ReactNode, useState } from 'react'\nimport { type MobileTab, MobileTabBar } from './MobileTabBar'\n\n/**\n * Props for the PlaygroundMobile component.\n */\nexport interface PlaygroundMobileProps {\n /** The editor panel content to render. */\n editorPanel: ReactNode\n /** The preview panel content to render. */\n previewPanel: ReactNode\n}\n\n/**\n * The mobile layout component for the playground.\n * Shows either the editor or preview panel based on the active tab.\n * This component is only visible on small screens (hidden on md+).\n *\n * @param props - The component props.\n * @returns The rendered mobile layout.\n */\nexport function PlaygroundMobile({\n editorPanel,\n previewPanel,\n}: PlaygroundMobileProps) {\n const [activeTab, setActiveTab] = useState<MobileTab>('editor')\n\n return (\n <div className=\"flex-1 flex flex-col gap-2 overflow-hidden md:hidden\">\n <MobileTabBar activeTab={activeTab} onTabChange={setActiveTab} />\n <div\n className={clsx(\n 'flex-1 flex-col min-h-0',\n activeTab === 'editor' ? 'flex' : 'hidden'\n )}\n >\n {editorPanel}\n </div>\n <div\n className={clsx(\n 'flex-1 flex-col min-h-0',\n activeTab === 'preview' ? 'flex' : 'hidden'\n )}\n >\n {previewPanel}\n </div>\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Editor } from '@/components'\n\n/**\n * Props for the CodeViewer component.\n */\nexport interface CodeViewerProps {\n /** The code content to display. */\n content: string\n /** The language of the code (markdown or latex). */\n language: 'markdown' | 'latex' | 'yaml'\n}\n\n/**\n * Component to preview code (Markdown or LaTeX) using Monaco Editor.\n *\n * @param props - The props for the CodePreview component.\n * @returns The rendered Monaco Editor.\n */\nexport function CodeViewer({ content, language }: CodeViewerProps) {\n return (\n <Editor\n language={language}\n value={content}\n readOnly={true}\n minimap={false}\n lineNumbers={false}\n />\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { renderAsync } from 'docx-preview'\nimport { useEffect, useRef, useState } from 'react'\n\n/**\n * Props for the DocxViewer component.\n */\nexport interface DocxViewerProps {\n /** The DOCX binary content to render. */\n content: Uint8Array | null\n}\n\n/**\n * Component to preview DOCX content by rendering it to HTML via docx-preview.\n *\n * @param props - The props for the DocxViewer component.\n * @returns The rendered DocxViewer component.\n */\nexport function DocxViewer({ content }: DocxViewerProps) {\n const containerRef = useRef<HTMLDivElement>(null)\n const [error, setError] = useState<string | null>(null)\n const [loading, setLoading] = useState<boolean>(false)\n\n useEffect(() => {\n if (!content || !containerRef.current) {\n setError(null)\n setLoading(false)\n return () => {}\n }\n\n setLoading(true)\n setError(null)\n\n const container = containerRef.current\n\n renderAsync(content, container, undefined, {\n className: 'docx',\n inWrapper: true,\n })\n .then(() => {\n setLoading(false)\n })\n .catch((e) => {\n setLoading(false)\n setError(\n `DOCX Render Error: ${e instanceof Error ? e.message : String(e)}`\n )\n })\n\n return () => {\n container.innerHTML = ''\n }\n }, [content])\n\n if (!content) {\n return (\n <div className=\"h-full w-full flex items-center justify-center text-gray-500 bg-gray-50\">\n No DOCX content to preview.\n </div>\n )\n }\n\n if (error) {\n return (\n <div\n role=\"alert\"\n aria-live=\"polite\"\n className=\"h-full w-full p-4 font-mono text-red-500 bg-red-50 border border-red-200\"\n >\n {error}\n </div>\n )\n }\n\n return (\n <div className=\"h-full w-full overflow-auto bg-white relative\">\n {loading && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-white/80 z-10\">\n <div className=\"text-gray-500\">Loading DOCX preview…</div>\n </div>\n )}\n <div ref={containerRef} className=\"docx-preview-container\" />\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * Props for the HtmlViewer component.\n */\nexport interface HtmlViewerProps {\n /** The HTML content to render. */\n content: string\n}\n\n/**\n * Component to preview HTML content in an iframe.\n *\n * @param props - The props for the HtmlPreview component.\n * @returns The rendered iframe element.\n */\nexport function HtmlViewer({ content }: HtmlViewerProps) {\n return (\n <iframe\n title=\"Resume HTML Preview\"\n className=\"w-full h-full border-none\"\n srcDoc={content}\n />\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\n\nimport logo from '@/resources/logo.png'\n\n/**\n * A placeholder component shown when no resume layouts are defined.\n * Displays a logo and a helpful message.\n *\n * @returns The rendered empty state component.\n */\nexport function PreviewNoLayouts() {\n return (\n <div\n className={clsx(\n 'h-full w-full',\n 'flex flex-col items-center justify-center gap-4',\n 'text-neutral-200'\n )}\n >\n <img\n src={logo}\n alt=\"YAML Resume Logo\"\n className=\"w-32 h-32 opacity-70 grayscale\"\n draggable={false}\n />\n <div className=\"text-lg font-medium\">No Layouts Defined</div>\n <p className=\"max-w-xs text-center text-sm text-neutral-400\">\n Your resume appears to be empty or contains no layout definitions.\n </p>\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n IconFileText,\n IconHtml,\n IconMarkdown,\n IconTex,\n} from '@tabler/icons-react'\nimport type { LayoutEngine } from '@yamlresume/core'\nimport clsx from 'clsx'\n\nimport { EDITOR_BG_COLOR, ICON_SIZES, ICON_STROKES } from '@/constants'\nimport { getExtension } from '@/utils'\n\n/**\n * Props for the PreviewTab component.\n */\ninterface PreviewTabProps {\n /** Whether this tab is currently active. */\n active: boolean\n /** Callback triggered when the tab is clicked. */\n onClick: () => void\n /** The layout engine (e.g., 'html', 'markdown') used for this tab. */\n engine: LayoutEngine\n /** The index of this layout in the resume configuration. */\n index: number\n /** The basename of the file (e.g., 'resume' from 'resume.yml'). */\n filename: string\n}\n\n/**\n * A tab button representing a specific resume layout.\n * Displays the engine icon and document name.\n *\n * @param props - The component props.\n * @returns The rendered tab button.\n */\nexport function getTabIcon(engine: LayoutEngine) {\n switch (engine) {\n case 'html':\n return <IconHtml size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n case 'markdown':\n return <IconMarkdown size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n case 'latex':\n return <IconTex size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n default:\n return <IconFileText size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n }\n}\n\nexport function PreviewTab({\n active,\n onClick,\n engine,\n index,\n filename,\n}: PreviewTabProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={clsx(\n 'flex items-center gap-2 max-w-[200px]',\n 'h-full px-4',\n 'transition-colors border-r border-neutral-600 last:border-neutral-400'\n )}\n title={`${filename}.${index}${getExtension(engine)}`}\n role=\"tab\"\n aria-selected={active}\n style={{\n backgroundColor: active && EDITOR_BG_COLOR,\n }}\n >\n {getTabIcon(engine)}\n <span className=\"truncate\">\n {filename}.{index}\n {getExtension(engine)}\n </span>\n </button>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { PropsWithChildren } from 'react'\n\n/**\n * A scrollable container for preview tabs.\n *\n * @param props - The component props.\n * @returns The rendered tabs container.\n */\nexport function PreviewTabs({ children }: PropsWithChildren) {\n return (\n <div role=\"tablist\" className={clsx('flex h-full overflow-x-auto')}>\n {children}\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { Resume } from '@yamlresume/core'\nimport clsx from 'clsx'\nimport { useResumeRenderer } from '../../hooks'\nimport { CodeViewer } from './CodeViewer'\nimport { DocxViewer } from './DocxViewer'\nimport { HtmlViewer } from './HtmlViewer'\n\n/**\n * Props for the ResumeViewer component.\n */\nexport interface ResumeViewerProps {\n /** The pre-parsed resume object. */\n resume: Resume | null\n /** The index of the layout to use for rendering. */\n layoutIndex: number\n}\n\n/**\n * ResumeViewer component responsible for rendering the appropriate preview\n * (HTML, Markdown, LaTeX, or DOCX) based on the selected layout.\n *\n * @param props - The props for the ResumeViewer component.\n * @returns The rendered ResumeViewer component.\n */\nexport function ResumeViewer({ resume, layoutIndex }: ResumeViewerProps) {\n const { renderedContent, binaryContent, engine, error } = useResumeRenderer({\n resume,\n layoutIndex,\n })\n\n if (error) {\n return (\n <div\n role=\"alert\"\n aria-live=\"polite\"\n className={clsx(\n 'h-full w-full p-4',\n 'font-mono text-red-500 bg-red-50',\n 'border border-red-200'\n )}\n >\n {error}\n </div>\n )\n }\n\n if (engine === 'docx') {\n return <DocxViewer content={binaryContent} />\n }\n\n return (\n <div className=\"h-full w-full flex flex-col bg-white\">\n {engine === 'html' ? (\n <HtmlViewer content={renderedContent} />\n ) : (\n <CodeViewer content={renderedContent} language={engine} />\n )}\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n IconDownload,\n IconExternalLink,\n IconPrinter,\n} from '@tabler/icons-react'\nimport type { Resume } from '@yamlresume/core'\nimport { useCallback, useMemo } from 'react'\n\nimport {\n Panel,\n PanelContent,\n PanelToolbar,\n ToolbarButton,\n ToolbarCopyButton,\n ToolbarSeparator,\n} from '@/components'\nimport { ICON_SIZES, ICON_STROKES } from '@/constants'\nimport type { PlaygroundTooltipMessages } from '@/messages'\nimport {\n copyResumeToClipboard,\n downloadResume,\n getBasename,\n openResumeInNewTab,\n printResume,\n} from '@/utils'\n\nimport { PreviewNoLayouts } from './PreviewNoLayouts'\nimport { PreviewTab } from './PreviewTab'\nimport { PreviewTabs } from './PreviewTabs'\nimport { ResumeViewer } from './ResumeViewer'\n\n/**\n * Props for the PreviewPanel component.\n */\nexport interface PreviewPanelProps {\n /** The index of the currently active layout. */\n activeLayoutIndex: number\n /** The name of the file being edited. */\n filename?: string\n /** The parsed resume object. */\n resume: Resume | null\n /** Callback to change the active layout index. */\n setActiveLayoutIndex: (index: number) => void\n /** Localized tooltip labels for preview actions. */\n tooltips: Pick<\n PlaygroundTooltipMessages,\n 'copy' | 'print' | 'openInNewTab' | 'download'\n >\n}\n\n/**\n * A panel component containing the resume preview, layout selector tabs, and actions.\n *\n * @param props - The component props.\n * @returns The rendered preview panel.\n */\nexport function PreviewPanel({\n activeLayoutIndex,\n filename,\n resume,\n setActiveLayoutIndex,\n tooltips,\n}: PreviewPanelProps) {\n // Filter out invalid layouts (null or missing engine property)\n // This can happen when user is typing incomplete YAML like \"- \" in layouts array\n const validLayouts = useMemo(() => {\n return (resume?.layouts || [])\n .map((layout, originalIndex) => ({ layout, originalIndex }))\n .filter(\n (item) =>\n item.layout !== null &&\n item.layout !== undefined &&\n typeof item.layout.engine === 'string'\n )\n }, [resume?.layouts])\n\n const basename = getBasename(filename, true) || 'resume'\n\n const handleCopy = useCallback(() => {\n copyResumeToClipboard(resume, activeLayoutIndex)\n }, [resume, activeLayoutIndex])\n\n const handlePrint = useCallback(() => {\n printResume(resume, activeLayoutIndex)\n }, [resume, activeLayoutIndex])\n\n const handleOpenInNewTab = useCallback(() => {\n openResumeInNewTab(resume, activeLayoutIndex)\n }, [resume, activeLayoutIndex])\n\n const handleDownload = useCallback(() => {\n downloadResume(resume, activeLayoutIndex)\n }, [resume, activeLayoutIndex])\n\n if (validLayouts.length === 0) {\n return (\n <Panel>\n <PanelToolbar />\n <PreviewNoLayouts />\n </Panel>\n )\n }\n\n return (\n <Panel>\n <PanelToolbar>\n <PreviewTabs>\n {validLayouts.map(({ layout, originalIndex }) => (\n <PreviewTab\n key={`${layout.engine}-${originalIndex}`}\n active={activeLayoutIndex === originalIndex}\n onClick={() => setActiveLayoutIndex(originalIndex)}\n engine={layout.engine}\n index={originalIndex}\n filename={basename}\n />\n ))}\n </PreviewTabs>\n <div className=\"flex-1\" />\n <div className=\"flex items-center gap-0.5 pr-2\">\n <ToolbarCopyButton onClick={handleCopy} title={tooltips.copy} />\n <ToolbarSeparator />\n {resume?.layouts?.[activeLayoutIndex]?.engine === 'html' && (\n <>\n <ToolbarButton onClick={handlePrint} title={tooltips.print}>\n <IconPrinter size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n <ToolbarButton\n onClick={handleOpenInNewTab}\n title={tooltips.openInNewTab}\n >\n <IconExternalLink\n size={ICON_SIZES.sm}\n stroke={ICON_STROKES.sm}\n />\n </ToolbarButton>\n <ToolbarSeparator />\n </>\n )}\n <ToolbarButton onClick={handleDownload} title={tooltips.download}>\n <IconDownload size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n </div>\n </PanelToolbar>\n <PanelContent>\n <ResumeViewer resume={resume} layoutIndex={activeLayoutIndex} />\n </PanelContent>\n </Panel>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { PropsWithChildren } from 'react'\n\n/**\n * A styled panel container component for the Playground.\n *\n * Provides consistent styling including:\n * - Flexbox layout for content organization\n * - Shadow effect for visual depth\n * - Border styling for clear boundaries\n *\n * @param props - The component props.\n * @returns The rendered panel container.\n */\nexport function Panel({ children }: PropsWithChildren) {\n return (\n <div\n className={clsx(\n 'flex-1 flex flex-col',\n 'border border-neutral-400 overflow-hidden'\n )}\n >\n {children}\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { PropsWithChildren } from 'react'\n\n/**\n * A shared container for panel content.\n * Provides a flexible layout for the main content area of a panel.\n *\n * @param props - The component props.\n * @returns The rendered content container.\n */\nexport function PanelContent({ children }: PropsWithChildren) {\n return <div className=\"flex-1 relative min-h-0\">{children}</div>\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport { Separator } from 'react-resizable-panels'\n\n/**\n * A separator component for the Playground.\n *\n * @returns The rendered separator.\n */\nexport function PanelSeparator() {\n return (\n <Separator\n className={clsx(\n 'w-2',\n 'flex flex-col justify-center items-center group',\n 'transition-colors cursor-col-resize'\n )}\n data-testid=\"separator\"\n >\n <div\n className={clsx(\n 'w-1 h-8',\n 'bg-neutral-400',\n 'group-hover:bg-neutral-300'\n )}\n />\n </Separator>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { PropsWithChildren } from 'react'\n\n/**\n * A shared toolbar component for panels.\n *\n * @param props - The component props.\n * @returns The rendered toolbar.\n */\nexport function PanelToolbar({ children }: PropsWithChildren) {\n return (\n <div\n className={clsx(\n 'flex items-center border-b border-neutral-400 h-10 text-sm shrink-0',\n 'bg-neutral-800'\n )}\n >\n {children}\n </div>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport clsx from 'clsx'\nimport type { ReactNode } from 'react'\n\n/**\n * Props for the ToolbarButton component.\n */\nexport interface ToolbarButtonProps {\n /** Callback triggered when the button is clicked. */\n onClick: () => void\n /** The content to be rendered inside the button, typically an icon. */\n children: ReactNode\n /** The tooltip text displayed when hovering over the button. */\n title: string\n}\n\n/**\n * A generic button component used in the playground toolbar.\n *\n * It provides consistent styling and behavior for all toolbar actions.\n *\n * @param props - The component props.\n * @returns The rendered toolbar button.\n */\nexport function ToolbarButton({\n onClick,\n children,\n title,\n}: ToolbarButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={clsx(\n 'flex items-center justify-center h-8 w-8',\n 'text-neutral-200 hover:text-neutral-700 hover:bg-neutral-200',\n 'transition-colors',\n 'focus:outline-none focus:ring-1 focus:ring-neutral-400'\n )}\n title={title}\n >\n {children}\n </button>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { IconCheck, IconCopy } from '@tabler/icons-react'\nimport { useState } from 'react'\n\nimport { ICON_SIZES, ICON_STROKES } from '@/constants'\nimport { ToolbarButton } from './ToolbarButton'\n\n/**\n * Props for the ToolbarCopyButton component.\n */\nexport interface ToolbarCopyButtonProps {\n /** Callback triggered to perform the copy action. Can be async. */\n onClick: () => Promise<void> | void\n /** The tooltip text. Defaults to 'Copy'. */\n title?: string\n}\n\n/**\n * A toolbar button for copying content to the clipboard.\n * It temporarily changes the icon to a checkmark upon successful copy.\n *\n * @param props - The component props.\n * @returns The rendered copy button.\n */\nexport function ToolbarCopyButton({\n onClick,\n title = 'Copy',\n}: ToolbarCopyButtonProps) {\n const [hasCopied, setHasCopied] = useState(false)\n\n const handleCopy = async () => {\n try {\n await onClick()\n setHasCopied(true)\n setTimeout(() => setHasCopied(false), 2000)\n } catch (e) {\n console.error('Failed to copy', e)\n }\n }\n\n return (\n <ToolbarButton onClick={handleCopy} title={title}>\n {hasCopied ? (\n <IconCheck size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n ) : (\n <IconCopy size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n )}\n </ToolbarButton>\n )\n}\n","/**\n * MIT License\n *\n * Copyright (c) 2023–Present PPResume (https://ppresume.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * A toolbar separator component.\n *\n * @returns The rendered separator.\n */\nexport function ToolbarSeparator() {\n return <div className=\"w-px h-4 bg-neutral-400 mx-1\" />\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yamlresume/playground",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"description": "Shared playground component for YAMLResume",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -45,17 +45,17 @@
|
|
|
45
45
|
"next-themes": "^0.4.6",
|
|
46
46
|
"react-resizable-panels": "^4.7.2",
|
|
47
47
|
"yaml": "^2.8.3",
|
|
48
|
-
"@yamlresume/core": "0.13.
|
|
48
|
+
"@yamlresume/core": "0.13.2"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@testing-library/react": "^16.3.2",
|
|
52
|
-
"@types/react": "^
|
|
53
|
-
"@types/react-dom": "^
|
|
54
|
-
"@vitejs/plugin-react": "^
|
|
55
|
-
"jsdom": "^29.
|
|
52
|
+
"@types/react": "^19.2.17",
|
|
53
|
+
"@types/react-dom": "^19.2.3",
|
|
54
|
+
"@vitejs/plugin-react": "^6.0.3",
|
|
55
|
+
"jsdom": "^29.1.1",
|
|
56
56
|
"monaco-editor": "^0.55.1",
|
|
57
|
-
"react": "^
|
|
58
|
-
"react-dom": "^
|
|
57
|
+
"react": "^19.2.7",
|
|
58
|
+
"react-dom": "^19.2.7"
|
|
59
59
|
},
|
|
60
60
|
"publishConfig": {
|
|
61
61
|
"access": "public"
|