Compare commits

..

11 Commits

Author SHA1 Message Date
62046c49b5 Merge pull request #2140 from AmruthPillai/release/v4.3.1
release: v4.3.1
2025-01-11 16:15:17 +01:00
3b73dcf29d fix issues brought up by coderabbit 2025-01-11 16:13:04 +01:00
9b20c46348 revert ci workflow to non-distributed 2025-01-11 16:09:07 +01:00
996ef650db update CI 2025-01-11 16:01:19 +01:00
1c36ac1d68 update CI workflow 2025-01-11 15:59:36 +01:00
198c269790 remove console.log statements 2025-01-11 15:55:06 +01:00
58ef309b68 release: v4.3.1 2025-01-11 15:38:26 +01:00
54bace451c Merge pull request #2138 from AmruthPillai/dependabot/npm_and_yarn/npm_and_yarn-45c02561f4
Bump the npm_and_yarn group across 1 directory with 10 updates
2025-01-11 14:03:54 +01:00
193b15edc1 Merge branch 'main' into dependabot/npm_and_yarn/npm_and_yarn-45c02561f4 2025-01-11 13:22:39 +01:00
e4ec678512 pin versions of chromium 2025-01-11 13:17:14 +01:00
29c18c1e89 Bump the npm_and_yarn group across 1 directory with 10 updates
Bumps the npm_and_yarn group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `5.4.2` | `5.4.6` |
| [braces](https://github.com/micromatch/braces) | `3.0.2` | `3.0.3` |
| [dset](https://github.com/lukeed/dset) | `3.1.3` | `3.1.4` |
| [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) | `4.3.5` | `4.5.1` |
| [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) | `2.0.6` | `2.0.7` |
| [nanoid](https://github.com/ai/nanoid) | `3.3.7` | `3.3.8` |
| [pug](https://github.com/pugjs/pug) | `3.0.2` | `3.0.3` |
| [rollup](https://github.com/rollup/rollup) | `4.21.0` | `4.30.1` |
| [webpack](https://github.com/webpack/webpack) | `5.90.3` | `5.97.1` |
| [ws](https://github.com/websockets/ws) | `7.5.9` | `7.5.10` |



Updates `vite` from 5.4.2 to 5.4.6
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.6/packages/vite)

Updates `braces` from 3.0.2 to 3.0.3
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

Updates `dset` from 3.1.3 to 3.1.4
- [Release notes](https://github.com/lukeed/dset/releases)
- [Commits](https://github.com/lukeed/dset/compare/v3.1.3...v3.1.4)

Updates `fast-xml-parser` from 4.3.5 to 4.5.1
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v4.3.5...v4.5.1)

Updates `http-proxy-middleware` from 2.0.6 to 2.0.7
- [Release notes](https://github.com/chimurai/http-proxy-middleware/releases)
- [Changelog](https://github.com/chimurai/http-proxy-middleware/blob/v2.0.7/CHANGELOG.md)
- [Commits](https://github.com/chimurai/http-proxy-middleware/compare/v2.0.6...v2.0.7)

Updates `nanoid` from 3.3.7 to 3.3.8
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

Updates `pug` from 3.0.2 to 3.0.3
- [Release notes](https://github.com/pugjs/pug/releases)
- [Commits](https://github.com/pugjs/pug/compare/pug@3.0.2...pug@3.0.3)

Updates `rollup` from 4.21.0 to 4.30.1
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.21.0...v4.30.1)

Updates `webpack` from 5.90.3 to 5.97.1
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.90.3...v5.97.1)

Updates `ws` from 7.5.9 to 7.5.10
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.5.9...7.5.10)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: braces
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: dset
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: fast-xml-parser
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: http-proxy-middleware
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: nanoid
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: pug
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: rollup
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: webpack
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: ws
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-11 11:37:06 +00:00
35 changed files with 1138 additions and 786 deletions

View File

@ -9,6 +9,7 @@
"plugins": ["simple-import-sort", "unused-imports"],
"rules": {
// eslint
"no-console": "error",
"no-return-await": "off",
// simple-import-sort

View File

@ -19,33 +19,30 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.2.2
with:
fetch-depth: 2
- name: Setup pnpm
uses: pnpm/action-setup@v3.0.0
uses: pnpm/action-setup@v4.0.0
- name: Setup Node.js
uses: actions/setup-node@v4.0.2
uses: actions/setup-node@v4.1.0
with:
cache: "pnpm"
node-version: 20.17.0
node-version: 22
- name: Install Dependencies
run: pnpm install --frozen-lockfile
- name: Lint
run: pnpm lint
run: pnpm run lint
- name: Format
run: pnpm format:check
run: pnpm run format:check
- name: Test
run: pnpm test
run: pnpm run test
- name: Build
run: pnpm build
env:
NODE_ENV: production
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
run: pnpm run build

View File

@ -17,7 +17,8 @@ export async function dynamicActivate(locale: string) {
if (dayjsLocales[locale]) {
dayjs.locale(await dayjsLocales[locale]());
}
} catch (error) {
console.error(error);
} catch {
// eslint-disable-next-line lingui/no-unlocalized-strings
throw new Error(`Failed to load messages for locale: ${locale}`);
}
}

View File

@ -104,7 +104,13 @@ export const AwardsDialog = () => {
{...field}
content={field.value}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
field.onChange(value);
}}
/>
)}
onChange={(value) => {
field.onChange(value);

View File

@ -98,7 +98,13 @@ export const CertificationsDialog = () => {
{...field}
content={field.value}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
field.onChange(value);
}}
/>
)}
onChange={(value) => {
field.onChange(value);

View File

@ -131,7 +131,13 @@ export const CustomSectionDialog = () => {
{...field}
content={field.value}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
field.onChange(value);
}}
/>
)}
onChange={(value) => {
field.onChange(value);

View File

@ -141,7 +141,13 @@ export const EducationDialog = () => {
{...field}
content={field.value}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
field.onChange(value);
}}
/>
)}
onChange={(value) => {
field.onChange(value);

View File

@ -117,7 +117,13 @@ export const ExperienceDialog = () => {
{...field}
content={field.value}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
field.onChange(value);
}}
/>
)}
onChange={(value) => {
field.onChange(value);

View File

@ -74,10 +74,10 @@ export const LanguagesDialog = () => {
}}
/>
{field.value === 0 ? (
<span className="text-base font-bold">{t`Hidden`}</span>
) : (
{field.value > 0 ? (
<span className="text-base font-bold">{field.value}</span>
) : (
<span className="text-base font-bold">{t`Hidden`}</span>
)}
</div>
</FormControl>

View File

@ -51,7 +51,7 @@ export const ProfilesDialog = () => {
<FormLabel>{t`Network`}</FormLabel>
<FormControl>
{/* eslint-disable-next-line lingui/no-unlocalized-strings */}
<Input {...field} placeholder="LinkedIn" />
<Input {...field} placeholder="GitHub" />
</FormControl>
<FormMessage />
</FormItem>
@ -79,7 +79,7 @@ export const ProfilesDialog = () => {
<FormItem className="sm:col-span-2">
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://linkedin.com/in/johndoe" />
<URLInput {...field} placeholder="https://github.com/johndoe" />
</FormControl>
<FormMessage />
</FormItem>
@ -100,7 +100,7 @@ export const ProfilesDialog = () => {
<Input
{...field}
id="iconSlug"
placeholder="linkedin"
placeholder="github"
onChange={(event) => {
field.onChange(event);
handleIconChange(event);

View File

@ -111,7 +111,13 @@ export const ProjectsDialog = () => {
{...field}
content={field.value}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
field.onChange(value);
}}
/>
)}
onChange={(value) => {
field.onChange(value);

View File

@ -98,7 +98,13 @@ export const PublicationsDialog = () => {
{...field}
content={field.value}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
field.onChange(value);
}}
/>
)}
onChange={(value) => {
field.onChange(value);

View File

@ -84,7 +84,13 @@ export const ReferencesDialog = () => {
{...field}
content={field.value}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
field.onChange(value);
}}
/>
)}
onChange={(value) => {
field.onChange(value);

View File

@ -88,10 +88,10 @@ export const SkillsDialog = () => {
}}
/>
{field.value === 0 ? (
<span className="text-base font-bold">{t`Hidden`}</span>
) : (
{field.value > 0 ? (
<span className="text-base font-bold">{field.value}</span>
) : (
<span className="text-base font-bold">{t`Hidden`}</span>
)}
</div>
</FormControl>

View File

@ -112,7 +112,13 @@ export const VolunteerDialog = () => {
{...field}
content={field.value}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
field.onChange(value);
}}
/>
)}
onChange={(value) => {
field.onChange(value);

View File

@ -1,4 +1,4 @@
import { t } from "@lingui/macro";
import { t, Trans } from "@lingui/macro";
import { createId } from "@paralleldrive/cuid2";
import { DotsSixVertical, Envelope, Plus, X } from "@phosphor-icons/react";
import { CustomField as ICustomField } from "@reactive-resume/schema";
@ -37,10 +37,10 @@ export const CustomField = ({ field, onChange, onRemove }: CustomFieldProps) =>
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -50 }}
>
<div className="flex items-end justify-between space-x-2">
<div className="flex items-end justify-between">
<Button
size="icon"
variant="link"
variant="ghost"
className="shrink-0"
onPointerDown={(event) => {
controls.start(event);
@ -52,12 +52,12 @@ export const CustomField = ({ field, onChange, onRemove }: CustomFieldProps) =>
<Popover>
<Tooltip content={t`Icon`}>
<PopoverTrigger asChild>
<Button size="icon" variant="ghost">
<Button size="icon" variant="ghost" className="shrink-0">
{field.icon ? <i className={cn(`ph ph-${field.icon}`)} /> : <Envelope />}
</Button>
</PopoverTrigger>
</Tooltip>
<PopoverContent className="p-1.5">
<PopoverContent side="bottom" align="start" className="flex flex-col gap-y-1.5 p-1.5">
<Input
value={field.icon}
placeholder={t`Enter Phosphor Icon`}
@ -65,19 +65,35 @@ export const CustomField = ({ field, onChange, onRemove }: CustomFieldProps) =>
onChange({ ...field, icon: event.target.value });
}}
/>
<p className="text-xs opacity-80">
<Trans>
Visit{" "}
<a
href="https://phosphoricons.com/"
target="_blank"
className="underline"
rel="noopener noreferrer nofollow"
>
Phosphor Icons
</a>{" "}
for a list of available icons
</Trans>
</p>
</PopoverContent>
</Popover>
<Input
className="mx-2"
placeholder={t`Name`}
value={field.name}
className="!ml-0"
onChange={(event) => {
handleChange("name", event.target.value);
}}
/>
<Input
className="mx-2"
placeholder={t`Value`}
value={field.value}
onChange={(event) => {
@ -87,8 +103,8 @@ export const CustomField = ({ field, onChange, onRemove }: CustomFieldProps) =>
<Button
size="icon"
variant="link"
className="!ml-0 shrink-0"
variant="ghost"
className="shrink-0"
onClick={() => {
onRemove(field.id);
}}
@ -111,7 +127,7 @@ export const CustomFieldsSection = ({ className }: Props) => {
const onAddCustomField = () => {
setValue("basics.customFields", [
...customFields,
{ id: createId(), icon: "", name: "", value: "" },
{ id: createId(), icon: "envelope", name: "", value: "" },
]);
};

View File

@ -70,12 +70,15 @@ export const SectionBase = <T extends SectionItem>({ id, title, description }: P
const onCreate = () => {
open("create", { id });
};
const onUpdate = (item: T) => {
open("update", { id, item });
};
const onDuplicate = (item: T) => {
open("duplicate", { id, item });
};
const onDelete = (item: T) => {
open("delete", { id, item });
};

View File

@ -1,6 +1,7 @@
import { t } from "@lingui/macro";
import { createId } from "@paralleldrive/cuid2";
import { CopySimple, PencilSimple, Plus } from "@phosphor-icons/react";
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
import { SectionItem, SectionWithItem } from "@reactive-resume/schema";
import {
AlertDialog,
@ -14,6 +15,7 @@ import {
Button,
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
@ -158,6 +160,10 @@ export const SectionDialog = <T extends SectionItem>({
</h2>
</div>
</DialogTitle>
<VisuallyHidden>
<DialogDescription />
</VisuallyHidden>
</DialogHeader>
{children}

View File

@ -3,11 +3,12 @@ import { CSS } from "@dnd-kit/utilities";
import { t } from "@lingui/macro";
import { CopySimple, DotsSixVertical, PencilSimple, TrashSimple } from "@phosphor-icons/react";
import {
ContextMenu,
ContextMenuCheckboxItem,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@reactive-resume/ui";
import { cn } from "@reactive-resume/utils";
import { motion } from "framer-motion";
@ -68,8 +69,8 @@ export const SectionListItem = ({
</div>
{/* List Item */}
<ContextMenu>
<ContextMenuTrigger asChild>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<div
className={cn(
"flex-1 cursor-context-menu p-4 hover:bg-secondary-accent",
@ -80,25 +81,26 @@ export const SectionListItem = ({
<h4 className="font-medium leading-relaxed">{title}</h4>
{description && <p className="text-xs leading-relaxed opacity-50">{description}</p>}
</div>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuCheckboxItem checked={visible} onCheckedChange={onToggleVisibility}>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuCheckboxItem checked={visible} onCheckedChange={onToggleVisibility}>
<span className="-ml-0.5">{t`Visible`}</span>
</ContextMenuCheckboxItem>
<ContextMenuItem onClick={onUpdate}>
</DropdownMenuCheckboxItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={onUpdate}>
<PencilSimple size={14} />
<span className="ml-2">{t`Edit`}</span>
</ContextMenuItem>
<ContextMenuItem onClick={onDuplicate}>
</DropdownMenuItem>
<DropdownMenuItem onClick={onDuplicate}>
<CopySimple size={14} />
<span className="ml-2">{t`Copy`}</span>
</ContextMenuItem>
<ContextMenuItem className="text-error" onClick={onDelete}>
</DropdownMenuItem>
<DropdownMenuItem className="text-error" onClick={onDelete}>
<TrashSimple size={14} />
<span className="ml-2">{t`Remove`}</span>
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</motion.section>
);

View File

@ -32,7 +32,13 @@ export const SummarySection = () => {
<RichInput
content={section.content}
footer={(editor) => (
<AiActions value={editor.getText()} onChange={editor.commands.setContent} />
<AiActions
value={editor.getText()}
onChange={(value) => {
editor.commands.setContent(value, true);
setValue("sections.summary.content", value);
}}
/>
)}
onChange={(value) => {
setValue("sections.summary.content", value);

View File

@ -1,5 +1,6 @@
import { Card } from "@reactive-resume/ui";
import { cn } from "@reactive-resume/utils";
import { forwardRef } from "react";
import Tilt from "react-parallax-tilt";
import { defaultTiltProps } from "@/client/constants/parallax-tilt";
@ -10,16 +11,19 @@ type Props = {
children?: React.ReactNode;
};
export const BaseCard = ({ children, className, onClick }: Props) => (
<Tilt {...defaultTiltProps}>
<Card
className={cn(
"relative flex aspect-[1/1.4142] scale-100 cursor-pointer items-center justify-center bg-secondary/50 p-0 transition-transform active:scale-95",
className,
)}
onClick={onClick}
>
{children}
</Card>
</Tilt>
export const BaseCard = forwardRef<HTMLDivElement, Props>(
({ children, className, onClick }, ref) => (
<Tilt {...defaultTiltProps}>
<Card
ref={ref}
className={cn(
"relative flex aspect-[1/1.4142] scale-100 cursor-pointer items-center justify-center bg-secondary/50 p-0 transition-transform active:scale-95",
className,
)}
onClick={onClick}
>
{children}
</Card>
</Tilt>
),
);

View File

@ -9,11 +9,11 @@ import {
} from "@phosphor-icons/react";
import { ResumeDto } from "@reactive-resume/dto";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuTrigger,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@reactive-resume/ui";
import { cn } from "@reactive-resume/utils";
import dayjs from "dayjs";
@ -33,6 +33,7 @@ export const ResumeCard = ({ resume }: Props) => {
const { open } = useDialog<ResumeDto>("resume");
const { open: lockOpen } = useDialog<ResumeDto>("lock");
const template = resume.data.metadata.template;
const lastUpdated = dayjs().to(resume.updatedAt);
const onOpen = () => {
@ -56,9 +57,9 @@ export const ResumeCard = ({ resume }: Props) => {
};
return (
<ContextMenu>
<ContextMenuTrigger>
<BaseCard className="space-y-0" onClick={onOpen}>
<DropdownMenu>
<DropdownMenuTrigger className="text-left">
<BaseCard className="cursor-context-menu space-y-0">
<AnimatePresence>
{resume.locked && (
<motion.div
@ -81,39 +82,45 @@ export const ResumeCard = ({ resume }: Props) => {
<h4 className="line-clamp-2 font-medium">{resume.title}</h4>
<p className="line-clamp-1 text-xs opacity-75">{t`Last updated ${lastUpdated}`}</p>
</div>
</BaseCard>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem onClick={onOpen}>
<img
src={`/templates/jpg/${template}.jpg`}
alt={template}
className="rounded-sm opacity-80"
/>
</BaseCard>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={onOpen}>
<FolderOpen size={14} className="mr-2" />
{t`Open`}
</ContextMenuItem>
<ContextMenuItem onClick={onUpdate}>
</DropdownMenuItem>
<DropdownMenuItem onClick={onUpdate}>
<PencilSimple size={14} className="mr-2" />
{t`Rename`}
</ContextMenuItem>
<ContextMenuItem onClick={onDuplicate}>
</DropdownMenuItem>
<DropdownMenuItem onClick={onDuplicate}>
<CopySimple size={14} className="mr-2" />
{t`Duplicate`}
</ContextMenuItem>
</DropdownMenuItem>
{resume.locked ? (
<ContextMenuItem onClick={onLockChange}>
<DropdownMenuItem onClick={onLockChange}>
<LockOpen size={14} className="mr-2" />
{t`Unlock`}
</ContextMenuItem>
</DropdownMenuItem>
) : (
<ContextMenuItem onClick={onLockChange}>
<DropdownMenuItem onClick={onLockChange}>
<Lock size={14} className="mr-2" />
{t`Lock`}
</ContextMenuItem>
</DropdownMenuItem>
)}
<ContextMenuSeparator />
<ContextMenuItem className="text-error" onClick={onDelete}>
<DropdownMenuSeparator />
<DropdownMenuItem className="text-error" onClick={onDelete}>
<TrashSimple size={14} className="mr-2" />
{t`Delete`}
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};

View File

@ -12,7 +12,6 @@ import {
FormMessage,
Input,
} from "@reactive-resume/ui";
import { cn } from "@reactive-resume/utils";
import { useForm } from "react-hook-form";
import { z } from "zod";
@ -29,6 +28,7 @@ const formSchema = z.object({
.string()
// eslint-disable-next-line lingui/no-unlocalized-strings
.regex(/https?:\/\/[^/]+\/?v1$/, "That doesn't look like a valid URL")
.or(z.literal(""))
.default(""),
model: z.string().default(DEFAULT_MODEL),
maxTokens: z.number().default(DEFAULT_MAX_TOKENS),
@ -39,7 +39,8 @@ type FormValues = z.infer<typeof formSchema>;
export const OpenAISettings = () => {
const { apiKey, setApiKey, baseURL, setBaseURL, model, setModel, maxTokens, setMaxTokens } =
useOpenAiStore();
const isEnabled = !!apiKey || !!baseURL || !!model || !!maxTokens;
const isEnabled = !!apiKey;
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
@ -75,7 +76,7 @@ export const OpenAISettings = () => {
return (
<div className="space-y-6">
<div>
<h3 className="text-2xl font-bold leading-relaxed tracking-tight">{t`OpenAI Integration`}</h3>
<h3 className="text-2xl font-bold leading-relaxed tracking-tight">{t`OpenAI/Ollama Integration`}</h3>
<p className="leading-relaxed opacity-75">
{t`You can make use of the OpenAI API to help you generate content, or improve your writing while composing your resume.`}
</p>
@ -97,16 +98,13 @@ export const OpenAISettings = () => {
from your settings.
</Trans>
</p>
</div>
<h3 className="text-2xl font-bold leading-relaxed tracking-tight">{t`Ollama Integration`}</h3>
<div className="prose prose-sm prose-zinc max-w-full dark:prose-invert">
<p>
<Trans>
You can integrate with Ollama simply by setting the API key to `sk-1234567890abcdef` and
the Base URL to your Ollama URL, i.e. `http://localhost:11434/v1`. You can also pick and
choose models and set the max tokens.
You can also integrate with Ollama simply by setting the API key to
`sk-1234567890abcdef` and the Base URL to your Ollama URL, i.e.
`http://localhost:11434/v1`. You can also pick and choose models and set the max tokens
as per your preference.
</Trans>
</p>
</div>
@ -118,7 +116,7 @@ export const OpenAISettings = () => {
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>{t`OpenAI / Ollama API Key`}</FormLabel>
<FormLabel>{t`OpenAI/Ollama API Key`}</FormLabel>
<FormControl>
<Input type="password" placeholder="sk-..." {...field} />
</FormControl>
@ -172,12 +170,7 @@ export const OpenAISettings = () => {
</FormItem>
)}
/>
<div
className={cn(
"flex items-center space-x-2 self-end sm:col-start-2",
!!form.formState.errors.apiKey && "self-center",
)}
>
<div className="flex items-center space-x-2 self-end sm:col-start-2">
<Button type="submit" disabled={!form.formState.isValid}>
{isEnabled && <FloppyDisk className="mr-2" />}
{isEnabled ? t`Saved` : t`Save Locally`}

View File

@ -204,7 +204,10 @@ export class PrinterService {
return resumeUrl;
} catch (error) {
console.trace(error);
throw new InternalServerErrorException(
ErrorMessage.ResumePrinterError,
(error as Error).message,
);
}
}

View File

@ -6,7 +6,7 @@ import { defaultItem, itemSchema } from "../shared";
export const languageSchema = itemSchema.extend({
name: z.string().min(1),
description: z.string(),
level: z.number().min(0).max(5).default(1),
level: z.coerce.number().min(0).max(5).default(1),
});
// Type

View File

@ -6,7 +6,7 @@ import { defaultItem, itemSchema } from "../shared";
export const skillSchema = itemSchema.extend({
name: z.string(),
description: z.string(),
level: z.number().min(0).max(5).default(1),
level: z.coerce.number().min(0).max(5).default(1),
keywords: z.array(z.string()).default([]),
});

View File

@ -34,7 +34,7 @@
"!{projectRoot}/test-setup.[jt]s",
"!{projectRoot}/**/*.stories.@(js|jsx|ts|tsx|mdx)"
],
"sharedGlobals": []
"sharedGlobals": ["{workspaceRoot}/.github/workflows/lint-test-build.yml"]
},
"generators": {
"@nx/react": {

View File

@ -1,7 +1,7 @@
{
"name": "@reactive-resume/source",
"description": "A free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.",
"version": "4.3.0",
"version": "4.3.1",
"license": "MIT",
"private": true,
"author": {
@ -113,7 +113,7 @@
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.5.4",
"vite": "^5.4.2",
"vite": "^5.4.6",
"vite-plugin-dts": "^4.1.0",
"vitest": "^2.0.5"
},
@ -166,6 +166,7 @@
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@radix-ui/react-visually-hidden": "^1.1.1",
"@swc/helpers": "^0.5.12",
"@tanstack/react-query": "^5.53.2",
"@tiptap/extension-highlight": "^2.6.6",
@ -238,7 +239,7 @@
"zundo": "^2.1.0",
"zustand": "^4.5.5"
},
"packageManager": "pnpm@9.9.0+sha512.60c18acd138bff695d339be6ad13f7e936eea6745660d4cc4a776d5247c540d0edee1a563695c183a66eb917ef88f2b4feb1fc25f32a7adcadc7aaf3438e99c1",
"packageManager": "pnpm@9.15.3+sha512.1f79bc245a66eb0b07c5d4d83131240774642caaa86ef7d0434ab47c0d16f66b04e21e0c086eb61e62c77efc4d7f7ec071afad3796af64892fae66509173893a",
"engines": {
"node": ">=20.13.1"
},

1562
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
services:
# Database (Postgres)
postgres:
image: postgres:latest
image: postgres:16-alpine
restart: unless-stopped
ports:
- ${POSTGRES_PORT:-5432}:5432
@ -52,7 +52,7 @@ services:
# Chrome Browser (for printing and previews)
chrome:
image: ghcr.io/browserless/chromium:latest
image: ghcr.io/browserless/chromium:v2.18.0 # Upgrading to newer versions causes issues
restart: unless-stopped
ports:
- ${CHROME_PORT:-8080}:3000

View File

@ -22,7 +22,7 @@ services:
# Storage (for image uploads)
minio:
image: minio/minio
image: minio/minio:latest
restart: unless-stopped
command: server /data
volumes:
@ -39,7 +39,7 @@ services:
# Chrome Browser (for printing and previews)
chrome:
image: ghcr.io/browserless/chromium:latest
image: ghcr.io/browserless/chromium:v2.18.0 # Upgrading to newer versions causes issues
restart: unless-stopped
environment:
TIMEOUT: 10000

View File

@ -21,7 +21,7 @@ services:
# Storage (for image uploads)
minio:
image: minio/minio
image: minio/minio:latest
restart: unless-stopped
command: server /data
ports:
@ -34,7 +34,7 @@ services:
# Chrome Browser (for printing and previews)
chrome:
image: ghcr.io/browserless/chromium:latest
image: ghcr.io/browserless/chromium:v2.18.0 # Upgrading to newer versions causes issues
restart: unless-stopped
environment:
TIMEOUT: 10000

View File

@ -28,7 +28,7 @@ services:
# Storage (for image uploads)
minio:
image: minio/minio
image: minio/minio:latest
command: server /data
networks:
- reactive_resume_network
@ -50,7 +50,7 @@ services:
# Chrome Browser (for printing and previews)
chrome:
image: ghcr.io/browserless/chromium:latest
image: ghcr.io/browserless/chromium:v2.18.0 # Upgrading to newer versions causes issues
networks:
- reactive_resume_network
environment:

View File

@ -24,7 +24,7 @@ services:
# Storage (for image uploads)
minio:
image: minio/minio
image: minio/minio:latest
restart: unless-stopped
command: server /data
volumes:
@ -41,7 +41,7 @@ services:
# Chrome Browser (for printing and previews)
chrome:
image: ghcr.io/browserless/chromium:latest
image: ghcr.io/browserless/chromium:v2.18.0 # Upgrading to newer versions causes issues
restart: unless-stopped
environment:
TIMEOUT: 10000

View File

@ -24,7 +24,7 @@ services:
# Storage (for image uploads)
minio:
image: minio/minio
image: minio/minio:latest
restart: unless-stopped
command: server /data
volumes:
@ -39,7 +39,7 @@ services:
# Chrome Browser (for printing and previews)
chrome:
image: ghcr.io/browserless/chromium:latest
image: ghcr.io/browserless/chromium:v2.18.0 # Upgrading to newer versions causes issues
restart: unless-stopped
environment:
TIMEOUT: 10000