Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 100 additions & 111 deletions frontend/app/[topic]/TopicLayout.tsx

Large diffs are not rendered by default.

123 changes: 123 additions & 0 deletions frontend/app/[topic]/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import {Skeleton} from "../components/Skeleton";

export default function TopicLoading() {
// Reusing the identical theme classes to ensure the skeleton flashes
// with the exact same background and border colors as the final layout.
const themeClasses = {
page: "bg-[#FFFFFF] text-[#111111] dark:bg-[#050505] dark:text-[#F5F5F5]",
sidebar: "bg-[#F7F7F7] dark:bg-[#101010]",
header: "bg-[#FFFFFF]/90 dark:bg-[#050505]/90",
border: "border-[#E5E5E5] dark:border-[#222222]",
};

return (
<div className={`${themeClasses.page} min-h-screen font-sans flex flex-col overflow-hidden`}>
{/* Header Placeholder */}
<header className={`sticky top-0 z-40 h-16 border-b ${themeClasses.border} ${themeClasses.header} backdrop-blur-md`}>
<div className="mx-auto flex h-full max-w-[1700px] items-center justify-between px-4 lg:px-6">
<div className="flex items-center gap-4">
{/* Mobile Menu Icon / Logo Placeholder */}
<Skeleton className="h-7 w-7 rounded-md lg:rounded-full" />
<Skeleton className="hidden lg:block h-4 w-16 rounded" />
</div>

<div className="flex-1 flex justify-center px-4 max-w-2xl mx-auto">
{/* Command Palette Search Placeholder */}
<Skeleton className="h-8 w-full rounded-full" />
</div>

{/* Theme Toggle Placeholder */}
<Skeleton className="shrink-0 h-8 w-[70px] rounded-full" />
</div>
</header>

<div className="flex-1 mx-auto flex w-full max-w-[1700px]">

{/* Left Sidebar (Directory) Placeholder */}
<aside className={`sticky top-16 hidden h-[calc(100vh-4rem)] w-[280px] shrink-0 overflow-hidden border-r lg:block ${themeClasses.sidebar} ${themeClasses.border}`}>
<div className="px-5 py-8">
<Skeleton className="h-3 w-20 mb-8 rounded" />
<div className="space-y-4">
{[...Array(12)].map((_, i) => (
<div key={i} className="flex items-center gap-3">
<Skeleton className="h-4 w-4 rounded shrink-0" />
<Skeleton
variant="text"
className={`h-4 rounded ${i % 3 === 0 ? 'w-3/4' : i % 2 === 0 ? 'w-1/2' : 'w-5/6'}`}
/>
</div>
))}
</div>
</div>
</aside>

{/* Main Content Area */}
<main className="flex-1 min-w-0 flex flex-col relative">

{/* Breadcrumbs Placeholder */}
<div className={`sticky top-16 z-30 flex items-center gap-3 py-3 px-5 md:px-10 xl:px-16 border-b ${themeClasses.border} ${themeClasses.header} backdrop-blur-md`}>
<Skeleton className="h-4 w-4 rounded" />
<Skeleton className="h-3 w-16 rounded" />
<Skeleton className="h-3 w-24 rounded" />
</div>

<div className="flex-1 px-5 pb-16 pt-6 md:px-10 lg:pt-10 xl:px-16 max-w-4xl mx-auto w-full">

{/* Title & Description Placeholder */}
<Skeleton className="h-12 w-3/4 sm:w-1/2 mb-6 rounded-lg" />
<div className="space-y-3 mb-10">
<Skeleton variant="text" className="h-5 w-full rounded" />
<Skeleton variant="text" className="h-5 w-11/12 rounded" />
</div>

{/* Paragraph 1 Placeholder */}
<div className="space-y-4 mb-10">
<Skeleton variant="text" className="h-4 w-full rounded" />
<Skeleton variant="text" className="h-4 w-full rounded" />
<Skeleton variant="text" className="h-4 w-5/6 rounded" />
</div>

{/* Code Block Placeholder */}
<Skeleton className="h-64 w-full rounded-xl mb-10" />

{/* Subheading & Paragraph 2 Placeholder */}
<Skeleton className="h-8 w-1/3 mb-6 rounded" />
<div className="space-y-4 mb-10">
<Skeleton variant="text" className="h-4 w-full rounded" />
<Skeleton variant="text" className="h-4 w-11/12 rounded" />
<Skeleton variant="text" className="h-4 w-4/5 rounded" />
</div>

{/* Secondary Code/Data Block Placeholder */}
<Skeleton className="h-32 w-full rounded-xl" />
</div>
</main>

{/* Right Sidebar (Table of Contents) Placeholder */}
<aside className={`sticky top-16 hidden h-[calc(100vh-4rem)] w-[260px] shrink-0 overflow-hidden border-l xl:block ${themeClasses.sidebar} ${themeClasses.border}`}>
<div className="px-6 py-10">
<Skeleton className="h-3 w-24 mb-6 rounded" />
<div className="space-y-5">
<div>
<Skeleton variant="text" className="h-3 w-3/4 rounded mb-3" />
<div className={`border-l ml-[3px] pl-3 space-y-3 ${themeClasses.border}`}>
<Skeleton variant="text" className="h-2.5 w-4/5 rounded" />
<Skeleton variant="text" className="h-2.5 w-5/6 rounded" />
</div>
</div>
<div>
<Skeleton variant="text" className="h-3 w-full rounded mb-3" />
<div className={`border-l ml-[3px] pl-3 space-y-3 ${themeClasses.border}`}>
<Skeleton variant="text" className="h-2.5 w-2/3 rounded" />
</div>
</div>
<Skeleton variant="text" className="h-3 w-5/6 rounded" />
<Skeleton variant="text" className="h-3 w-4/5 rounded" />
</div>
</div>
</aside>

</div>
</div>
);
}
48 changes: 30 additions & 18 deletions frontend/app/[topic]/opengraph-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,14 @@ import { ImageResponse } from 'next/og';

