* 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
@@ -0,0 +1,22 @@
import { useMemo } from "react";
import { CommandGroup } from "@reactive-resume/ui/components/command";
import { useCommandPaletteStore } from "../store";
type Props = {
page?: string;
heading: React.ReactNode;
children: React.ReactNode;
};
export const BaseCommandGroup = ({ page, heading, children }: Props) => {
const pages = useCommandPaletteStore((state) => state.pages);
const currentPage = pages[pages.length - 1];
const isEnabled = useMemo(() => {
return currentPage === page;
}, [currentPage, page]);
if (!isEnabled) return null;
return <CommandGroup heading={heading}>{children}</CommandGroup>;
};
@@ -0,0 +1,115 @@
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
import {
GearIcon,
HouseSimpleIcon,
KeyIcon,
OpenAiLogoIcon,
ReadCvLogoIcon,
ShieldCheckIcon,
UserCircleIcon,
WarningIcon,
} from "@phosphor-icons/react";
import { useNavigate, useRouteContext } from "@tanstack/react-router";
import { CommandItem } from "@reactive-resume/ui/components/command";
import { useCommandPaletteStore } from "../store";
import { BaseCommandGroup } from "./base";
export function NavigationCommandGroup() {
const navigate = useNavigate();
const { session } = useRouteContext({ strict: false });
const reset = useCommandPaletteStore((state) => state.reset);
const pushPage = useCommandPaletteStore((state) => state.pushPage);
const onNavigate = async (path: string) => {
await navigate({ to: path });
reset();
};
return (
<>
<BaseCommandGroup heading={<Trans>Go to...</Trans>}>
<CommandItem keywords={[t`Home`]} value="navigation.home" onSelect={() => onNavigate("/")}>
<HouseSimpleIcon />
<Trans>Home</Trans>
</CommandItem>
<CommandItem
disabled={!session}
keywords={[t`Resumes`]}
value="navigation.resumes"
onSelect={() => onNavigate("/dashboard/resumes")}
>
<ReadCvLogoIcon />
<Trans>Resumes</Trans>
</CommandItem>
<CommandItem
disabled={!session}
keywords={[t`Settings`]}
value="navigation.settings"
onSelect={() => pushPage("settings")}
>
<GearIcon />
<Trans>Settings</Trans>
</CommandItem>
</BaseCommandGroup>
<BaseCommandGroup page="settings" heading={<Trans>Settings</Trans>}>
<CommandItem
keywords={[t`Profile`]}
value="navigation.settings.profile"
onSelect={() => onNavigate("/dashboard/settings/profile")}
>
<UserCircleIcon />
<Trans>Profile</Trans>
</CommandItem>
<CommandItem
keywords={[t`Preferences`]}
value="navigation.settings.preferences"
onSelect={() => onNavigate("/dashboard/settings/preferences")}
>
<GearIcon />
<Trans>Preferences</Trans>
</CommandItem>
<CommandItem
keywords={[t`Authentication`]}
value="navigation.settings.authentication"
onSelect={() => onNavigate("/dashboard/settings/authentication")}
>
<ShieldCheckIcon />
<Trans>Authentication</Trans>
</CommandItem>
<CommandItem
keywords={[t`API Keys`]}
value="navigation.settings.api-keys"
onSelect={() => onNavigate("/dashboard/settings/api-keys")}
>
<KeyIcon />
<Trans>API Keys</Trans>
</CommandItem>
<CommandItem
keywords={[t`Integrations`, t`Artificial Intelligence`]}
value="navigation.settings.integrations"
onSelect={() => onNavigate("/dashboard/settings/integrations")}
>
<OpenAiLogoIcon />
<Trans>Integrations</Trans>
</CommandItem>
<CommandItem
keywords={[t`Danger Zone`]}
value="navigation.settings.danger-zone"
onSelect={() => onNavigate("/dashboard/settings/danger-zone")}
>
<WarningIcon />
<Trans>Danger Zone</Trans>
</CommandItem>
</BaseCommandGroup>
</>
);
}
@@ -0,0 +1,30 @@
import { Trans } from "@lingui/react/macro";
import { PaletteIcon, TranslateIcon } from "@phosphor-icons/react";
import { CommandItem } from "@reactive-resume/ui/components/command";
import { useCommandPaletteStore } from "../../store";
import { BaseCommandGroup } from "../base";
import { LanguageCommandPage } from "./language";
import { ThemeCommandPage } from "./theme";
export function PreferencesCommandGroup() {
const pushPage = useCommandPaletteStore((state) => state.pushPage);
return (
<>
<BaseCommandGroup heading={<Trans>Preferences</Trans>}>
<CommandItem onSelect={() => pushPage("theme")}>
<PaletteIcon />
<Trans>Change theme to...</Trans>
</CommandItem>
<CommandItem onSelect={() => pushPage("language")}>
<TranslateIcon />
<Trans>Change language to...</Trans>
</CommandItem>
</BaseCommandGroup>
<ThemeCommandPage />
<LanguageCommandPage />
</>
);
}
@@ -0,0 +1,26 @@
import { useLingui } from "@lingui/react";
import { Trans } from "@lingui/react/macro";
import { CommandItem } from "@reactive-resume/ui/components/command";
import { isLocale, loadLocale, localeMap, setLocaleServerFn } from "@/libs/locale";
import { BaseCommandGroup } from "../base";
export function LanguageCommandPage() {
const { i18n } = useLingui();
const handleLocaleChange = async (value: string) => {
if (!value || !isLocale(value)) return;
await Promise.all([loadLocale(value), setLocaleServerFn({ data: value })]);
window.location.reload();
};
return (
<BaseCommandGroup page="language" heading={<Trans>Language</Trans>}>
{Object.entries(localeMap).map(([value, label]) => (
<CommandItem key={value} onSelect={() => handleLocaleChange(value)}>
<span className="font-mono text-muted-foreground text-xs">{value}</span>
{i18n.t(label)}
</CommandItem>
))}
</BaseCommandGroup>
);
}
@@ -0,0 +1,30 @@
import { Trans } from "@lingui/react/macro";
import { MoonIcon, SunIcon } from "@phosphor-icons/react";
import { CommandItem } from "@reactive-resume/ui/components/command";
import { useTheme } from "@/components/theme/provider";
import { useCommandPaletteStore } from "../../store";
import { BaseCommandGroup } from "../base";
export function ThemeCommandPage() {
const { setTheme } = useTheme();
const setOpen = useCommandPaletteStore((state) => state.setOpen);
const handleThemeChange = (theme: "light" | "dark") => {
setTheme(theme, { playSound: false });
setOpen(false);
};
return (
<BaseCommandGroup page="theme" heading={<Trans>Theme</Trans>}>
<CommandItem value="light" onSelect={() => handleThemeChange("light")}>
<SunIcon />
<Trans>Light theme</Trans>
</CommandItem>
<CommandItem value="dark" onSelect={() => handleThemeChange("dark")}>
<MoonIcon />
<Trans>Dark theme</Trans>
</CommandItem>
</BaseCommandGroup>
);
}
@@ -0,0 +1,84 @@
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
import { PlusIcon, ReadCvLogoIcon } from "@phosphor-icons/react";
import { useQuery } from "@tanstack/react-query";
import { useNavigate, useRouteContext } from "@tanstack/react-router";
import { CommandLoading } from "cmdk";
import { CommandItem, CommandShortcut } from "@reactive-resume/ui/components/command";
import { Kbd } from "@reactive-resume/ui/components/kbd";
import { useDialogStore } from "@/dialogs/store";
import { orpc } from "@/libs/orpc/client";
import { useCommandPaletteStore } from "../store";
import { BaseCommandGroup } from "./base";
export function ResumesCommandGroup() {
const navigate = useNavigate();
const { openDialog } = useDialogStore();
const { session } = useRouteContext({ strict: false });
const reset = useCommandPaletteStore((state) => state.reset);
const peekPage = useCommandPaletteStore((state) => state.peekPage);
const pushPage = useCommandPaletteStore((state) => state.pushPage);
const isResumesPage = peekPage() === "resumes";
const { data: resumes, isLoading } = useQuery(
orpc.resume.list.queryOptions({
enabled: !!session && isResumesPage,
}),
);
const onCreate = async () => {
await navigate({ to: "/dashboard/resumes" });
openDialog("resume.create", undefined);
reset();
};
const onNavigate = async (path: string) => {
await navigate({ to: path });
reset();
};
if (!session) return null;
return (
<>
<BaseCommandGroup heading={<Trans>Search for...</Trans>}>
<CommandItem keywords={[t`Resumes`]} value="search.resumes" onSelect={() => pushPage("resumes")}>
<ReadCvLogoIcon />
<Trans>Resumes</Trans>
</CommandItem>
</BaseCommandGroup>
<BaseCommandGroup page="resumes" heading={<Trans>Resumes</Trans>}>
<CommandItem onSelect={onCreate}>
<PlusIcon />
<Trans>Create a new resume</Trans>
</CommandItem>
{isLoading ? (
<CommandLoading>
<Trans>Loading resumes...</Trans>
</CommandLoading>
) : (
resumes?.map((resume) => (
<CommandItem
key={resume.id}
value={resume.id}
keywords={[resume.name]}
onSelect={() => onNavigate(`/builder/${resume.id}`)}
>
<ReadCvLogoIcon />
{resume.name}
<CommandShortcut className="opacity-0 transition-opacity group-data-[selected=true]/command-item:opacity-100">
<Trans comment="Command palette hint that pressing Enter opens the selected resume">
Press <Kbd>Enter</Kbd> to open
</Trans>
</CommandShortcut>
</CommandItem>
))
)}
</BaseCommandGroup>
</>
);
}