diff --git a/app/page.tsx b/app/page.tsx
index 76cd4ed..1a304d6 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,9 +1,16 @@
import ProjectList from "@/components/projects/project-list";
import SearchBar, { SearchBarPlaceholder } from "@/components/ui/search-bar";
+import { ProjectSorts } from "@/lib/project";
import { Twitter } from "@dub/ui";
import { Suspense } from "react";
-export default function Home() {
+export default function Home({
+ searchParams,
+}: {
+ searchParams?: {
+ sort?: ProjectSorts;
+ };
+}) {
return (
<>
@@ -45,7 +52,7 @@ export default function Home() {
className="animate-fade-up opacity-0"
style={{ animationDelay: "0.35s", animationFillMode: "forwards" }}
>
-
+
>
);
diff --git a/components/projects/project-list.tsx b/components/projects/project-list.tsx
index 9dacd18..cfcb3a7 100644
--- a/components/projects/project-list.tsx
+++ b/components/projects/project-list.tsx
@@ -1,24 +1,24 @@
import prisma from "@/lib/prisma";
import { Suspense } from "react";
import ProjectGrid from "./project-grid";
+import ProjectSort from "./project-sort";
+import { ProjectSorts, sortOrderBy } from "@/lib/project";
-export default function ProjectList() {
+export default function ProjectList({ sort }: {sort?: ProjectSorts;}) {
return (
-
+
);
}
-async function ProjectListRSC() {
+async function ProjectListRSC({ sort }: {sort?: ProjectSorts;}) {
const featured = ["gallery", "dub", "ui"];
const projects = await prisma.project.findMany({
where: {
verified: true,
},
- orderBy: {
- stars: "desc",
- },
+ orderBy: sortOrderBy[sort] ?? sortOrderBy.stars,
});
const featuredProjects = featured.map((slug) =>
@@ -35,7 +35,11 @@ async function ProjectListRSC() {
diff --git a/components/projects/project-sort.tsx b/components/projects/project-sort.tsx
new file mode 100644
index 0000000..79c77f5
--- /dev/null
+++ b/components/projects/project-sort.tsx
@@ -0,0 +1,74 @@
+"use client";
+
+import { IconMenu, Popover, Tick, useRouterStuff } from "@dub/ui";
+import { ChevronDown, SortDesc } from "lucide-react";
+import { useSearchParams } from "next/navigation";
+import { useMemo, useState } from "react";
+import Sort from "@/components/ui/icons/sort";
+import { sortOptions } from "@/lib/project";
+
+
+export default function ProjectSort() {
+ const [openPopover, setOpenPopover] = useState(false);
+ const searchParams = useSearchParams();
+ const sort = searchParams?.get("sort");
+ const { queryParams } = useRouterStuff();
+
+ const selectedSort = useMemo(() => {
+ return sortOptions.find((s) => s.slug === sort) || sortOptions[0];
+ }, [sort]);
+
+ return (
+
+ {sortOptions.map(({ display, slug }) => (
+
+ ))}
+
+ }
+ openPopover={openPopover}
+ setOpenPopover={setOpenPopover}
+ >
+
+
+ );
+}
diff --git a/components/ui/icons/sort.tsx b/components/ui/icons/sort.tsx
new file mode 100644
index 0000000..3ce4b16
--- /dev/null
+++ b/components/ui/icons/sort.tsx
@@ -0,0 +1,18 @@
+export default function Sort({ className }: { className: string }) {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/lib/project.ts b/lib/project.ts
new file mode 100644
index 0000000..a6dfb7d
--- /dev/null
+++ b/lib/project.ts
@@ -0,0 +1,34 @@
+import { Project } from "@prisma/client";
+
+export const sorts = ["stars", "newest", "alphabetical"] as const;
+
+export type ProjectSorts = typeof sorts[number];
+
+export const sortOptions: { display: string, slug: ProjectSorts }[] = [
+ {
+ display: "Number of Stars",
+ slug: "stars",
+ },
+ {
+ display: "Newest",
+ slug: "newest",
+ },
+ {
+ display: "A to Z",
+ slug: "alphabetical",
+ },
+];
+
+export type ProjectOrderBy = Record>>;
+
+export const sortOrderBy: ProjectOrderBy = {
+ alphabetical: {
+ name: "asc"
+ },
+ newest: {
+ createdAt: "desc"
+ },
+ stars: {
+ stars: "desc"
+ }
+}
\ No newline at end of file