過去の記事
今回は基本的なレイアウトを作った後、microCMSに登録したRSSから一覧表示までを目標にやっていきます。
レイアウトの作成
ヘッダーの作成
import React from 'react'
import styles from './Header.module.scss'
import Link from 'next/link'
import Search from '@/public/components/search/Search'
const Header = () => {
return (
<header className={styles['c-header']}>
<Link href={`/`}>
<h1>UNORSS</h1>
</Link>
<nav className={styles['c-header__nav']}>
<ul className={styles['c-header__nav__list']}>
<li className={styles['c-header__nav__list__item']}>
<Link href={`/bookmark`}>
ブックマーク
</Link>
</li>
<li className={styles['c-header__nav__list__item']}>
<Search />
</li>
</ul>
</nav>
</header>
)
}
export default Header
フッターの作成
import React from 'react'
import styles from './Footer.module.scss'
const Footer = () => {
return (
<footer className={styles['c-footer']}>
Footer
</footer>
)
}
export default Footer
サイドバーの作成
import React from 'react'
import styles from './Sidebar.module.scss'
const Sidebar = () => {
return (
<aside className={styles['c-sidebar']}>
<ul className={styles['c-sidebar__card']}>
<p className={styles['c-sidebar__card--title']}>配信元別</p>
<li className={styles['c-sidebar__card__item']}>
<a href="/">リンク</a>
</li>
<li className={styles['c-sidebar__card__item']}>
<a href="/">リンク</a>
</li>
<li className={styles['c-sidebar__card__item']}>
<a href="/">リンク</a>
</li>
</ul>
<ul className={styles['c-sidebar__card']}>
<p className={styles['c-sidebar__card--title']}>カテゴリ別</p>
<li className={styles['c-sidebar__card__item']}>
<a href="/">リンク</a>
</li>
<li className={styles['c-sidebar__card__item']}>
<a href="/">リンク</a>
</li>
<li className={styles['c-sidebar__card__item']}>
<a href="/">リンク</a>
</li>
</ul>
<ul className={styles['c-sidebar__card']}>
<p className={styles['c-sidebar__card--title']}>月別</p>
<li className={styles['c-sidebar__card__item']}>
<a href="/">リンク</a>
</li>
<li className={styles['c-sidebar__card__item']}>
<a href="/">リンク</a>
</li>
<li className={styles['c-sidebar__card__item']}>
<a href="/">リンク</a>
</li>
</ul>
</aside>
)
}
export default Sidebar
レイアウトへの組み込み
import type { Metadata } from "next";
import "@/public/styles/destyle.css"
import "@/public/styles/global.scss"
import Header from "@/public/components/header/Header";
import Footer from "@/public/components/footer/Footer";
import Sidebar from "@/public/components/sidebar/Sidebar";
export const metadata: Metadata = {
title: "RSS reader",
description: "ワタシのワタシによるワタシのためのRSSリーダー",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ja" id="html">
<body>
<Header />
<div className="l-inner">
<main>
{children}
</main>
<Sidebar />
</div>
<Footer />
</body>
</html>
);
}
(リンク等全てダミー状態。)
RSS一覧取得
rss-parceのインストール
$ npm i rss-parser
試しにzennのrssを取得・表示
import Parser from 'rss-parser'
const feed = await new Parser().parseURL("https://zenn.dev/niiyama_k/feed")
console.log(feed.title)
feed.items.map(item => {
console.log(item.title)
console.log(item.link)
})
新山 慶介さんのフィード
MAMPによるWordPress開発環境の最大アップロード容量を変更する
https://zenn.dev/niiyama_k/articles/change-max-upload-size-mamp
【EC-CUBE】ECサイトの移転がうまくいかない
https://zenn.dev/niiyama_k/articles/6774e2befe7a67
【Xserver】phpMyAdminのID・パスワード
https://zenn.dev/niiyama_k/articles/c01c402e3f59c6
【React】useLocation で 今いるページ・前いたページのpathを取得する
https://zenn.dev/niiyama_k/articles/eab421dddf2956
Sass * FROCSSによるサイトコーディングのベストプラクティス
https://zenn.dev/niiyama_k/articles/7b041bc8ee577a
Swagger(OpenAPI)によるAPI設計
https://zenn.dev/niiyama_k/articles/3975164ab205df
gridレイアウトでカレンダーのデザイン(html / sass)
https://zenn.dev/niiyama_k/articles/e83f57ad0b880b
[almalinux9 + laravel] sodiumがなくて怒られる
https://zenn.dev/niiyama_k/articles/c3ec0913a4ba61
ChatGPTでシステム開発の設計書テンプレートを作成する
https://zenn.dev/niiyama_k/articles/7aebf968001607
TOPページで一覧取得
import { client, getList } from '@/libs/client'
import styles from './FrontPage.module.scss'
import Parser from 'rss-parser'
import ArticleCard from '@/public/components/card/ArticleCard'
const FrontPage = async () => {
const { contents } = await getList();
const parse = new Parser();
return (
<div className='p-front-page'>
<ul className={styles['p-front-page__list']}>
{contents.map(async (rss) => {
const feed = await parse.parseURL(rss.url)
return feed.items.map((item) => {
return (
<ArticleCard
date={item.pubDate ?? item.date}
link={item.link}
title={item.title}
site_title={rss.title}
/>
)
})
})}
</ul>
//後でお気に入りカテゴリのループが入る
</div>
)
}
export default FrontPage
{contents.map(async (rss) => {
const feed = await parse.parseURL(rss.url)
return feed.items.map((item) => {
return (
)
})
})}
これの理解に結構時間がかかった。
microCMSに登録してあるRSSのURLを取得 → rss-parserでパース → 並び替え
という流れが必要だった。
(個人的にmap関数のネストはあまり良くなさそうですがどうなんでしょう...?教えて有識者様)
各記事のカードはコンポーネントにした。
コンポーネントに渡している情報は以下の通り
- item.pubDate ?? item.date:日付情報
- item.link:各記事へのリンク
- item.title:各記事のタイトル
- rss.title:microCMSで登録したRSSタイトル
カードコンポーネント
import Link from 'next/link'
import React from 'react'
import dayjs from 'dayjs';
import styles from './ArticleCard.module.scss';
type Props = {
date: string | undefined
link: string | undefined
title: string | undefined
site_title: string
}
function getOrder(millis: number, asc = false) {
return (asc ? 1 : -1) * Math.floor(millis / 1000); // order は昇順なので、降順に見せたい場合は -1 を掛ける
}
const ArticleCard = (props: Props) => {
return (
<li style={{ order: getOrder(dayjs(props.date).valueOf()) }} className={styles['c-article-card']}>
<Link href={`${props.link}`}>
<img src="" alt="" className={styles['c-article-card--img']} />
<time className={styles['c-article-card--time']}>{dayjs(props.date).format('YYYY-MM-DD')}</time>
<h2 className={styles['c-article-card--title']}>{props.title}</h2>
<span className={styles['c-article-card--site-title']}>{props.site_title}</span>
</Link>
</li>
)
}
export default ArticleCard
最初の function getOrder
は、取得したカードを昇順で並べるために必要な関数。
コピペしてきたので正直よくわかってない。けど動いてるからとりあえずOK。
(難しいことは後で考える派。)
日付順の並び替えやフォーマットに日付や時間を扱うパッケージが必要だったのでインストールした。
$ npm i dayjs
使用用途は次のとおり。
//渡された日付情報をYYYY-MM-DD形式でフォーマットしている
{dayjs(props.date).format('YYYY-MM-DD')}
//渡された日付情報をミリ秒unixtimeに変換(昇順ソートに必要)
(dayjs(props.date).valueOf())
ここまで作ってスタイル適用するとこうなる。
時間かかったのでちょっと調整して一旦プッシュ。
次回予告
次回はリンク別ページ・カテゴリページの作成を行っていく予定。
一気に進めすぎて疲れたのでちょっぴり更新頻度落ちます。
案件のご依頼・ご相談について
ワタシが運営するUNOTAMEでは、制作案件やPM業務の外部委託案件などを承っております。
少しでも興味のある方はぜひカジュアルにお話しさせていただけますと嬉しいです。
Twitter(X)のDMや下記ポートフォリオサイトからのお問い合わせ、お待ちしております。