@recruitnepal/shared-packages 1.5.0 → 1.6.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/dist/components/cv/TemplatePicker.d.ts +14 -0
- package/dist/components/cv/TemplatePicker.d.ts.map +1 -0
- package/dist/components/cv/TemplatePicker.js +161 -0
- package/dist/components/cv/TemplateRenderer.d.ts +20 -0
- package/dist/components/cv/TemplateRenderer.d.ts.map +1 -0
- package/dist/components/cv/TemplateRenderer.js +14 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/stores/cvDrafts.store.d.ts +44 -0
- package/dist/stores/cvDrafts.store.d.ts.map +1 -0
- package/dist/stores/cvDrafts.store.js +86 -0
- package/dist/stores/cvLayout.store.d.ts +24 -0
- package/dist/stores/cvLayout.store.d.ts.map +1 -0
- package/dist/stores/cvLayout.store.js +116 -0
- package/dist/stores/cvPreview.store.d.ts +29 -0
- package/dist/stores/cvPreview.store.d.ts.map +1 -0
- package/dist/stores/cvPreview.store.js +80 -0
- package/dist/types/cv-blocks.types.d.ts +44 -0
- package/dist/types/cv-blocks.types.d.ts.map +1 -0
- package/dist/types/cv-blocks.types.js +1 -0
- package/dist/types/cv-draft.types.d.ts +32 -0
- package/dist/types/cv-draft.types.d.ts.map +1 -0
- package/dist/types/cv-draft.types.js +1 -0
- package/dist/types/template.types.d.ts +122 -0
- package/dist/types/template.types.d.ts.map +1 -0
- package/dist/types/template.types.js +1 -0
- package/dist/utils/cv/pdf/printReset.d.ts +3 -0
- package/dist/utils/cv/pdf/printReset.d.ts.map +1 -0
- package/dist/utils/cv/pdf/printReset.js +41 -0
- package/dist/utils/cv/pdf/styles/base.d.ts +2 -0
- package/dist/utils/cv/pdf/styles/base.d.ts.map +1 -0
- package/dist/utils/cv/pdf/styles/base.js +44 -0
- package/dist/utils/cv/pdf/styles/preprocessCssClient.d.ts +3 -0
- package/dist/utils/cv/pdf/styles/preprocessCssClient.d.ts.map +1 -0
- package/dist/utils/cv/pdf/styles/preprocessCssClient.js +33 -0
- package/dist/utils/cv-block-converter.d.ts +11 -0
- package/dist/utils/cv-block-converter.d.ts.map +1 -0
- package/dist/utils/cv-block-converter.js +83 -0
- package/package.json +1 -44
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TemplateData } from '../../types/template.types';
|
|
2
|
+
import type { CvTemplateRegistry } from './TemplateRenderer';
|
|
3
|
+
export declare function generateSampleTemplateData(seed: string): TemplateData;
|
|
4
|
+
export type TemplatePickerProps = {
|
|
5
|
+
/** Template registry from the host app */
|
|
6
|
+
registry: CvTemplateRegistry;
|
|
7
|
+
/** Optional list of slugs to show; defaults to Object.keys(registry) */
|
|
8
|
+
allowedSlugs?: string[];
|
|
9
|
+
/** Optional display names: slug -> title */
|
|
10
|
+
slugTitles?: Record<string, string>;
|
|
11
|
+
onPicked: (slug: string) => void;
|
|
12
|
+
};
|
|
13
|
+
export default function TemplatePicker({ registry, allowedSlugs, slugTitles, onPicked, }: TemplatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=TemplatePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/cv/TemplatePicker.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AA0B7D,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAqFrE;AAuED,MAAM,MAAM,mBAAmB,GAAG;IAChC,0CAA0C;IAC1C,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC,CAAC;AA+BF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,QAAQ,EACR,YAAY,EACZ,UAAe,EACf,QAAQ,GACT,EAAE,mBAAmB,2CAwBrB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useLayoutEffect, useRef, useState } from 'react';
|
|
4
|
+
import TemplateRenderer from './TemplateRenderer';
|
|
5
|
+
const FIRST_NAMES = ['Prakash', 'Bikash', 'Nabin', 'Suresh', 'Raj', 'Amit', 'Kumar', 'Sita', 'Gita', 'Pooja'];
|
|
6
|
+
const LAST_NAMES = ['Shrestha', 'Pradhan', 'Sharma', 'Pandey', 'Thapa', 'Karki', 'Gurung', 'Rai', 'Tamang', 'Lama'];
|
|
7
|
+
const TITLES = ['Software Engineer', 'Data Scientist', 'Product Manager', 'Frontend Developer', 'Full Stack Engineer'];
|
|
8
|
+
const COMPANIES = ['TechCorp', 'InnovateLab', 'Digital Solutions', 'Cloud Systems', 'Smart Solutions'];
|
|
9
|
+
const CITIES = ['Kathmandu', 'Pokhara', 'Lalitpur', 'Bhaktapur', 'Biratnagar'];
|
|
10
|
+
const INSTITUTIONS = ['Kathmandu University', 'Tribhuvan University', 'Pokhara University', 'NEC'];
|
|
11
|
+
const DEGREES = ['B.E.', 'B.Sc.', 'M.Sc.', 'M.B.A.'];
|
|
12
|
+
const FIELDS = ['Computer Engineering', 'Computer Science', 'Information Technology', 'Data Science'];
|
|
13
|
+
const PROJECT_NAMES = ['E-Commerce Platform', 'Task Management System', 'Analytics Dashboard', 'Mobile Banking App'];
|
|
14
|
+
const TECH_STACKS = [['React', 'Next.js', 'TypeScript'], ['Python', 'Django', 'PostgreSQL'], ['Node.js', 'Express', 'MongoDB']];
|
|
15
|
+
function seededRandom(seed) {
|
|
16
|
+
let h = 0;
|
|
17
|
+
for (let i = 0; i < seed.length; i++) {
|
|
18
|
+
h = ((h << 5) - h + seed.charCodeAt(i)) | 0;
|
|
19
|
+
}
|
|
20
|
+
return function next() {
|
|
21
|
+
h = (Math.imul(1664525, h) + 1013904223) >>> 0;
|
|
22
|
+
return h / 0x100000000;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const pick = (rng, arr) => arr[Math.floor(rng() * arr.length)];
|
|
26
|
+
export function generateSampleTemplateData(seed) {
|
|
27
|
+
const rng = seededRandom(seed);
|
|
28
|
+
const randomItem = (arr) => pick(rng, arr);
|
|
29
|
+
const firstName = randomItem(FIRST_NAMES);
|
|
30
|
+
const lastName = randomItem(LAST_NAMES);
|
|
31
|
+
const title = randomItem(TITLES);
|
|
32
|
+
const company = randomItem(COMPANIES);
|
|
33
|
+
const city = randomItem(CITIES);
|
|
34
|
+
const institution = randomItem(INSTITUTIONS);
|
|
35
|
+
const degree = randomItem(DEGREES);
|
|
36
|
+
const field = randomItem(FIELDS);
|
|
37
|
+
const projectName = randomItem(PROJECT_NAMES);
|
|
38
|
+
const techStack = randomItem(TECH_STACKS);
|
|
39
|
+
const currentYear = new Date().getFullYear();
|
|
40
|
+
const startYear = currentYear - Math.floor(rng() * 5) - 1;
|
|
41
|
+
const endYear = currentYear - Math.floor(rng() * 2);
|
|
42
|
+
const eduStartYear = startYear - 4;
|
|
43
|
+
const eduEndYear = startYear;
|
|
44
|
+
const gpa = (3.0 + rng() * 1.0).toFixed(1);
|
|
45
|
+
return {
|
|
46
|
+
personalInfo: {
|
|
47
|
+
firstName,
|
|
48
|
+
lastName,
|
|
49
|
+
title,
|
|
50
|
+
email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`,
|
|
51
|
+
phone: `+977-98${Math.floor(rng() * 10000000).toString().padStart(7, '0')}`,
|
|
52
|
+
location: { city },
|
|
53
|
+
summary: `${title} specializing in modern technologies.`,
|
|
54
|
+
links: [
|
|
55
|
+
{ type: 'LinkedIn', label: `linkedin.com/in/${firstName.toLowerCase()}`, url: `https://linkedin.com/in/${firstName.toLowerCase()}` },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
sections: {
|
|
59
|
+
experience: [
|
|
60
|
+
{
|
|
61
|
+
id: 'exp1',
|
|
62
|
+
position: title,
|
|
63
|
+
company,
|
|
64
|
+
location: city,
|
|
65
|
+
startDate: `${startYear}-01-01`,
|
|
66
|
+
endDate: `${endYear}-12-31`,
|
|
67
|
+
current: rng() > 0.5,
|
|
68
|
+
description: `Responsible for developing solutions.`,
|
|
69
|
+
highlights: ['Improved performance.', 'Led implementation.'],
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
education: [
|
|
73
|
+
{
|
|
74
|
+
id: 'edu1',
|
|
75
|
+
degree,
|
|
76
|
+
field,
|
|
77
|
+
institution,
|
|
78
|
+
location: city,
|
|
79
|
+
startDate: `${eduStartYear}-01-01`,
|
|
80
|
+
endDate: `${eduEndYear}-12-31`,
|
|
81
|
+
current: false,
|
|
82
|
+
gpa: `${gpa}/4.0`,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
projects: [
|
|
86
|
+
{
|
|
87
|
+
id: 'prj1',
|
|
88
|
+
name: projectName,
|
|
89
|
+
description: `A comprehensive ${projectName.toLowerCase()} built with modern technologies.`,
|
|
90
|
+
technologies: techStack,
|
|
91
|
+
url: `https://example.com`,
|
|
92
|
+
startDate: `${endYear - 1}-01-01`,
|
|
93
|
+
endDate: `${endYear - 1}-10-01`,
|
|
94
|
+
highlights: ['Implemented core features.', 'Deployed to production.'],
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
skills: [
|
|
98
|
+
{ id: 's1', category: 'Languages', skills: techStack.slice(0, 3).map((name) => ({ name })) },
|
|
99
|
+
{ id: 's2', category: 'Tools', skills: ['Git', 'Docker', 'AWS'].map((name) => ({ name })) },
|
|
100
|
+
],
|
|
101
|
+
certifications: [
|
|
102
|
+
{ id: 'c1', name: 'AWS Certified Cloud Practitioner', issuer: 'AWS', date: `${endYear - 1}-06-01` },
|
|
103
|
+
],
|
|
104
|
+
languages: [
|
|
105
|
+
{ id: 'l1', language: 'English', proficiency: 'professional' },
|
|
106
|
+
{ id: 'l2', language: 'Nepali', proficiency: 'native' },
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const MM_PER_IN = 25.4;
|
|
112
|
+
const DPI = 96;
|
|
113
|
+
const PDF_MARGINS_MM = { top: 10, bottom: 10, left: 10, right: 10 };
|
|
114
|
+
const mmToPx = (mm) => (mm / MM_PER_IN) * DPI;
|
|
115
|
+
const A4_W_PX = mmToPx(210);
|
|
116
|
+
const A4_H_PX = mmToPx(297);
|
|
117
|
+
const CONTENT_W_PX = A4_W_PX - mmToPx(PDF_MARGINS_MM.left + PDF_MARGINS_MM.right);
|
|
118
|
+
const CONTENT_H_PX = A4_H_PX - mmToPx(PDF_MARGINS_MM.top + PDF_MARGINS_MM.bottom);
|
|
119
|
+
function FitPreview({ registry, slug, data, }) {
|
|
120
|
+
const wrapRef = useRef(null);
|
|
121
|
+
const [scale, setScale] = useState(0.25);
|
|
122
|
+
useLayoutEffect(() => {
|
|
123
|
+
const update = () => {
|
|
124
|
+
const el = wrapRef.current;
|
|
125
|
+
if (!el)
|
|
126
|
+
return;
|
|
127
|
+
setScale(Math.max(0.1, el.clientWidth / CONTENT_W_PX));
|
|
128
|
+
};
|
|
129
|
+
update();
|
|
130
|
+
const ro = new ResizeObserver(update);
|
|
131
|
+
if (wrapRef.current)
|
|
132
|
+
ro.observe(wrapRef.current);
|
|
133
|
+
return () => ro.disconnect();
|
|
134
|
+
}, []);
|
|
135
|
+
return (_jsx("div", { ref: wrapRef, className: "relative w-full overflow-hidden rounded-xl bg-white", style: { aspectRatio: `${CONTENT_W_PX} / ${CONTENT_H_PX}` }, children: _jsx("div", { className: "absolute top-0 left-0", style: {
|
|
136
|
+
width: A4_W_PX,
|
|
137
|
+
height: A4_H_PX,
|
|
138
|
+
transform: `scale(${scale})`,
|
|
139
|
+
transformOrigin: 'top left',
|
|
140
|
+
pointerEvents: 'none',
|
|
141
|
+
}, children: _jsx("div", { style: {
|
|
142
|
+
position: 'relative',
|
|
143
|
+
width: '100%',
|
|
144
|
+
height: '100%',
|
|
145
|
+
paddingTop: mmToPx(PDF_MARGINS_MM.top),
|
|
146
|
+
paddingBottom: mmToPx(PDF_MARGINS_MM.bottom),
|
|
147
|
+
paddingLeft: mmToPx(PDF_MARGINS_MM.left),
|
|
148
|
+
paddingRight: mmToPx(PDF_MARGINS_MM.right),
|
|
149
|
+
boxSizing: 'border-box',
|
|
150
|
+
overflow: 'hidden',
|
|
151
|
+
}, children: _jsx(TemplateRenderer, { registry: registry, slug: slug, data: data, printMode: true }) }) }) }));
|
|
152
|
+
}
|
|
153
|
+
function TemplateCard({ registry, slug, title, onPick, }) {
|
|
154
|
+
const [templateData] = useState(() => generateSampleTemplateData(slug));
|
|
155
|
+
return (_jsxs("button", { type: "button", onClick: () => onPick(slug), className: "w-full text-left rounded-2xl border bg-white hover:shadow-lg transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary", children: [_jsxs("div", { className: "p-4 border-b rounded-t-2xl", children: [_jsx("div", { className: "text-sm font-medium", children: title }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Click to select" })] }), _jsx("div", { className: "p-4", children: _jsx(FitPreview, { registry: registry, slug: slug, data: templateData }) })] }));
|
|
156
|
+
}
|
|
157
|
+
export default function TemplatePicker({ registry, allowedSlugs, slugTitles = {}, onPicked, }) {
|
|
158
|
+
const slugs = allowedSlugs ?? Object.keys(registry);
|
|
159
|
+
const titleFor = (slug) => slugTitles[slug] ?? slug.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
160
|
+
return (_jsxs("div", { className: "custom-container py-8", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h1", { className: "text-2xl font-semibold", children: "Select a CV Template" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Preview templates with sample data and pick one to start." })] }), _jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6", children: slugs.map((slug) => (_jsx(TemplateCard, { registry: registry, slug: slug, title: titleFor(slug), onPick: onPicked }, slug))) })] }));
|
|
161
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { TemplateData, TemplateProps } from '../../types/template.types';
|
|
3
|
+
/** Registry map: template slug -> component that receives TemplateProps */
|
|
4
|
+
export type CvTemplateRegistry = Record<string, React.ComponentType<TemplateProps>>;
|
|
5
|
+
export type TemplateRendererProps = {
|
|
6
|
+
/** Template registry provided by the host app (each project defines its own templates) */
|
|
7
|
+
registry: CvTemplateRegistry;
|
|
8
|
+
/** Template slug (e.g. 'modern', 'professional') */
|
|
9
|
+
slug: string;
|
|
10
|
+
/** CV data to render */
|
|
11
|
+
data: TemplateData;
|
|
12
|
+
printMode?: boolean;
|
|
13
|
+
className?: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Renders a CV template by slug using the registry provided by the host app.
|
|
17
|
+
* Host app must pass its own TEMPLATE_REGISTRY (no templates are shipped in the package).
|
|
18
|
+
*/
|
|
19
|
+
export default function TemplateRenderer({ registry, slug, data, printMode, className, }: TemplateRendererProps): import("react/jsx-runtime").JSX.Element | null;
|
|
20
|
+
//# sourceMappingURL=TemplateRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateRenderer.d.ts","sourceRoot":"","sources":["../../../src/components/cv/TemplateRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE9E,2EAA2E;AAC3E,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC;AAEpF,MAAM,MAAM,qBAAqB,GAAG;IAClC,0FAA0F;IAC1F,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,SAAiB,EACjB,SAAc,GACf,EAAE,qBAAqB,kDAOvB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Renders a CV template by slug using the registry provided by the host app.
|
|
5
|
+
* Host app must pass its own TEMPLATE_REGISTRY (no templates are shipped in the package).
|
|
6
|
+
*/
|
|
7
|
+
export default function TemplateRenderer({ registry, slug, data, printMode = false, className = '', }) {
|
|
8
|
+
const fallbackSlug = Object.keys(registry)[0] ?? 'modern';
|
|
9
|
+
const Comp = registry[slug] ?? registry[fallbackSlug];
|
|
10
|
+
if (!Comp) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return _jsx(Comp, { data: data, printMode: printMode, className: className });
|
|
14
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -23,4 +23,17 @@ export { default as JobsClient } from './components/JobsClient';
|
|
|
23
23
|
export type { JobsClientProps } from './components/JobsClient';
|
|
24
24
|
export { default as JobDescriptionClient } from './components/JobDescriptionClient';
|
|
25
25
|
export type { JobDescriptionClientProps } from './components/JobDescriptionClient';
|
|
26
|
+
export type { TemplateData, TemplatePersonalInfo, TemplateSections, TemplateExperience, TemplateEducation, TemplateProject, TemplateSkill, TemplateSkillCategory, TemplateCertification, TemplateLanguage, TemplateReference, TemplateTraining, TemplateLink, TemplateProps, } from './types/template.types';
|
|
27
|
+
export type { CvBlock, CvBlockType, CvBlockStyle, CvLayout, } from './types/cv-blocks.types';
|
|
28
|
+
export type { CvDraft, CreateCvDraftPayload, UpdateCvDraftPayload, CvDraftListResponse, } from './types/cv-draft.types';
|
|
29
|
+
export { convertTemplateToBlocks, getDefaultColumns, getDefaultStyles, } from './utils/cv-block-converter';
|
|
30
|
+
export { preprocessTemplateCssClient, clearCssCacheClient, } from './utils/cv/pdf/styles/preprocessCssClient';
|
|
31
|
+
export { useCvPreview } from './stores/cvPreview.store';
|
|
32
|
+
export { useCvLayout } from './stores/cvLayout.store';
|
|
33
|
+
export { useCvDraftsStore } from './stores/cvDrafts.store';
|
|
34
|
+
export { default as TemplateRenderer } from './components/cv/TemplateRenderer';
|
|
35
|
+
export type { CvTemplateRegistry, TemplateRendererProps } from './components/cv/TemplateRenderer';
|
|
36
|
+
export { default as TemplatePicker } from './components/cv/TemplatePicker';
|
|
37
|
+
export type { TemplatePickerProps } from './components/cv/TemplatePicker';
|
|
38
|
+
export { generateSampleTemplateData } from './components/cv/TemplatePicker';
|
|
26
39
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxD,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,eAAe,GAChB,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,UAAU,EACV,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,eAAe,EACf,eAAe,EACf,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,YAAY,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACpF,YAAY,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -17,3 +17,14 @@ export { useEasyApplyFormHook, easyApplyUserSchema, screeningAnswerSchema, scree
|
|
|
17
17
|
// Components
|
|
18
18
|
export { default as JobsClient } from './components/JobsClient';
|
|
19
19
|
export { default as JobDescriptionClient } from './components/JobDescriptionClient';
|
|
20
|
+
// CV Builder: utils
|
|
21
|
+
export { convertTemplateToBlocks, getDefaultColumns, getDefaultStyles, } from './utils/cv-block-converter';
|
|
22
|
+
export { preprocessTemplateCssClient, clearCssCacheClient, } from './utils/cv/pdf/styles/preprocessCssClient';
|
|
23
|
+
// CV Builder: stores
|
|
24
|
+
export { useCvPreview } from './stores/cvPreview.store';
|
|
25
|
+
export { useCvLayout } from './stores/cvLayout.store';
|
|
26
|
+
export { useCvDraftsStore } from './stores/cvDrafts.store';
|
|
27
|
+
// CV Builder: components (registry-based; no templates in package)
|
|
28
|
+
export { default as TemplateRenderer } from './components/cv/TemplateRenderer';
|
|
29
|
+
export { default as TemplatePicker } from './components/cv/TemplatePicker';
|
|
30
|
+
export { generateSampleTemplateData } from './components/cv/TemplatePicker';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { TemplateData } from '../types/template.types';
|
|
2
|
+
import type { CvDraft } from '../types/cv-draft.types';
|
|
3
|
+
type LocalCvDraft = {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
template: string;
|
|
7
|
+
cv_data: TemplateData | null;
|
|
8
|
+
isAnonymous: boolean;
|
|
9
|
+
backendId?: string;
|
|
10
|
+
createdAt: string;
|
|
11
|
+
updatedAt: string;
|
|
12
|
+
};
|
|
13
|
+
type CvDraftsState = {
|
|
14
|
+
drafts: LocalCvDraft[];
|
|
15
|
+
currentDraftId: string | null;
|
|
16
|
+
setCurrentDraft: (id: string | null) => void;
|
|
17
|
+
addDraft: (draft: Omit<LocalCvDraft, 'id' | 'createdAt' | 'updatedAt'>) => string;
|
|
18
|
+
updateDraft: (id: string, updates: Partial<LocalCvDraft>) => void;
|
|
19
|
+
deleteDraft: (id: string) => void;
|
|
20
|
+
getCurrentDraft: () => LocalCvDraft | null;
|
|
21
|
+
getDraftById: (id: string) => LocalCvDraft | null;
|
|
22
|
+
syncDraftToBackend: (localId: string, backendId: string) => void;
|
|
23
|
+
loadDraftsFromBackend: (backendDrafts: CvDraft[]) => void;
|
|
24
|
+
clearDrafts: () => void;
|
|
25
|
+
};
|
|
26
|
+
export declare const useCvDraftsStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<CvDraftsState>, "persist"> & {
|
|
27
|
+
persist: {
|
|
28
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<CvDraftsState, {
|
|
29
|
+
drafts: LocalCvDraft[];
|
|
30
|
+
currentDraftId: string | null;
|
|
31
|
+
}>>) => void;
|
|
32
|
+
clearStorage: () => void;
|
|
33
|
+
rehydrate: () => Promise<void> | void;
|
|
34
|
+
hasHydrated: () => boolean;
|
|
35
|
+
onHydrate: (fn: (state: CvDraftsState) => void) => () => void;
|
|
36
|
+
onFinishHydration: (fn: (state: CvDraftsState) => void) => () => void;
|
|
37
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<CvDraftsState, {
|
|
38
|
+
drafts: LocalCvDraft[];
|
|
39
|
+
currentDraftId: string | null;
|
|
40
|
+
}>>;
|
|
41
|
+
};
|
|
42
|
+
}>;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=cvDrafts.store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cvDrafts.store.d.ts","sourceRoot":"","sources":["../../src/stores/cvDrafts.store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,KAAK,MAAM,CAAC;IAClF,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IAClE,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,eAAe,EAAE,MAAM,YAAY,GAAG,IAAI,CAAC;IAC3C,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,YAAY,GAAG,IAAI,CAAC;IAClD,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,qBAAqB,EAAE,CAAC,aAAa,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAC1D,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;EAyG5B,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { persist } from 'zustand/middleware';
|
|
3
|
+
export const useCvDraftsStore = create()(persist((set, get) => ({
|
|
4
|
+
drafts: [],
|
|
5
|
+
currentDraftId: null,
|
|
6
|
+
setCurrentDraft: (id) => set({ currentDraftId: id }),
|
|
7
|
+
addDraft: (draft) => {
|
|
8
|
+
const id = `local_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
9
|
+
const newDraft = {
|
|
10
|
+
...draft,
|
|
11
|
+
id,
|
|
12
|
+
createdAt: new Date().toISOString(),
|
|
13
|
+
updatedAt: new Date().toISOString(),
|
|
14
|
+
};
|
|
15
|
+
set((state) => ({
|
|
16
|
+
drafts: [...state.drafts, newDraft],
|
|
17
|
+
currentDraftId: id,
|
|
18
|
+
}));
|
|
19
|
+
return id;
|
|
20
|
+
},
|
|
21
|
+
updateDraft: (id, updates) => {
|
|
22
|
+
set((state) => ({
|
|
23
|
+
drafts: state.drafts.map((d) => d.id === id ? { ...d, ...updates, updatedAt: new Date().toISOString() } : d),
|
|
24
|
+
}));
|
|
25
|
+
},
|
|
26
|
+
deleteDraft: (id) => {
|
|
27
|
+
set((state) => ({
|
|
28
|
+
drafts: state.drafts.filter((d) => d.id !== id),
|
|
29
|
+
currentDraftId: state.currentDraftId === id ? null : state.currentDraftId,
|
|
30
|
+
}));
|
|
31
|
+
},
|
|
32
|
+
getCurrentDraft: () => {
|
|
33
|
+
const { drafts, currentDraftId } = get();
|
|
34
|
+
return drafts.find((d) => d.id === currentDraftId) || null;
|
|
35
|
+
},
|
|
36
|
+
getDraftById: (id) => {
|
|
37
|
+
const { drafts } = get();
|
|
38
|
+
return drafts.find((d) => d.id === id) || null;
|
|
39
|
+
},
|
|
40
|
+
syncDraftToBackend: (localId, backendId) => {
|
|
41
|
+
set((state) => ({
|
|
42
|
+
drafts: state.drafts.map((d) => d.id === localId ? { ...d, backendId } : d),
|
|
43
|
+
}));
|
|
44
|
+
},
|
|
45
|
+
loadDraftsFromBackend: (backendDrafts) => {
|
|
46
|
+
const { drafts: existingDrafts } = get();
|
|
47
|
+
const activeDrafts = backendDrafts.filter((draft) => draft.is_active !== false);
|
|
48
|
+
const syncedDrafts = activeDrafts.map((backendDraft) => {
|
|
49
|
+
const existing = existingDrafts.find((d) => d.backendId === backendDraft.id);
|
|
50
|
+
if (existing) {
|
|
51
|
+
return {
|
|
52
|
+
...existing,
|
|
53
|
+
name: backendDraft.name,
|
|
54
|
+
template: backendDraft.template,
|
|
55
|
+
cv_data: backendDraft.cv_data,
|
|
56
|
+
updatedAt: backendDraft.updated_at,
|
|
57
|
+
isAnonymous: false,
|
|
58
|
+
backendId: backendDraft.id,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
id: `backend_${backendDraft.id}`,
|
|
63
|
+
name: backendDraft.name,
|
|
64
|
+
template: backendDraft.template,
|
|
65
|
+
cv_data: backendDraft.cv_data,
|
|
66
|
+
isAnonymous: false,
|
|
67
|
+
backendId: backendDraft.id,
|
|
68
|
+
createdAt: backendDraft.created_at,
|
|
69
|
+
updatedAt: backendDraft.updated_at,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
const anonymousDrafts = existingDrafts.filter((d) => d.isAnonymous);
|
|
73
|
+
const backendIds = new Set(activeDrafts.map((d) => d.id));
|
|
74
|
+
const validSyncedDrafts = existingDrafts.filter((d) => !d.isAnonymous && d.backendId && backendIds.has(d.backendId));
|
|
75
|
+
const newSyncedDrafts = syncedDrafts.filter((d) => !validSyncedDrafts.some((e) => e.backendId === d.backendId));
|
|
76
|
+
const mergedDrafts = [...anonymousDrafts, ...validSyncedDrafts, ...newSyncedDrafts];
|
|
77
|
+
set({ drafts: mergedDrafts });
|
|
78
|
+
},
|
|
79
|
+
clearDrafts: () => set({ drafts: [], currentDraftId: null }),
|
|
80
|
+
}), {
|
|
81
|
+
name: 'cv-drafts-storage',
|
|
82
|
+
partialize: (state) => ({
|
|
83
|
+
drafts: state.drafts.filter((d) => d.isAnonymous),
|
|
84
|
+
currentDraftId: state.currentDraftId,
|
|
85
|
+
}),
|
|
86
|
+
}));
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CvLayout, CvBlock } from '../types/cv-blocks.types';
|
|
2
|
+
import type { TemplateData } from '../types/template.types';
|
|
3
|
+
type CvLayoutState = {
|
|
4
|
+
layout: CvLayout | null;
|
|
5
|
+
isEditMode: boolean;
|
|
6
|
+
loadTemplate: (templateSlug: string, data: TemplateData) => void;
|
|
7
|
+
addBlock: (block: CvBlock) => void;
|
|
8
|
+
updateBlock: (id: string, updates: Partial<CvBlock>) => void;
|
|
9
|
+
deleteBlock: (id: string) => void;
|
|
10
|
+
moveBlock: (id: string, newPosition: {
|
|
11
|
+
column?: number;
|
|
12
|
+
order?: number;
|
|
13
|
+
}) => void;
|
|
14
|
+
reorderBlocks: (ids: string[]) => void;
|
|
15
|
+
setGridColumns: (columns: number) => void;
|
|
16
|
+
setGlobalStyle: (key: string, value: unknown) => void;
|
|
17
|
+
toggleEditMode: () => void;
|
|
18
|
+
saveLayout: () => Promise<void>;
|
|
19
|
+
loadSavedLayout: (layoutId: string) => Promise<void>;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
};
|
|
22
|
+
export declare const useCvLayout: import("zustand").UseBoundStore<import("zustand").StoreApi<CvLayoutState>>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=cvLayout.store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cvLayout.store.d.ts","sourceRoot":"","sources":["../../src/stores/cvLayout.store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAO5D,KAAK,aAAa,GAAG;IACnB,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACjE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7D,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAClF,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACtD,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,WAAW,4EA+HrB,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { convertTemplateToBlocks, getDefaultColumns, getDefaultStyles, } from '../utils/cv-block-converter';
|
|
3
|
+
export const useCvLayout = create((set, get) => ({
|
|
4
|
+
layout: null,
|
|
5
|
+
isEditMode: false,
|
|
6
|
+
loadTemplate: (templateSlug, data) => {
|
|
7
|
+
const blocks = convertTemplateToBlocks(templateSlug, data);
|
|
8
|
+
const layout = {
|
|
9
|
+
id: `layout-${Date.now()}`,
|
|
10
|
+
name: `${templateSlug} - Custom`,
|
|
11
|
+
template: templateSlug,
|
|
12
|
+
grid: {
|
|
13
|
+
columns: getDefaultColumns(templateSlug),
|
|
14
|
+
gap: 16,
|
|
15
|
+
width: 210,
|
|
16
|
+
},
|
|
17
|
+
blocks,
|
|
18
|
+
globalStyles: getDefaultStyles(templateSlug),
|
|
19
|
+
};
|
|
20
|
+
set({ layout });
|
|
21
|
+
},
|
|
22
|
+
addBlock: (block) => set((state) => ({
|
|
23
|
+
layout: state.layout
|
|
24
|
+
? { ...state.layout, blocks: [...state.layout.blocks, block] }
|
|
25
|
+
: null,
|
|
26
|
+
})),
|
|
27
|
+
updateBlock: (id, updates) => set((state) => ({
|
|
28
|
+
layout: state.layout
|
|
29
|
+
? {
|
|
30
|
+
...state.layout,
|
|
31
|
+
blocks: state.layout.blocks.map((b) => b.id === id ? { ...b, ...updates } : b),
|
|
32
|
+
}
|
|
33
|
+
: null,
|
|
34
|
+
})),
|
|
35
|
+
deleteBlock: (id) => set((state) => ({
|
|
36
|
+
layout: state.layout
|
|
37
|
+
? {
|
|
38
|
+
...state.layout,
|
|
39
|
+
blocks: state.layout.blocks.filter((b) => b.id !== id),
|
|
40
|
+
}
|
|
41
|
+
: null,
|
|
42
|
+
})),
|
|
43
|
+
moveBlock: (id, { column, order }) => set((state) => {
|
|
44
|
+
if (!state.layout)
|
|
45
|
+
return state;
|
|
46
|
+
return {
|
|
47
|
+
layout: {
|
|
48
|
+
...state.layout,
|
|
49
|
+
blocks: state.layout.blocks.map((b) => {
|
|
50
|
+
if (b.id === id) {
|
|
51
|
+
return {
|
|
52
|
+
...b,
|
|
53
|
+
style: {
|
|
54
|
+
...b.style,
|
|
55
|
+
gridColumn: column !== undefined ? column : b.style.gridColumn,
|
|
56
|
+
order: order !== undefined ? order : b.style.order,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return b;
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}),
|
|
65
|
+
reorderBlocks: (ids) => set((state) => {
|
|
66
|
+
if (!state.layout)
|
|
67
|
+
return state;
|
|
68
|
+
const blockMap = new Map(state.layout.blocks.map((b) => [b.id, b]));
|
|
69
|
+
const reordered = ids
|
|
70
|
+
.map((id) => blockMap.get(id))
|
|
71
|
+
.filter(Boolean);
|
|
72
|
+
return {
|
|
73
|
+
layout: { ...state.layout, blocks: reordered },
|
|
74
|
+
};
|
|
75
|
+
}),
|
|
76
|
+
setGridColumns: (columns) => set((state) => ({
|
|
77
|
+
layout: state.layout
|
|
78
|
+
? { ...state.layout, grid: { ...state.layout.grid, columns } }
|
|
79
|
+
: null,
|
|
80
|
+
})),
|
|
81
|
+
setGlobalStyle: (key, value) => set((state) => ({
|
|
82
|
+
layout: state.layout
|
|
83
|
+
? {
|
|
84
|
+
...state.layout,
|
|
85
|
+
globalStyles: { ...state.layout.globalStyles, [key]: value },
|
|
86
|
+
}
|
|
87
|
+
: null,
|
|
88
|
+
})),
|
|
89
|
+
toggleEditMode: () => set((state) => ({ isEditMode: !state.isEditMode })),
|
|
90
|
+
saveLayout: async () => {
|
|
91
|
+
const { layout } = get();
|
|
92
|
+
if (!layout)
|
|
93
|
+
return;
|
|
94
|
+
try {
|
|
95
|
+
if (typeof localStorage !== 'undefined') {
|
|
96
|
+
localStorage.setItem('cv-layout-draft', JSON.stringify(layout));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (_err) {
|
|
100
|
+
/* noop */
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
loadSavedLayout: async (_layoutId) => {
|
|
104
|
+
try {
|
|
105
|
+
if (typeof localStorage === 'undefined')
|
|
106
|
+
return;
|
|
107
|
+
const saved = localStorage.getItem('cv-layout-draft');
|
|
108
|
+
if (saved)
|
|
109
|
+
set({ layout: JSON.parse(saved) });
|
|
110
|
+
}
|
|
111
|
+
catch (_err) {
|
|
112
|
+
/* noop */
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
reset: () => set({ layout: null }),
|
|
116
|
+
}));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { TemplateData, TemplateSections, TemplatePersonalInfo } from '../types/template.types';
|
|
2
|
+
type CvPreviewState = {
|
|
3
|
+
slug: string;
|
|
4
|
+
live: TemplateData | null;
|
|
5
|
+
setSlug: (s: string) => void;
|
|
6
|
+
setPersonal: (p: Partial<TemplatePersonalInfo>) => void;
|
|
7
|
+
setSections: (s: Partial<TemplateSections>) => void;
|
|
8
|
+
setAll: (d: TemplateData) => void;
|
|
9
|
+
reset: () => void;
|
|
10
|
+
};
|
|
11
|
+
export declare const useCvPreview: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<CvPreviewState>, "persist"> & {
|
|
12
|
+
persist: {
|
|
13
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<CvPreviewState, {
|
|
14
|
+
slug: string;
|
|
15
|
+
live: TemplateData | null;
|
|
16
|
+
}>>) => void;
|
|
17
|
+
clearStorage: () => void;
|
|
18
|
+
rehydrate: () => Promise<void> | void;
|
|
19
|
+
hasHydrated: () => boolean;
|
|
20
|
+
onHydrate: (fn: (state: CvPreviewState) => void) => () => void;
|
|
21
|
+
onFinishHydration: (fn: (state: CvPreviewState) => void) => () => void;
|
|
22
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<CvPreviewState, {
|
|
23
|
+
slug: string;
|
|
24
|
+
live: TemplateData | null;
|
|
25
|
+
}>>;
|
|
26
|
+
};
|
|
27
|
+
}>;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=cvPreview.store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cvPreview.store.d.ts","sourceRoot":"","sources":["../../src/stores/cvPreview.store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,yBAAyB,CAAC;AAEjC,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,KAAK,IAAI,CAAC;IACxD,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACpD,MAAM,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;IAClC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;EAsFxB,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { persist } from 'zustand/middleware';
|
|
3
|
+
export const useCvPreview = create()(persist((set) => ({
|
|
4
|
+
slug: 'professional',
|
|
5
|
+
live: null,
|
|
6
|
+
setSlug: (slug) => set({ slug }),
|
|
7
|
+
setPersonal: (p) => set((st) => {
|
|
8
|
+
if (st.live) {
|
|
9
|
+
return {
|
|
10
|
+
live: { ...st.live, personalInfo: { ...st.live.personalInfo, ...p } },
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
live: {
|
|
15
|
+
personalInfo: {
|
|
16
|
+
firstName: '',
|
|
17
|
+
lastName: '',
|
|
18
|
+
email: '',
|
|
19
|
+
phone: '',
|
|
20
|
+
location: { city: '', state: '', country: 'Nepal' },
|
|
21
|
+
summary: '',
|
|
22
|
+
links: [],
|
|
23
|
+
...p,
|
|
24
|
+
},
|
|
25
|
+
sections: {
|
|
26
|
+
education: [],
|
|
27
|
+
experience: [],
|
|
28
|
+
projects: [],
|
|
29
|
+
skills: [],
|
|
30
|
+
certifications: [],
|
|
31
|
+
languages: [],
|
|
32
|
+
references: [],
|
|
33
|
+
trainings: [],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}),
|
|
38
|
+
setSections: (s) => set((st) => {
|
|
39
|
+
if (st.live) {
|
|
40
|
+
return {
|
|
41
|
+
live: {
|
|
42
|
+
...st.live,
|
|
43
|
+
sections: {
|
|
44
|
+
...st.live.sections,
|
|
45
|
+
...Object.fromEntries(Object.entries(s).map(([k, v]) => [
|
|
46
|
+
k,
|
|
47
|
+
Array.isArray(v) ? v : st.live.sections[k],
|
|
48
|
+
])),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
live: {
|
|
55
|
+
personalInfo: {
|
|
56
|
+
firstName: '',
|
|
57
|
+
lastName: '',
|
|
58
|
+
email: '',
|
|
59
|
+
phone: '',
|
|
60
|
+
location: { city: '', state: '', country: 'Nepal' },
|
|
61
|
+
summary: '',
|
|
62
|
+
links: [],
|
|
63
|
+
},
|
|
64
|
+
sections: {
|
|
65
|
+
education: [],
|
|
66
|
+
experience: [],
|
|
67
|
+
projects: [],
|
|
68
|
+
skills: [],
|
|
69
|
+
certifications: [],
|
|
70
|
+
languages: [],
|
|
71
|
+
references: [],
|
|
72
|
+
trainings: [],
|
|
73
|
+
...s,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}),
|
|
78
|
+
setAll: (d) => set({ live: d }),
|
|
79
|
+
reset: () => set({ live: null }),
|
|
80
|
+
}), { name: 'cv-preview-storage', partialize: (state) => ({ slug: state.slug, live: state.live }) }));
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type CvBlockType = 'header' | 'summary' | 'experience' | 'education' | 'skills' | 'projects' | 'certifications' | 'languages' | 'references' | 'custom-text';
|
|
2
|
+
export type CvBlockStyle = {
|
|
3
|
+
gridColumn?: number | string;
|
|
4
|
+
gridRow?: number | string;
|
|
5
|
+
order?: number;
|
|
6
|
+
marginTop?: number;
|
|
7
|
+
marginBottom?: number;
|
|
8
|
+
padding?: number;
|
|
9
|
+
fontSize?: string;
|
|
10
|
+
fontWeight?: string;
|
|
11
|
+
color?: string;
|
|
12
|
+
backgroundColor?: string;
|
|
13
|
+
borderRadius?: number;
|
|
14
|
+
border?: string;
|
|
15
|
+
};
|
|
16
|
+
export type CvBlock = {
|
|
17
|
+
id: string;
|
|
18
|
+
type: CvBlockType;
|
|
19
|
+
data: unknown;
|
|
20
|
+
style: CvBlockStyle;
|
|
21
|
+
minWidth?: number;
|
|
22
|
+
maxWidth?: number;
|
|
23
|
+
resizable?: boolean;
|
|
24
|
+
movable?: boolean;
|
|
25
|
+
deletable?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export type CvLayout = {
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
template: string;
|
|
31
|
+
grid: {
|
|
32
|
+
columns: number;
|
|
33
|
+
gap: number;
|
|
34
|
+
width: number;
|
|
35
|
+
};
|
|
36
|
+
blocks: CvBlock[];
|
|
37
|
+
globalStyles: {
|
|
38
|
+
fontFamily?: string;
|
|
39
|
+
primaryColor?: string;
|
|
40
|
+
backgroundColor?: string;
|
|
41
|
+
textColor?: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=cv-blocks.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cv-blocks.types.d.ts","sourceRoot":"","sources":["../../src/types/cv-blocks.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,SAAS,GACT,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,UAAU,GACV,gBAAgB,GAChB,WAAW,GACX,YAAY,GACZ,aAAa,CAAC;AAElB,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,YAAY,EAAE;QACZ,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { TemplateData } from './template.types';
|
|
2
|
+
export interface CvDraft {
|
|
3
|
+
id: string;
|
|
4
|
+
user_id: string | null;
|
|
5
|
+
name: string;
|
|
6
|
+
template: string;
|
|
7
|
+
cv_data: TemplateData;
|
|
8
|
+
is_active: boolean;
|
|
9
|
+
created_at: string;
|
|
10
|
+
updated_at: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CreateCvDraftPayload {
|
|
13
|
+
name?: string;
|
|
14
|
+
template?: string;
|
|
15
|
+
cv_data: TemplateData;
|
|
16
|
+
}
|
|
17
|
+
export interface UpdateCvDraftPayload {
|
|
18
|
+
name?: string;
|
|
19
|
+
template?: string;
|
|
20
|
+
cv_data?: TemplateData;
|
|
21
|
+
is_active?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface CvDraftListResponse {
|
|
24
|
+
data: CvDraft[];
|
|
25
|
+
pagination?: {
|
|
26
|
+
total: number;
|
|
27
|
+
page: number;
|
|
28
|
+
pages: number;
|
|
29
|
+
nextPage: number | null;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=cv-draft.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cv-draft.types.d.ts","sourceRoot":"","sources":["../../src/types/cv-draft.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACzB,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export type TemplateLink = {
|
|
2
|
+
type?: string;
|
|
3
|
+
label?: string;
|
|
4
|
+
url: string;
|
|
5
|
+
};
|
|
6
|
+
export type TemplateSkill = {
|
|
7
|
+
name: string;
|
|
8
|
+
level?: string;
|
|
9
|
+
rating?: number;
|
|
10
|
+
};
|
|
11
|
+
export type TemplateSkillCategory = {
|
|
12
|
+
id: string;
|
|
13
|
+
category: string;
|
|
14
|
+
skills: TemplateSkill[];
|
|
15
|
+
};
|
|
16
|
+
export type TemplateExperience = {
|
|
17
|
+
id: string;
|
|
18
|
+
position: string;
|
|
19
|
+
company: string;
|
|
20
|
+
location: string;
|
|
21
|
+
startDate: string;
|
|
22
|
+
endDate?: string;
|
|
23
|
+
current?: boolean;
|
|
24
|
+
description?: string;
|
|
25
|
+
highlights?: string[];
|
|
26
|
+
};
|
|
27
|
+
export type TemplateEducation = {
|
|
28
|
+
id: string;
|
|
29
|
+
degree: string;
|
|
30
|
+
field: string;
|
|
31
|
+
institution: string;
|
|
32
|
+
location?: string;
|
|
33
|
+
startDate: string;
|
|
34
|
+
endDate?: string;
|
|
35
|
+
current?: boolean;
|
|
36
|
+
gpa?: string;
|
|
37
|
+
honors?: string[];
|
|
38
|
+
};
|
|
39
|
+
export type TemplateProject = {
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
technologies: string[];
|
|
44
|
+
url?: string;
|
|
45
|
+
startDate?: string;
|
|
46
|
+
endDate?: string;
|
|
47
|
+
highlights?: string[];
|
|
48
|
+
};
|
|
49
|
+
export type TemplateTraining = {
|
|
50
|
+
id: string;
|
|
51
|
+
course: string;
|
|
52
|
+
institute: string;
|
|
53
|
+
description?: string;
|
|
54
|
+
skills?: string[];
|
|
55
|
+
startDate?: string;
|
|
56
|
+
endDate?: string;
|
|
57
|
+
url?: string;
|
|
58
|
+
};
|
|
59
|
+
export type TemplateReference = {
|
|
60
|
+
id: string;
|
|
61
|
+
name: string;
|
|
62
|
+
position?: string;
|
|
63
|
+
email?: string;
|
|
64
|
+
phone?: string;
|
|
65
|
+
company?: string;
|
|
66
|
+
};
|
|
67
|
+
export type TemplateCertification = {
|
|
68
|
+
id: string;
|
|
69
|
+
name: string;
|
|
70
|
+
issuer: string;
|
|
71
|
+
date?: string;
|
|
72
|
+
};
|
|
73
|
+
export type TemplateLanguage = {
|
|
74
|
+
id: string;
|
|
75
|
+
language: string;
|
|
76
|
+
proficiency?: 'native' | 'professional' | 'conversational' | 'basic';
|
|
77
|
+
reading?: 'Excellent' | 'good' | 'basic' | number;
|
|
78
|
+
writing?: 'Excellent' | 'good' | 'basic' | number;
|
|
79
|
+
speaking?: 'Excellent' | 'good' | 'basic' | number;
|
|
80
|
+
};
|
|
81
|
+
export type TemplateSections = {
|
|
82
|
+
experience?: TemplateExperience[];
|
|
83
|
+
education?: TemplateEducation[];
|
|
84
|
+
projects?: TemplateProject[];
|
|
85
|
+
certifications?: TemplateCertification[];
|
|
86
|
+
references?: TemplateReference[];
|
|
87
|
+
awards?: {
|
|
88
|
+
id: string;
|
|
89
|
+
title: string;
|
|
90
|
+
issuer?: string;
|
|
91
|
+
date?: string;
|
|
92
|
+
description?: string;
|
|
93
|
+
}[];
|
|
94
|
+
skills?: TemplateSkillCategory[];
|
|
95
|
+
languages?: TemplateLanguage[];
|
|
96
|
+
trainings?: TemplateTraining[];
|
|
97
|
+
};
|
|
98
|
+
export type TemplatePersonalInfo = {
|
|
99
|
+
firstName: string;
|
|
100
|
+
lastName: string;
|
|
101
|
+
title?: string;
|
|
102
|
+
email: string;
|
|
103
|
+
phone?: string;
|
|
104
|
+
location: {
|
|
105
|
+
city?: string;
|
|
106
|
+
state?: string;
|
|
107
|
+
country?: string;
|
|
108
|
+
};
|
|
109
|
+
photo?: string;
|
|
110
|
+
summary?: string;
|
|
111
|
+
links?: TemplateLink[];
|
|
112
|
+
};
|
|
113
|
+
export type TemplateData = {
|
|
114
|
+
personalInfo: TemplatePersonalInfo;
|
|
115
|
+
sections: TemplateSections;
|
|
116
|
+
};
|
|
117
|
+
export type TemplateProps = {
|
|
118
|
+
data: TemplateData;
|
|
119
|
+
className?: string;
|
|
120
|
+
printMode?: boolean;
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=template.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.types.d.ts","sourceRoot":"","sources":["../../src/types/template.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const printReset = "\n @page :first { size: A4; margin: 0; }\n @page { size: A4; margin: 0; margin-top: 16px; }\n html, body { margin: 0 !important; padding: 0 !important; }\n @media print {\n html, body { min-height: 100vh; }\n #cv-root {\n width: 210mm !important;\n min-height: 297mm !important;\n margin: 0 !important;\n box-sizing: border-box !important;\n }\n #cv-root[data-template=\"professional\"],\n #cv-root[data-template=\"academic\"] { padding: 10mm !important; }\n #cv-root[data-template=\"modern\"],\n #cv-root[data-template=\"tech\"] { padding: 0 !important; }\n div[class*=\"mb-6\"]:not([class*=\"space-y\"]),\n div[class*=\"mb-8\"]:not([class*=\"space-y\"]) {\n page-break-before: avoid;\n break-before: avoid;\n break-inside: auto;\n page-break-inside: auto;\n }\n div[class*=\"mb-6\"]:not([class*=\"space-y\"]) > h2,\n div[class*=\"mb-8\"]:not([class*=\"space-y\"]) > h2 {\n page-break-after: avoid;\n break-after: avoid;\n }\n div[class*=\"space-y\"] { break-inside: auto; page-break-inside: auto; }\n div[class*=\"border-l-2\"] {\n break-inside: avoid !important;\n page-break-inside: avoid !important;\n }\n p, li { orphans: 2; widows: 2; }\n * {\n -webkit-print-color-adjust: exact !important;\n print-color-adjust: exact !important;\n }\n }\n";
|
|
2
|
+
export default printReset;
|
|
3
|
+
//# sourceMappingURL=printReset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printReset.d.ts","sourceRoot":"","sources":["../../../../src/utils/cv/pdf/printReset.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,UAAU,w2CAuCf,CAAC;AACF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const printReset = `
|
|
2
|
+
@page :first { size: A4; margin: 0; }
|
|
3
|
+
@page { size: A4; margin: 0; margin-top: 16px; }
|
|
4
|
+
html, body { margin: 0 !important; padding: 0 !important; }
|
|
5
|
+
@media print {
|
|
6
|
+
html, body { min-height: 100vh; }
|
|
7
|
+
#cv-root {
|
|
8
|
+
width: 210mm !important;
|
|
9
|
+
min-height: 297mm !important;
|
|
10
|
+
margin: 0 !important;
|
|
11
|
+
box-sizing: border-box !important;
|
|
12
|
+
}
|
|
13
|
+
#cv-root[data-template="professional"],
|
|
14
|
+
#cv-root[data-template="academic"] { padding: 10mm !important; }
|
|
15
|
+
#cv-root[data-template="modern"],
|
|
16
|
+
#cv-root[data-template="tech"] { padding: 0 !important; }
|
|
17
|
+
div[class*="mb-6"]:not([class*="space-y"]),
|
|
18
|
+
div[class*="mb-8"]:not([class*="space-y"]) {
|
|
19
|
+
page-break-before: avoid;
|
|
20
|
+
break-before: avoid;
|
|
21
|
+
break-inside: auto;
|
|
22
|
+
page-break-inside: auto;
|
|
23
|
+
}
|
|
24
|
+
div[class*="mb-6"]:not([class*="space-y"]) > h2,
|
|
25
|
+
div[class*="mb-8"]:not([class*="space-y"]) > h2 {
|
|
26
|
+
page-break-after: avoid;
|
|
27
|
+
break-after: avoid;
|
|
28
|
+
}
|
|
29
|
+
div[class*="space-y"] { break-inside: auto; page-break-inside: auto; }
|
|
30
|
+
div[class*="border-l-2"] {
|
|
31
|
+
break-inside: avoid !important;
|
|
32
|
+
page-break-inside: avoid !important;
|
|
33
|
+
}
|
|
34
|
+
p, li { orphans: 2; widows: 2; }
|
|
35
|
+
* {
|
|
36
|
+
-webkit-print-color-adjust: exact !important;
|
|
37
|
+
print-color-adjust: exact !important;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
export default printReset;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const baseCssContent = "\n @page { size: A4; margin: 12mm; }\n html { font-size: 16px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }\n html, body { margin: 0; padding: 0; }\n *, *::before, *::after { box-sizing: border-box; }\n * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }\n @font-face {\n font-family: \"Manrope\";\n src: url(\"__MANROPE_URL__\") format(\"woff2\");\n font-weight: 200 800;\n font-style: normal;\n font-display: swap;\n }\n body {\n font-family: \"Manrope\", ui-sans-serif, system-ui, -apple-system, sans-serif;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n }\n .cv-only-mobile { display: none !important; }\n .cv-hide-mobile { display: block !important; }\n :root{\n --page-h: 297mm;\n --page-mt: 12mm;\n --page-mb: 18mm;\n --pad-t: 0mm;\n --pad-b: 14mm;\n --cv-min-h: calc(var(--page-h) - var(--page-mt) - var(--page-mb) - var(--pad-t) - var(--pad-b));\n }\n .cv-page {\n width: 210mm;\n min-height: var(--cv-min-h);\n padding: 0mm 14mm 14mm 14mm;\n overflow: visible;\n display: grid;\n grid-template-rows: 1fr auto;\n page-break-after: auto !important;\n page-break-inside: avoid;\n break-inside: avoid;\n }\n .cv-content { min-height: 0; }\n .cv-footer { display: none; }\n .cv-page ul { list-style: disc outside; padding-left: 1.25rem; margin: 0; }\n .cv-page li { margin: .25rem 0; }\n";
|
|
2
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../../src/utils/cv/pdf/styles/base.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,06CA2C1B,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const baseCssContent = `
|
|
2
|
+
@page { size: A4; margin: 12mm; }
|
|
3
|
+
html { font-size: 16px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
|
|
4
|
+
html, body { margin: 0; padding: 0; }
|
|
5
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
6
|
+
* { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }
|
|
7
|
+
@font-face {
|
|
8
|
+
font-family: "Manrope";
|
|
9
|
+
src: url("__MANROPE_URL__") format("woff2");
|
|
10
|
+
font-weight: 200 800;
|
|
11
|
+
font-style: normal;
|
|
12
|
+
font-display: swap;
|
|
13
|
+
}
|
|
14
|
+
body {
|
|
15
|
+
font-family: "Manrope", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
16
|
+
line-height: 1.5;
|
|
17
|
+
-webkit-font-smoothing: antialiased;
|
|
18
|
+
}
|
|
19
|
+
.cv-only-mobile { display: none !important; }
|
|
20
|
+
.cv-hide-mobile { display: block !important; }
|
|
21
|
+
:root{
|
|
22
|
+
--page-h: 297mm;
|
|
23
|
+
--page-mt: 12mm;
|
|
24
|
+
--page-mb: 18mm;
|
|
25
|
+
--pad-t: 0mm;
|
|
26
|
+
--pad-b: 14mm;
|
|
27
|
+
--cv-min-h: calc(var(--page-h) - var(--page-mt) - var(--page-mb) - var(--pad-t) - var(--pad-b));
|
|
28
|
+
}
|
|
29
|
+
.cv-page {
|
|
30
|
+
width: 210mm;
|
|
31
|
+
min-height: var(--cv-min-h);
|
|
32
|
+
padding: 0mm 14mm 14mm 14mm;
|
|
33
|
+
overflow: visible;
|
|
34
|
+
display: grid;
|
|
35
|
+
grid-template-rows: 1fr auto;
|
|
36
|
+
page-break-after: auto !important;
|
|
37
|
+
page-break-inside: avoid;
|
|
38
|
+
break-inside: avoid;
|
|
39
|
+
}
|
|
40
|
+
.cv-content { min-height: 0; }
|
|
41
|
+
.cv-footer { display: none; }
|
|
42
|
+
.cv-page ul { list-style: disc outside; padding-left: 1.25rem; margin: 0; }
|
|
43
|
+
.cv-page li { margin: .25rem 0; }
|
|
44
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preprocessCssClient.d.ts","sourceRoot":"","sources":["../../../../../src/utils/cv/pdf/styles/preprocessCssClient.ts"],"names":[],"mappings":"AAKA,wBAAsB,2BAA2B,CAC/C,QAAQ,GAAE,MAAiB,EAC3B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAI1C"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { baseCssContent } from './base';
|
|
2
|
+
import printReset from '../printReset';
|
|
3
|
+
const PREPROCESSED_CSS_CACHE = {};
|
|
4
|
+
export async function preprocessTemplateCssClient(template = 'modern', origin) {
|
|
5
|
+
const cacheKey = `${template}:${origin || ''}`;
|
|
6
|
+
if (PREPROCESSED_CSS_CACHE[cacheKey]) {
|
|
7
|
+
return PREPROCESSED_CSS_CACHE[cacheKey];
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
let baseCss = baseCssContent;
|
|
11
|
+
if (origin) {
|
|
12
|
+
baseCss = baseCss.replace('__MANROPE_URL__', `${origin}/fonts/Manrope-Variable.woff2`);
|
|
13
|
+
}
|
|
14
|
+
else if (typeof window !== 'undefined') {
|
|
15
|
+
baseCss = baseCss.replace('__MANROPE_URL__', `${window.location.origin}/fonts/Manrope-Variable.woff2`);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
baseCss = baseCss.replace('__MANROPE_URL__', '');
|
|
19
|
+
}
|
|
20
|
+
const preprocessed = [baseCss, printReset].filter(Boolean).join('\n');
|
|
21
|
+
PREPROCESSED_CSS_CACHE[cacheKey] = preprocessed;
|
|
22
|
+
return preprocessed;
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.error('[preprocessCssClient] Error preprocessing CSS:', error);
|
|
26
|
+
return baseCssContent + printReset;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function clearCssCacheClient() {
|
|
30
|
+
Object.keys(PREPROCESSED_CSS_CACHE).forEach((key) => {
|
|
31
|
+
delete PREPROCESSED_CSS_CACHE[key];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TemplateData } from '../types/template.types';
|
|
2
|
+
import type { CvBlock } from '../types/cv-blocks.types';
|
|
3
|
+
export declare function convertTemplateToBlocks(_templateSlug: string, data: TemplateData): CvBlock[];
|
|
4
|
+
export declare function getDefaultColumns(templateSlug: string): number;
|
|
5
|
+
export declare function getDefaultStyles(_templateSlug: string): {
|
|
6
|
+
fontFamily: string;
|
|
7
|
+
primaryColor: string;
|
|
8
|
+
backgroundColor: string;
|
|
9
|
+
textColor: string;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=cv-block-converter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cv-block-converter.d.ts","sourceRoot":"","sources":["../../src/utils/cv-block-converter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAExD,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,YAAY,GACjB,OAAO,EAAE,CA4EX;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAQ9D;AAED,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM;;;;;EAOrD"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export function convertTemplateToBlocks(_templateSlug, data) {
|
|
2
|
+
const blocks = [];
|
|
3
|
+
let order = 0;
|
|
4
|
+
blocks.push({
|
|
5
|
+
id: 'block-header',
|
|
6
|
+
type: 'header',
|
|
7
|
+
data: data.personalInfo,
|
|
8
|
+
style: { order: order++ },
|
|
9
|
+
deletable: false,
|
|
10
|
+
});
|
|
11
|
+
if (data.personalInfo.summary) {
|
|
12
|
+
blocks.push({
|
|
13
|
+
id: 'block-summary',
|
|
14
|
+
type: 'summary',
|
|
15
|
+
data: { text: data.personalInfo.summary },
|
|
16
|
+
style: { order: order++ },
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (data.sections.experience?.length) {
|
|
20
|
+
blocks.push({
|
|
21
|
+
id: 'block-experience',
|
|
22
|
+
type: 'experience',
|
|
23
|
+
data: { items: data.sections.experience },
|
|
24
|
+
style: { order: order++ },
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if (data.sections.education?.length) {
|
|
28
|
+
blocks.push({
|
|
29
|
+
id: 'block-education',
|
|
30
|
+
type: 'education',
|
|
31
|
+
data: { items: data.sections.education },
|
|
32
|
+
style: { order: order++ },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
if (data.sections.skills?.length) {
|
|
36
|
+
blocks.push({
|
|
37
|
+
id: 'block-skills',
|
|
38
|
+
type: 'skills',
|
|
39
|
+
data: { items: data.sections.skills },
|
|
40
|
+
style: { order: order++ },
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (data.sections.projects?.length) {
|
|
44
|
+
blocks.push({
|
|
45
|
+
id: 'block-projects',
|
|
46
|
+
type: 'projects',
|
|
47
|
+
data: { items: data.sections.projects },
|
|
48
|
+
style: { order: order++ },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (data.sections.certifications?.length) {
|
|
52
|
+
blocks.push({
|
|
53
|
+
id: 'block-certifications',
|
|
54
|
+
type: 'certifications',
|
|
55
|
+
data: { items: data.sections.certifications },
|
|
56
|
+
style: { order: order++ },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (data.sections.languages?.length) {
|
|
60
|
+
blocks.push({
|
|
61
|
+
id: 'block-languages',
|
|
62
|
+
type: 'languages',
|
|
63
|
+
data: { items: data.sections.languages },
|
|
64
|
+
style: { order: order++ },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return blocks;
|
|
68
|
+
}
|
|
69
|
+
export function getDefaultColumns(templateSlug) {
|
|
70
|
+
if (templateSlug.includes('sidebar') ||
|
|
71
|
+
templateSlug.includes('europass-sidebar')) {
|
|
72
|
+
return 2;
|
|
73
|
+
}
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
export function getDefaultStyles(_templateSlug) {
|
|
77
|
+
return {
|
|
78
|
+
fontFamily: 'Inter, sans-serif',
|
|
79
|
+
primaryColor: '#2276D2',
|
|
80
|
+
backgroundColor: '#ffffff',
|
|
81
|
+
textColor: '#111827',
|
|
82
|
+
};
|
|
83
|
+
}
|
package/package.json
CHANGED
|
@@ -1,44 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@recruitnepal/shared-packages",
|
|
3
|
-
"version": "1.5.0",
|
|
4
|
-
"description": "Shared UI components and hooks for Recruit Nepal projects",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"build": "tsc",
|
|
9
|
-
"dev": "tsc --watch",
|
|
10
|
-
"prepublishOnly": "npm run build"
|
|
11
|
-
},
|
|
12
|
-
"keywords": [
|
|
13
|
-
"react",
|
|
14
|
-
"nextjs",
|
|
15
|
-
"recruit-nepal",
|
|
16
|
-
"shared-components"
|
|
17
|
-
],
|
|
18
|
-
"author": "",
|
|
19
|
-
"license": "MIT",
|
|
20
|
-
"peerDependencies": {
|
|
21
|
-
"react": "^18.2.0",
|
|
22
|
-
"react-dom": "^18.2.0",
|
|
23
|
-
"@tanstack/react-query": "^5.50.0",
|
|
24
|
-
"zod": "^3.22.0",
|
|
25
|
-
"react-hook-form": "^7.49.0",
|
|
26
|
-
"@hookform/resolvers": "^3.3.0"
|
|
27
|
-
},
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"axios": "^1.7.8"
|
|
30
|
-
},
|
|
31
|
-
"devDependencies": {
|
|
32
|
-
"@types/node": "^20.11.17",
|
|
33
|
-
"@types/react": "^18.2.55",
|
|
34
|
-
"@types/react-dom": "^18.2.19",
|
|
35
|
-
"typescript": "^5.3.3",
|
|
36
|
-
"zod": "^3.22.0",
|
|
37
|
-
"react-hook-form": "^7.49.0",
|
|
38
|
-
"@hookform/resolvers": "^3.3.0"
|
|
39
|
-
},
|
|
40
|
-
"files": [
|
|
41
|
-
"dist",
|
|
42
|
-
"README.md"
|
|
43
|
-
]
|
|
44
|
-
}
|
|
1
|
+
{"name":"@recruitnepal/shared-packages","version":"1.6.0","description":"Shared UI components and hooks for Recruit Nepal projects","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","dev":"tsc --watch","prepublishOnly":"npm run build"},"keywords":["react","nextjs","recruit-nepal","shared-components","cv-builder"],"author":"","license":"MIT","peerDependencies":{"react":"^18.2.0","react-dom":"^18.2.0","@tanstack/react-query":"^5.50.0","zod":"^3.22.0","react-hook-form":"^7.49.0","@hookform/resolvers":"^3.3.0","zustand":"^4.5.0"},"dependencies":{"axios":"^1.7.8"},"devDependencies":{"@types/node":"^20.11.17","@types/react":"^18.2.55","@types/react-dom":"^18.2.19","typescript":"^5.3.3","zod":"^3.22.0","react-hook-form":"^7.49.0","@hookform/resolvers":"^3.3.0","zustand":"^4.5.0"},"files":["dist","README.md"]}
|