Skip to content

Commit

Permalink
feat: Add pagination and more button at the bottom
Browse files Browse the repository at this point in the history
  • Loading branch information
Guillaume FORTAINE authored and gfortaine committed Dec 10, 2022
1 parent d2f76fa commit 47d238f
Show file tree
Hide file tree
Showing 16 changed files with 224 additions and 190 deletions.
19 changes: 19 additions & 0 deletions app/item/[id]/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { notFound } from 'next/navigation';
import Item from '../../../components/item';

// Utils
import fetchData from '../../../lib/fetch-data';
import { transform } from '../../../lib/get-item';

export default async function ItemPage({ params }) {
const { id } = params;

if (!id) {
notFound();
}

const data = await fetchData(`item/${id}`);
const story = transform(data);

return <Item story={story} />;
}
19 changes: 0 additions & 19 deletions app/item/page.js

This file was deleted.

22 changes: 22 additions & 0 deletions app/news/[page]/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Server Components
import SystemInfo from '../../../components/server-info'

// Client Components
import Stories from '../../../components/stories'
import Footer from '../../../components/footer'

// Utils
import fetchData from '../../../lib/fetch-data'

export default async function RSCPage({ params }) {
const { page } = params;
const storyIds = await fetchData('topstories')

return (
<>
<Stories page={page} storyIds={storyIds} />
<Footer />
<SystemInfo />
</>
)
}
30 changes: 0 additions & 30 deletions app/page.js

This file was deleted.

12 changes: 9 additions & 3 deletions components/header.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
}

.left {
flex: 9;
display: grid;
grid-auto-flow: column;
align-items: center;
}

