* chore(release): v5.1.0

* feat: implement resume thumbnails

* fix: remove unused mcp tools

* docs: fix formatting of docs
This commit is contained in:
Amruth Pillai
2026-05-07 15:12:33 +02:00
committed by GitHub
parent 51c366310e
commit 50ba37a27f
1015 changed files with 106087 additions and 141872 deletions
+98
View File
@@ -0,0 +1,98 @@
import * as React from "react";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@reactive-resume/ui/components/alert-dialog";
import { cn } from "@reactive-resume/utils/style";
interface ConfirmOptions {
description?: string;
confirmText?: string;
cancelText?: string;
}
interface ConfirmState extends ConfirmOptions {
open: boolean;
title: string;
resolve: ((value: boolean) => void) | null;
}
type ConfirmContextType = {
confirm: (title: string, options?: ConfirmOptions) => Promise<boolean>;
};
const ConfirmContext = React.createContext<ConfirmContextType | null>(null);
export function ConfirmDialogProvider({ children }: { children: React.ReactNode }) {
const [state, setState] = React.useState<ConfirmState>({
open: false,
resolve: null,
title: "",
description: undefined,
confirmText: undefined,
cancelText: undefined,
});
const confirm = React.useCallback(async (title: string, options?: ConfirmOptions): Promise<boolean> => {
return new Promise<boolean>((resolve) => {
setState({
open: true,
resolve,
title,
description: options?.description,
confirmText: options?.confirmText,
cancelText: options?.cancelText,
});
});
}, []);
const handleConfirm = React.useCallback(() => {
if (state.resolve) state.resolve(true);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve]);
const handleCancel = React.useCallback(() => {
if (state.resolve) state.resolve(false);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve]);
return (
<ConfirmContext.Provider value={{ confirm }}>
{children}
<AlertDialog open={state.open} onOpenChange={(open) => !open && handleCancel()}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{state.title}</AlertDialogTitle>
<AlertDialogDescription className={cn(!state.description && "sr-only")}>
{state.description}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={handleCancel}>{state.cancelText ?? "Cancel"}</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirm}>{state.confirmText ?? "Confirm"}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</ConfirmContext.Provider>
);
}
export function useConfirm() {
const context = React.useContext(ConfirmContext);
if (!context) {
throw new Error("useConfirm must be used within a <ConfirmDialogProvider />.");
}
return context.confirm;
}
@@ -0,0 +1,32 @@
import { useCallback, useEffect, useState } from "react";
interface CommonControlledStateProps<T> {
value?: T;
defaultValue?: T;
}
type UseControlledStateProps<T, Rest extends unknown[] = []> = CommonControlledStateProps<T> & {
onChange?: (value: T, ...args: Rest) => void;
};
export function useControlledState<T, Rest extends unknown[] = []>(
props: UseControlledStateProps<T, Rest>,
): readonly [T, (next: T, ...args: Rest) => void] {
const { value, defaultValue, onChange } = props;
const [state, setInternalState] = useState<T>(value !== undefined ? value : (defaultValue as T));
useEffect(() => {
if (value !== undefined) setInternalState(value);
}, [value]);
const setState = useCallback(
(next: T, ...args: Rest) => {
setInternalState(next);
onChange?.(next, ...args);
},
[onChange],
);
return [state, setState] as const;
}
+69
View File
@@ -0,0 +1,69 @@
import { t } from "@lingui/core/macro";
import { useStore } from "@tanstack/react-form";
import { useCallback, useEffect } from "react";
import { useDialogStore } from "@/dialogs/store";
import { useConfirm } from "@/hooks/use-confirm";
interface UseFormBlockerOptions {
shouldBlock?: () => boolean;
}
type BlockableFormStore = {
get: () => {
isDirty: boolean;
isSubmitting: boolean;
};
subscribe: {
(observer: {
next?: (value: { isDirty: boolean; isSubmitting: boolean }) => void;
error?: (error: unknown) => void;
complete?: () => void;
}): { unsubscribe: () => void };
(
next: (value: { isDirty: boolean; isSubmitting: boolean }) => void,
error?: (error: unknown) => void,
complete?: () => void,
): { unsubscribe: () => void };
};
};
export function useFormBlocker<TStore extends BlockableFormStore>(
form: { store: TStore },
options?: UseFormBlockerOptions,
) {
const confirm = useConfirm();
const closeDialog = useDialogStore((state) => state.closeDialog);
const setOnBeforeClose = useDialogStore((state) => state.setOnBeforeClose);
const isDirty = useStore(form.store, (state) => state.isDirty);
const isSubmitting = useStore(form.store, (state) => state.isSubmitting);
const shouldBlock = useCallback(() => {
if (options?.shouldBlock) return options.shouldBlock();
return isDirty && !isSubmitting;
}, [options, isDirty, isSubmitting]);
const confirmClose = useCallback(async () => {
if (!shouldBlock()) return true;
return confirm(t`Are you sure you want to close this dialog?`, {
description: t`You have unsaved changes that will be lost.`,
confirmText: t`Leave`,
cancelText: t`Stay`,
});
}, [shouldBlock, confirm]);
const requestClose = useCallback(async () => {
const confirmed = await confirmClose();
if (!confirmed) return;
closeDialog();
}, [confirmClose, closeDialog]);
useEffect(() => {
setOnBeforeClose(confirmClose);
return () => setOnBeforeClose(null);
}, [confirmClose, setOnBeforeClose]);
return { requestClose };
}
+20
View File
@@ -0,0 +1,20 @@
import { useEffect, useState } from "react";
const MOBILE_BREAKPOINT = 768;
const MOBILE_QUERY = `(max-width: ${MOBILE_BREAKPOINT - 1}px)`;
export function useIsMobile() {
const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);
useEffect(() => {
const mql = window.matchMedia(MOBILE_QUERY);
const onChange = (e: MediaQueryListEvent) => {
setIsMobile(e.matches);
};
mql.addEventListener("change", onChange);
setIsMobile(mql.matches);
return () => mql.removeEventListener("change", onChange);
}, []);
return !!isMobile;
}
+142
View File
@@ -0,0 +1,142 @@
import { t } from "@lingui/core/macro";
import * as React from "react";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@reactive-resume/ui/components/alert-dialog";
import { Input } from "@reactive-resume/ui/components/input";
import { cn } from "@reactive-resume/utils/style";
type PromptOptions = {
description?: string;
defaultValue?: string;
confirmText?: string;
cancelText?: string;
inputProps?: Omit<React.ComponentProps<typeof Input>, "value" | "onChange" | "onKeyDown">;
};
type PromptState = PromptOptions & {
open: boolean;
title: string;
value: string;
resolve: ((value: string | null) => void) | null;
};
type PromptContextType = {
prompt: (title: string, options?: PromptOptions) => Promise<string | null>;
};
const PromptContext = React.createContext<PromptContextType | null>(null);
export function PromptDialogProvider({ children }: { children: React.ReactNode }) {
const inputRef = React.useRef<HTMLInputElement>(null);
const [state, setState] = React.useState<PromptState>({
open: false,
resolve: null,
title: "",
value: "",
description: undefined,
defaultValue: undefined,
confirmText: undefined,
cancelText: undefined,
inputProps: undefined,
});
const cancelText = state.cancelText ?? t`Cancel`;
const confirmText = state.confirmText ?? t`Confirm`;
React.useEffect(() => {
if (!state.open) return;
setTimeout(() => {
if (!inputRef.current) return;
inputRef.current.focus();
}, 0);
}, [state.open]);
const prompt = React.useCallback(async (title: string, options?: PromptOptions): Promise<string | null> => {
return new Promise<string | null>((resolve) => {
setState({
open: true,
resolve,
title,
value: options?.defaultValue ?? "",
description: options?.description,
defaultValue: options?.defaultValue,
confirmText: options?.confirmText,
cancelText: options?.cancelText,
inputProps: options?.inputProps,
});
});
}, []);
const handleConfirm = React.useCallback(() => {
if (state.resolve) state.resolve(state.value);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve, state.value]);
const handleCancel = React.useCallback(() => {
if (state.resolve) state.resolve(null);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve]);
const handleValueChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setState((prev) => ({ ...prev, value: e.target.value }));
}, []);
const handleKeyDown = React.useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") handleConfirm();
},
[handleConfirm],
);
return (
<PromptContext.Provider value={{ prompt }}>
{children}
<AlertDialog open={state.open} onOpenChange={(open) => !open && handleCancel()}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{state.title}</AlertDialogTitle>
<AlertDialogDescription className={cn(!state.description && "sr-only")}>
{state.description}
</AlertDialogDescription>
</AlertDialogHeader>
<Input
ref={inputRef}
value={state.value}
onKeyDown={handleKeyDown}
onChange={handleValueChange}
{...state.inputProps}
/>
<AlertDialogFooter>
<AlertDialogCancel onClick={handleCancel}>{cancelText}</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirm}>{confirmText}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</PromptContext.Provider>
);
}
export function usePrompt() {
const context = React.useContext(PromptContext);
if (!context) {
throw new Error("usePrompt must be used within a <PromptDialogProvider />.");
}
return context.prompt;
}