diff --git a/public/BG-Grid-Light.svg b/public/BG-Grid-Light.svg new file mode 100644 index 00000000..605c50ee --- /dev/null +++ b/public/BG-Grid-Light.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/BG-Grid.svg b/public/BG-Grid.svg new file mode 100644 index 00000000..bc3ad0b1 --- /dev/null +++ b/public/BG-Grid.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/adobe.svg b/public/adobe.svg new file mode 100644 index 00000000..daf07c3a --- /dev/null +++ b/public/adobe.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/public/atlassian.svg b/public/atlassian.svg new file mode 100644 index 00000000..069d641a --- /dev/null +++ b/public/atlassian.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/coinbase.svg b/public/coinbase.svg new file mode 100644 index 00000000..ee909ff9 --- /dev/null +++ b/public/coinbase.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/fonts/satoshi.ttf b/public/fonts/satoshi.ttf new file mode 100644 index 00000000..976e85cb Binary files /dev/null and b/public/fonts/satoshi.ttf differ diff --git a/public/framer.svg b/public/framer.svg new file mode 100644 index 00000000..380a14e7 --- /dev/null +++ b/public/framer.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/google.svg b/public/google.svg index 95932e27..0da1cadc 100644 --- a/public/google.svg +++ b/public/google.svg @@ -1,10 +1,15 @@ - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + diff --git a/public/main.svg b/public/main.svg new file mode 100644 index 00000000..8b2115f7 --- /dev/null +++ b/public/main.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/medium.svg b/public/medium.svg new file mode 100644 index 00000000..681f8201 --- /dev/null +++ b/public/medium.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/spotify.svg b/public/spotify.svg new file mode 100644 index 00000000..0540f2fa --- /dev/null +++ b/public/spotify.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/actions/job.action.ts b/src/actions/job.action.ts index 3b752977..e33069bc 100644 --- a/src/actions/job.action.ts +++ b/src/actions/job.action.ts @@ -158,3 +158,29 @@ export const getCityFilters = async () => { cities, }).serialize(); }; + +export const getRecentJobs = async () => { + const recentJobs = await prisma.job.findMany({ + orderBy: { + postedAt: 'desc', + }, + select: { + id: true, + title: true, + description: true, + companyName: true, + city: true, + address: true, + workMode: true, + minSalary: true, + maxSalary: true, + postedAt: true, + companyLogo: true, + type: true, + }, + take: 6, + }); + return new SuccessResponse('Recently added jobs fetch successfully', 200, { + recentJobs, + }).serialize(); +}; diff --git a/src/app/create/page.tsx b/src/app/create/page.tsx index 92548bd3..f0a33bc3 100644 --- a/src/app/create/page.tsx +++ b/src/app/create/page.tsx @@ -3,10 +3,10 @@ import React from 'react'; const page = () => { return ( -
+

Post a job

-

+

100xJobs is trusted by leading companies

diff --git a/src/app/globals.css b/src/app/globals.css index 419e4fd3..42d62086 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -299,11 +299,16 @@ } /* Custom styles for Quill editor */ -.ql-toolbar.ql-snow { +.dark .ql-toolbar.ql-snow { border: none !important; background-color: #1f2937 !important; border-bottom: 1px solid #374151 !important; } +.ql-toolbar.ql-snow { + border: none !important; + background-color: #fff !important; + border-bottom: 1px solid #dfdfdf !important; +} .ql-container.ql-snow { border: none !important; @@ -375,3 +380,9 @@ html { scroll-behavior: smooth; } + +.career-span { + display: inline-block; + transform: rotate(-2deg); +} + diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b92cdc45..fb3dacde 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,14 +3,19 @@ import Header from '@/layouts/header'; import { cn } from '@/lib/utils'; import Providers from '@/providers/providers'; import type { Metadata } from 'next'; -import { Inter as FontSans } from 'next/font/google'; import './globals.css'; -/* import TopLoader from '@/components/Toploader'; */ import ScrollToTop from '@/components/ScrollToTop'; +import localFont from 'next/font/local'; -const fontSans = FontSans({ - subsets: ['latin'], - variable: '--font-sans', + +const satoshi = localFont({ + display: 'swap', + src: [ + { + path: '../../public/fonts/satoshi.ttf', + }, + ], + variable: '--font-satoshi', }); export const metadata: Metadata = { @@ -27,11 +32,10 @@ export default async function RootLayout({ - {/* */}
{children}
diff --git a/src/app/page.tsx b/src/app/page.tsx index f654ef4d..bd78e16e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,29 +1,15 @@ -import BackgroundSvg from '@/components/BackgroundSvg'; import Faqs from '@/components/Faqs'; -import HalfCircleGradient from '@/components/HalfCircleGradient'; import HeroSection from '@/components/hero-section'; import { JobLanding } from '@/components/job-landing'; import Testimonials from '@/components/Testimonials'; -import { JobQuerySchemaType } from '@/lib/validators/jobs.validator'; -const HomePage = async ({ - searchParams, -}: { - searchParams: JobQuerySchemaType; -}) => { +const HomePage = async () => { return (
- - -
- -
-
- -
- + + + -
); }; diff --git a/src/components/DescriptionEditor.tsx b/src/components/DescriptionEditor.tsx index 51399be8..21f437be 100644 --- a/src/components/DescriptionEditor.tsx +++ b/src/components/DescriptionEditor.tsx @@ -56,7 +56,7 @@ const DescriptionEditor: React.FC = ({ style={{ width: "100%" }} onChange={handleChange} placeholder={placeholder} - className="text-white bg-gray-800 overflow-hidden job-description-editor" + className="dark:text-white dark:bg-gray-800 bg-[#FFFF] overflow-hidden job-description-editor" /> ); }; diff --git a/src/components/Faqs.tsx b/src/components/Faqs.tsx index 3c71427e..ab139374 100644 --- a/src/components/Faqs.tsx +++ b/src/components/Faqs.tsx @@ -3,7 +3,6 @@ import { faqData } from '@/lib/constant/faqs.constants'; import { ChevronDown } from 'lucide-react'; import { useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; -import FaqsGetintouchCard from './FaqsGetintouchCard'; export default function Faqs() { const [expandedIndex, setExpandedIndex] = useState(null); @@ -15,27 +14,29 @@ export default function Faqs() { return (
-

FAQs

-

+

+ Frequently Asked Questions +

+

Quick answers to any questions you may have.

-
+
{faqData.map((faq, i) => (
toggleExpand(i)} - aria-expanded={expandedIndex === i} + className={`w-full flex flex-col items-start md:p-4 p-2`} > -
+
+ {expandedIndex === i && ( -

+

{faq.answer}

@@ -65,7 +66,6 @@ export default function Faqs() { ))}
-
); } diff --git a/src/components/RecentJobs.tsx b/src/components/RecentJobs.tsx new file mode 100644 index 00000000..fed56a11 --- /dev/null +++ b/src/components/RecentJobs.tsx @@ -0,0 +1,81 @@ +import { getRecentJobs } from '@/actions/job.action'; +import { calculateTimeSincePosted, getFirstLetterCaps } from './job-landing'; +import Image from 'next/image'; +import { formatSalary } from '@/lib/utils'; +import { Briefcase, MapPin } from 'lucide-react'; + +export default async function RecentJobs() { + const recentJobs = await getRecentJobs(); + if (!recentJobs.status) { + return
Error {recentJobs.message}
; + } + + return ( +
+ {recentJobs.additional.recentJobs.map((job, i) => ( +
+
+ {job.companyLogo ? ( +
+ company-logo +
+ ) : ( +
+

+ {getFirstLetterCaps(job.companyName)} +

+
+ )} +
+

+ {job.title} +

+
+

{job.companyName}

+

+ + {calculateTimeSincePosted(job.postedAt)} +

+
+
+
+
+

+ {job.type} +

+
+ +

2-3 Yrs

+
+

+ {job.maxSalary ? `$${formatSalary(job.maxSalary)}` : '$$$$$'} +

+
+ +

{job.city}

+
+
+
+ {['Git', 'Aws', 'Javascript', 'Nodejs', 'Python', 'Typescript'].map( + (data, i) => ( +

+ {data} +

+ ) + )} +
+
+ ))} +
+ ); +} diff --git a/src/components/TestimonialCard.tsx b/src/components/TestimonialCard.tsx index 72369199..08ebd659 100644 --- a/src/components/TestimonialCard.tsx +++ b/src/components/TestimonialCard.tsx @@ -1,27 +1,48 @@ 'use client'; import { testimonialItem } from '@/types/testimonials.types'; import { motion } from 'framer-motion'; +import { Quote } from 'lucide-react'; +import { useTheme } from 'next-themes'; interface testimonialCardProps { testimonial: testimonialItem; } -export default function TestimonialCard({ - testimonial, -}: testimonialCardProps) { +export default function TestimonialCard({ testimonial }: testimonialCardProps) { + const { theme } = useTheme(); return ( -
-

- {testimonial.name.charAt(0).toUpperCase()} -

-

{testimonial.name}

+
+
+
+ +

+ {testimonial.name.charAt(0).toUpperCase()} +

+
+

{testimonial.name}

+

+ Talent Acquisition Lead at Spotify +

+
+
+

{testimonial.testimonial}

+
-

"{testimonial.testimonial}"

); } diff --git a/src/components/Testimonials.tsx b/src/components/Testimonials.tsx index 575dbaf7..d028af0d 100644 --- a/src/components/Testimonials.tsx +++ b/src/components/Testimonials.tsx @@ -1,29 +1,27 @@ 'use client'; -import { Button } from './ui/button'; import { testimonials } from '@/lib/constant/testimonials.constants'; import TestimonialCard from './TestimonialCard'; export default function Testimonials() { return (

Testimonials

-

- Trusted by those who matter. +

+ Real Success Stories from Job Seekers and Employers

-
- {testimonials.map((testimonial, i) => ( - +
+ {testimonials.slice(0,3).map((testimonial, i) => ( + ))}
-
-

- Your story matters. Share it with us! -

- +
+ {testimonials.slice(3,5).map((testimonial, i) => ( + + ))}
); diff --git a/src/components/gmaps-autosuggest.tsx b/src/components/gmaps-autosuggest.tsx index d6e6b76e..162365a3 100644 --- a/src/components/gmaps-autosuggest.tsx +++ b/src/components/gmaps-autosuggest.tsx @@ -35,7 +35,7 @@ export function GmapsAutocompleteAddress({ form }: { form: any }) { diff --git a/src/components/hero-section.tsx b/src/components/hero-section.tsx index ef8b3dad..67e1b839 100644 --- a/src/components/hero-section.tsx +++ b/src/components/hero-section.tsx @@ -1,41 +1,54 @@ -import { GITHUB_REPO } from '@/lib/constant/app.constant'; +import Image from 'next/image'; +import { trustedCompanies } from '@/lib/constant/app.constant'; import Link from 'next/link'; -import Icon from './ui/icon'; -import { LogoMarquee } from './infinitescroll'; - const HeroSection = () => { return ( <> -
-
- - -

Star us on Github

- -
-
-

- {/* Find the Right{' '} - - Opportunity +
+
+
+
+

+ #1 Platform for jobs +

+

+ Build Your + + Career - , Hire the Perfect Talent */} - Find Your Perfect Job Today! +
+ with 100xJobs

-
-
-

- Discover a thoughtfully selected collection of job opportunities - chosen by our dedicated team of experts. +

+ Unlock exclusive job and internship opportunities. Remote, + onsite, or hybrid—we've got what you're looking for.

+
+ + +
+
+
+

+ Trusted By Leading Companies +

+
+ {trustedCompanies.map((company, i) => ( + {`${company.name}-icon`} + ))} +
-
); diff --git a/src/components/job-form.tsx b/src/components/job-form.tsx index ac217430..6d026794 100644 --- a/src/components/job-form.tsx +++ b/src/components/job-form.tsx @@ -148,32 +148,34 @@ const PostJobForm = () => { form.setValue('companyLogo', 'https://wwww.example.com'); }, [watchHasSalaryRange, form]); return ( -
-
-
+
+
+

Posted for

-

30 days

+

30 days

-
+

Emailed to

-

290,301 subscribers

+

+ 290,301 subscribers +

-
+

Reach

-

+

300,000+

- -
+ +

Job details

{ @@ -205,7 +207,7 @@ const PostJobForm = () => { defaultValue={field.value} > - + @@ -233,7 +235,7 @@ const PostJobForm = () => { defaultValue={field.value} > - + @@ -260,7 +262,7 @@ const PostJobForm = () => { defaultValue={field.value} > - + @@ -275,9 +277,9 @@ const PostJobForm = () => { )} />
-
+
-
+
{ @@ -301,7 +303,7 @@ const PostJobForm = () => { />
{watchHasSalaryRange && ( -
+
{ @@ -333,7 +335,7 @@ const PostJobForm = () => { {' '} @@ -358,7 +360,7 @@ const PostJobForm = () => { @@ -366,9 +368,11 @@ const PostJobForm = () => { )} />
-
-

Job description

-
+
+

+ Job description +

+
{ />
-
-

+
+

Company

{/* Logo Upload Section */}
{previewImg ? ( @@ -398,7 +402,7 @@ const PostJobForm = () => { height={80} /> ) : ( - + )}
{ @@ -447,7 +451,7 @@ const PostJobForm = () => { @@ -470,7 +474,7 @@ const PostJobForm = () => {

-
+
@@ -478,14 +482,16 @@ const PostJobForm = () => { -
-

Payment

+
+

+ Payment +

-

+

"I'm a huge fan of remote work and 100xJobs is by far my favorite job board."

@@ -496,8 +502,8 @@ const PostJobForm = () => { height={40} className="rounded-full" /> -

Harkirat Singh

-

100xJobs.com

+

Harkirat Singh

+

100xJobs.com

diff --git a/src/components/job-landing.tsx b/src/components/job-landing.tsx index 7cde3269..c8a22018 100644 --- a/src/components/job-landing.tsx +++ b/src/components/job-landing.tsx @@ -1,147 +1,39 @@ -import { getAllJobs } from '@/actions/job.action'; -import { formatSalary } from '@/lib/utils'; -import Link from 'next/link'; -import JobCardLoader from '@/components/job-card-loader'; - -import { DEFAULT_PAGE, JOBS_PER_PAGE } from '@/config/app.config'; -import JobsHeader from '@/layouts/jobs-header'; -import { Suspense } from 'react'; -import { - JobQuerySchema, - JobQuerySchemaType, -} from '@/lib/validators/jobs.validator'; -import { Pagination, PaginationContent, PaginationItem } from './ui/pagination'; -import { - PaginationNextButton, - PaginationPreviousButton, -} from './pagination-client'; -import { PaginationPages } from './ui/paginator'; -import APP_PATHS from '@/config/path.config'; - import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; -import { redirect } from 'next/navigation'; -import Image from 'next/image'; - +import { ChevronRight } from 'lucide-react'; +import RecentJobs from './RecentJobs'; +import Link from 'next/link'; dayjs.extend(relativeTime); export const calculateTimeSincePosted = (postedAt: Date): string => { return dayjs(postedAt).fromNow(); }; -export const JobLanding = async ({ - searchParams, -}: { - searchParams: JobQuerySchemaType; -}) => { - const parsedData = JobQuerySchema.safeParse(searchParams); - if (!(parsedData.success && parsedData.data)) { - console.error(parsedData.error); - redirect('/'); - } - const parsedSearchParams = parsedData.data; - return ( -
-
- - }> - - -
-
- ); -}; - -type PaginatorProps = { - searchParams: JobQuerySchemaType; +export const getFirstLetterCaps = (str: string): string => { + return str.charAt(0).toUpperCase(); }; -const JobCard = async ({ searchParams }: PaginatorProps) => { - const jobs = await getAllJobs(searchParams); - if (!jobs.status) { - return
Error {jobs.message}
; - } - - const totalPages = - Math.ceil((jobs.additional?.totalJobs || 0) / JOBS_PER_PAGE) || - DEFAULT_PAGE; - const currentPage = parseInt(searchParams.page?.toString()) || DEFAULT_PAGE; +export const JobLanding = () => { return ( -
- {jobs.additional?.jobs.map((job) => { - return ( - -
-
-
- {job.companyLogo && ( - job image - )} -
-
-
-

- {job.title} - {job.companyName} -

-

- {calculateTimeSincePosted(job.postedAt)} • {job.workMode} -

-
- -
- - {job.minSalary && job.maxSalary - ? `$${formatSalary(job.maxSalary)}` - : 'Not Disclosed'} - - {job.minSalary && job.maxSalary && ( -

- per annum -

- )} -
-
+
+
+

Recently Added jobs

+

+ Stay ahead with newly added jobs +

+
+ +
+ +
); -}; +}; \ No newline at end of file diff --git a/src/components/navitem.tsx b/src/components/navitem.tsx index e1595950..9b90519e 100644 --- a/src/components/navitem.tsx +++ b/src/components/navitem.tsx @@ -31,7 +31,7 @@ export const NavItem = ({ {label} diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx index 037a5baf..5ee97cd2 100644 --- a/src/components/ui/sheet.tsx +++ b/src/components/ui/sheet.tsx @@ -31,7 +31,7 @@ const SheetOverlay = React.forwardRef< SheetOverlay.displayName = SheetPrimitive.Overlay.displayName; const sheetVariants = cva( - 'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500', + 'fixed z-50 gap-4 dark:bg-[#020817F2] bg-[#ffff] p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500', { variants: { side: { @@ -65,10 +65,7 @@ const SheetContent = React.forwardRef< {...props} > {children} - - - Close - + )); diff --git a/src/layouts/footer.tsx b/src/layouts/footer.tsx index d5a30f56..b2b75c40 100644 --- a/src/layouts/footer.tsx +++ b/src/layouts/footer.tsx @@ -1,76 +1,25 @@ import Icon from '@/components/ui/icon'; -import { socials, footerLinks } from '@/lib/constant/app.constant'; -import Image from 'next/image'; +import { footerItems, socials } from '@/lib/constant/app.constant'; import Link from 'next/link'; const Footer = () => { return ( -