Initial commit

This commit is contained in:
Akshay Kolli
2026-02-08 02:32:45 -05:00
commit 3f72118348
26 changed files with 6355 additions and 0 deletions

23
app/api/rss/route.ts Normal file
View File

@@ -0,0 +1,23 @@
import { NextResponse } from 'next/server';
import Parser from 'rss-parser';
export const dynamic = 'force-dynamic';
export async function GET() {
const parser = new Parser();
try {
const feed = await parser.parseURL('https://news.ycombinator.com/rss');
const items = feed.items.slice(0, 10).map(item => ({
title: item.title,
link: item.link,
pubDate: item.pubDate,
creator: item.creator || 'Unknown',
contentSnippet: item.contentSnippet,
}));
return NextResponse.json(items);
} catch (error) {
return NextResponse.json({ error: 'Failed to parse RSS' }, { status: 500 });
}
}

53
app/api/status/route.ts Normal file
View File

@@ -0,0 +1,53 @@
import { NextResponse } from 'next/server';
// Configuration - Update these URLs to match your actual services
const SERVICES = [
{ name: 'Website', url: 'https://www.akkolli.net' },
{ name: 'Gitea', url: 'https://code.akkolli.net' },
{ name: 'Nextcloud', url: 'http://localhost:6060' },
];
export const dynamic = 'force-dynamic';
export async function GET() {
const results = await Promise.all(
SERVICES.map(async (service) => {
const start = performance.now();
try {
// Set a short timeout (e.g., 5 seconds)
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch(service.url, {
method: 'HEAD',
signal: controller.signal,
cache: 'no-store',
});
clearTimeout(timeoutId);
const end = performance.now();
const latency = Math.round(end - start);
return {
name: service.name,
url: service.url,
status: response.ok ? 'up' : 'down',
latency: latency,
timestamp: new Date().toISOString(),
};
} catch (error) {
return {
name: service.name,
url: service.url,
status: 'down',
latency: 0,
timestamp: new Date().toISOString(),
error: 'Unreachable'
};
}
})
);
return NextResponse.json(results);
}

BIN
app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

26
app/globals.css Normal file
View File

@@ -0,0 +1,26 @@
@import "tailwindcss";
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}

22
app/layout.tsx Normal file
View File

@@ -0,0 +1,22 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}

26
app/page.tsx Normal file
View File

@@ -0,0 +1,26 @@
import { GridShell } from "@/components/dashboard/GridShell";
import { UptimeCard } from "@/components/widgets/UptimeCard";
import { GlobeCard } from "@/components/widgets/GlobeCard";
import { WeatherCard } from "@/components/widgets/WeatherCard";
import { NewsFeed } from "@/components/widgets/NewsFeed";
export default function Home() {
return (
<GridShell>
{/* Row 1 */}
<UptimeCard />
<WeatherCard />
{/* Row 1 & 2 (Globe spans 2 rows) */}
<GlobeCard />
{/* Row 2 */}
<NewsFeed />
{/* Future widget placeholder to fill grid if needed */}
<div className="col-span-1 md:col-span-2 lg:col-span-2 row-span-1 bg-neutral-900/50 border border-neutral-800/50 rounded-xl flex items-center justify-center border-dashed">
<span className="text-xs text-neutral-600 font-mono">System Metric Placeholder</span>
</div>
</GridShell>
);
}