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
76 changes: 76 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```bash
bun run dev # local dev server
bun run build # Next.js build
bun run preview # OpenNext Cloudflare build + local preview
bun run deploy # OpenNext Cloudflare build + deploy to Workers
bun run prepare # regenerate PandaCSS styled-system/ (run after panda.config.ts changes)
bun run cf-typegen # regenerate cloudflare-env.d.ts bindings
```

No test suite is configured.

## Environment

Copy `.env.local.example` to `.env.local` and set:

```
CMS_API_KEY=<microCMS API key>
```

The microCMS service domain is hard-coded as `nknighta-github` in `src/utils/cms.ts`.

## Architecture

**Stack**: Next.js 16 (Pages Router) · React 19 · TypeScript · PandaCSS · microCMS · GSAP · Framer Motion · deployed to **Cloudflare Workers** via `@opennextjs/cloudflare`.

### Styling — PandaCSS

All styles use the `css()` utility imported from `../../styled-system/css` (a codegen artifact). This is **not** Tailwind. The `styled-system/` directory is generated — never edit it by hand; run `bun run prepare` to regenerate after config changes.

### CMS — microCMS

`src/utils/cms.ts` exports a singleton client and typed helpers (`getBlogs`, `getBlog`, `getCategories`). Content endpoints used across the site:

| Endpoint | Used by |
|---|---|
| `blogs` | `/blog`, `/blog/[id]`, `/blog/category/[id]`, `/blog/page/[p]` |
| `categories` | `/blog` |
| `projects` | `/dev`, `/dev/[id]` |
| `scraps` | `/scraps`, `/scraps/[id]` |

CMS content bodies are rendered as raw HTML via `dangerouslySetInnerHTML`. An inline `<style>` string (`cmsstyle`) is appended to handle code block formatting on detail pages.

Draft preview: `src/middleware.ts` intercepts `?draftKey=` query params and redirects to `/api/draft` for draft mode activation.

### Layout & shared components

- `src/layout/main.tsx` — site-wide shell: announcement banner, header nav (`Blog`, `Dev Projects`, `Apps`, `Scraps`), footer, and `ClickSpark` canvas overlay
- `src/components/headermeta.tsx` (`HMeta`) — OG/Twitter meta tags; auto-generates OG image via `ogp-img-gen.vercel.app` if no image is supplied
- `src/libs/gtag.ts` — Google Analytics (GA4 ID `G-9TG7JEDDCX`) pageview/event helpers; called from `_app.tsx` on route changes

### Animation components

