feat: add public /riji app intro page
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-12 14:44:12 +08:00
parent c9808d4f5b
commit 33048b7602
4 changed files with 528 additions and 2 deletions

150
app/riji/page.tsx Normal file
View File

@ -0,0 +1,150 @@
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "RiJi — Offline Journal & Private Notes",
description:
"RiJi is an offline-first journal and notes app that helps you record moments, thoughts, photos, and videos — privately and beautifully.",
openGraph: {
title: "RiJi — Offline Journal & Private Notes",
description:
"Capture your day, anytime. Offline-first journaling with private notes, photos & videos, and encrypted backups.",
},
};
export default function RiJiIntroPage() {
return (
<main
className="min-h-dvh text-foreground"
style={{
background:
"radial-gradient(1200px 600px at 20% -10%, rgba(124, 92, 255, 0.22), transparent 55%), radial-gradient(900px 520px at 90% 10%, rgba(45, 212, 191, 0.18), transparent 50%), linear-gradient(180deg, var(--background), var(--background))",
}}
>
<div className="mx-auto max-w-[980px] px-5 py-8 pb-16">
<header className="mb-7 flex items-center justify-between gap-4">
<div className="flex min-w-0 items-center gap-3">
<div
aria-hidden="true"
className="relative h-10 w-10 shrink-0 rounded-xl bg-gradient-to-br from-violet-500 to-teal-400 shadow-2xl"
>
<div className="absolute inset-2.5 rounded-lg border border-white/20 bg-white/15" />
</div>
<div className="min-w-0">
<p className="truncate text-sm font-semibold tracking-tight">
RiJi — Offline Journal &amp; Private Notes
</p>
<p className="text-xs text-muted-foreground">
Offline-first journaling, private notes, and encrypted backups.
</p>
</div>
</div>
</header>
<section className="relative overflow-hidden rounded-3xl border border-border bg-card/60 p-7 shadow-2xl backdrop-blur">
<p className="mb-4 inline-flex items-center rounded-full border border-violet-500/25 bg-violet-500/10 px-3 py-1 text-xs font-semibold tracking-wide">
Page Title
</p>
<h1 className="mb-3 text-balance text-3xl font-semibold tracking-tight sm:text-5xl">
Capture your day, anytime.
</h1>
<p className="max-w-[70ch] text-pretty text-base leading-relaxed text-muted-foreground">
RiJi is an offline-first journal and notes app that helps you record moments, thoughts,
photos, and videos — privately and beautifully.
</p>
</section>
<section className="mt-8">
<h2 className="mb-3 text-base font-semibold tracking-tight">
Primary Highlights
</h2>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
<Card
title="Offline First"
body="Your notes stay available even without a network connection."
className="lg:col-span-2"
/>
<Card
title="Private by Design"
body="Protect selected notes with password and Face ID."
/>
<Card
title="Photos & Videos"
body="Add media to make every memory more vivid."
/>
<Card
title="Timeline & Calendar"
body="Review your life by date, timeline, or calendar view."
/>
<Card
title="Backup & Restore"
body="Export encrypted backups and restore anytime."
/>
</div>
</section>
<section className="mt-8">
<h2 className="mb-3 text-base font-semibold tracking-tight">About</h2>
<div className="rounded-2xl border border-border bg-card/50 p-5 shadow-sm">
<p className="text-sm leading-relaxed text-muted-foreground">
RiJi is designed for people who want a clean, private, and distraction-free place to
write daily notes. Whether you're journaling, keeping life records, or saving quick
thoughts, RiJi keeps everything organized and secure on your device.
</p>
</div>
</section>
<section className="mt-8">
<h2 className="mb-3 text-base font-semibold tracking-tight">Features</h2>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<Card
title="Write Freely"
body="Create and edit notes with text, images, and video attachments."
/>
<Card
title="Stay Organized"
body="Browse entries in a timeline or jump through dates in calendar view."
/>
<Card
title="Protect What Matters"
body="Lock private notes with a privacy password and Face ID."
/>
<Card
title="Keep Control of Your Data"
body="Export encrypted backups and restore them whenever needed."
/>
</div>
</section>
<footer className="mt-10 flex flex-wrap items-center justify-between gap-3 border-t border-border pt-5 text-xs text-muted-foreground">
<span>RiJi — Offline Journal &amp; Private Notes</span>
<span>A simple public app intro page for review.</span>
</footer>
</div>
</main>
);
}
function Card({
title,
body,
className,
}: {
title: string;
body: string;
className?: string;
}) {
return (
<article
className={[
"rounded-2xl border border-border bg-card/50 p-5 shadow-sm",
className,
]
.filter(Boolean)
.join(" ")}
>
<h3 className="mb-1 text-sm font-semibold tracking-tight">{title}</h3>
<p className="text-sm leading-relaxed text-muted-foreground">{body}</p>
</article>
);
}

