Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Projects/AI-Resume-Analyser/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.react-router
build
node_modules
README.md
6 changes: 6 additions & 0 deletions Projects/AI-Resume-Analyser/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.DS_Store
/node_modules/

# React Router
/.react-router/
/build/
22 changes: 22 additions & 0 deletions Projects/AI-Resume-Analyser/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM node:20-alpine AS development-dependencies-env
COPY . /app
WORKDIR /app
RUN npm ci

FROM node:20-alpine AS production-dependencies-env
COPY ./package.json package-lock.json /app/
WORKDIR /app
RUN npm ci --omit=dev

FROM node:20-alpine AS build-env
COPY . /app/
COPY --from=development-dependencies-env /app/node_modules /app/node_modules
WORKDIR /app
RUN npm run build

FROM node:20-alpine
COPY ./package.json package-lock.json /app/
COPY --from=production-dependencies-env /app/node_modules /app/node_modules
COPY --from=build-env /app/build /app/build
WORKDIR /app
CMD ["npm", "run", "start"]
76 changes: 76 additions & 0 deletions Projects/AI-Resume-Analyser/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
**Ai-Resume-Analyser-For-ROSPL**

**INTRODUCTION**

Build an AI-powered Resume Analyzer with React, React Router, and Puter.js! Implement seamless auth, upload and store resumes, and match candidates to jobs using smart AI evaluations. Get custom feedback and ATS scores tailored to each listing—all wrapped in a clean, reusable UI.

## <a name="tech-stack">⚙️ Tech Stack</a>

