mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-27 18:34:51 +10:00
3e16586d7a
* feat: add job listings feature with JSearch API integration, resume tailoring, and per-user rate limiting * feat(jobs): add search filters UI, filter helper functions with tests, and job_search_quota DB migration * feat(jobs): add pagination with 30 results per page and prev/next navigation * refactor(job-detail): Adjust sheet width and scroll area height * feat(ai): Add resume tailoring feature and prompt * refactor(ai): Revise tailoring prompts and schema for full skill rewrite * feat(ai): Add reference tailoring and output sanitization * feat(testing): Add Vitest testing framework * fix: address PR review - atomic rate limiting, calendar-month quota, skill sync warning, gitignore routeTree.gen.ts * feat(jobs): Add location filter to job listings * feat(job-listings): Add DOCX document generation * feat(job-listings): Enable search by location and on Enter key * feat(job-listings): Split location filter into city, state, and country * feat(jobs): Implement job search adapter and JSearch * Update 'locale/' directory * feat(resume): Simplify filename generation and add tests * fix(JSearch): reduce JSearch API usage to 1 request per search to prevent quota exhaustion * fix(JSearch): Displayed quota amounts on Job Search functionality and settings fixed to pull from RapidAPI/JSearch response * fix(internal rate limit): Removed internal rate limit and .env.example addition, cloud based implementation handles. * style(job-filters): Adjust layout of switch filters * fix(typecheck): Fixed typecheck issues introduced to sync with origin * feat(jobs): Enhance tailor dialog with apply link and tags * feat(locale files): updated locale files with the latest build * feat(jobs): Add job search provider and integrate testing functionality - Introduced `createJobSearchProvider` function to instantiate a JSearchProvider. - Enhanced job search provider with methods for searching jobs, retrieving job details, and testing connection. - Updated `vite.config.ts` to include new testing configurations and plugins. - Added new dependencies in `package.json` for testing and document generation. - Removed obsolete `vitest.config.ts` file. - Improved job search provider tests for better coverage and reliability. * refactor: Update job search routes and remove obsolete test configurations - Removed the test configuration from `vite.config.ts`. - Updated localization files to reflect changes in job search routes, renaming references from `jobs` to `job-search` across multiple languages. - Adjusted autofix workflow to run formatting without the `--fix` flag for better control over code style adjustments. * chore: Update dependencies and improve animation performance - Added `jsdom` as a new dependency in `package.json`. - Updated `vite-plus` and `vitest` to the latest versions for better compatibility. - Enhanced animation components with `willChange` styles to optimize rendering performance. - Adjusted various UI components to improve responsiveness and visual effects. - Removed obsolete job details functionality from the job search provider and related tests. * chore(locales): Update localization files for job search improvements - Modified job search related strings to remove references to "this month" for a more concise format. - Updated file references in localization entries to reflect changes in the job search component structure. - Added new strings for API usage, quota remaining, and job fetching error messages across multiple languages. - Removed obsolete "Monthly Usage" string from localization files. * chore(dependencies): Update @typescript/native-preview to version 7.0.0-dev.20260319.1 --------- Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
158 lines
5.7 KiB
TypeScript
158 lines
5.7 KiB
TypeScript
import { t } from "@lingui/core/macro";
|
|
import { Trans } from "@lingui/react/macro";
|
|
import { ArrowRightIcon, BookIcon, SparkleIcon } from "@phosphor-icons/react";
|
|
import { Link } from "@tanstack/react-router";
|
|
import { motion } from "motion/react";
|
|
|
|
import { CometCard } from "@/components/animation/comet-card";
|
|
import { Spotlight } from "@/components/animation/spotlight";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
export function Hero() {
|
|
return (
|
|
<section
|
|
id="hero"
|
|
className="relative flex min-h-svh w-svw flex-col items-center justify-center overflow-hidden border-b py-24"
|
|
>
|
|
<Spotlight />
|
|
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 100 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 1.1, ease: "easeOut" }}
|
|
style={{ willChange: "transform, opacity" }}
|
|
>
|
|
<CometCard glareOpacity={0} className="3xl:max-w-7xl relative -mb-12 max-w-4xl px-8 md:-mb-24 md:px-12 lg:px-0">
|
|
<video
|
|
loop
|
|
muted
|
|
autoPlay
|
|
playsInline
|
|
// @ts-expect-error - typescript doesn't know about fetchPriority for video elements
|
|
fetchPriority="high"
|
|
src="/videos/timelapse.mp4"
|
|
aria-label={t`Timelapse demonstration of building a resume with Reactive Resume`}
|
|
className="pointer-events-none size-full rounded-md border object-cover"
|
|
/>
|
|
|
|
<div
|
|
aria-hidden="true"
|
|
className="pointer-events-none absolute inset-0 bg-linear-to-b from-transparent via-transparent via-40% to-background"
|
|
/>
|
|
</CometCard>
|
|
</motion.div>
|
|
|
|
<div className="xs:px-0 relative z-10 flex max-w-2xl flex-col items-center gap-y-6 px-4 text-center">
|
|
{/* Badge */}
|
|
<motion.a
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.45, delay: 0.55 }}
|
|
whileHover={{ y: -2, scale: 1.01 }}
|
|
whileTap={{ scale: 0.985 }}
|
|
style={{ willChange: "transform, opacity" }}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
href="https://docs.rxresu.me/getting-started"
|
|
>
|
|
<Badge variant="secondary" className="h-auto gap-1.5 px-3 py-0.5">
|
|
<SparkleIcon aria-hidden="true" className="size-3.5" weight="fill" />
|
|
<Trans>What's new in the latest version?</Trans>
|
|
</Badge>
|
|
</motion.a>
|
|
|
|
{/* Headline */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.45, delay: 0.7 }}
|
|
style={{ willChange: "transform, opacity" }}
|
|
>
|
|
<Trans>
|
|
<p className="font-medium tracking-tight text-muted-foreground md:text-lg">Finally,</p>
|
|
<h1 className="mt-1 text-4xl font-bold tracking-tight md:text-5xl lg:text-6xl">
|
|
A free and open-source resume builder
|
|
</h1>
|
|
</Trans>
|
|
</motion.div>
|
|
|
|
{/* Description */}
|
|
<motion.p
|
|
className="max-w-xl text-base leading-relaxed text-muted-foreground md:text-lg"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.45, delay: 0.82 }}
|
|
style={{ willChange: "transform, opacity" }}
|
|
>
|
|
<Trans>
|
|
Reactive Resume is a free and open-source resume builder that simplifies the process of creating, updating,
|
|
and sharing your resume.
|
|
</Trans>
|
|
</motion.p>
|
|
|
|
{/* CTA Buttons */}
|
|
<motion.div
|
|
className="flex flex-col items-center gap-3 sm:flex-row sm:gap-4"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.45, delay: 0.95 }}
|
|
style={{ willChange: "transform, opacity" }}
|
|
>
|
|
<Button
|
|
size="lg"
|
|
nativeButton={false}
|
|
className="group relative overflow-hidden px-4"
|
|
render={
|
|
<Link to="/dashboard">
|
|
<span className="relative z-10 flex items-center gap-2">
|
|
<Trans>Get Started</Trans>
|
|
<ArrowRightIcon
|
|
aria-hidden="true"
|
|
className="size-4 transition-transform group-hover:translate-x-0.5"
|
|
/>
|
|
</span>
|
|
</Link>
|
|
}
|
|
/>
|
|
|
|
<Button
|
|
size="lg"
|
|
variant="ghost"
|
|
className="gap-2 px-4"
|
|
nativeButton={false}
|
|
render={
|
|
<a href="https://docs.rxresu.me" target="_blank" rel="noopener noreferrer">
|
|
<BookIcon aria-hidden="true" className="size-4" />
|
|
<Trans>Learn More</Trans>
|
|
<span className="sr-only">
|
|
<Trans>(opens in new tab)</Trans>
|
|
</span>
|
|
</a>
|
|
}
|
|
/>
|
|
</motion.div>
|
|
</div>
|
|
|
|
{/* Scroll indicator - decorative */}
|
|
<motion.div
|
|
aria-hidden="true"
|
|
role="presentation"
|
|
className="absolute inset-s-1/2 bottom-8 -translate-x-1/2"
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
transition={{ delay: 1.25, duration: 0.7 }}
|
|
>
|
|
<motion.div
|
|
className="flex h-8 w-5 items-start justify-center rounded-full border border-muted-foreground/30 p-1.5"
|
|
animate={{ y: [0, 5, 0] }}
|
|
transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
|
|
style={{ willChange: "transform" }}
|
|
>
|
|
<motion.div className="h-1.5 w-1 rounded-full bg-muted-foreground/50" />
|
|
</motion.div>
|
|
</motion.div>
|
|
</section>
|
|
);
|
|
}
|