feat: add public /riji app intro page
This commit is contained in:
parent
c9808d4f5b
commit
33048b7602
150
app/riji/page.tsx
Normal file
150
app/riji/page.tsx
Normal 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 & 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 & 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>
|
||||
);
|
||||
}
|
||||
|
||||
11
proxy.ts
11
proxy.ts
@ -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
36
riji/README.md
Normal 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
333
riji/index.html
Normal 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 & 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 & Private Notes" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Capture your day, anytime. Offline-first journaling with private notes, photos & 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 & 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 & Videos</h3>
|
||||
<p>Add media to make every memory more vivid.</p>
|
||||
</article>
|
||||
<article class="card span-4">
|
||||
<h3>Timeline & Calendar</h3>
|
||||
<p>Review your life by date, timeline, or calendar view.</p>
|
||||
</article>
|
||||
<article class="card span-4">
|
||||
<h3>Backup & 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 & Private Notes</span>
|
||||
<span class="small">A simple public app intro page for review.</span>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user