- **[React](https://react.dev/)** is a popular open‑source JavaScript library for building user interfaces using reusable components and a virtual DOM, enabling efficient, dynamic single-page and native apps.

- **[React Router v7](https://reactrouter.com/)** is the go‑to routing library for React apps, offering nested routes, data loaders/actions, error boundaries, code splitting, and SSR support—all with a smooth upgrade path from v6.

- **[Puter.com](https://jsm.dev/resumind-puter)** is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. Puter can be used as: A privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time.

- **[Puter.js](https://jsm.dev/resumind-puterjs)** is a tiny client‑side SDK that adds serverless auth, storage, database, and AI (GPT, Claude, DALL·E, OCR…) straight into your browser app—no backend needed and costs borne by users.

- **[Tailwind CSS](https://tailwindcss.com/)** is a utility-first CSS framework that allows developers to design custom user interfaces by applying low-level utility classes directly in HTML, streamlining the design process.

- **[TypeScript](https://www.typescriptlang.org/)** is a superset of JavaScript that adds static typing, providing better tooling, code quality, and error detection for developers, making it ideal for building large-scale applications.

- **[Vite](https://vite.dev/)** is a fast build tool and dev server using native ES modules for instant startup, hot‑module replacement, and Rollup‑powered production builds—perfect for modern web development.

- **[Zustand](https://github.com/pmndrs/zustand)** is a minimal, hook-based state management library for React. It lets you manage global state with zero boilerplate, no context providers, and excellent performance through selective state subscriptions.

**FEATURES**

**Easy & convenient auth**: Handle authentication entirely in the browser using Puter.js—no backend or setup required.

**Resume upload & storage**: Let users upload and store all their resumes in one place, safely and reliably.

**AI resume matching**: Provide a job listing and get an ATS score with custom feedback tailored to each resume.

**Reusable, modern UI**: Built with clean, consistent components for a great-looking and maintainable interface.

**Code Reusability**: Leverage reusable components and a modular codebase for efficient development.

**Cross-Device Compatibility**: Fully responsive design that works seamlessly across all devices.

**Modern UI/UX**: Clean, responsive design built with Tailwind CSS and shadcn/ui for a sleek user experience.

And many more, including code architecture and reusability.

## <a name="quick-start">🤸 Quick Start</a>

Follow these steps to set up the project locally on your machine.

**Prerequisites**

Make sure you have the following installed on your machine:

- [Git](https://git-scm.com/)
- [Node.js](https://nodejs.org/en)
- [npm](https://www.npmjs.com/) (Node Package Manager)

**Cloning the Repository**

```bash
git clone https://github.com/adrianhajdin/ai-resume-analyzer.git
cd ai-resume-analyzer
```

**Installation**

Install the project dependencies using npm:

```bash
npm install
```

**Running the Project**

```bash
npm run dev
```

Open [http://localhost:5173](http://localhost:5173) in your browser to view the project.
152 changes: 152 additions & 0 deletions Projects/AI-Resume-Analyser/app/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
@import url("https://fonts.googleapis.com/css2?family=Mona+Sans:ital,wght@0,200..900;1,200..900&display=swap");
@import "tailwindcss";
@import "tw-animate-css";

@theme {
--font-sans: "Mona Sans", ui-sans-serif, system-ui, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--color-dark-200: #475467;
--color-light-blue-100: #c1d3f81a;
--color-light-blue-200: #a7bff14d;

--color-badge-green: #d5faf1;
--color-badge-red: #f9e3e2;
--color-badge-yellow: #fceed8;

--color-badge-green-text: #254d4a;
--color-badge-red-text: #752522;
--color-badge-yellow-text: #73321b;
}

html,
body {
@apply bg-white;
}

main {
@apply min-h-screen pt-10;
}
h1 {
@apply text-6xl text-gradient leading-tight tracking-[-2px] font-semibold;
}

h2 {
@apply text-3xl text-dark-200;
}

label {
@apply text-dark-200;
}
input {
@apply w-full p-4 inset-shadow rounded-2xl focus:outline-none bg-white;
}

textarea {
@apply w-full p-4 inset-shadow rounded-2xl focus:outline-none bg-white;
}

form {
@apply flex flex-col items-start gap-8 w-full;
}

@layer components {
.text-gradient {
@apply bg-clip-text text-transparent bg-gradient-to-r from-[#AB8C95] via-[#000000] to-[#8E97C5];
}
.gradient-border {
@apply bg-gradient-to-b from-light-blue-100 to-light-blue-200 p-4 rounded-2xl;
}
.primary-button {
@apply primary-gradient text-white rounded-full px-4 py-2 cursor-pointer w-full;
}
.resume-nav {
@apply flex flex-row justify-between items-center p-4 border-b border-gray-200;
}
.resume-summary {
@apply flex flex-row items-center justify-center p-4 gap-4;
.category {
@apply flex flex-row gap-2 items-center bg-gray-50 rounded-2xl p-4 w-full justify-between;
}
}
.back-button {
@apply flex flex-row items-center gap-2 border border-gray-200 rounded-lg p-2 shadow-sm;
}
.auth-button {
@apply primary-gradient rounded-full py-4 px-8 cursor-pointer w-[600px] max-md:w-full text-3xl font-semibold text-white;
}
.main-section {
@apply flex flex-col items-center gap-8 pt-12 mx-15 pb-5;
}
.page-heading {
@apply flex flex-col items-center gap-8 max-w-4xl text-center;
}
.resumes-section {
@apply flex flex-wrap max-lg:flex-col gap-6 items-start w-full max-w-[1850px] justify-evenly;
}

.resume-card {
@apply flex flex-col gap-8 h-[560px] w-full lg:w-[450px] xl:w-[490px] bg-white rounded-2xl p-4;
}

.resume-card-header {
@apply flex flex-row gap-2 justify-between min-h-[110px] max-sm:flex-col items-center max-md:justify-center max-md:items-center;
}

.feedback-section {
@apply flex flex-col gap-8 w-1/2 px-8 max-lg:w-full py-6;
}

.navbar {
@apply flex flex-row justify-between items-center bg-white rounded-full p-4 w-full px-10 max-w-[1200px] mx-auto;
}

.score-badge {
@apply flex flex-row items-center justify-center py-1 px-2 gap-4 rounded-[96px];
}

.form-div {
@apply flex flex-col gap-2 w-full items-start;
}

.uplader-drag-area {
@apply relative p-8 text-center transition-all duration-700 cursor-pointer bg-white rounded-2xl min-h-[208px];
}
.uploader-selected-file {
@apply flex items-center justify-between p-3 bg-gray-50 rounded-2xl;
}
}

@utility bg-gradient {
background: linear-gradient(to bottom, #f0f4ff 60%, #fa7185cc);
}

@utility text-gradient {
@apply bg-clip-text text-transparent bg-gradient-to-r from-[#AB8C95] via-[#000000] to-[#8E97C5];
}

@utility gradient-hover {
@apply bg-gradient-to-b from-light-blue-100 to-light-blue-200;
}

@utility primary-gradient {
background: linear-gradient(to bottom, #8e98ff, #606beb);
box-shadow: 0px 74px 21px 0px #6678ef00;
}

@utility primary-gradient-hover {
background: linear-gradient(to bottom, #717dff, #4957eb);
}

@utility inset-shadow {
box-shadow: inset 0 0 12px 0 rgba(36, 99, 235, 0.2);
backdrop-filter: blur(10px);
}

@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
77 changes: 77 additions & 0 deletions Projects/AI-Resume-Analyser/app/components/ATS.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react'

interface Suggestion {
type: "good" | "improve";
tip: string;
}

interface ATSProps {
score: number;
suggestions: Suggestion[];
}

const ATS: React.FC<ATSProps> = ({ score, suggestions }) => {
// Determine background gradient based on score
const gradientClass = score > 69
? 'from-green-100'
: score > 49
? 'from-yellow-100'
: 'from-red-100';

// Determine icon based on score
const iconSrc = score > 69
? '/icons/ats-good.svg'
: score > 49
? '/icons/ats-warning.svg'
: '/icons/ats-bad.svg';

// Determine subtitle based on score
const subtitle = score > 69
? 'Great Job!'
: score > 49
? 'Good Start'
: 'Needs Improvement';

return (
<div className={`bg-gradient-to-b ${gradientClass} to-white rounded-2xl shadow-md w-full p-6`}>
{/* Top section with icon and headline */}
<div className="flex items-center gap-4 mb-6">
<img src={iconSrc} alt="ATS Score Icon" className="w-12 h-12" />
<div>
<h2 className="text-2xl font-bold">ATS Score - {score}/100</h2>
</div>
</div>

{/* Description section */}
<div className="mb-6">
<h3 className="text-xl font-semibold mb-2">{subtitle}</h3>
<p className="text-gray-600 mb-4">
This score represents how well your resume is likely to perform in Applicant Tracking Systems used by employers.
</p>

{/* Suggestions list */}
<div className="space-y-3">
{suggestions.map((suggestion, index) => (
<div key={index} className="flex items-start gap-3">
<img
src={suggestion.type === "good" ? "/icons/check.svg" : "/icons/warning.svg"}
alt={suggestion.type === "good" ? "Check" : "Warning"}
className="w-5 h-5 mt-1"
/>
<p className={suggestion.type === "good" ? "text-green-700" : "text-amber-700"}>
{suggestion.tip}
</p>
</div>
))}
</div>
</div>

{/* Closing encouragement */}
<p className="text-gray-700 italic">
Keep refining your resume to improve your chances of getting past ATS filters and into the hands of recruiters.
</p>
</div>
)
}

export default ATS
Loading