View File

@ -233,8 +233,15 @@ export async function proxy(request: NextRequest) {
process.env.AUTH_URL ??
`${request.nextUrl.protocol}//${request.headers.get("host") ?? request.nextUrl.host}`;
// 未登录用户允许访问 /(新版首页)、/login、/register,其余需要登录
if (!token && !["/", "/login", "/register"].includes(pathname)) {
const isPublicPage =
pathname === "/" ||
pathname === "/login" ||
pathname === "/register" ||
pathname === "/riji" ||
pathname.startsWith("/riji/");
// 未登录用户允许访问公开页面,其余需要登录
if (!token && !isPublicPage) {
// 对于 API 路由的非 GET 请求,直接返回 401 JSON 响应(不重定向)
if (pathname.startsWith("/api/") && request.method !== "GET") {
return NextResponse.json(

36
riji/README.md Normal file
View File

@ -0,0 +1,36 @@
# RiJi App Intro Page (Subpage)
This folder contains a simple, single-page public app introduction website for **RiJi — Offline Journal & Private Notes**.
## Publish as a subpage (Recommended)
If you already have a GitHub Pages repo/site (with its own homepage), just copy the whole `riji/` folder into it.
The page URL will be `.../riji/` (a subpage), for example:
- Project pages: `https://<user>.github.io/<repo>/riji/`
- User/org pages: `https://<user>.github.io/riji/`
## New repo, but still a subpage
If you want a brand-new repo and still keep this as a subpage:
1. Create a new GitHub repository (public).
2. Put this folder into the repo as `riji/index.html`.
3. (Optional) Add a tiny root `index.html` that redirects to `/riji/`.
4. In GitHub: **Settings → Pages → Build and deployment → Deploy from a branch**
- Branch: `main`
- Folder: `/ (root)`
Example redirect file (optional):
```html
<!doctype html>
<meta charset="utf-8" />
<meta http-equiv="refresh" content="0; url=./riji/" />
<title>Redirecting…</title>
<a href="./riji/">Open RiJi page</a>
```
## If you want it as the homepage instead
Copy `riji/index.html` to the repo root as `index.html`.

333
riji/index.html Normal file
View File

@ -0,0 +1,333 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>RiJi — Offline Journal &amp; Private Notes</title>
<meta
name="description"
content="RiJi is an offline-first journal and notes app that helps you record moments, thoughts, photos, and videos — privately and beautifully."
/>
<meta property="og:title" content="RiJi — Offline Journal &amp; Private Notes" />
<meta
property="og:description"
content="Capture your day, anytime. Offline-first journaling with private notes, photos &amp; videos, and encrypted backups."
/>
<meta name="theme-color" content="#0b1220" />
<style>
:root {
--bg: #070b14;
--panel: rgba(255, 255, 255, 0.06);
--panel2: rgba(255, 255, 255, 0.08);
--text: rgba(255, 255, 255, 0.92);
--muted: rgba(255, 255, 255, 0.68);
--border: rgba(255, 255, 255, 0.12);
--shadow: rgba(0, 0, 0, 0.35);
--accent: #7c5cff;
--accent2: #2dd4bf;
--maxw: 980px;
}
@media (prefers-color-scheme: light) {
:root {
--bg: #f7f8fc;
--panel: rgba(0, 0, 0, 0.04);
--panel2: rgba(0, 0, 0, 0.06);
--text: rgba(10, 12, 18, 0.92);
--muted: rgba(10, 12, 18, 0.66);
--border: rgba(10, 12, 18, 0.12);
--shadow: rgba(0, 0, 0, 0.12);
}
}
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
}
body {
margin: 0;
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial,
"Apple Color Emoji", "Segoe UI Emoji";
color: var(--text);
background: radial-gradient(1200px 600px at 20% -10%, rgba(124, 92, 255, 0.34), transparent 55%),
radial-gradient(900px 520px at 90% 10%, rgba(45, 212, 191, 0.26), transparent 50%),
linear-gradient(180deg, var(--bg), var(--bg));
}
a {
color: inherit;
}
.container {
max-width: var(--maxw);
margin: 0 auto;
padding: 28px 20px 64px;
}
header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 26px;
}
.brand {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
}
.mark {
width: 38px;
height: 38px;
border-radius: 12px;
background: linear-gradient(135deg, var(--accent), var(--accent2));
box-shadow: 0 14px 30px var(--shadow);
position: relative;
flex: 0 0 auto;
}
.mark::after {
content: "";
position: absolute;
inset: 10px;
border-radius: 9px;
background: rgba(255, 255, 255, 0.18);
border: 1px solid rgba(255, 255, 255, 0.24);
}
.brand-text {
min-width: 0;
}
.brand-title {
font-weight: 700;
letter-spacing: -0.02em;
margin: 0;
font-size: 15px;
line-height: 1.25;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.brand-subtitle {
margin: 2px 0 0;
font-size: 12px;
color: var(--muted);
}
.hero {
padding: 28px;
border-radius: 20px;
background: linear-gradient(180deg, var(--panel2), var(--panel));
border: 1px solid var(--border);
box-shadow: 0 26px 60px var(--shadow);
overflow: hidden;
position: relative;
}
.hero::before {
content: "";
position: absolute;
width: 620px;
height: 620px;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%, rgba(124, 92, 255, 0.28), transparent 60%);
top: -420px;
right: -380px;
pointer-events: none;
filter: blur(2px);
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
border-radius: 999px;
background: rgba(124, 92, 255, 0.12);
border: 1px solid rgba(124, 92, 255, 0.22);
color: var(--text);
font-weight: 600;
font-size: 12px;
letter-spacing: 0.02em;
margin: 0 0 14px;
}
h1 {
font-size: clamp(28px, 4vw, 44px);
line-height: 1.1;
letter-spacing: -0.03em;
margin: 0 0 10px;
}
.lead {
margin: 0;
font-size: 16px;
line-height: 1.6;
color: var(--muted);
max-width: 70ch;
}
section {
margin-top: 30px;
}
h2 {
font-size: 18px;
margin: 0 0 12px;
letter-spacing: -0.02em;
}
.grid {
display: grid;
gap: 12px;
grid-template-columns: repeat(12, 1fr);
}
.card {
grid-column: span 12;
padding: 16px;
border-radius: 16px;
background: var(--panel);
border: 1px solid var(--border);
}
.card h3 {
margin: 0 0 6px;
font-size: 14px;
letter-spacing: -0.01em;
}
.card p {
margin: 0;
color: var(--muted);
line-height: 1.55;
font-size: 13px;
}
@media (min-width: 720px) {
.card.span-6 {
grid-column: span 6;
}
.card.span-4 {
grid-column: span 4;
}
}
footer {
margin-top: 40px;
padding-top: 18px;
border-top: 1px solid var(--border);
color: var(--muted);
font-size: 12px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
}
.small {
color: var(--muted);
}
</style>
</head>
<body>
<div class="container">
<header>
<div class="brand" aria-label="RiJi">
<div class="mark" aria-hidden="true"></div>
<div class="brand-text">
<p class="brand-title">RiJi — Offline Journal &amp; Private Notes</p>
<p class="brand-subtitle">Offline-first journaling, private notes, and encrypted backups.</p>
</div>
</div>
</header>
<main>
<div class="hero">
<p class="eyebrow">Page Title</p>
<h1>Capture your day, anytime.</h1>
<p class="lead">
RiJi is an offline-first journal and notes app that helps you record moments, thoughts,
photos, and videos — privately and beautifully.
</p>
</div>
<section aria-labelledby="highlights">
<h2 id="highlights">Primary Highlights</h2>
<div class="grid">
<article class="card span-6">
<h3>Offline First</h3>
<p>Your notes stay available even without a network connection.</p>
</article>
<article class="card span-6">
<h3>Private by Design</h3>
<p>Protect selected notes with password and Face ID.</p>
</article>
<article class="card span-4">
<h3>Photos &amp; Videos</h3>
<p>Add media to make every memory more vivid.</p>
</article>
<article class="card span-4">
<h3>Timeline &amp; Calendar</h3>
<p>Review your life by date, timeline, or calendar view.</p>
</article>
<article class="card span-4">
<h3>Backup &amp; Restore</h3>
<p>Export encrypted backups and restore anytime.</p>
</article>
</div>
</section>
<section aria-labelledby="about">
<h2 id="about">About</h2>
<div class="card">
<p>
RiJi is designed for people who want a clean, private, and distraction-free place to
write daily notes. Whether you're journaling, keeping life records, or saving quick
thoughts, RiJi keeps everything organized and secure on your device.
</p>
</div>
</section>
<section aria-labelledby="features">
<h2 id="features">Features</h2>
<div class="grid">
<article class="card span-6">
<h3>Write Freely</h3>
<p>Create and edit notes with text, images, and video attachments.</p>
</article>
<article class="card span-6">
<h3>Stay Organized</h3>
<p>Browse entries in a timeline or jump through dates in calendar view.</p>
</article>
<article class="card span-6">
<h3>Protect What Matters</h3>
<p>Lock private notes with a privacy password and Face ID.</p>
</article>
<article class="card span-6">
<h3>Keep Control of Your Data</h3>
<p>Export encrypted backups and restore them whenever needed.</p>
</article>
</div>
</section>
<footer>
<span class="small">RiJi — Offline Journal &amp; Private Notes</span>
<span class="small">A simple public app intro page for review.</span>
</footer>
</main>
</div>
</body>
</html>