.right {
Expand All @@ -31,8 +33,7 @@
a.login {
padding: 10px;
display: inline-block;
font-size: 11px;
text-transform: uppercase;
font-size: 10pt;
text-decoration: none;
color: #000;
}
Expand All @@ -47,6 +48,10 @@ a.login {
}

@media (max-width: 750px) {
.left {
grid-auto-flow: row;
}

.site-title {
font-size: 16px;
padding-bottom: 0;
Expand All @@ -58,5 +63,6 @@ a.login {

.nav {
display: block;
margin-left: 10px;
}
}
18 changes: 13 additions & 5 deletions components/nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@ import styles from './nav.module.css'
export default function Nav() {
return (
<ul className={styles['nav-ul']}>
<Item href="/">new</Item>
<Item href="/">show</Item>
<Item href="/">ask</Item>
<Item href="/">jobs</Item>
<Item href="/">submit</Item>
<Item href="/newest">new</Item>
{" | "}
<Item href="/front">past</Item>
{" | "}
<Item href="/newcomments">show</Item>
{" | "}
<Item href="/ask">ask</Item>
{" | "}
<Item href="/show">show</Item>
{" | "}
<Item href="/jobs">jobs</Item>
{" | "}
<Item href="/submit">submit</Item>
</ul>
)
}
Expand Down
4 changes: 1 addition & 3 deletions components/nav.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@

.nav-ul li a {
display: inline-block;
padding: 10px;
font-size: 11px;
text-transform: uppercase;
font-size: 10pt;
text-decoration: none;
color: #000;
}
Expand Down
1 change: 1 addition & 0 deletions components/skeletons.module.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.item-skeleton {
margin: 5px 0;
overflow: hidden;
flex: 100 1;
}

.item-skeleton:before,
Expand Down
45 changes: 29 additions & 16 deletions components/stories.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
import Story from './story'
import Link from 'next/link'
import Story from './story'

import fetchData from '../lib/fetch-data'
import { transform } from '../lib/get-item'

import styles from './stories.module.css'

export default ({ stories, page = 1, offset = null }) => (
<div>
{stories.map((story, i) => (
<div key={story.id} className={styles.item}>
{null != offset ? (
<span className={styles.count}>{i + offset + 1}</span>
) : null}
<div className={styles.story}>
<Story {...story} />
async function StoryWithData({ id }) {
const data = await fetchData(`item/${id}`)
const story = transform(data)

return <Story {...story} />
}

export default async function Stories({ storyIds, page = 1 }) {
const limit = 30
const offset = (page - 1) * limit

return (
<div>
{storyIds.slice(offset, offset + limit).map((id, i) => (
<div key={id} className={styles.item}>
{null != offset ? (
<span className={styles.count}>{i + offset + 1}</span>
) : null}
<StoryWithData id={id} key={id} />
</div>
))}
<div className={styles.footer}>
<Link href={`/news/${+page + 1}`}>More</Link>
</div>
))}
<footer className={styles.footer}>
<Link href={`/news?p=${page + 1}`}>More</Link>
</footer>
</div>
)
</div>
)
}
3 changes: 1 addition & 2 deletions components/stories.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
.count {
flex-basis: auto;
flex-grow: 1;
vertical-align: top;
font-size: 14px;
padding-right: 5px;
display: block;
Expand All @@ -24,7 +23,7 @@
}

.footer {
padding: 10px 0 40px 30px;
padding: 10px 0 0 32px;
}

.footer a {
Expand Down
35 changes: 16 additions & 19 deletions components/story.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
'use client';
'use client'

import { useState } from 'react';
import { useState } from 'react'

import timeAgo from '../lib/time-ago';
import timeAgo from '../lib/time-ago'

import styles from './story.module.css';
import styles from './story.module.css'

export default function Story({
id,
Expand All @@ -13,45 +13,42 @@ export default function Story({
url,
user,
score,
commentsCount,
commentsCount
}) {
const { host } = url ? new URL(url) : { host: '#' };
const [voted, setVoted] = useState(false);
const { host } = url ? new URL(url) : { host: '#' }
const [voted, setVoted] = useState(false)

return (
<div style={{ margin: '5px 0' }}>
<div className={styles.story}>
<div className={styles.title}>
<span
style={{
cursor: 'pointer',
fontFamily: 'sans-serif',
marginRight: 5,
color: voted ? '#ffa52a' : '#ccc',
}}
className={voted ? styles['votearrow--voted'] : styles.votearrow}
onClick={() => setVoted(!voted)}
>
&#9650;
</span>
<a href={url}>{title}</a>
{url && (
<span className={styles.source}>
{' ('}
<a href={`http://${host}`}>{host.replace(/^www\./, '')}</a>
{')'}
</span>
)}
</div>
<div className={styles.meta}>
{score} {plural(score, 'point')} by{' '}
<a href={`/user?id=${user}`}>{user}</a>{' '}
<a href={`/item?id=${id}`}>
<a href={`/user/${user}`}>{user}</a>{' '}
<a href={`/item/${id}`}>
{timeAgo(new Date(date)) /* note: we re-hydrate due to ssr */} ago
</a>{' '}
|{' '}
<a href={`/item?id=${id}`}>
<a href={`/item/${id}`}>
{commentsCount} {plural(commentsCount, 'comment')}
</a>
</div>
</div>
);
)
}

const plural = (n, s) => s + (n === 0 || n > 1 ? 's' : '');
const plural = (n, s) => s + (n === 0 || n > 1 ? 's' : '')
16 changes: 16 additions & 0 deletions components/story.module.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
.story {
flex: 100 1;
display: inline-block;
}

.title {
font-size: 15px;
margin-bottom: 3px;
}

.votearrow {
cursor: pointer;
font-family: sans-serif;
color: #ccc;
}

.votearrow--voted {
composes: votearrow;
color: #ffa52a
}

.title > a {
color: #000;
text-decoration: none;
Expand Down
36 changes: 20 additions & 16 deletions lib/get-item.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
import fetchData from './fetch-data';
import fetchData from './fetch-data'

export default async function (id) {
const val = await fetchData(`item/${id}`);
const val = await fetchData(`item/${id}`)
if (val) {
return transform(val);
return transform(val)
} else {
return null;
return null
}
}

export function transform(val) {
return {
id: val.id,
url: val.url || '',
user: val.by,
// time is seconds since epoch, not ms
date: new Date(val.time * 1000).getTime() || 0,
// sometimes `kids` is `undefined`
comments: val.kids || [],
commentsCount: val.descendants || 0,
score: val.score,
title: val.title,
};
if (val) {
return {
id: val.id,
url: val.url || '',
user: val.by,
// time is seconds since epoch, not ms
date: new Date(val.time * 1000).getTime() || 0,
// sometimes `kids` is `undefined`
comments: val.kids || [],
commentsCount: val.descendants || 0,
score: val.score,
title: val.title
}
} else {
return null
}
}
Loading

0 comments on commit 47d238f

Please sign in to comment.