diff --git a/package.json b/package.json
index a97427d..92c6e45 100644
--- a/package.json
+++ b/package.json
@@ -13,8 +13,8 @@
"blur": "yarn dlx tsx ./processImages.ts"
},
"dependencies": {
- "@mdx-js/loader": "^3.0.1",
- "@mdx-js/react": "^3.0.1",
+ "@mdx-js/loader": "^3.1.0",
+ "@mdx-js/react": "^3.1.0",
"@next/mdx": "^15.0.0",
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
@@ -22,6 +22,7 @@
"@radix-ui/react-hover-card": "^1.1.2",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.2",
+ "@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.3",
@@ -29,9 +30,9 @@
"clsx": "^2.1.1",
"drizzle-orm": "^0.36.0",
"jose": "^5.6.3",
- "lucide-react": "^0.427.0",
+ "lucide-react": "^0.454.0",
"next": "^15.0.2",
- "next-themes": "^0.3.0",
+ "next-themes": "^0.4.1",
"postgres": "^3.4.5",
"react": "19.0.0-rc-7c8e5e7a-20241101",
"react-dom": "19.0.0-rc-7c8e5e7a-20241101",
@@ -41,7 +42,7 @@
},
"devDependencies": {
"@faker-js/faker": "^9.0.0",
- "@tailwindcss/postcss": "^4.0.0-alpha.17",
+ "@tailwindcss/postcss": "^4.0.0-alpha.31",
"@types/mdx": "^2.0.13",
"@types/node": "^20",
"@types/react": "npm:types-react@19.0.0-rc.1",
@@ -53,7 +54,7 @@
"eslint-plugin-react-compiler": "19.0.0-beta-8a03594-20241020",
"prettier": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.5",
- "tailwindcss": "^4.0.0-alpha.17",
+ "tailwindcss": "^4.0.0-alpha.31",
"tsx": "^4.19.2",
"typescript": "^5.5.3"
},
diff --git a/processImages.ts b/processImages.ts
deleted file mode 100644
index 188fbea..0000000
--- a/processImages.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import fs from "fs";
-import path from "path";
-import sharp from "sharp";
-
-type imgMeta = {
- fileName: string;
- relativePath: string;
- width: number;
- height: number;
- imgBase64: string;
-};
-
-async function processImage(imagePath: string) {
- const sharpImg = sharp(imagePath);
- const meta = await sharpImg.metadata();
- if (!meta) {
- return null;
- }
- const placeholderImgWidth = 20;
- const imgAspectRatio = meta.width! / meta.height!;
- const placeholderImgHeight = Math.round(placeholderImgWidth / imgAspectRatio);
- const imgBase64 = await sharpImg
- .resize(placeholderImgWidth, placeholderImgHeight)
- .toBuffer()
- .then(
- (buffer) =>
- `data:image/${meta.format};base64,${buffer.toString("base64")}`,
- );
-
- return {
- fileName: path.basename(imagePath),
- // Strip public prefix, /public is / in Nextjs runtime environment
- relativePath: path
- .relative(process.cwd(), imagePath)
- .substring("public".length),
- width: meta.width!,
- height: meta.height!,
- imgBase64,
- };
-}
-async function processImages(folderName: string, recursive: boolean) {
- const imageFolder = fs.readdirSync(folderName);
-
- const recurseFolders = [];
- const folderImgMeta = {} as { [key: string]: imgMeta };
-
- for await (const item of imageFolder) {
- const itemIsDir = fs.lstatSync(path.join(folderName, item)).isDirectory();
- if (itemIsDir) {
- recurseFolders.push(path.join(folderName, item));
- } else if (path.extname(item) !== ".json") {
- const imgMeta = await processImage(path.join(folderName, item));
- folderImgMeta[imgMeta!.fileName] = imgMeta!;
- }
- }
-
- fs.writeFileSync(
- path.join(folderName, "imgMeta.json"),
- JSON.stringify(folderImgMeta),
- );
-
- if (Object.keys(folderImgMeta).length !== 0) {
- const constantsFilePath = path.join(
- process.cwd(),
- "/src",
- "lib",
- "imgMeta.ts",
- );
-
- const constName = folderName.split("/").slice(-1)[0];
- const fileContent = `export const ${constName} = ${JSON.stringify(folderImgMeta)};`;
- fs.appendFileSync(constantsFilePath, fileContent);
- }
-
- if (recursive)
- recurseFolders.forEach(async (folder) => await processImages(folder, true));
-
- return;
-}
-
-async function processAllImages() {
- const imgMetaFilePath = path.join(process.cwd(), "/src", "lib", "imgMeta.ts");
- if (fs.existsSync(imgMetaFilePath)) {
- fs.rmSync(imgMetaFilePath);
- }
- await processImages(path.join(process.cwd(), "/public", "assets"), true);
-}
-
-processAllImages();
diff --git a/src/app/forum/components/Header.tsx b/src/app/forum/components/Header.tsx
new file mode 100644
index 0000000..76cf894
--- /dev/null
+++ b/src/app/forum/components/Header.tsx
@@ -0,0 +1,10 @@
+import Auth from "@/components/auth";
+
+export default async function Header() {
+ return (
+
+ );
+}
diff --git a/src/app/forum/components/SidePanel.tsx b/src/app/forum/components/SidePanel.tsx
new file mode 100644
index 0000000..db5e4a9
--- /dev/null
+++ b/src/app/forum/components/SidePanel.tsx
@@ -0,0 +1,67 @@
+import { Calendar, Home, Inbox, Search, Settings } from "lucide-react";
+
+import {
+ Sidebar,
+ SidebarContent,
+ SidebarGroup,
+ SidebarGroupContent,
+ SidebarGroupLabel,
+ SidebarMenu,
+ SidebarMenuButton,
+ SidebarMenuItem,
+} from "@/components/ui/sidebar";
+
+// Menu items.
+const items = [
+ {
+ title: "Home",
+ url: "#",
+ icon: Home,
+ },
+ {
+ title: "Inbox",
+ url: "#",
+ icon: Inbox,
+ },
+ {
+ title: "Calendar",
+ url: "#",
+ icon: Calendar,
+ },
+ {
+ title: "Search",
+ url: "#",
+ icon: Search,
+ },
+ {
+ title: "Settings",
+ url: "#",
+ icon: Settings,
+ },
+];
+
+export function SidePanel() {
+ return (
+
+
+
+ Application
+
+
+ {items.map((item) => (
+
+
+
+
+ {item.title}
+
+
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/src/app/forum/error.tsx b/src/app/forum/error.tsx
new file mode 100644
index 0000000..9440da8
--- /dev/null
+++ b/src/app/forum/error.tsx
@@ -0,0 +1,30 @@
+"use client"; // Error components must be Client Components
+
+import { useEffect } from "react";
+
+export default function Error({
+ error,
+ reset,
+}: {
+ error: Error & { digest?: string };
+ reset: () => void;
+}) {
+ useEffect(() => {
+ // Log the error to an error reporting service
+ console.error(error);
+ }, [error]);
+
+ return (
+
+
Something went wrong!
+
+
+ );
+}
diff --git a/src/app/forum/home/page.tsx b/src/app/forum/home/page.tsx
index 4032352..1c31b76 100644
--- a/src/app/forum/home/page.tsx
+++ b/src/app/forum/home/page.tsx
@@ -1,3 +1,23 @@
-export default function Home() {
- return null;
+import { dbClient } from "@/db/forum/db";
+import { messages } from "@/db/forum/schema";
+import { desc, isNull } from "drizzle-orm";
+
+export default async function Home() {
+ const posts = await dbClient()
+ .db.select()
+ .from(messages)
+ .where(isNull(messages.parent_id))
+ .orderBy(desc(messages.createdAt));
+ return (
+
+ {posts.map((post) => (
+
+ ))}
+
+ );
}
diff --git a/src/app/forum/layout.tsx b/src/app/forum/layout.tsx
index 5788c57..c6cf2a2 100644
--- a/src/app/forum/layout.tsx
+++ b/src/app/forum/layout.tsx
@@ -1,5 +1,7 @@
import type { Metadata } from "next";
-
+import Header from "./components/Header";
+import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
+import { SidePanel } from "./components/SidePanel";
export const metadata: Metadata = {
title: "Forum",
description: "Created by DJ Sisson",
@@ -10,5 +12,21 @@ export default function AsteroidzLayout({
}: Readonly<{
children: React.ReactNode;
}>) {
- return children;
+ return (
+
+
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+ );
}
diff --git a/src/app/forum/page.tsx b/src/app/forum/page.tsx
index cb4db69..20da874 100644
--- a/src/app/forum/page.tsx
+++ b/src/app/forum/page.tsx
@@ -1,3 +1,5 @@
-export default function Forum() {
- return null;
+import { redirect } from "next/navigation";
+
+export default function Home() {
+ return {redirect("/home")};
}
diff --git a/src/app/forum/template.tsx b/src/app/forum/template.tsx
new file mode 100644
index 0000000..9aceb93
--- /dev/null
+++ b/src/app/forum/template.tsx
@@ -0,0 +1,3 @@
+export default function Template({ children }: { children: React.ReactNode }) {
+ return {children}
;
+}
diff --git a/src/app/global.css b/src/app/global.css
index 0ec2e43..c8d5a7c 100755
--- a/src/app/global.css
+++ b/src/app/global.css
@@ -28,8 +28,15 @@
--animate-appear-up: animate-appear-up 500ms ease-in-out;
--animate-slide-in: animate-slide-in 500ms ease-in-out;
--font-family-sans: var(--font-inter), sans-serif;
+ --color-sidebar: hsl(var(--sidebar-background));
+ --color-sidebar-foreground: hsl(var(--sidebar-foreground));
+ --color-sidebar-primary: hsl(var(--sidebar-primary));
+ --color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));
+ --color-sidebar-accent: hsl(var(--sidebar-accent));
+ --color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));
+ --color-sidebar-border: hsl(var(--sidebar-border));
+ --color-sidebar-ring: hsl(var(--sidebar-ring));
}
-
:root {
color-scheme: light dark;
--clr-1: #0e4b50;
@@ -71,6 +78,14 @@
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
+ --sidebar-background: 0 0% 98%;
+ --sidebar-foreground: 240 5.3% 26.1%;
+ --sidebar-primary: 240 5.9% 10%;
+ --sidebar-primary-foreground: 0 0% 98%;
+ --sidebar-accent: 240 4.8% 95.9%;
+ --sidebar-accent-foreground: 240 5.9% 10%;
+ --sidebar-border: 220 13% 91%;
+ --sidebar-ring: 217.2 91.2% 59.8%;
}
.dark {
@@ -98,6 +113,14 @@
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
+ --sidebar-background: 240 5.9% 10%;
+ --sidebar-foreground: 240 4.8% 95.9%;
+ --sidebar-primary: 224.3 76.3% 48%;
+ --sidebar-primary-foreground: 0 0% 100%;
+ --sidebar-accent: 240 3.7% 15.9%;
+ --sidebar-accent-foreground: 240 4.8% 95.9%;
+ --sidebar-border: 240 3.7% 15.9%;
+ --sidebar-ring: 217.2 91.2% 59.8%;
}
}
@@ -109,6 +132,7 @@
@apply bg-background text-foreground;
}
}
+
@keyframes rainbow-scroll {
0% {
background-position: 0% 50%;
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 17f17e2..3ac0a2a 100755
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -23,6 +23,11 @@ export default function Home() {
Tilez
+
+
+ Forum
+
+
);
diff --git a/src/app/redirect/[[...redirect]]/route.ts b/src/app/redirect/[[...redirect]]/route.ts
index d168cbc..ed4bf4f 100755
--- a/src/app/redirect/[[...redirect]]/route.ts
+++ b/src/app/redirect/[[...redirect]]/route.ts
@@ -7,7 +7,7 @@ export async function GET(
props: { params: Promise<{ redirect?: string[] }> },
) {
const params = await props.params;
- const { searchParams, hostname, protocol } = new URL(request.url);
+ const { searchParams, hostname, protocol, port } = new URL(request.url);
const code = searchParams.get("code");
const redirectUrl = `/${params.redirect?.join("/") ?? ""}`;
@@ -19,7 +19,9 @@ export async function GET(
const isLocalEnv = process.env.NODE_ENV === "development";
if (isLocalEnv) {
// we can be sure that there is no load balancer in between, so no need to watch for X-Forwarded-Host
- return NextResponse.redirect(`${protocol}//${hostname}${redirectUrl}`);
+ return NextResponse.redirect(
+ `${protocol}//${hostname}:${port}${redirectUrl}`,
+ );
} else if (forwardedHost) {
return NextResponse.redirect(`https://${forwardedHost}${redirectUrl}`);
} else {
diff --git a/src/components/auth.tsx b/src/components/auth.tsx
index d965ab9..27e75a9 100644
--- a/src/components/auth.tsx
+++ b/src/components/auth.tsx
@@ -65,6 +65,7 @@ export default async function Auth({ app }: { app: string }) {
xmlns="http://www.w3.org/2000/svg"
fill="white"
color="#181717"
+ style={{ width: "32px", height: "32px" }}
>
GitHub
@@ -81,8 +82,7 @@ export default async function Auth({ app }: { app: string }) {
>