Skip to content
This repository was archived by the owner on May 13, 2025. It is now read-only.

Commit c46829c

Browse files
authored
feat(bump): 2.0.0 (#283)
* feat(bump): 2.0.0 * feat(bump): 2.0.0
1 parent da47279 commit c46829c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+2274
-4106
lines changed

.env.example

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,14 @@
1-
NOTION_API =
2-
NOTION_TABLE_SLUG =
1+
# Notion
2+
NOTION_API_KEY=
3+
NOTION_DATABASE_ID=
4+
5+
# Redis
6+
REDIS_URL=
7+
REDIS_TOKEN=
8+
9+
# Umami
10+
NEXT_PUBLIC_UMAMI_URL=
11+
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
12+
13+
# Site
14+
NEXT_PUBLIC_SITE_URL=

.eslintrc.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

.gitignore

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
# dependencies
44
/node_modules
55
/.pnp
6-
.pnp.js
6+
.pnp.*
7+
.yarn/*
8+
!.yarn/patches
9+
!.yarn/plugins
10+
!.yarn/releases
11+
!.yarn/versions
712

813
# testing
914
/coverage
@@ -23,15 +28,17 @@
2328
npm-debug.log*
2429
yarn-debug.log*
2530
yarn-error.log*
31+
.pnpm-debug.log*
2632

27-
# local env files
28-
.env.local
29-
.env.development.local
30-
.env.test.local
31-
.env.production.local
33+
# env files (can opt-in for committing if needed)
34+
.env*
3235

3336
# vercel
3437
.vercel
3538

3639
# typescript
3740
*.tsbuildinfo
41+
next-env.d.ts
42+
43+
# Turborepo
44+
.turbo

.vscode/settings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"editor.codeActionsOnSave": {
3+
"source.organizeImports.biome": "explicit"
4+
},
5+
"i18n-ally.localesPaths": [
6+
"**/locales"
7+
]
8+
}

LICENSE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2021 Harry Yep
3+
Copyright (c) 2025 Harry Yep
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
21+
SOFTWARE.

README.md

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,12 @@
11
# Notion Photo React
22