export const runtime = 'edge';

export const alt = 'RefMe Documentation';
export const alt = 'RefMe_ | Technical Reference for Modern Developers';
export const size = {
width: 1200,
height: 630,
};
export const contentType = 'image/png';

export default async function Image({ params }: { params: Promise<{ topic: string }> }) {
const { topic } = await params;

const formattedTitle = topic
.split('-')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');

export default async function Image() {
return new ImageResponse(
(
<div
Expand All @@ -41,40 +34,59 @@ export default async function Image({ params }: { params: Promise<{ topic: strin
/>

<div tw="flex items-center" style={{ zIndex: 10 }}>
{/* Note: The container wrapper below has a background and border.
Since your SVG also has a background/border, you may want to strip
the wrapper's bg/border if it looks like a box-inside-a-box,
but it is technically sound as-is. */}
<div
tw="flex items-center justify-center rounded-2xl bg-[#0F1115] text-white border border-white/10"
tw="flex items-center justify-center rounded-2xl bg-[#0F1115] text-white border border-white/10 overflow-hidden"
style={{ width: '72px', height: '72px', boxShadow: '0 8px 32px rgba(0,0,0,0.4)' }}
>
<span tw="font-black leading-none" style={{ fontSize: '36px', letterSpacing: '-0.14em' }}>
R<span tw="text-zinc-500">_</span>
</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100%" height="100%">
<rect width="512" height="512" rx="116" fill="#09090b"/>
<rect x="6" y="6" width="500" height="500" rx="110" fill="none" stroke="#27272a" strokeWidth="4"/>
<g>
<text
x="150"
y="365"
fontFamily="system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
fontWeight="900"
fontSize="290"
fill="#ffffff"
letterSpacing="-8"
>
R
</text>
<rect x="350" y="325" width="55" height="24" rx="5" fill="#a1a1aa"/>
</g>
</svg>
</div>
<div tw="flex flex-row ml-6 items-center font-semibold uppercase" style={{ fontSize: '22px', letterSpacing: '0.28em' }}>
<span tw="text-[#F5F5F5]">RefMe</span>
<span tw="ml-3 text-zinc-500">docs</span>
</div>
</div>

<div tw="flex flex-col mt-auto" style={{ zIndex: 10 }}>
<div tw="flex flex-col mt-auto" style={{ zIndex: 10, maxWidth: '960px' }}>
<div
tw="flex font-semibold uppercase mb-4 opacity-90 text-[#C699FF]"
style={{ fontSize: '24px', letterSpacing: '0.2em' }}
>
Reference Guide
Technical Reference
</div>

<div
tw="flex font-extrabold text-white leading-none"
style={{ fontSize: '110px', letterSpacing: '-0.04em' }}
>
{formattedTitle}
RefMe_
</div>

<div
tw="flex mt-8 text-zinc-400 font-medium"
style={{ fontSize: '36px', letterSpacing: '-0.02em' }}
style={{ fontSize: '32px', letterSpacing: '-0.01em', lineHeight: 1.4 }}
>
The developer's quick-reference guide.
The ultimate centralized, fast, and minimal technical reference hub for modern full-stack development. Built for clarity and speed.
</div>
</div>

Expand Down
83 changes: 83 additions & 0 deletions frontend/app/[topic]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Metadata } from "next";
import { getAllTopics, getTopicBySlug } from "../../src/lib/mdx";
import { MDXRemote } from "next-mdx-remote/rsc";
import SkeletonTopic from "../components/SkeletonTopic";
Expand All @@ -20,6 +21,40 @@ const mdxComponents = {
},
};

export async function generateMetadata({
params,
}: {
params: Promise<{ topic: string }>;
}): Promise<Metadata> {
const resolvedParams = await params;
const topicData = getTopicBySlug(resolvedParams.topic);

if (!topicData || !topicData.frontmatter) {
return {};
}

const { title, description } = topicData.frontmatter;
const pageTitle = `${title} | RefMe_`;

return {
title: pageTitle,
description: description,
openGraph: {
title: pageTitle,
description: description,
type: "article",
},
twitter: {
card: "summary_large_image",
title: pageTitle,
description: description,
},
alternates: {
canonical: `https://refmev1.vercel.app/${resolvedParams.topic}`,
},
};
}

export async function generateStaticParams() {
const topics = getAllTopics();

Expand Down Expand Up @@ -58,6 +93,46 @@ export default async function TopicPage({
);
}

const { title, description, category } = topicData.frontmatter;
const pageUrl = `https://refmev1.vercel.app/${resolvedParams.topic}`;

const breadcrumbJsonLd = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "Home",
item: "https://refmev1.vercel.app",
},
{
"@type": "ListItem",
position: 2,
name: category || "Category",
},
{
"@type": "ListItem",
position: 3,
name: title,
item: pageUrl,
},
],
};

const articleJsonLd = {
"@context": "https://schema.org",
"@type": "TechArticle",
headline: title,
description: description,
author: {
"@type": "Person",
name: "Yash Vardhan",
url: "https://www.linkedin.com/in/vardhan-yash3105/",
},
url: pageUrl,
};

return (
<TopicLayout
frontmatter={topicData.frontmatter}
Expand All @@ -67,6 +142,14 @@ export default async function TopicPage({
prevTopic={prevTopic}
nextTopic={nextTopic}
>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbJsonLd) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(articleJsonLd) }}
/>
<MDXRemote source={topicData.content} components={mdxComponents} />
</TopicLayout>
);
Expand Down
27 changes: 23 additions & 4 deletions frontend/app/components/ClientCodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useTheme } from "../../src/context/ThemeContext";
import { useState } from "react";
import { Copy, Check, FileCode2 } from "lucide-react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import {Skeleton} from "../../app/components/Skeleton";

export interface ClientCodeBlockProps {
/** The raw code string to be highlighted */
Expand Down Expand Up @@ -203,11 +204,29 @@ export default function ClientCodeBlock({
</div>

<div className="w-full py-4 overflow-x-auto bg-[#F4F4F0] dark:bg-[#101010] transition-colors duration-200">
{/* Render a height-preserving invisible block before hydration, then swap to real highlighter */}
{/* Render a height-preserving invisible block before hydration, overlaid with Skeleton lines, then swap to real highlighter */}
{!mounted ? (
<pre className="m-0 p-0 text-[0.9rem] leading-[1.7] opacity-0" aria-hidden="true">
<code>{code}</code>
</pre>
<div className="relative w-full">
<div
className="absolute inset-0 flex flex-col gap-[10.5px] pl-[13px] pr-[16px] pt-[2px] overflow-hidden pointer-events-none"
aria-hidden="true"
>
{Array.from({ length: Math.min(code.split('\n').length, 30) }).map((_, i) => {
// cycle through varied widths to mock natural code lines
const widths = ['w-3/4', 'w-1/2', 'w-5/6', 'w-2/3', 'w-1/3', 'w-4/5', 'w-[90%]', 'w-2/5', 'w-3/5', 'w-1/4'];
return (
<Skeleton
key={i}
variant="text"
className={`h-[14px] rounded-sm ${widths[i % widths.length]}`}
/>
);
})}
</div>
<pre className="m-0 p-0 text-[0.9rem] leading-[1.7] opacity-0" aria-hidden="true">
<code>{code}</code>
</pre>
</div>
) : (
<SyntaxHighlighter
language={language}
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function Footer() {

<div
aria-hidden="true"
className="relative w-full overflow-hidden pointer-events-none select-none"
className="hidden md:block relative w-full overflow-hidden pointer-events-none select-none "
style={{ height: "clamp(65px, 10vw, 150px)" }}
>
<div
Expand Down Expand Up @@ -102,7 +102,7 @@ export default function Footer() {
<div className="relative flex flex-col sm:flex-row items-center justify-between gap-4 pt-5 border-t border-[#E5E5E5] dark:border-[#333] text-[13px] font-medium text-zinc-500 dark:text-zinc-400">

<div
className="absolute top-0 left-0 w-full h-[95px] -translate-y-full pointer-events-none z-10 bg-[linear-gradient(to_top,#fafafa_10%,rgba(250,250,250,0.85)_40%,transparent_100%)] dark:bg-[linear-gradient(to_top,#050505_10%,rgba(5,5,5,0.85)_40%,transparent_100%)]"
className="absolute top-0 left-0 w-full h-[95px] hidden md:block -translate-y-full pointer-events-none z-10 bg-[linear-gradient(to_top,#fafafa_10%,rgba(250,250,250,0.85)_40%,transparent_100%)] dark:bg-[linear-gradient(to_top,#050505_10%,rgba(5,5,5,0.85)_40%,transparent_100%)]"
/>

<p className="relative z-20">© 2026 RefMe</p>
Expand Down
Loading
Loading