All sourced from [reactbits.dev](https://reactbits.dev):

- `AnimatedContent` — GSAP ScrollTrigger slide-in wrapper
- `SplitText` — GSAP SplitText character/word/line stagger animation
- `ClickSpark` — canvas spark burst on click (wraps the entire page in `Layout`)
- `CurvedLoop` / `TextType` — CSS-based marquee and typewriter animations

### Static generation pattern

Content pages use `getStaticPaths` + `getStaticProps` with `fallback: false`. Unpublished items (no `publishedAt`) are excluded from paths and return `{ notFound: true }` from `getStaticProps`.

### Redirect/shortlink pages

Single-character pages (`/g`, `/i`, `/q`, `/x`) and pages under `/l/vx/*` are thin client-side redirects using `useEffect(() => { router.push(url) }, [])`.

### Devmode panel

Detail pages (`/blog/[id]`, `/dev/[id]`, `/scraps/[id]`) render a raw CMS JSON viewer when `process.env.NODE_ENV === 'development'`, toggled by a fixed-position button.
2 changes: 1 addition & 1 deletion CNAME
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nknighta.me
apps.nknighta.me
18 changes: 0 additions & 18 deletions README.md

This file was deleted.

43 changes: 43 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nknight AMAMIYA's apps@nk4dev</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
</head>

<body>
<header class="bg-[#000021] text-white p-4">
<h1>Nknight AMAMIYA's apps@nk4dev</h1>
</header>
<main class="p-4">
<ul>
<li>
<a href="https://apps.nknighta.me/ytimage-dl" class="text-blue-500 hover:underline">ytimage-dl</a>
</li>
<li>
<a href="https://apps.nknighta.me/x_img_reformat"
class="text-blue-500 hover:underline">x_img_reformat</a>
</li>
<li>
<a href="https://apps.nknighta.me/grove-player/" class="text-blue-500 hover:underline">grove player
(HTML5)</a>
</li>

<li>
<a href="https://nknighta.me/apps/grove" class="text-blue-500 hover:underline">grove player (Nextjs)</a>
</li>
<li>
<a href="https://apps.nknighta.me/qrcode-gen/" class="text-blue-500 hover:underline">qrcode-gen</a>
</li>
</ul>
</main>
<footer class="bg-[#000021] text-white p-4">
<a href="https://nknighta.me/" class="text-white underline">Nknight AMAMIYA@nk4dev</a>
<p> All rights reserved.</p>
</footer>
</body>

</html>
5 changes: 2 additions & 3 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
import "./.next/types/routes.d.ts";
import "./.next/dev/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
5 changes: 1 addition & 4 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { createMDX } from 'fumadocs-mdx/next';

import { defineCloudflareConfig } from "@opennextjs/cloudflare";

const withMDX = createMDX();

/** @type {import('next').NextConfig} */
const nextConfig = {
plugins: [
Expand All @@ -20,4 +17,4 @@ plugins: [
},
};

export default withMDX(nextConfig);
export default nextConfig;
11 changes: 2 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,19 @@
"license": "MIT",
"scripts": {
"prepare": "panda codegen",
"postinstall": "fumadocs-mdx",
"dev": "next dev",
"build": "fumadocs-mdx && next build",
"build": "next build",
"start": "next start",
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
},
"dependencies": {
"@opennextjs/cloudflare": "^1.19.4",
"framer-motion": "^12.23.7",
"fumadocs-core": "^16.8.5",
"fumadocs-mdx": "^14.3.2",
"fumadocs-ui": "^16.8.5",
"gh-pages": "^6.3.0",
"gray-matter": "^4.0.3",
"gsap": "^3.13.0",
"microcms-js-sdk": "^3.1.2",
"motion": "^12.38.0",
"next": "16.0.10",
"next-mdx-remote": "^5.0.0",
"react": "^19.2.0",
Expand All @@ -32,10 +27,8 @@
},
"devDependencies": {
"@pandacss/dev": "^0.53.0",
"@tailwindcss/postcss": "^4.2.4",
"@types/node": "22.13.8",
"@types/react": "19.0.10",
"tailwindcss": "^4.2.4",
"typescript": "5.8.2"
}
}
1 change: 0 additions & 1 deletion postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module.exports = {
plugins: {
'@pandacss/dev/postcss': {},
'@tailwindcss/postcss': {},
},
}
9 changes: 0 additions & 9 deletions source.config.ts

This file was deleted.

7 changes: 0 additions & 7 deletions src/lib/source.ts

This file was deleted.

24 changes: 21 additions & 3 deletions src/pages/404.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import HMeta from "../components/headermeta";
import Link from "next/link";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { useSearchParams } from 'next/navigation'

export default function Custom404() {
const searchParams = useSearchParams();
const router = useRouter();
const [redirectUrl, setRedirectUrl] = useState("");
if (!searchParams) {
// Render fallback UI while search params are not yet available
return null;
}

const fallback = searchParams.get('notfoundfallback');
useEffect(() => {
const pathname = router.asPath;
if (!fallback) {
router.push("https://apps.nknighta.me/" + pathname);
}
}, [fallback, router]);

return (
<>
{redirectUrl}
<div style={{ textAlign: "center", marginTop: "100px", marginBottom: "100px" }}>
<h1>Sorry!</h1>
</div>

<div style={{ textAlign: "center", marginTop: "100px", marginBottom: "100px" }}>
<h1>404 - Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<Link href="/" style={{textDecoration: "underline"}}>Go to Home</Link>
<Link href="/" style={{ textDecoration: "underline" }}>Go to Home</Link>
</div>
<div style={{ textAlign: "center", marginTop: "100px", marginBottom: "100px" }}>
&copy; 2021 - {new Date().getFullYear()} Nknight AMAMIYA@nk4dev
Expand Down
8 changes: 8 additions & 0 deletions src/pages/api/teapot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { NextApiRequest, NextApiResponse } from 'next';

export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
res.status(418).send("I'm a teapot");
}
24 changes: 0 additions & 24 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,7 @@ import Script from "next/script";
import Popup from "../components/Popup";

export default function Index({ data }) {
const [repos, setRepos] = useState(null);
const [isPressClosed, setIsPressClosed] = useState(true);
const based_duration = 0.6;
useEffect(() => {
const githubrepos = async () => {
const res = await fetch("https://api.github.com/repos/nk4dev/vx3");
const data = await res.json();
return data;
};
const data = githubrepos();
data.then((data) => setRepos(data));
}, [data]);
return (
<Layout>
<HMeta
Expand Down Expand Up @@ -207,19 +196,6 @@ export default function Index({ data }) {
VX3 <br /> Web3 tool for developers
</ProfileLink>
<ProfileBody>
<p>
Default branch
{repos && " : " + repos.default_branch}
</p>
<p>
Latest commit
<span>{repos && " : " + repos.pushed_at}</span>
</p>

<p>
Watchers
<span>{repos && " : " + repos.watchers}</span>
</p>
<ProfileLink href={"/dev/vx3-mcp"} target="_blank">
VX3 MCP server (now testing)
</ProfileLink>
Expand Down
10 changes: 10 additions & 0 deletions src/pages/nk4dev/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Layout from "../../layout/main";
import LinkPage from "../../components/redirect";

export default function Nk4dev() {
return (
<Layout>
<LinkPage url="/" text="Redirecting..." />
</Layout>
);
}
3 changes: 3 additions & 0 deletions src/pages/vrchat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export default function VRCRedirect() {
pagePath="/vrchat"
/>
<LinkPage url="https://vrchat.com/home/user/usr_3c0e5ebc-16db-4f61-bdfb-88ff8385a7d4" text="VRChat" />
<div>
<p>test</p>
</div>
</Layout>
);
}
Loading