@yamlresume/playground 0.11.0
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/LICENSE +21 -0
- package/README.md +172 -0
- package/dist/index.d.ts +693 -0
- package/dist/index.js +289 -0
- package/dist/index.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +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/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/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","content","getResumeRenderer","layout","extension","filename","blob","url","a","e","copyResumeToClipboard","printResume","iframe","doc","openResumeInNewTab","EditorTitle","jsxs","clsx","IconFileCode","ResumeEditor","EditorPanel","editorRef","useRef","handleEditorMount","editor","handleUndo","useCallback","handleRedo","handleCopy","handleClear","Panel","PanelToolbar","ToolbarCopyButton","ToolbarSeparator","ToolbarButton","IconArrowBackUp","IconArrowForwardUp","IconEraser","PanelContent","useResumeRenderer","renderedContent","setRenderedContent","useState","setEngine","error","setError","useEffect","currentEngine","renderer","default_resume_default","useResumeState","yaml","activeLayoutIndex","setActiveLayoutIndex","handleYamlChange","v","useMemo","parse","Playground","yamlStr","editorPanel","previewPanel","PreviewPanel","PlaygroundMobile","PlaygroundDesktop","Group","PanelSeparator","MobileTabButton","label","active","onClick","Icon","MobileTabBar","activeTab","onTabChange","IconEdit","IconEye","setActiveTab","CodeViewer","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":";;;;;;;;;AAwBO,IAAMA,EAAa,CACxB,EAAA,CAAI,GACJ,EAAA,CAAI,EAAA,CACJ,EAAA,CAAI,EAAA,CACJ,GAAI,EAAA,CACJ,EAAA,CAAI,EACN,CAAA,CAEaC,CAAAA,CAAe,CAC1B,EAAA,CAAI,CAAA,CACJ,EAAA,CAAI,IAAA,CACJ,GAAI,GAAA,CACJ,EAAA,CAAI,KACJ,EAAA,CAAI,CACN,EAGaC,CAAAA,CAAkB,SAAA,CAGlBC,EAAAA,CAAmB,GCRhC,SAASC,EAAAA,CAAsBC,CAAAA,CAAgB,CAE7C,IAAMC,CAAAA,CAA4C,CAChD,WAAA,CAAa,QACb,IAAA,CAAM,OAAA,CACN,UAAW,CAAC,YAAA,CAAc,UAAU,CAAA,CACpC,cAAA,CAAgB,CAAC,KAAA,CAAO,MAAO,KAAK,CAAA,CAEpC,aAAc,QAAA,CACd,YAAA,CAAc,GAEd,QAAA,CAAU,CACR,iBAAA,CACA,eAAA,CACA,eACA,SAAA,CACA,aAAA,CACA,YACA,MAAA,CACA,UAAA,CACA,SACA,QAAA,CACA,WAAA,CACA,eACA,iBAAA,CACA,IAAA,CACA,UACA,eAAA,CACA,SAAA,CACA,WACA,YAAA,CACA,KAAA,CACA,UACA,OAAA,CACA,WAAA,CACA,SAAA,CACA,QAAA,CACA,OACA,iBAAA,CACA,WAAA,CACA,QACA,SAAA,CACA,OAAA,CACA,YACA,SAAA,CACA,MAAA,CACA,OAAA,CACA,eAAA,CACA,UACA,IAAA,CACA,MAAA,CACA,aACA,UAAA,CACA,MAAA,CACA,OACA,aAAA,CACA,UAAA,CACA,UAAA,CACA,cAAA,CACA,eACA,cAAA,CACA,MAAA,CACA,QACA,UAAA,CACA,eAAA,CACA,QACA,OAAA,CACA,MAAA,CACA,YACA,QAAA,CACA,MAAA,CACA,OACA,aAAA,CACA,SAAA,CACA,kBACA,aAAA,CACA,QAAA,CACA,QACA,IAAA,CACA,MAAA,CACA,MAAA,CACA,OAAA,CACA,QACA,OAAA,CACA,OAAA,CACA,QACA,QAAA,CACA,OAAA,CACA,OACA,SAAA,CACA,MAAA,CACA,WAAA,CACA,eAAA,CACA,YACA,eAAA,CACA,cAAA,CACA,WACA,SAAA,CACA,WAAA,CACA,WACA,SAAA,CACA,QAAA,CACA,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,MAAA,CACA,WAAA,CACA,WACA,WAAA,CACA,eAAA,CACA,UACA,WAAA,CACA,KAAA,CACA,YACA,QAAA,CACA,WAAA,CACA,SAAA,CACA,MAAA,CACA,UACA,gBAAA,CACA,KAAA,CACA,eACA,YAAA,CACA,aAAA,CACA,WACA,KAAA,CACA,cAAA,CACA,OAAA,CACA,IAAA,CACA,QACA,MAAA,CACA,SAAA,CACA,OACA,IAAA,CACA,YAAA,CACA,UACA,YAAA,CACA,WAAA,CACA,YAAA,CACA,IAAA,CACA,aACA,WAAA,CACA,IAAA,CACA,QACA,OAAA,CACA,WAAA,CACA,OACA,OAAA,CACA,MAAA,CACA,UAAA,CACA,aAAA,CACA,eACA,YAAA,CACA,eAAA,CACA,kBACA,WAAA,CACA,KAAA,CACA,SACA,WAAA,CACA,QAAA,CACA,QAAA,CACA,YAAA,CACA,SACA,QAAA,CACA,QAAA,CACA,SACA,QAAA,CACA,QAAA,CACA,YACA,YAAA,CACA,QAAA,CACA,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,UAAA,CACA,QAAA,CAEA,iBACA,gBAAA,CACA,YAAA,CACA,QACA,SAAA,CACA,eAAA,CACA,gBACA,KAAA,CACA,MAAA,CACA,YAAA,CACA,IAAA,CACA,QACA,OAAA,CACA,KAAA,CACA,KACA,MAAA,CACA,Y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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 /** 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 }}\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 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 = (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 download')\n return\n }\n\n const renderer = getResumeRenderer(resume, layoutIndex)\n const content = renderer.render()\n const layout = layouts[layoutIndex]\n const extension = getExtension(layout.engine)\n const filename = `resume.${layoutIndex}${extension}`\n\n const blob = 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\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\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\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'\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}\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({ value, onChange, filename }: 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} />\n <ToolbarSeparator />\n <ToolbarButton onClick={handleUndo} title=\"Undo\">\n <IconArrowBackUp size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n <ToolbarButton onClick={handleRedo} title=\"Redo\">\n <IconArrowForwardUp size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n <ToolbarSeparator />\n <ToolbarButton onClick={handleClear} title=\"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 [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 setRenderedContent(renderer.render())\n setError(null)\n } catch (e) {\n setError(`Render Error: ${e instanceof Error ? e.message : String(e)}`)\n }\n }, [resume, layoutIndex])\n\n return {\n renderedContent,\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'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 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}\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}: PlaygroundProps) {\n const {\n yaml,\n handleYamlChange,\n activeLayoutIndex,\n setActiveLayoutIndex,\n resume,\n } = useResumeState({\n yaml: yamlStr,\n onChange,\n })\n\n // Create editor panel element\n const editorPanel = (\n <EditorPanel\n value={yaml}\n onChange={(v) => handleYamlChange(v || '')}\n filename={filename}\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 />\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\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 { 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, or LaTeX) 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, 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 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 {\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}\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}: 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} />\n <ToolbarSeparator />\n {resume?.layouts?.[activeLayoutIndex]?.engine === 'html' && (\n <>\n <ToolbarButton onClick={handlePrint} title=\"Print\">\n <IconPrinter size={ICON_SIZES.sm} stroke={ICON_STROKES.sm} />\n </ToolbarButton>\n <ToolbarButton\n onClick={handleOpenInNewTab}\n title=\"Open in New Tab\"\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=\"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"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yamlresume/playground",
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"description": "Shared playground component for YAMLResume",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "YAMLResume",
|
|
8
|
+
"email": "support@yamlresume.com",
|
|
9
|
+
"url": "https://yamlresume.dev"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/yamlresume/yamlresume.git",
|
|
14
|
+
"directory": "packages/playground"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/yamlresume/yamlresume/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://yamlresume.dev/playground",
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": ">=18",
|
|
36
|
+
"react-dom": ">=18",
|
|
37
|
+
"tailwindcss": ">=3"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@monaco-editor/react": "^4.6.0",
|
|
41
|
+
"@tabler/icons-react": "^3.36.1",
|
|
42
|
+
"clsx": "^2.1.1",
|
|
43
|
+
"next-themes": "^0.4.6",
|
|
44
|
+
"react-resizable-panels": "^4.4.1",
|
|
45
|
+
"yaml": "^2.8.2",
|
|
46
|
+
"@yamlresume/core": "0.11.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@testing-library/react": "^16.3.2",
|
|
50
|
+
"@types/react": "^18.2.0",
|
|
51
|
+
"@types/react-dom": "^18.2.0",
|
|
52
|
+
"@vitejs/plugin-react": "^4.7.0",
|
|
53
|
+
"jsdom": "^27.4.0",
|
|
54
|
+
"monaco-editor": "^0.55.1",
|
|
55
|
+
"react": "^18.2.0",
|
|
56
|
+
"react-dom": "^18.2.0"
|
|
57
|
+
},
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsup",
|
|
63
|
+
"build:prod": "tsup --dts --minify --sourcemap",
|
|
64
|
+
"build:watch": "tsup --watch",
|
|
65
|
+
"build:clean": "rm -rf dist",
|
|
66
|
+
"test": "vitest --run",
|
|
67
|
+
"test:cov": "vitest --coverage --run",
|
|
68
|
+
"test:watch": "vitest",
|
|
69
|
+
"lint": "biome check src"
|
|
70
|
+
}
|
|
71
|
+
}
|