mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-22 12:41:31 +10:00
feat(i18n): implement localization using LinguiJS
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { awardSchema, defaultAward } from "@reactive-resume/schema";
|
||||
import {
|
||||
FormControl,
|
||||
@ -35,9 +36,9 @@ export const AwardsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Title</FormLabel>
|
||||
<FormLabel>{t({ message: "Title", context: "Name of the Award" })}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="3rd Runner Up" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -49,9 +50,9 @@ export const AwardsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Awarder</FormLabel>
|
||||
<FormLabel>{t`Awarder`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="TechCrunch Disrupt SF" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -63,9 +64,15 @@ export const AwardsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Date</FormLabel>
|
||||
<FormLabel>{t`Date`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Aug 2019" />
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t({
|
||||
message: "March 2023",
|
||||
comment: "The month and year should be uniform across all languages.",
|
||||
})}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -77,9 +84,9 @@ export const AwardsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Website</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} placeholder="https://techcrunch.com/events/disrupt-sf-2019" />
|
||||
<URLInput {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -91,7 +98,7 @@ export const AwardsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<FormLabel>{t`Summary`}</FormLabel>
|
||||
<FormControl>
|
||||
<RichInput
|
||||
{...field}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { certificationSchema, defaultCertification } from "@reactive-resume/schema";
|
||||
import {
|
||||
FormControl,
|
||||
@ -35,9 +36,9 @@ export const CertificationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{t({ message: "Name", context: "Name of the Certification" })}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Web Developer Bootcamp" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -49,9 +50,9 @@ export const CertificationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Issuer</FormLabel>
|
||||
<FormLabel>{t`Issuer`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Udemy" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -63,9 +64,9 @@ export const CertificationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Date</FormLabel>
|
||||
<FormLabel>{t`Date`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Aug 2019" />
|
||||
<Input {...field} placeholder={t`March 2023`} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -77,7 +78,7 @@ export const CertificationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Website</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} placeholder="https://udemy.com/certificate/UC-..." />
|
||||
</FormControl>
|
||||
@ -91,7 +92,7 @@ export const CertificationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<FormLabel>{t`Summary`}</FormLabel>
|
||||
<FormControl>
|
||||
<RichInput
|
||||
{...field}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { X } from "@phosphor-icons/react";
|
||||
import { CustomSection, customSectionSchema, defaultCustomSection } from "@reactive-resume/schema";
|
||||
import {
|
||||
@ -49,7 +50,7 @@ export const CustomSectionDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{t`Name`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
@ -63,7 +64,7 @@ export const CustomSectionDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Description</FormLabel>
|
||||
<FormLabel>{t`Description`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
@ -77,7 +78,7 @@ export const CustomSectionDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Date</FormLabel>
|
||||
<FormLabel>{t`Date`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
@ -91,7 +92,7 @@ export const CustomSectionDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Location</FormLabel>
|
||||
<FormLabel>{t`Location`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
@ -105,7 +106,7 @@ export const CustomSectionDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-2">
|
||||
<FormLabel>Website</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} />
|
||||
</FormControl>
|
||||
@ -119,7 +120,7 @@ export const CustomSectionDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<FormLabel>{t`Summary`}</FormLabel>
|
||||
<FormControl>
|
||||
<RichInput
|
||||
{...field}
|
||||
@ -141,12 +142,12 @@ export const CustomSectionDialog = () => {
|
||||
render={({ field }) => (
|
||||
<div className="col-span-2 space-y-3">
|
||||
<FormItem>
|
||||
<FormLabel>Keywords</FormLabel>
|
||||
<FormLabel>{t`Keywords`}</FormLabel>
|
||||
<FormControl>
|
||||
<BadgeInput {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
You can add multiple keywords by separating them with a comma.
|
||||
{t`You can add multiple keywords by separating them with a comma or pressing enter.`}
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { defaultEducation, educationSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
FormControl,
|
||||
@ -35,9 +36,9 @@ export const EducationDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Institution</FormLabel>
|
||||
<FormLabel>{t`Institution`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Carnegie Mellon University" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -49,9 +50,14 @@ export const EducationDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Type of Study</FormLabel>
|
||||
<FormLabel>
|
||||
{t({
|
||||
message: "Type of Study",
|
||||
comment: "For example, Bachelor's Degree or Master's Degree",
|
||||
})}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Bachelor's Degree" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -63,9 +69,14 @@ export const EducationDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Area of Study</FormLabel>
|
||||
<FormLabel>
|
||||
{t({
|
||||
message: "Area of Study",
|
||||
comment: "For example, Computer Science or Business Administration",
|
||||
})}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Computer Science" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -77,7 +88,12 @@ export const EducationDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Score</FormLabel>
|
||||
<FormLabel>
|
||||
{t({
|
||||
message: "Score",
|
||||
comment: "Score or honors for the degree, for example, CGPA or magna cum laude",
|
||||
})}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="9.2 GPA" />
|
||||
</FormControl>
|
||||
@ -91,9 +107,9 @@ export const EducationDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Date</FormLabel>
|
||||
<FormLabel>{t`Date`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Aug 2006 - Oct 2012" />
|
||||
<Input {...field} placeholder={t`March 2023 - Present`} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -105,9 +121,9 @@ export const EducationDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Website</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} placeholder="https://www.cmu.edu/" />
|
||||
<URLInput {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -119,7 +135,7 @@ export const EducationDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<FormLabel>{t`Summary`}</FormLabel>
|
||||
<FormControl>
|
||||
<RichInput
|
||||
{...field}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { defaultExperience, experienceSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
FormControl,
|
||||
@ -35,9 +36,9 @@ export const ExperienceDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Company</FormLabel>
|
||||
<FormLabel>{t`Company`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Alphabet Inc." />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -49,9 +50,14 @@ export const ExperienceDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Position</FormLabel>
|
||||
<FormLabel>
|
||||
{t({
|
||||
message: "Position",
|
||||
context: "Position held at a company, for example, Software Engineer",
|
||||
})}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Chief Executive Officer" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -63,9 +69,9 @@ export const ExperienceDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Date</FormLabel>
|
||||
<FormLabel>{t`Date`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Dec 2019 - Present" />
|
||||
<Input {...field} placeholder={t`March 2023 - Present`} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -77,9 +83,9 @@ export const ExperienceDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Location</FormLabel>
|
||||
<FormLabel>{t`Location`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="New York, NY" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -91,9 +97,9 @@ export const ExperienceDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Website</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} placeholder="https://www.abc.xyz/" />
|
||||
<URLInput {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -105,7 +111,7 @@ export const ExperienceDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<FormLabel>{t`Summary`}</FormLabel>
|
||||
<FormControl>
|
||||
<RichInput
|
||||
{...field}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { X } from "@phosphor-icons/react";
|
||||
import { defaultInterest, interestSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
@ -36,9 +37,9 @@ export const InterestsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-2">
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{t`Name`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Video Games" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -51,12 +52,12 @@ export const InterestsDialog = () => {
|
||||
render={({ field }) => (
|
||||
<div className="col-span-2 space-y-3">
|
||||
<FormItem>
|
||||
<FormLabel>Keywords</FormLabel>
|
||||
<FormLabel>{t`Keywords`}</FormLabel>
|
||||
<FormControl>
|
||||
<BadgeInput {...field} placeholder="FIFA 23, Call of Duty, etc." />
|
||||
<BadgeInput {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
You can add multiple keywords by separating them with a comma.
|
||||
{t`You can add multiple keywords by separating them with a comma or pressing enter.`}
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { defaultLanguage, languageSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
FormControl,
|
||||
@ -33,9 +34,9 @@ export const LanguagesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{t`Name`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="German" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -47,9 +48,9 @@ export const LanguagesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Fluency</FormLabel>
|
||||
<FormLabel>{t`Fluency`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Native Speaker" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -61,7 +62,7 @@ export const LanguagesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-2">
|
||||
<FormLabel>Fluency (CEFR)</FormLabel>
|
||||
<FormLabel>{t`Fluency (CEFR)`}</FormLabel>
|
||||
<FormControl className="py-2">
|
||||
<div className="flex items-center gap-x-4">
|
||||
<Slider
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { defaultProfile, profileSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
Avatar,
|
||||
@ -35,8 +36,9 @@ export const ProfilesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Network</FormLabel>
|
||||
<FormLabel>{t`Network`}</FormLabel>
|
||||
<FormControl>
|
||||
{/* eslint-disable-next-line lingui/no-unlocalized-strings */}
|
||||
<Input {...field} placeholder="LinkedIn" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@ -49,9 +51,9 @@ export const ProfilesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormLabel>{t`Username`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="johndoe" />
|
||||
<Input {...field} placeholder="john.doe" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -63,7 +65,7 @@ export const ProfilesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>URL</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} placeholder="https://linkedin.com/in/johndoe" />
|
||||
</FormControl>
|
||||
@ -77,7 +79,7 @@ export const ProfilesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-2">
|
||||
<FormLabel htmlFor="iconSlug">Icon</FormLabel>
|
||||
<FormLabel htmlFor="iconSlug">{t`Icon`}</FormLabel>
|
||||
<FormControl>
|
||||
<div className="flex items-center gap-x-2">
|
||||
<Avatar className="h-8 w-8 bg-white">
|
||||
@ -93,15 +95,17 @@ export const ProfilesDialog = () => {
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription className="ml-10">
|
||||
Powered by{" "}
|
||||
<a
|
||||
href="https://simpleicons.org/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
className="font-medium"
|
||||
>
|
||||
Simple Icons
|
||||
</a>
|
||||
<Trans>
|
||||
Powered by{" "}
|
||||
<a
|
||||
href="https://simpleicons.org/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
className="font-medium"
|
||||
>
|
||||
Simple Icons
|
||||
</a>
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { X } from "@phosphor-icons/react";
|
||||
import { defaultProject, projectSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
@ -40,9 +41,9 @@ export const ProjectsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{t`Name`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Reactive Resume" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -54,9 +55,9 @@ export const ProjectsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Description</FormLabel>
|
||||
<FormLabel>{t`Description`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Open Source Resume Builder" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -68,9 +69,9 @@ export const ProjectsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Date</FormLabel>
|
||||
<FormLabel>{t`Date`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Sep 2018 - Present" />
|
||||
<Input {...field} placeholder={t`March 2023 - Present`} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -82,7 +83,7 @@ export const ProjectsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Website</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} placeholder="https://rxresu.me" />
|
||||
</FormControl>
|
||||
@ -96,7 +97,7 @@ export const ProjectsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<FormLabel>{t`Summary`}</FormLabel>
|
||||
<FormControl>
|
||||
<RichInput
|
||||
{...field}
|
||||
@ -118,12 +119,12 @@ export const ProjectsDialog = () => {
|
||||
render={({ field }) => (
|
||||
<div className="col-span-2 space-y-3">
|
||||
<FormItem>
|
||||
<FormLabel>Keywords</FormLabel>
|
||||
<FormLabel>{t`Keywords`}</FormLabel>
|
||||
<FormControl>
|
||||
<BadgeInput {...field} placeholder="FIFA 23, Call of Duty, etc." />
|
||||
<BadgeInput {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
You can add multiple keywords by separating them with a comma.
|
||||
{t`You can add multiple keywords by separating them with a comma or pressing enter.`}
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { defaultPublication, publicationSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
FormControl,
|
||||
@ -35,9 +36,9 @@ export const PublicationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{t`Name`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="The Great Gatsby" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -49,9 +50,9 @@ export const PublicationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Publisher</FormLabel>
|
||||
<FormLabel>{t`Publisher`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Charles Scribner's Sons" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -63,9 +64,9 @@ export const PublicationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Release Date</FormLabel>
|
||||
<FormLabel>{t`Date`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="April 10, 1925" />
|
||||
<Input {...field} placeholder={t`March 2023`} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -77,9 +78,9 @@ export const PublicationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Website</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} placeholder="https://books.google.com/..." />
|
||||
<URLInput {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -91,7 +92,7 @@ export const PublicationsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<FormLabel>{t`Summary`}</FormLabel>
|
||||
<FormControl>
|
||||
<RichInput
|
||||
{...field}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { defaultReference, referenceSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
FormControl,
|
||||
@ -35,9 +36,9 @@ export const ReferencesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{t`Name`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Cosmo Kramer" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -49,9 +50,9 @@ export const ReferencesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Description</FormLabel>
|
||||
<FormLabel>{t`Description`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Neighbour" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -63,9 +64,9 @@ export const ReferencesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-2">
|
||||
<FormLabel>Website</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} placeholder="https://linkedin.com/in/cosmo.kramer" />
|
||||
<URLInput {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -77,7 +78,7 @@ export const ReferencesDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<FormLabel>{t`Summary`}</FormLabel>
|
||||
<FormControl>
|
||||
<RichInput
|
||||
{...field}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { X } from "@phosphor-icons/react";
|
||||
import { defaultSkill, skillSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
@ -37,9 +38,9 @@ export const SkillsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{t`Name`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Content Management" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -51,9 +52,9 @@ export const SkillsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Description</FormLabel>
|
||||
<FormLabel>{t`Description`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Advanced" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -65,7 +66,7 @@ export const SkillsDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-2">
|
||||
<FormLabel>Level</FormLabel>
|
||||
<FormLabel>{t`Level`}</FormLabel>
|
||||
<FormControl className="py-2">
|
||||
<div className="flex items-center gap-x-4">
|
||||
<Slider
|
||||
@ -91,12 +92,12 @@ export const SkillsDialog = () => {
|
||||
render={({ field }) => (
|
||||
<div className="col-span-2 space-y-3">
|
||||
<FormItem>
|
||||
<FormLabel>Keywords</FormLabel>
|
||||
<FormLabel>{t`Keywords`}</FormLabel>
|
||||
<FormControl>
|
||||
<BadgeInput {...field} placeholder="WordPress, Joomla, Webflow etc." />
|
||||
<BadgeInput {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
You can add multiple keywords by separating them with a comma.
|
||||
{t`You can add multiple keywords by separating them with a comma or pressing enter.`}
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/macro";
|
||||
import { defaultVolunteer, volunteerSchema } from "@reactive-resume/schema";
|
||||
import {
|
||||
FormControl,
|
||||
@ -35,9 +36,9 @@ export const VolunteerDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Organization</FormLabel>
|
||||
<FormLabel>{t`Organization`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Amnesty International" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -49,9 +50,9 @@ export const VolunteerDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Position</FormLabel>
|
||||
<FormLabel>{t`Position`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Recruiter" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -63,9 +64,9 @@ export const VolunteerDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Date</FormLabel>
|
||||
<FormLabel>{t`Date`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Dec 2016 - Aug 2017" />
|
||||
<Input {...field} placeholder={t`March 2023 - Present`} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -77,9 +78,9 @@ export const VolunteerDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1">
|
||||
<FormLabel>Location</FormLabel>
|
||||
<FormLabel>{t`Location`}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="New York, NY" />
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -91,9 +92,9 @@ export const VolunteerDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Website</FormLabel>
|
||||
<FormLabel>{t`Website`}</FormLabel>
|
||||
<FormControl>
|
||||
<URLInput {...field} placeholder="https://www.amnesty.org/" />
|
||||
<URLInput {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -105,7 +106,7 @@ export const VolunteerDialog = () => {
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<FormLabel>{t`Summary`}</FormLabel>
|
||||
<FormControl>
|
||||
<RichInput
|
||||
{...field}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { Plus, PlusCircle } from "@phosphor-icons/react";
|
||||
import {
|
||||
Award,
|
||||
@ -50,7 +51,15 @@ export const LeftSidebar = () => {
|
||||
</Button>
|
||||
|
||||
<div className="flex flex-col items-center justify-center gap-y-2">
|
||||
<SectionIcon id="basics" name="Basics" onClick={() => scrollIntoView("#basics")} />
|
||||
<SectionIcon
|
||||
id="basics"
|
||||
onClick={() => scrollIntoView("#basics")}
|
||||
name={t({
|
||||
message: "Basics",
|
||||
context:
|
||||
"The Basics section of a Resume consists of User's Picture, Full Name, Location etc.",
|
||||
})}
|
||||
/>
|
||||
<SectionIcon id="summary" onClick={() => scrollIntoView("#summary")} />
|
||||
<SectionIcon id="profiles" onClick={() => scrollIntoView("#profiles")} />
|
||||
<SectionIcon id="experience" onClick={() => scrollIntoView("#experience")} />
|
||||
@ -68,10 +77,11 @@ export const LeftSidebar = () => {
|
||||
<SectionIcon
|
||||
id="custom"
|
||||
variant="outline"
|
||||
name="Add a new section"
|
||||
name={t`Add a new section`}
|
||||
icon={<Plus size={14} />}
|
||||
onClick={() => {
|
||||
addSection();
|
||||
// eslint-disable-next-line lingui/no-unlocalized-strings
|
||||
scrollIntoView("& > section:last-of-type");
|
||||
}}
|
||||
/>
|
||||
@ -184,7 +194,7 @@ export const LeftSidebar = () => {
|
||||
|
||||
<Button size="lg" variant="outline" onClick={addSection}>
|
||||
<PlusCircle />
|
||||
<span className="ml-2">Add a new section</span>
|
||||
<span className="ml-2">{t`Add a new section`}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { basicsSchema } from "@reactive-resume/schema";
|
||||
import { Input, Label } from "@reactive-resume/ui";
|
||||
|
||||
@ -17,7 +18,7 @@ export const BasicsSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("basics")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Basics</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Basics`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -27,10 +28,9 @@ export const BasicsSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 sm:col-span-2">
|
||||
<Label htmlFor="basics.name">Full Name</Label>
|
||||
<Label htmlFor="basics.name">{t`Full Name`}</Label>
|
||||
<Input
|
||||
id="basics.name"
|
||||
placeholder="John Doe"
|
||||
value={basics.name}
|
||||
hasError={!basicsSchema.pick({ name: true }).safeParse({ name: basics.name }).success}
|
||||
onChange={(event) => setValue("basics.name", event.target.value)}
|
||||
@ -38,17 +38,16 @@ export const BasicsSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 sm:col-span-2">
|
||||
<Label htmlFor="basics.headline">Headline</Label>
|
||||
<Label htmlFor="basics.headline">{t`Headline`}</Label>
|
||||
<Input
|
||||
id="basics.headline"
|
||||
placeholder="Highly Creative Frontend Web Developer"
|
||||
value={basics.headline}
|
||||
onChange={(event) => setValue("basics.headline", event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="basics.email">Email Address</Label>
|
||||
<Label htmlFor="basics.email">{t`Email`}</Label>
|
||||
<Input
|
||||
id="basics.email"
|
||||
placeholder="john.doe@example.com"
|
||||
@ -61,7 +60,7 @@ export const BasicsSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="basics.url">Website</Label>
|
||||
<Label htmlFor="basics.url">{t`Website`}</Label>
|
||||
<URLInput
|
||||
id="basics.url"
|
||||
value={basics.url}
|
||||
@ -71,7 +70,7 @@ export const BasicsSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="basics.phone">Phone Number</Label>
|
||||
<Label htmlFor="basics.phone">{t`Phone`}</Label>
|
||||
<Input
|
||||
id="basics.phone"
|
||||
placeholder="+1 (123) 4567 7890"
|
||||
@ -81,10 +80,9 @@ export const BasicsSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="basics.location">Location</Label>
|
||||
<Label htmlFor="basics.location">{t`Location`}</Label>
|
||||
<Input
|
||||
id="basics.location"
|
||||
placeholder="105 Cedarhurst Ave, Cedarhurst, NY 11516"
|
||||
value={basics.location}
|
||||
onChange={(event) => setValue("basics.location", event.target.value)}
|
||||
/>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
import { DotsSixVertical, Plus, X } from "@phosphor-icons/react";
|
||||
import { CustomField as ICustomField } from "@reactive-resume/schema";
|
||||
@ -38,21 +39,22 @@ export const CustomField = ({ field, onChange, onRemove }: CustomFieldProps) =>
|
||||
<DotsSixVertical />
|
||||
</Button>
|
||||
|
||||
<Input
|
||||
placeholder="Icon"
|
||||
{/* <Input
|
||||
placeholder={t`Icon`}
|
||||
value={field.icon}
|
||||
className="!ml-0"
|
||||
onChange={(event) => handleChange("icon", event.target.value)}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
<Input
|
||||
placeholder="Name"
|
||||
placeholder={t`Name`}
|
||||
value={field.name}
|
||||
className="!ml-0"
|
||||
onChange={(event) => handleChange("name", event.target.value)}
|
||||
/>
|
||||
|
||||
<Input
|
||||
placeholder="Value"
|
||||
placeholder={t`Value`}
|
||||
value={field.value}
|
||||
onChange={(event) => handleChange("value", event.target.value)}
|
||||
/>
|
||||
@ -126,7 +128,7 @@ export const CustomFieldsSection = ({ className }: Props) => {
|
||||
|
||||
<Button variant="link" onClick={onAddCustomField}>
|
||||
<Plus className="mr-2" />
|
||||
<span>Add a custom field</span>
|
||||
<span>{t`Add a custom field`}</span>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import {
|
||||
AspectRatio,
|
||||
Checkbox,
|
||||
@ -69,7 +70,7 @@ export const PictureOptions = () => {
|
||||
<div className="flex flex-col gap-y-5">
|
||||
<div className="grid grid-cols-3 items-center gap-x-6">
|
||||
<Label htmlFor="picture.size" className="col-span-1">
|
||||
Size (in px)
|
||||
{t`Size (in px)`}
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
@ -85,7 +86,7 @@ export const PictureOptions = () => {
|
||||
|
||||
<div className="grid grid-cols-3 items-center gap-x-6">
|
||||
<Label htmlFor="picture.aspectRatio" className="col-span-1">
|
||||
Aspect Ratio
|
||||
{t`Aspect Ratio`}
|
||||
</Label>
|
||||
<div className="col-span-2 flex items-center justify-between">
|
||||
<ToggleGroup
|
||||
@ -94,19 +95,19 @@ export const PictureOptions = () => {
|
||||
onValueChange={onAspectRatioChange}
|
||||
className="flex items-center justify-center"
|
||||
>
|
||||
<Tooltip content="Square">
|
||||
<Tooltip content={t`Square`}>
|
||||
<ToggleGroupItem value="square">
|
||||
<div className="h-3 w-3 border border-foreground" />
|
||||
</ToggleGroupItem>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content="Horizontal">
|
||||
<Tooltip content={t`Horizontal`}>
|
||||
<ToggleGroupItem value="horizontal">
|
||||
<div className="h-2 w-3 border border-foreground" />
|
||||
</ToggleGroupItem>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content="Portrait">
|
||||
<Tooltip content={t`Portrait`}>
|
||||
<ToggleGroupItem value="portrait">
|
||||
<div className="h-3 w-2 border border-foreground" />
|
||||
</ToggleGroupItem>
|
||||
@ -130,7 +131,7 @@ export const PictureOptions = () => {
|
||||
|
||||
<div className="grid grid-cols-3 items-center gap-x-6">
|
||||
<Label htmlFor="picture.borderRadius" className="col-span-1">
|
||||
Border Radius
|
||||
{t`Border Radius`}
|
||||
</Label>
|
||||
<div className="col-span-2 flex items-center justify-between">
|
||||
<ToggleGroup
|
||||
@ -139,19 +140,19 @@ export const PictureOptions = () => {
|
||||
onValueChange={onBorderRadiusChange}
|
||||
className="flex items-center justify-center"
|
||||
>
|
||||
<Tooltip content="Square">
|
||||
<Tooltip content={t`Square`}>
|
||||
<ToggleGroupItem value="square">
|
||||
<div className="h-3 w-3 border border-foreground" />
|
||||
</ToggleGroupItem>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content="Rounded">
|
||||
<Tooltip content={t`Rounded`}>
|
||||
<ToggleGroupItem value="rounded">
|
||||
<div className="h-3 w-3 rounded-sm border border-foreground" />
|
||||
</ToggleGroupItem>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content="Circle">
|
||||
<Tooltip content={t`Circle`}>
|
||||
<ToggleGroupItem value="circle">
|
||||
<div className="h-3 w-3 rounded-full border border-foreground" />
|
||||
</ToggleGroupItem>
|
||||
@ -176,7 +177,7 @@ export const PictureOptions = () => {
|
||||
<div>
|
||||
<div className="grid grid-cols-3 items-start gap-x-6">
|
||||
<div className="col-span-1">
|
||||
<Label>Effects</Label>
|
||||
<Label>{t`Effects`}</Label>
|
||||
</div>
|
||||
<div className="col-span-2 space-y-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
@ -187,7 +188,7 @@ export const PictureOptions = () => {
|
||||
setValue("basics.picture.effects.hidden", checked);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="picture.effects.hidden">Hidden</Label>
|
||||
<Label htmlFor="picture.effects.hidden">{t`Hidden`}</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
@ -198,7 +199,7 @@ export const PictureOptions = () => {
|
||||
setValue("basics.picture.effects.border", checked);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="picture.effects.border">Border</Label>
|
||||
<Label htmlFor="picture.effects.border">{t`Border`}</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
@ -209,7 +210,7 @@ export const PictureOptions = () => {
|
||||
setValue("basics.picture.effects.grayscale", checked);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="picture.effects.grayscale">Grayscale</Label>
|
||||
<Label htmlFor="picture.effects.grayscale">{t`Grayscale`}</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { Aperture, UploadSimple } from "@phosphor-icons/react";
|
||||
import {
|
||||
Avatar,
|
||||
@ -48,7 +49,7 @@ export const PictureSection = () => {
|
||||
</Avatar>
|
||||
|
||||
<div className="flex w-full flex-col gap-y-1.5">
|
||||
<Label htmlFor="basics.picture.url">Picture</Label>
|
||||
<Label htmlFor="basics.picture.url">{t`Picture`}</Label>
|
||||
<div className="flex items-center gap-x-2">
|
||||
<Input
|
||||
id="basics.picture.url"
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
sortableKeyboardCoordinates,
|
||||
verticalListSortingStrategy,
|
||||
} from "@dnd-kit/sortable";
|
||||
import { t } from "@lingui/macro";
|
||||
import { Plus } from "@phosphor-icons/react";
|
||||
import { SectionItem, SectionKey, SectionWithItem } from "@reactive-resume/schema";
|
||||
import { Button } from "@reactive-resume/ui";
|
||||
@ -103,7 +104,12 @@ export const SectionBase = <T extends SectionItem>({ id, title, description }: P
|
||||
className="gap-x-2 border-dashed py-6 leading-relaxed hover:bg-secondary-accent"
|
||||
>
|
||||
<Plus size={14} />
|
||||
<span className="font-medium">Add New {section.name}</span>
|
||||
<span className="font-medium">
|
||||
{t({
|
||||
message: "Add New Item",
|
||||
context: "For example, add a new work experience, or add a new profile.",
|
||||
})}
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@ -137,7 +143,12 @@ export const SectionBase = <T extends SectionItem>({ id, title, description }: P
|
||||
<footer className="flex items-center justify-end">
|
||||
<Button variant="outline" className="ml-auto gap-x-2" onClick={onCreate}>
|
||||
<Plus />
|
||||
<span>Add New {section.name}</span>
|
||||
<span>
|
||||
{t({
|
||||
message: "Add New Item",
|
||||
context: "For example, add a new work experience, or add a new profile.",
|
||||
})}
|
||||
</span>
|
||||
</Button>
|
||||
</footer>
|
||||
)}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
import { CopySimple, PencilSimple, Plus } from "@phosphor-icons/react";
|
||||
import { SectionItem, SectionWithItem } from "@reactive-resume/schema";
|
||||
@ -20,7 +21,7 @@ import {
|
||||
} from "@reactive-resume/ui";
|
||||
import { produce } from "immer";
|
||||
import get from "lodash.get";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
|
||||
import { DialogName, useDialog } from "@/client/stores/dialog";
|
||||
@ -40,12 +41,12 @@ export const SectionDialog = <T extends SectionItem>({
|
||||
children,
|
||||
}: Props<T>) => {
|
||||
const { isOpen, mode, close, payload } = useDialog<T>(id);
|
||||
|
||||
const setValue = useResumeStore((state) => state.setValue);
|
||||
const section = useResumeStore((state) => {
|
||||
if (!id) return null;
|
||||
return get(state.resume.data.sections, id);
|
||||
}) as SectionWithItem<T> | null;
|
||||
const name = useMemo(() => section?.name ?? "", [section?.name]);
|
||||
|
||||
const isCreate = mode === "create";
|
||||
const isUpdate = mode === "update";
|
||||
@ -111,18 +112,16 @@ export const SectionDialog = <T extends SectionItem>({
|
||||
<Form {...form}>
|
||||
<form>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Are you sure you want to delete this {name}?</AlertDialogTitle>
|
||||
<AlertDialogTitle>{t`Are you sure you want to delete this item?`}</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action can be reverted by clicking on the undo button in the floating
|
||||
toolbar.
|
||||
{t`This action can be reverted by clicking on the undo button in the floating toolbar.`}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
|
||||
<AlertDialogCancel>{t`Cancel`}</AlertDialogCancel>
|
||||
<AlertDialogAction variant="error" onClick={form.handleSubmit(onSubmit)}>
|
||||
Delete
|
||||
{t`Delete`}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</form>
|
||||
@ -144,9 +143,9 @@ export const SectionDialog = <T extends SectionItem>({
|
||||
{isUpdate && <PencilSimple />}
|
||||
{isDuplicate && <CopySimple />}
|
||||
<h2>
|
||||
{isCreate && `Create a new ${name}`}
|
||||
{isUpdate && `Update an existing ${name}`}
|
||||
{isDuplicate && `Duplicate an existing ${name}`}
|
||||
{isCreate && t`Create a new item`}
|
||||
{isUpdate && t`Update an existing item`}
|
||||
{isDuplicate && t`Duplicate an existing item`}
|
||||
</h2>
|
||||
</div>
|
||||
</DialogTitle>
|
||||
@ -156,9 +155,9 @@ export const SectionDialog = <T extends SectionItem>({
|
||||
|
||||
<DialogFooter>
|
||||
<Button type="submit">
|
||||
{isCreate && "Create"}
|
||||
{isUpdate && "Save Changes"}
|
||||
{isDuplicate && "Duplicate"}
|
||||
{isCreate && t`Create`}
|
||||
{isUpdate && t`Save Changes`}
|
||||
{isDuplicate && t`Duplicate`}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { useSortable } from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
import { t } from "@lingui/macro";
|
||||
import { CopySimple, DotsSixVertical, PencilSimple, TrashSimple } from "@phosphor-icons/react";
|
||||
import {
|
||||
DropdownMenu,
|
||||
@ -81,19 +82,19 @@ export const SectionListItem = ({
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="center" side="left" sideOffset={-16}>
|
||||
<DropdownMenuCheckboxItem checked={visible} onCheckedChange={onToggleVisibility}>
|
||||
<span className="-ml-0.5">Visible</span>
|
||||
<span className="-ml-0.5">{t`Visible`}</span>
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuItem onClick={onUpdate}>
|
||||
<PencilSimple size={14} />
|
||||
<span className="ml-2">Edit</span>
|
||||
<span className="ml-2">{t`Edit`}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={onDuplicate}>
|
||||
<CopySimple size={14} />
|
||||
<span className="ml-2">Copy</span>
|
||||
<span className="ml-2">{t`Copy`}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="text-error" onClick={onDelete}>
|
||||
<TrashSimple size={14} />
|
||||
<span className="ml-2">Remove</span>
|
||||
<span className="ml-2">{t`Remove`}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { plural, t } from "@lingui/macro";
|
||||
import {
|
||||
ArrowCounterClockwise,
|
||||
Broom,
|
||||
@ -63,7 +64,7 @@ export const SectionOptions = ({ id }: Props) => {
|
||||
<>
|
||||
<DropdownMenuItem onClick={onCreate}>
|
||||
<Plus />
|
||||
<span className="ml-2">Add a new item</span>
|
||||
<span className="ml-2">{t`Add a new item`}</span>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
@ -73,12 +74,12 @@ export const SectionOptions = ({ id }: Props) => {
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem onClick={toggleVisibility}>
|
||||
{section.visible ? <Eye /> : <EyeSlash />}
|
||||
<span className="ml-2">{section.visible ? "Hide" : "Show"}</span>
|
||||
<span className="ml-2">{section.visible ? t`Hide` : t`Show`}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<PencilSimple />
|
||||
<span className="ml-2">Rename</span>
|
||||
<span className="ml-2">{t`Rename`}</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>
|
||||
<div className="relative col-span-2">
|
||||
@ -103,15 +104,15 @@ export const SectionOptions = ({ id }: Props) => {
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<Columns />
|
||||
<span className="ml-2">Columns</span>
|
||||
<span className="ml-2">{t`Columns`}</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuRadioGroup value={`${section.columns}`} onValueChange={onChangeColumns}>
|
||||
<DropdownMenuRadioItem value="1">1 Column</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="2">2 Columns</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="3">3 Columns</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="4">4 Columns</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="5">5 Columns</DropdownMenuRadioItem>
|
||||
{Array.from({ length: 5 }, (_, i) => i + 1).map((value) => (
|
||||
<DropdownMenuRadioItem value={`${value}`}>
|
||||
{plural(value, { one: "Column", other: "Columns" })}
|
||||
</DropdownMenuRadioItem>
|
||||
))}
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
@ -119,12 +120,12 @@ export const SectionOptions = ({ id }: Props) => {
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem disabled={!hasItems} onClick={onResetItems}>
|
||||
<Broom />
|
||||
<span className="ml-2">Reset</span>
|
||||
<span className="ml-2">{t`Reset`}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem className="text-error" disabled={!isCustomSection} onClick={onRemove}>
|
||||
<TrashSimple />
|
||||
<span className="ml-2">Remove</span>
|
||||
<span className="ml-2">{t`Remove`}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { Tag } from "@phosphor-icons/react";
|
||||
import { URL, urlSchema } from "@reactive-resume/schema";
|
||||
import { Button, Input, Popover, PopoverContent, PopoverTrigger } from "@reactive-resume/ui";
|
||||
@ -36,14 +37,14 @@ export const URLInput = forwardRef<HTMLInputElement, Props>(
|
||||
<PopoverContent className="p-1.5">
|
||||
<Input
|
||||
value={value.label}
|
||||
placeholder="Label"
|
||||
placeholder={t`Label`}
|
||||
onChange={(event) => onChange({ ...value, label: event.target.value })}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
{hasError && <small className="opacity-75">URL must start with https://</small>}
|
||||
{hasError && <small className="opacity-75">{t`URL must start with https://`}</small>}
|
||||
</>
|
||||
);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user