diff --git a/package-lock.json b/package-lock.json index 95a6b3a..02e2654 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "@clerk/nextjs": "^4.29.5", + "@clerk/themes": "^1.7.9", "@hookform/resolvers": "^3.3.4", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-label": "^2.0.2", @@ -186,6 +187,17 @@ } } }, + "node_modules/@clerk/themes": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/@clerk/themes/-/themes-1.7.9.tgz", + "integrity": "sha512-9hXxgoPuUSlZ7sH9diJEK1rTWEnk0zGKBYw4Tqaqp0RA1dtB+OHE02DK5pnTypZTnreBJYac3VmxFVTxVV35xg==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16" + } + }, "node_modules/@clerk/types": { "version": "3.60.0", "resolved": "https://registry.npmjs.org/@clerk/types/-/types-3.60.0.tgz", diff --git a/package.json b/package.json index 24b6a2d..5b58188 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ }, "dependencies": { "@clerk/nextjs": "^4.29.5", + "@clerk/themes": "^1.7.9", "@hookform/resolvers": "^3.3.4", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-label": "^2.0.2", diff --git a/public/jobs.png b/public/jobs.png new file mode 100644 index 0000000..24965f8 Binary files /dev/null and b/public/jobs.png differ diff --git a/src/app/Providers.tsx b/src/app/Providers.tsx index b0c1a2c..529404d 100644 --- a/src/app/Providers.tsx +++ b/src/app/Providers.tsx @@ -4,24 +4,26 @@ import { PropsWithChildren } from "react"; import { ConvexReactClient } from "convex/react"; import { ClerkProvider, useAuth } from "@clerk/nextjs"; import { ConvexProviderWithClerk } from "convex/react-clerk"; -import { ThemeProvider } from "./theme-provider"; +import { dark } from "@clerk/themes"; +import { useTheme } from "next-themes"; const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); export default function Providers({ children }: PropsWithChildren) { + const { theme, systemTheme } = useTheme(); + return ( - - {children} - + {children} ); diff --git a/src/app/theme-provider.tsx b/src/app/ThemeProvider.tsx similarity index 100% rename from src/app/theme-provider.tsx rename to src/app/ThemeProvider.tsx diff --git a/src/app/create/page.tsx b/src/app/create/page.tsx index 4be3b9a..81bf111 100644 --- a/src/app/create/page.tsx +++ b/src/app/create/page.tsx @@ -3,9 +3,17 @@ import JobForm from "@/components/JobForm"; export default function Create() { return (
-
-
- +
+
+
+

+ Generate your perfect job with just a few skills +

+

+ Use the form below and let A.I do all the heavey lifting. +

+ +
diff --git a/src/app/explore/page.tsx b/src/app/explore/page.tsx index 2e021b2..9157c59 100644 --- a/src/app/explore/page.tsx +++ b/src/app/explore/page.tsx @@ -4,13 +4,13 @@ export default function Explore() { return (
-
+

- Find your perfect job with just a few skills + Explore all of the jobs you have created.

- Input your skills and we'll find the perfect job for you. + Look back on some of your previous creations.

diff --git a/src/app/header.tsx b/src/app/header.tsx index 1b9c5e5..50a8987 100644 --- a/src/app/header.tsx +++ b/src/app/header.tsx @@ -4,12 +4,14 @@ import ThemeToggle from "@/components/ThemeToggle"; import { buttonVariants } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { SignedIn, UserButton, SignedOut, SignInButton } from "@clerk/nextjs"; -import { Briefcase } from "lucide-react"; +import { useQuery } from "convex/react"; +import { Briefcase, Loader2 } from "lucide-react"; import Link from "next/link"; -import { usePathname } from "next/navigation"; +import { api } from "../../convex/_generated/api"; export default function Header() { - const path = usePathname(); + const jobs = useQuery(api.queries.getJobs); + return (
What's my job?
- + + {jobs?.some((job) => job.status === "pending") && ( + + )}{" "} Explore diff --git a/src/app/layout.tsx b/src/app/layout.tsx index d2b5d73..bbe0cd5 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,7 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; import Providers from "./Providers"; import Header from "./header"; +import { ThemeProvider } from "./ThemeProvider"; const inter = Inter({ subsets: ["latin"] }); @@ -19,10 +20,17 @@ export default function RootLayout({ return ( - -
- {children} - + + +
+ {children} + + ); diff --git a/src/app/page.tsx b/src/app/page.tsx index 92b0190..4206450 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,11 +1,12 @@ import Link from "next/link"; import { Button } from "@/components/ui/button"; +import Image from "next/image"; export default function Home() { return ( -
-
-
+
+
+

Find your perfect job with just a few skills @@ -14,10 +15,28 @@ export default function Home() { Input your skills and we'll find the perfect job for you.

-
+
+ People jon hunting +
+
+
+
+
+

+ Lorem ipsum dolor sit, amet consectetur adipisicing elit. Cum eaque + sequi deleniti esse odio? Veniam officiis officia deserunt similique + repellat ratione, perspiciatis, minima blanditiis provident + doloremque, et iste unde! Corporis. +

diff --git a/src/components/JobCard/JobCard.tsx b/src/components/JobCard/JobCard.tsx index a907b0a..d2f4197 100644 --- a/src/components/JobCard/JobCard.tsx +++ b/src/components/JobCard/JobCard.tsx @@ -9,50 +9,51 @@ import { getImageUrl } from "@/lib/utils"; export default function JobCard({ job, result }: JobCardProps) { return ( - - {job.status === "pending" ? ( -
-
- - Generating top job based on skills... +
+ + {job.status === "pending" ? ( +
+
+ + Generating top job based on skills... +
-
- ) : ( - <> - {`An -
-
- -

- {result?.jobTitle || ""} -

-
- - {!!job.skills.length && ( -
- {job.skills.split(",").map((skill) => ( - - {skill} - - ))} -
- )} - {job.status === "failed" && } - {job.status === "completed" && ( -
-

{result?.jobDescription || ""}

-
- )} -
-
- - )} - + ) : ( + <> + {`An +
+
+ +

+ {result?.jobTitle || ""} +

+
+ + {!!job.skills.length && ( +
+ {job.skills.split(",").map((skill) => ( + + {skill} + + ))} +
+ )} + {job.status === "failed" && } + {job.status === "completed" && ( +

{result?.jobDescription || ""}

+ )} +
+
+ + )} + + ); } diff --git a/src/components/JobForm/JobForm.tsx b/src/components/JobForm/JobForm.tsx index 0d35f6d..21ed27c 100644 --- a/src/components/JobForm/JobForm.tsx +++ b/src/components/JobForm/JobForm.tsx @@ -1,6 +1,6 @@ "use client"; -import { useSession, useUser } from "@clerk/nextjs"; +import { useSession } from "@clerk/nextjs"; import { zodResolver } from "@hookform/resolvers/zod"; import { useMutation } from "convex/react"; import React from "react"; @@ -49,34 +49,28 @@ export default function JobForm() { }; return ( -
-

- Generate a new job matched by your skills -

-

- -
- - ( - - Skills - - - - - Comma seperated list of all the skills you have. - - - - )} - /> - - - -
-
+ +
+ + ( + + Skills + + + + + Comma seperated list of all the skills you have. + + + + )} + /> + + + +
); } diff --git a/src/components/JobList/JobList.tsx b/src/components/JobList/JobList.tsx index 298e941..289fc86 100644 --- a/src/components/JobList/JobList.tsx +++ b/src/components/JobList/JobList.tsx @@ -20,7 +20,7 @@ export default function JobList({ jobs }: JobListProps) {
)} {!!jobs?.length && ( -
    +
      {jobs?.map((job) => { const result: JobCardResult = JSON.parse(job?.result || "{}"); diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index f000e3e..5544e25 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -1,36 +1,36 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const badgeVariants = cva( - "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", - { - variants: { - variant: { - default: - "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", - secondary: - "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", - destructive: - "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", - outline: "text-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-black dark:text-white border-black dark:border-white", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); export interface BadgeProps - extends React.HTMLAttributes, - VariantProps {} + extends React.HTMLAttributes, + VariantProps {} function Badge({ className, variant, ...props }: BadgeProps) { - return ( -
      - ) + return ( +
      + ); } -export { Badge, badgeVariants } +export { Badge, badgeVariants };