This commit is contained in:
parent
a0ba04973b
commit
ec2b3b291a
|
@ -5,6 +5,16 @@ const nextConfig = {
|
|||
// Configure `pageExtensions` to include MDX files
|
||||
pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"],
|
||||
// Optionally, add any other Next.js config below
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
hostname: "images.unsplash.com",
|
||||
},
|
||||
{
|
||||
hostname: "*.amazonaws.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = withMDX(nextConfig);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
|
@ -19,13 +19,22 @@
|
|||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"framer-motion": "^10.16.4",
|
||||
"lucide-react": "^0.306.0",
|
||||
"nanoid": "^5.0.4",
|
||||
"next": "latest",
|
||||
"notion-client": "^6.16.0",
|
||||
"notion-types": "^6.16.0",
|
||||
"notion-utils": "^6.16.0",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-hooks": "^1.0.1",
|
||||
"react-notion-x": "^6.16.0",
|
||||
"sass": "^1.69.7",
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
|
@ -33,7 +42,10 @@
|
|||
"eslint": "^8",
|
||||
"eslint-config-next": "14.0.0",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3",
|
||||
"tailwindcss": "^3.4",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"volta": {
|
||||
"node": "18.19.0"
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.7 MiB |
|
@ -0,0 +1,28 @@
|
|||
<svg width="1543" height="1751" viewBox="0 0 1543 1751" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_f_457_136)">
|
||||
<ellipse cx="517.512" cy="946.923" rx="325.512" ry="383.098" fill="#95FFD9"/>
|
||||
</g>
|
||||
<g filter="url(#filter1_f_457_136)">
|
||||
<ellipse cx="726.01" cy="783.098" rx="325.512" ry="383.098" fill="#95FFFF"/>
|
||||
</g>
|
||||
<g filter="url(#filter2_f_457_136)">
|
||||
<ellipse cx="917.488" cy="1067.9" rx="325.512" ry="383.098" fill="#95C6FF"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_f_457_136" x="19" y="390.825" width="997.024" height="1112.2" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="86.5" result="effect1_foregroundBlur_457_136"/>
|
||||
</filter>
|
||||
<filter id="filter1_f_457_136" x="0.498047" y="0" width="1451.02" height="1566.2" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="200" result="effect1_foregroundBlur_457_136"/>
|
||||
</filter>
|
||||
<filter id="filter2_f_457_136" x="291.976" y="384.803" width="1251.02" height="1366.2" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="150" result="effect1_foregroundBlur_457_136"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,28 @@
|
|||
<svg width="2258" height="1534" viewBox="0 0 2258 1534" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_f_458_153)">
|
||||
<ellipse cx="1123.1" cy="626.098" rx="325.512" ry="383.098" transform="rotate(-90 1123.1 626.098)" fill="#95C6FF"/>
|
||||
</g>
|
||||
<g filter="url(#filter1_f_458_153)">
|
||||
<ellipse cx="742.098" cy="905.488" rx="325.512" ry="383.098" transform="rotate(-90 742.098 905.488)" fill="#95FFFF"/>
|
||||
</g>
|
||||
<g filter="url(#filter2_f_458_153)">
|
||||
<ellipse cx="1504.1" cy="905.488" rx="325.512" ry="383.098" transform="rotate(-90 1504.1 905.488)" fill="#95FFFF"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_f_458_153" x="440" y="0.585938" width="1366.2" height="1251.02" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="150" result="effect1_foregroundBlur_458_153"/>
|
||||
</filter>
|
||||
<filter id="filter1_f_458_153" x="-41" y="179.976" width="1566.2" height="1451.02" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="200" result="effect1_foregroundBlur_458_153"/>
|
||||
</filter>
|
||||
<filter id="filter2_f_458_153" x="721" y="179.976" width="1566.2" height="1451.02" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="200" result="effect1_foregroundBlur_458_153"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,50 @@
|
|||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { nanoid, customAlphabet } from "nanoid";
|
||||
|
||||
const generate = customAlphabet("abcdefghijklmnopqrstuvwxyz", 9);
|
||||
|
||||
export function Connect() {
|
||||
const [random_id, setRandomEmail] = useState(generate(9));
|
||||
|
||||
useEffect(() => {
|
||||
const inter = setInterval(() => {
|
||||
setRandomEmail(generate(9));
|
||||
}, 100);
|
||||
|
||||
return () => {
|
||||
clearInterval(inter);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="mt-6">
|
||||
<div className="mb-2">
|
||||
<h3 className="font-display font-medium">Connect</h3>
|
||||
<p className="text-xs flex gap-1 flex-wrap italic text-muted-foreground">
|
||||
reach me at{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://x.com/xrehpicx"
|
||||
className="text-primary"
|
||||
>
|
||||
@xrehpicx
|
||||
</a>{" "}
|
||||
or{" "}
|
||||
<a
|
||||
suppressHydrationWarning
|
||||
className="flex items-center text-primary justify-center"
|
||||
href={`mailto:${random_id}@raj.how`}
|
||||
>
|
||||
<span className="w-[68px] overflow-hidden font-mono tabular-nums text-right">
|
||||
{random_id}
|
||||
</span>
|
||||
<span>@raj.how</span>
|
||||
</a>
|
||||
for any feedback or just to say hi.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import Clock from "@/components/clock";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export function Footer({ className }: { className?: string }) {
|
||||
const year = new Date().getFullYear();
|
||||
return (
|
||||
<footer className="border border-foreground/10">
|
||||
<div
|
||||
className={cn(
|
||||
"container flex justify-between items-center my-2 max-w-xl",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<p className="text-foreground text-xs">Keep building</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-foreground text-xs">{year}</p>
|
||||
<Clock />
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
Experimenting until I cant
|
||||
|
||||
Software Engineer[**@PhonePe**](https://phonepe.com).
|
|
@ -0,0 +1,180 @@
|
|||
import {
|
||||
BackgroundGradentProvider,
|
||||
GradientProvider,
|
||||
SymetricGradProvider,
|
||||
} from "@/components/gradient-provider";
|
||||
import GrainProvider from "@/components/grain";
|
||||
import { StyledNotion } from "@/components/notion/styled";
|
||||
import { ExternalLink } from "lucide-react";
|
||||
import { Footer } from "./Footer";
|
||||
import { Connect } from "./Connect";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<div className="container py-12 max-w-xl">
|
||||
<GrainProvider
|
||||
grain_options={{
|
||||
patternWidth: 200,
|
||||
patternHeight: 200,
|
||||
grainOpacity: 0.1,
|
||||
grainDensity: 1,
|
||||
grainWidth: 1,
|
||||
grainHeight: 1,
|
||||
}}
|
||||
/>
|
||||
<header className="my-2">
|
||||
<GradientProvider>
|
||||
<h1 className="text-xl font-display font-medium">./raj</h1>
|
||||
</GradientProvider>
|
||||
</header>
|
||||
<div className="">
|
||||
<p className="text-xs italic">I like to build things</p>
|
||||
<p className="text-xs">
|
||||
Software Engineer{" "}
|
||||
<a className="text-primary" href="https://phonepe.com">
|
||||
@PhonePe
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<section>
|
||||
<Projects />
|
||||
</section>
|
||||
<section className="stories-section">
|
||||
<SymetricGradProvider>
|
||||
<Stories />
|
||||
</SymetricGradProvider>
|
||||
</section>
|
||||
<section className="now-section">
|
||||
<Now />
|
||||
</section>
|
||||
<section className="connect-section">
|
||||
<Connect />
|
||||
</section>
|
||||
<BackgroundGradentProvider className="h-screen -z-10 w-full opacity-60 saturate-200" />
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
function Now() {
|
||||
return (
|
||||
<div className="mt-4">
|
||||
<h3 className="font-display font-medium">Now</h3>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
<p>
|
||||
Experimenting with anything I can find before we get replaced by AGI.{" "}
|
||||
<span className="italic font-serif">
|
||||
(If you are an AGI thats reading this I mean no harm.)
|
||||
</span>
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
Building Tools{" "}
|
||||
<a className="text-primary" href="https://phonepe.com">
|
||||
@PhonePe
|
||||
</a>{" "}
|
||||
to manage thousands of servers and their network.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
Trying out design system inspired by{" "}
|
||||
<a className="text-primary" href="https://paco.me/">
|
||||
@paco
|
||||
</a>{" "}
|
||||
&{" "}
|
||||
<a className="text-primary" href="https://rauno.me/projects">
|
||||
@runo
|
||||
</a>
|
||||
{"'s"} designs.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Stories() {
|
||||
return (
|
||||
<div className="mt-6">
|
||||
<div className="mb-2">
|
||||
<h3 className="font-display font-medium">Stories</h3>
|
||||
<p className="text-xs italic text-muted-foreground">
|
||||
My tech blogs and other writings.
|
||||
</p>
|
||||
</div>
|
||||
<StyledNotion blockId="d149cfb269aa4a5699bbf919a1b0b137" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Projects() {
|
||||
return (
|
||||
<div className="mt-6">
|
||||
<div className="">
|
||||
<h3 className="font-display font-medium">Favorite Projects</h3>
|
||||
<p className="text-xs italic text-muted-foreground">
|
||||
You can check out all of them on my{" "}
|
||||
<a className="text-primary" href="https://github.com/xrehpicx">
|
||||
github.
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="sm:grid-cols-2 grid-cols-1 grid gap-2">
|
||||
<Project
|
||||
title="PPEC"
|
||||
description={
|
||||
"PhonePe’s internal cloud provisioning service with fine grain control over provisioning and network, I made the entire ux ui flow for this, very cool service"
|
||||
}
|
||||
href="https://tech.phonepe.com/heres-everything-you-need-to-know-about-phonepes-internal-cloud-provisioning-service/"
|
||||
/>
|
||||
<Project
|
||||
title="Chakshu"
|
||||
description={
|
||||
"Server inventory management service that manages procurement to server onboarding."
|
||||
}
|
||||
href="https://tech.phonepe.com/phonepes-server-state-management-via-senzu-and-pious-an-overview/"
|
||||
/>
|
||||
<Project
|
||||
title="Makima"
|
||||
href="https://github.com/xrehpicx/makima"
|
||||
description={`Manage servers using natural language.
|
||||
Keep track of stats of various things by memory.
|
||||
Schedule absolutely anything across all kind of tasks by making the ai talk to itself in the future.`}
|
||||
/>
|
||||
<Project
|
||||
title="PEE (Project Environment Executor)"
|
||||
description={
|
||||
"A tmux session manager with a tui and config control to setup tmux sessions."
|
||||
}
|
||||
href="https://github.com/xrehpicx/pee"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Project({
|
||||
title,
|
||||
description,
|
||||
href,
|
||||
}: {
|
||||
title: string;
|
||||
description: JSX.Element | string;
|
||||
href?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="mt-4">
|
||||
<div className="flex items-center gap-1">
|
||||
<h4 className="font-display font-medium text-sm">{title}</h4>
|
||||
{href ? (
|
||||
<a href={href} className="group" target="_blank">
|
||||
<ExternalLink className="w-3 group-hover:animate-bounce" />
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground text-balance">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
import { NRenderer } from "@/components/notion/renderer";
|
||||
import { NotionAPI } from "notion-client";
|
||||
import Image from "next/image";
|
||||
import { getPageImageUrls, getPageTitle } from "notion-utils";
|
||||
import "@/components/notion/notion.scss";
|
||||
import "react-notion-x/src/styles.css";
|
||||
import "prismjs/themes/prism-tomorrow.css";
|
||||
|
||||
import {
|
||||
BackgroundGradentProvider,
|
||||
GradientProvider,
|
||||
SymetricGradProvider,
|
||||
} from "@/components/gradient-provider";
|
||||
import GrainProvider from "@/components/grain";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Footer } from "../Footer";
|
||||
import { Connect } from "../Connect";
|
||||
|
||||
export default async function Story({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { id?: string };
|
||||
}) {
|
||||
if (!searchParams.id) return null;
|
||||
|
||||
const notion = new NotionAPI();
|
||||
|
||||
const recordMap = await notion.getPage(searchParams.id);
|
||||
|
||||
const title = getPageTitle(recordMap);
|
||||
|
||||
const images = getPageImageUrls(recordMap, { mapImageUrl: (url) => url });
|
||||
|
||||
return (
|
||||
<article suppressHydrationWarning className="relative">
|
||||
<GrainProvider
|
||||
grain_options={{
|
||||
patternWidth: 200,
|
||||
patternHeight: 200,
|
||||
grainOpacity: 0.1,
|
||||
grainDensity: 1,
|
||||
grainWidth: 1,
|
||||
grainHeight: 1,
|
||||
}}
|
||||
/>
|
||||
<BackgroundGradentProvider className="-z-10 h-screen w-full opacity-90" />
|
||||
<SymetricGradProvider gradient_class={cn("rotate-0")} className="w-full">
|
||||
<Image
|
||||
width={400}
|
||||
height={300}
|
||||
src={images[0]}
|
||||
alt={title}
|
||||
className="w-full h-48 object-cover opacity-70 backdrop-saturate-200 backdrop-contrast-200 -z-50"
|
||||
/>
|
||||
</SymetricGradProvider>
|
||||
<div className="container py-12 max-w-2xl">
|
||||
<h1 className="text-2xl text-center text-pretty font-medium">
|
||||
{title}
|
||||
</h1>
|
||||
<NRenderer recordMap={recordMap} />
|
||||
<section className="connect-section">
|
||||
<Connect />
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<Footer className="max-w-2xl" />
|
||||
</article>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 20 14.3% 4.1%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 20 14.3% 4.1%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 20 14.3% 4.1%;
|
||||
|
||||
--primary: 180 80% 30%;
|
||||
--primary-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--secondary: 60 4.8% 95.9%;
|
||||
--secondary-foreground: 24 9.8% 10%;
|
||||
|
||||
--muted: 60 4.8% 95.9%;
|
||||
--muted-foreground: 25 5.3% 44.7%;
|
||||
|
||||
--accent: 60 4.8% 95.9%;
|
||||
--accent-foreground: 24 9.8% 10%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--border: 20 5.9% 90%;
|
||||
--input: 20 5.9% 90%;
|
||||
--ring: 20 14.3% 4.1%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 20 14.3% 4.1%;
|
||||
--foreground: 60 9.1% 97.8%;
|
||||
|
||||
--card: 20 14.3% 4.1%;
|
||||
--card-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--popover: 20 14.3% 4.1%;
|
||||
--popover-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--primary: 60 9.1% 97.8%;
|
||||
--primary-foreground: 24 9.8% 10%;
|
||||
|
||||
--secondary: 12 6.5% 15.1%;
|
||||
--secondary-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--muted: 12 6.5% 15.1%;
|
||||
--muted-foreground: 24 5.4% 63.9%;
|
||||
|
||||
--accent: 12 6.5% 15.1%;
|
||||
--accent-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--border: 12 6.5% 15.1%;
|
||||
--input: 12 6.5% 15.1%;
|
||||
--ring: 24 5.7% 82.9%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import type { Metadata } from "next";
|
||||
import { DM_Sans, Inter } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { TopBlur } from "@/components/top-blur";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"], variable: "--body-font" });
|
||||
const dm = DM_Sans({ subsets: ["latin"], variable: "--display-font" });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "./raj",
|
||||
description: "My experiments",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html suppressHydrationWarning lang="en">
|
||||
<body
|
||||
className={cn(inter.className, inter.variable, dm.variable, "relative")}
|
||||
>
|
||||
<TopBlur />
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function Page() {
|
||||
redirect("/");
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function Page() {
|
||||
redirect("/");
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
:root {
|
||||
--page-top: 128px;
|
||||
--header-height: 48px;
|
||||
--footer-height: 48px;
|
||||
--icon-primary: var(--mono11);
|
||||
--icon-secondary: transparent;
|
||||
--layer-sticky: 10;
|
||||
--mask-visible: #000;
|
||||
--mask-hidden: transparent;
|
||||
--mask-invisible: transparent;
|
||||
}
|
||||
.top-blur {
|
||||
position: relative;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
--h: min(96px, var(--page-top));
|
||||
width: 100%;
|
||||
height: var(--h);
|
||||
z-index: 1;
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
backdrop-filter: blur(5px);
|
||||
opacity: 0.95;
|
||||
-webkit-mask-image: linear-gradient(
|
||||
to bottom,
|
||||
var(--mask-visible) 25%,
|
||||
var(--mask-hidden)
|
||||
);
|
||||
mask-image: linear-gradient(
|
||||
to bottom,
|
||||
var(--mask-visible) 25%,
|
||||
var(--mask-hidden)
|
||||
);
|
||||
box-sizing: border-box; /* New addition */
|
||||
left: 0; /* New addition */
|
||||
right: 0; /* New addition */
|
||||
}
|
||||
|
||||
// .top-blur::after {
|
||||
// content: "";
|
||||
// position: absolute;
|
||||
// // inset: 0;
|
||||
// background: linear-gradient(
|
||||
// to bottom,
|
||||
// var(--bg, transparent),
|
||||
// var(--transparent, transparent)
|
||||
// );
|
||||
// }
|
|
@ -0,0 +1,70 @@
|
|||
"use client";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
const Clock: React.FC = () => {
|
||||
const [time, setTime] = useState(new Date());
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
const now = new Date();
|
||||
const indiaTime = new Date(
|
||||
now.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }),
|
||||
);
|
||||
setTime(indiaTime);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
const calculateRotation = (unit: number, isHour: boolean = false) => {
|
||||
const degree = isHour ? unit * 30 : unit * 6;
|
||||
return `rotate(${degree} 50 50)`;
|
||||
};
|
||||
|
||||
const hours = time.getHours() % 12;
|
||||
const minutes = time.getMinutes();
|
||||
const seconds = time.getSeconds();
|
||||
|
||||
return (
|
||||
<svg width="18px" height="18px" viewBox="0 0 100 100">
|
||||
<circle
|
||||
cx="50"
|
||||
cy="50"
|
||||
r="45"
|
||||
stroke="black"
|
||||
strokeWidth="4"
|
||||
fill="transparent"
|
||||
/>
|
||||
<line
|
||||
x1="50"
|
||||
y1="50"
|
||||
x2="50"
|
||||
y2="20"
|
||||
transform={calculateRotation(hours, true)}
|
||||
stroke="black"
|
||||
strokeWidth="4"
|
||||
/>
|
||||
<line
|
||||
x1="50"
|
||||
y1="50"
|
||||
x2="50"
|
||||
y2="15"
|
||||
transform={calculateRotation(minutes)}
|
||||
stroke="black"
|
||||
strokeWidth="4"
|
||||
/>
|
||||
<line
|
||||
x1="50"
|
||||
y1="50"
|
||||
x2="50"
|
||||
y2="10"
|
||||
transform={calculateRotation(seconds)}
|
||||
stroke="black"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default Clock;
|
|
@ -0,0 +1,61 @@
|
|||
import gradient from "@/app/(assets)/gradient.svg";
|
||||
import symetric_gradient from "@/app/(assets)/symetric-grad.svg";
|
||||
import background_gradient from "@/app/(assets)/background-gradient.png";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Image from "next/image";
|
||||
|
||||
export function GradientProvider({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="relative w-fit">
|
||||
<div className="absolute rotate-180 w-[600px] -z-10 h-[800px] opacity-60 top-1/2 -translate-x-1/2 -translate-y-1/2 left-1/2">
|
||||
<Image src={gradient} alt="gradient" />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function SymetricGradProvider({
|
||||
children,
|
||||
className,
|
||||
gradient_class,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
gradient_class?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={cn("relative w-fit", className)}>
|
||||
<div
|
||||
className={cn(
|
||||
"absolute w-full -z-10 h-[800px] opacity-70 top-1/4 rotate-180 -translate-x-1/2 -translate-y-1/2 left-1/2",
|
||||
gradient_class,
|
||||
)}
|
||||
>
|
||||
<Image src={symetric_gradient} alt="gradient" />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function BackgroundGradentProvider({
|
||||
className,
|
||||
}: {
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"fixed overflow-hidden w-full h-full opacity-50 top-0 left-0",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<Image
|
||||
className="w-full h-full object-cover"
|
||||
src={background_gradient}
|
||||
alt="gradient"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
"use client";
|
||||
|
||||
// Grain.tsx
|
||||
import React, { useEffect, useRef } from "react";
|
||||
|
||||
type GrainOptions = {
|
||||
patternWidth?: number;
|
||||
patternHeight?: number;
|
||||
grainOpacity?: number;
|
||||
grainDensity?: number;
|
||||
grainWidth?: number;
|
||||
grainHeight?: number;
|
||||
};
|
||||
|
||||
export const GrainProvider = ({
|
||||
grain_options,
|
||||
}: {
|
||||
grain_options?: GrainOptions;
|
||||
}) => {
|
||||
const providerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Function to generate and apply grain effect
|
||||
const applyGrain = (ele: HTMLElement, opt: GrainOptions) => {
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
canvas.width = opt.patternWidth ?? 100;
|
||||
canvas.height = opt.patternHeight ?? 100;
|
||||
|
||||
for (let w = 0; w < canvas.width; w += opt.grainDensity ?? 1) {
|
||||
for (let h = 0; h < canvas.height; h += opt.grainDensity ?? 1) {
|
||||
const rgb = Math.floor(Math.random() * 256);
|
||||
ctx.fillStyle = `rgba(${rgb / 2}, ${rgb / 2}, ${rgb}, ${opt.grainOpacity ?? 0.1
|
||||
})`;
|
||||
ctx.fillRect(w, h, opt.grainWidth ?? 1, opt.grainHeight ?? 1);
|
||||
}
|
||||
}
|
||||
|
||||
ele.style.backgroundImage = `url(${canvas.toDataURL("image/png")})`;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const element = providerRef.current;
|
||||
if (!element) return;
|
||||
|
||||
// Define options here
|
||||
const options: GrainOptions = {
|
||||
patternWidth: 240,
|
||||
patternHeight: 300,
|
||||
grainOpacity: 0.05,
|
||||
grainDensity: 1,
|
||||
grainWidth: 2,
|
||||
grainHeight: 2,
|
||||
};
|
||||
|
||||
// Apply grain initially
|
||||
applyGrain(element, grain_options ?? options);
|
||||
|
||||
// Set interval to update grain
|
||||
const intervalId = setInterval(() => {
|
||||
applyGrain(element, grain_options ?? options);
|
||||
}, 100);
|
||||
|
||||
// Cleanup function
|
||||
return () => clearInterval(intervalId);
|
||||
}, [grain_options]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={providerRef}
|
||||
id="grained-bg"
|
||||
className="fixed left-0 top-0 inset-0 z-50 pointer-events-none w-full h-full"
|
||||
></div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GrainProvider;
|
|
@ -0,0 +1,22 @@
|
|||
import { NotionAPI } from "notion-client";
|
||||
import { NRenderer } from "./renderer";
|
||||
export const revalidate = 10;
|
||||
export async function Notion({
|
||||
blockId,
|
||||
className,
|
||||
}: {
|
||||
blockId: string;
|
||||
className?: string;
|
||||
id?: string;
|
||||
}) {
|
||||
console.log("Notion", blockId);
|
||||
const notion = new NotionAPI();
|
||||
|
||||
const recordMap = await notion.getPage(blockId);
|
||||
console.log("recordMap", recordMap);
|
||||
return (
|
||||
<>
|
||||
<NRenderer className={className} recordMap={recordMap} />
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
:root {
|
||||
--notion-max-width: 100%;
|
||||
--notion-font: var(--display-font);
|
||||
}
|
||||
|
||||
.notion {
|
||||
@apply font-display;
|
||||
}
|
||||
|
||||
.notion-page {
|
||||
@apply px-0;
|
||||
|
||||
.notion-asset-wrapper iframe {
|
||||
@apply bg-transparent;
|
||||
}
|
||||
.notion-column {
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.notion-collection-header-title {
|
||||
@apply font-display font-medium text-xl;
|
||||
}
|
||||
|
||||
.stories-section {
|
||||
.notion-collection-header {
|
||||
@apply hidden;
|
||||
}
|
||||
.notion-collection-card-cover {
|
||||
@apply h-24;
|
||||
}
|
||||
.notion-collection-card {
|
||||
@apply rounded-sm opacity-90 backdrop-contrast-200 backdrop-brightness-150 backdrop-saturate-200;
|
||||
}
|
||||
.notion-gallery-grid {
|
||||
@apply border-none pt-0;
|
||||
}
|
||||
.notion-gallery-grid-size-medium {
|
||||
@apply md:grid-cols-2;
|
||||
}
|
||||
}
|
||||
|
||||
.notion-bookmark {
|
||||
@apply rounded-lg border md:flex-row flex-col-reverse;
|
||||
|
||||
& > div:first-child {
|
||||
@apply flex-none md:flex-1 md:basis-36;
|
||||
}
|
||||
.notion-bookmark-title {
|
||||
@apply font-display font-bold text-lg;
|
||||
}
|
||||
.notion-bookmark-link {
|
||||
@apply opacity-60;
|
||||
}
|
||||
.notion-bookmark-image {
|
||||
@apply block;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
"use client";
|
||||
import { type ExtendedRecordMap } from "notion-types";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import { NotionRenderer } from "react-notion-x";
|
||||
|
||||
const Code = dynamic(() =>
|
||||
import("react-notion-x/build/third-party/code").then((m) => m.Code),
|
||||
);
|
||||
const Collection = dynamic(() =>
|
||||
import("react-notion-x/build/third-party/collection").then(
|
||||
(m) => m.Collection,
|
||||
),
|
||||
);
|
||||
const Equation = dynamic(() =>
|
||||
import("react-notion-x/build/third-party/equation").then((m) => m.Equation),
|
||||
);
|
||||
|
||||
const Modal = dynamic(
|
||||
() => import("react-notion-x/build/third-party/modal").then((m) => m.Modal),
|
||||
{
|
||||
ssr: false,
|
||||
},
|
||||
);
|
||||
|
||||
export function NRenderer({
|
||||
recordMap,
|
||||
className,
|
||||
fullPage,
|
||||
}: {
|
||||
recordMap: ExtendedRecordMap;
|
||||
className?: string;
|
||||
fullPage?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className={className}>
|
||||
<NotionRenderer
|
||||
components={{
|
||||
Code,
|
||||
Collection,
|
||||
Equation,
|
||||
Modal,
|
||||
}}
|
||||
mapPageUrl={(pageId) => `/story?id=${pageId}`}
|
||||
fullPage={fullPage}
|
||||
recordMap={recordMap}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import { NotionAPI } from "notion-client";
|
||||
import { NRenderer } from "./renderer";
|
||||
|
||||
import "react-notion-x/src/styles.css";
|
||||
import "./notion.scss";
|
||||
|
||||
export async function StyledNotion({
|
||||
blockId,
|
||||
className,
|
||||
fullPage,
|
||||
}: {
|
||||
blockId: string;
|
||||
className?: string;
|
||||
id?: string;
|
||||
fullPage?: boolean;
|
||||
}) {
|
||||
const notion = new NotionAPI();
|
||||
|
||||
const recordMap = await notion.getPage(blockId);
|
||||
return (
|
||||
<>
|
||||
<NRenderer
|
||||
fullPage={fullPage}
|
||||
className={className}
|
||||
recordMap={recordMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import "./blur.scss";
|
||||
|
||||
export function TopBlur() {
|
||||
return (
|
||||
<div className="fixed z-50 top-0 left-0 w-full h-24 overflow-hidden">
|
||||
<div className="top-blur"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,12 +1,7 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ["class"],
|
||||
content: [
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
'./src/**/*.{ts,tsx}',
|
||||
],
|
||||
content: ["./src/**/*.{ts,tsx}"],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
|
@ -16,6 +11,10 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
extend: {
|
||||
fontFamily: {
|
||||
body: "var(--body-font)",
|
||||
display: "var(--display-font)",
|
||||
},
|
||||
colors: {
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
|
@ -72,5 +71,5 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
}
|
||||
plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue