diff --git a/package.json b/package.json index 1c62bb6..0c43d84 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cv-editor", "private": true, - "version": "1.0.1", + "version": "1.0.2", "type": "module", "scripts": { "dev": "vite", diff --git a/public/lang/en/bar.json b/public/lang/en/bar.json index cc41d9e..4e305a1 100644 --- a/public/lang/en/bar.json +++ b/public/lang/en/bar.json @@ -2,6 +2,7 @@ "sidebar": { "edit": "Editor", "new": "New", + "exemple": "Sample", "design": "Template's Design", "pdfLanguage": "CV language", "searchTheme": "Search theme", diff --git a/public/lang/fr/bar.json b/public/lang/fr/bar.json index 2c15d3e..1249c1c 100644 --- a/public/lang/fr/bar.json +++ b/public/lang/fr/bar.json @@ -2,6 +2,7 @@ "sidebar": { "edit": "Editeur", "new": "Nouveau", + "exemple": "Exemple", "design": "Design Template", "pdfLanguage": "Langue du CV", "searchTheme": "Chercher un theme", diff --git a/src/core/store/useCvStore.ts b/src/core/store/useCvStore.ts index 2ff5e5d..328c450 100644 --- a/src/core/store/useCvStore.ts +++ b/src/core/store/useCvStore.ts @@ -9,6 +9,7 @@ interface CvState { data: CVData; updateData: (newData: Partial) => void; reset: () => void; + exemple: () => void; } export const useCvStore = create()( @@ -43,6 +44,29 @@ export const useCvStore = create()( }); } }, + + exemple: async () => { + const result = await Swal.fire({ + title: "Êtes-vous sûr ?", + text: "Toutes vos données locales seront supprimées définitivement.", + icon: "warning", + showCancelButton: true, + confirmButtonText: "Oui, effacer tout", + cancelButtonText: "Annuler", + }); + + if (result.isConfirmed) { + set({ data: INITIAL_CV_DATA }); + + Swal.fire({ + title: "Réinitialisé !", + text: "Votre CV est de nouveau vierge.", + icon: "success", + timer: 1500, + showConfirmButton: false, + }); + } + }, }), { name: "cv-storage", diff --git a/src/features/cv-preview/themes/BoldTheme.tsx b/src/features/cv-preview/themes/BoldTheme.tsx new file mode 100644 index 0000000..836f4a3 --- /dev/null +++ b/src/features/cv-preview/themes/BoldTheme.tsx @@ -0,0 +1,270 @@ +import { ExternalLink, Globe } from "lucide-react"; +import type { CVData } from "../../../core/domain/cv.types"; +import { + CONTACT_ICONS, + SOCIAL_ICONS, + type ContactType, + type SocialType, +} from "../../shared/icon"; +import { useTranslation } from "react-i18next"; + +export const BoldTheme = ({ data }: { data: CVData }) => { + const { t } = useTranslation("theme", { + lng: data.metadata.language || "fr", + }); + + return ( +
+
+
+
+
+
+

+ {data.personalInfo.fullName || t("defaultName")} +

+

+ {data.personalInfo.title || t("defaultTitle")} +

+
+
+ +
+ {data.personalInfo.summary && ( +
+

+ {t("sections.summary")} +

+

+ {data.personalInfo.summary} +

+
+ )} + + {data.experiences?.length > 0 && ( +
+

+ {t("sections.experience")} +

+
+ {data.experiences.map((exp) => ( +
+
+
+

+ {exp.role} +

+

+ {exp.company} +

+
+ + {exp.startDate} — {exp.endDate} + +
+ {exp.mission?.length > 0 && ( +
    + {exp.mission.map((m, i) => ( +
  • + + → + + {m} +
  • + ))} +
+ )} +
+ ))} +
+
+ )} + + {data.educations?.length > 0 && ( +
+

+ {t("sections.education")} +

+
+ {data.educations.map((edu) => ( +
+
+

+ {edu.degree} +

+

+ {edu.school} +

+
+ + {edu.year} + +
+ ))} +
+
+ )} + + {data.certifications?.length > 0 && ( +
+

+ {t("sections.certifications")} +

+
+ {data.certifications.map((cert) => ( +
+
+

+ {cert.name} +

+ {cert.issuer && ( +

+ {cert.issuer} +

+ )} +
+ + {cert.year} + +
+ ))} +
+
+ )} +
+
+ + +
+ ); +}; diff --git a/src/features/cv-preview/themes/ThemeIndex.ts b/src/features/cv-preview/themes/ThemeIndex.ts index a1338af..c170e1a 100644 --- a/src/features/cv-preview/themes/ThemeIndex.ts +++ b/src/features/cv-preview/themes/ThemeIndex.ts @@ -5,8 +5,10 @@ import { StandardTheme } from "./StandardTheme"; import { HipsterTheme } from "./HipsterTheme"; import { ElegantTheme } from "./ElegantTheme"; import { NeoBentoTheme } from "./NeoBentoTheme"; +import { BoldTheme } from "./BoldTheme"; export const CV_THEMES = { + boldtheme: { component: BoldTheme, label: "Bold" }, classic: { component: ClassicTheme, label: "Classique" }, elegant: { component : ElegantTheme, label : "Elegant" }, hipster: { component : HipsterTheme, label : "Hipster" }, diff --git a/src/features/shared/components/Sidebar.tsx b/src/features/shared/components/Sidebar.tsx index 1b8f946..855988c 100644 --- a/src/features/shared/components/Sidebar.tsx +++ b/src/features/shared/components/Sidebar.tsx @@ -8,7 +8,7 @@ import { LANGUAGES } from "../../../core/config/language"; export const Sidebar = () => { const { t } = useTranslation("bar"); - const { data, updateData, reset } = useCvStore(); + const { data, updateData, reset, exemple } = useCvStore(); const { layout: currentUrlLayout } = useParams(); const [isThemeOpen, setIsThemeOpen] = useState(false); @@ -85,6 +85,22 @@ export const Sidebar = () => { +
+ + `flex items-center gap-3 p-3 rounded-lg transition-colors ${ + isActive + ? "bg-blue-600 text-white" + : "text-slate-400 hover:bg-slate-700 hover:text-white" + }` + } + > + {t("sidebar.exemple")} + +
+