3-
> A fast serverless Photo Gallery powered by Notion.
3+
> A Notion Photo powered by Next.js
44
5-
A Photo Gallery powered by [Notion](https://notion.so), built with [React.JS](https://reactjs.org), [Next.JS](https://nextjs.org), [tailwindcss](https://tailwindcss.com), [TypeScript](https://www.typescriptlang.org/), [notion-api-worker](https://github.com/splitbee/notion-api-worker) and more.
6-
7-
> See [Notion Blog React](https://github.com/Harry-Yep/Notion-Blog-React), if you would like to blog with Notion.
5+
> See [Notion Blog React](https://github.com/okisdev/Notion-Blog-React) for a similar project that uses Notion as a database for blog posts.
86
97
## Demo
108

11-
- [npr.okis.dev](https://npr.okis.dev)
12-
13-
## Features
14-
15-
- Easily change the things you want by editing [`.env`](./.env.example) file.
16-
- Support [Google Analytics](https://analytics.google.com/) & [Splitbee Analytics](https://splitbee.io/).
17-
- Self host notion-api by using [Cloudflare Workers](https://workers.dev). (Default [notion-api](https://notion-api.splitbee.io) By Splitbee)
18-
- Use your favorite Google Fonts.
19-
- Use your own domain.
20-
21-
## Performance
22-
23-
![Notion-Photo-React-Lighthouse-Performance-Desktop](https://cdn.harrly.com/project/GitHub/Notion-Photo-React/img/Lighthouse-Performance-Desktop.png)
24-
25-
- Use [Lighthouse](https://developers.google.com/web/tools/lighthouse) for testing
9+
- [nbr.okis.dev](https://nbr.okis.dev)
2610

2711
## How to deploy
2812

@@ -31,16 +15,16 @@ Please visit Notion Photo React [Documentation](https://docs.okis.dev/docs/notio
3115
## Problem(s) with deployment
3216

3317
34-
- Telegram: [@okisdev](https://t.me/okisdev)
3518

36-
## Improvement / Plans
19+
## Alternatives
3720

38-
- [ ] Add PostView.
39-
- [ ] Using [Notion Official API](https://developers.notion.com/).
40-
- [ ] Add Tag.
21+
> Turn Notion to Blog/Page
4122
42-
## Credits
23+
- [React-Notion](https://github.com/splitbee/react-notion)
24+
- [React-Notion-X](https://github.com/NotionX/react-notion-x)
25+
- [Super.so](https://super.so/)
26+
- [Fruition](https://fruitionsite.com/)
4327

44-
Copyright (c) 2022 Harry Yep
28+
## Credits
4529

46-
- All Authors & Contributors who own its repository
30+
Copyright (c) 2025 Harry Yep

README.zh-CN.md

Lines changed: 0 additions & 44 deletions
This file was deleted.

app/(posts)/[slug]/loading.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { PostLoadingSkeleton } from '@/components/post/loading';
2+
3+
export default function PostLoading() {
4+
return <PostLoadingSkeleton />;
5+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { env } from '@/lib/env';
2+
import { getPhotoBySlug } from '@/lib/notion';
3+
import { format } from 'date-fns';
4+
import { ImageResponse } from 'next/og';
5+
6+
export const size = {
7+
width: 1200,
8+
height: 630,
9+
};
10+
11+
export const contentType = 'image/png';
12+
13+
// Image generation
14+
export default async function Image({ params }: { params: { slug: string } }) {
15+
const photo = await getPhotoBySlug(params.slug);
16+
17+
if (!photo) {
18+
return new Response('Not found', { status: 404 });
19+
}
20+
21+
return new ImageResponse(
22+
<div
23+
style={{
24+
height: '100%',
25+
width: '100%',
26+
display: 'flex',
27+
flexDirection: 'column',
28+
backgroundColor: 'white',
29+
padding: '60px 80px',
30+
fontFamily: 'Inter, system-ui, sans-serif',
31+
}}
32+
>
33+
<div
34+
style={{
35+
display: 'flex',
36+
flexDirection: 'column',
37+
flex: 1,
38+
justifyContent: 'center',
39+
alignItems: 'center',
40+
textAlign: 'center',
41+
}}
42+
>
43+
<h1
44+
style={{
45+
fontSize: '60px',
46+
fontWeight: 'bold',
47+
color: 'black',
48+
marginBottom: '20px',
49+
lineHeight: 1.2,
50+
maxWidth: '1000px',
51+
}}
52+
>
53+
{photo.title}
54+
</h1>
55+
56+
<div
57+
style={{
58+
display: 'flex',
59+
alignItems: 'center',
60+
gap: '20px',
61+
fontSize: '24px',
62+
color: '#666',
63+
}}
64+
>
65+
{photo.date && <div>{format(new Date(photo.date), 'MMMM d, yyyy')}</div>}
66+
{photo.location && photo.location.length > 0 && (
67+
<div style={{ display: 'flex', gap: '10px' }}>
68+
{photo.location.map((location) => (
69+
<div
70+
key={location}
71+
style={{
72+
backgroundColor: '#f0f0f0',
73+
padding: '4px 12px',
74+
borderRadius: '4px',
75+
fontSize: '18px',
76+
}}
77+
>
78+
{location}
79+
</div>
80+
))}
81+
</div>
82+
)}
83+
</div>
84+
</div>
85+
86+
<div
87+
style={{
88+
display: 'flex',
89+
justifyContent: 'space-between',
90+
alignItems: 'center',
91+
marginTop: '40px',
92+
fontSize: '20px',
93+
color: '#666',
94+
}}
95+
>
96+
<div>{env.NEXT_PUBLIC_SITE_URL}</div>
97+
<div>View Photo →</div>
98+
</div>
99+
</div>,
100+
{
101+
...size,
102+
}
103+
);
104+
}

app/(posts)/[slug]/page.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { PhotoContent } from '@/components/post/content';
2+
import { PhotoHeader } from '@/components/post/header';
3+
import { PhotoContentSkeleton, PhotoHeaderSkeleton, RelatedPhotosSkeleton } from '@/components/post/loading';
4+
import { RelatedPhotos } from '@/components/post/related';
5+
import { config } from '@/config';
6+
import { getPhotoBySlug } from '@/lib/notion';
7+
import { notFound } from 'next/navigation';
8+
import { Suspense } from 'react';
9+
10+
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
11+
const { slug } = await params;
12+
const photo = await getPhotoBySlug(slug);
13+
14+
if (!photo) return notFound();
15+
16+
return {
17+
title: `${photo.title} - ${config.site.name}`,
18+
description: photo.location || `Photo taken on ${photo.date}`,
19+
};
20+
}
21+
22+
export default async function PhotoPage({ params }: { params: Promise<{ slug: string }> }) {
23+
const { slug } = await params;
24+
const photo = await getPhotoBySlug(slug);
25+
26+
if (!photo) return notFound();
27+
28+
return (
29+
<div className='mx-auto max-w-4xl space-y-8'>
30+
<Suspense fallback={<PhotoHeaderSkeleton />}>
31+
<PhotoHeader photo={photo} />
32+
</Suspense>
33+
34+
<Suspense fallback={<PhotoContentSkeleton />}>
35+
<PhotoContent photo={photo} />
36+
</Suspense>
37+
38+
<div className='border-tertiary border-b' />
39+
40+
<Suspense fallback={<RelatedPhotosSkeleton />}>
41+
<RelatedPhotos currentPhotoId={photo.id} />
42+
</Suspense>
43+
44+
{config.post.footer}
45+
</div>
46+
);
47+
}

0 commit comments

Comments
 (0)