diff --git a/README.md b/README.md index e12c896..f0bf8e2 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,16 @@ - **フロントエンド**: Vite + React をベースに、Markdownエディタや認証機能、UI等を提供 - **バックエンド**: AWS Lambda (Node.js) + API Gateway + DynamoDB のサーバーレス構成 +## デモアプリケーションイメージ +### (認証不要)Markdownエディタ画面 +![image](https://github.com/user-attachments/assets/c41ac2b7-c24a-405d-9653-bf599715891b) + +### (要認証)ドキュメント一覧画面 +![image](https://github.com/user-attachments/assets/99ea0435-ed2c-40a2-abad-9ec9094ea55a) + +### (認証不要)公開ドキュメント閲覧画面 +![](https://github.com/user-attachments/assets/4d0d0eb4-7aae-45d1-97d7-93aed02a5491) + ## 主な特徴 - **Markdown ドキュメントの作成・編集・公開** diff --git a/frontend/src/pages/DocsListPage.tsx b/frontend/src/pages/DocsListPage.tsx index de3572b..48b940b 100644 --- a/frontend/src/pages/DocsListPage.tsx +++ b/frontend/src/pages/DocsListPage.tsx @@ -1,10 +1,8 @@ -// DocsListPage.tsx -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, useMemo } from "react"; import { Link } from "react-router-dom"; import { useApiClient } from "../services/apiClient"; -import { useAuthContextSwitch as useAuthContext} from "../context/useAuthContextSwitch"; +import { useAuthContextSwitch as useAuthContext } from "../context/useAuthContextSwitch"; import { AxiosError } from "axios"; - import styles from "../styles/DocsListPage.module.scss"; const extractTitle = (markdown: string): string => { @@ -20,6 +18,14 @@ const extractTitle = (markdown: string): string => { const DocsListPage: React.FC = () => { const [documents, setDocuments] = useState([]); //eslint-disable-line const [error, setError] = useState(null); + + // ★ 検索用ステートを追加 + const [searchTerm, setSearchTerm] = useState(""); + + // ★ ページング用ステート + const [currentPage, setCurrentPage] = useState(1); + const pageSize = 15; // 1ページあたりの表示件数 + const { user, isSignedIn } = useAuthContext(); const api = useApiClient(); @@ -48,14 +54,42 @@ const DocsListPage: React.FC = () => { } } }; + if (isSignedIn) { fetchDocs(); } }, [api, user, isSignedIn]); - if (error) { - return
{error}
; - } + // ★ 1) 検索フィルタリング:searchTerm を含むドキュメントだけを抽出 + const filteredDocs = useMemo(() => { + const lowerSearchTerm = searchTerm.toLowerCase(); + if (!lowerSearchTerm) return documents; + + return documents.filter((doc) => { + const title = extractTitle(doc.content).toLowerCase(); + const content = doc.content?.toLowerCase() || ""; + return ( + title.includes(lowerSearchTerm) || content.includes(lowerSearchTerm) + ); + }); + }, [documents, searchTerm]); + + // ★ 2) ページング + const totalPages = Math.ceil(filteredDocs.length / pageSize); + + const paginatedDocs = useMemo(() => { + const startIndex = (currentPage - 1) * pageSize; + const endIndex = startIndex + pageSize; + return filteredDocs.slice(startIndex, endIndex); + }, [filteredDocs, currentPage]); + + // 前へ/次へボタンの挙動 + const goToPrevious = () => { + setCurrentPage((prev) => Math.max(prev - 1, 1)); + }; + const goToNext = () => { + setCurrentPage((prev) => Math.min(prev + 1, totalPages)); + }; // 「共有」ボタン押下時の挙動例 const handleShare = (slug: string) => { @@ -64,12 +98,15 @@ const DocsListPage: React.FC = () => { alert("公開URLをクリップボードにコピーしました!\n" + publicUrl); }; + if (error) { + return
{error}
; + } + return ( -
+
{isSignedIn ? ( <>
- {/* 新規ドキュメントは "/" に */} {

ドキュメント一覧

+ {/* ★ 検索入力欄 */} +
+ { + setSearchTerm(e.target.value); + setCurrentPage(1); // 検索語が変わったら1ページ目に戻す + }} + style={{ + padding: "8px", + borderRadius: "4px", + border: "1px solid #ccc", + width: "240px", + }} + /> +
+ @@ -99,12 +155,11 @@ const DocsListPage: React.FC = () => { - {documents.map((doc) => { + {paginatedDocs.map((doc) => { const title = extractTitle(doc.content); const isPublic = doc.isPublic; return ( - {/* タイトル */} - - {/* 公開/非公開 */} - - {/* 共有ボタン(公開時のみ) */}
{ {title} {isPublic ? ( 公開 @@ -122,11 +175,12 @@ const DocsListPage: React.FC = () => { 非公開 )} {isPublic ? ( - ) : ( @@ -138,6 +192,25 @@ const DocsListPage: React.FC = () => { })}
+ + {/* ★ ページングナビゲーション */} + {filteredDocs.length > 0 && totalPages > 1 && ( +
+ {/* 前へボタン: currentPage>1 のときだけ表示 */} + {currentPage > 1 && ( + + )} + +
+ ページ {currentPage} / {totalPages} +
+ + {/* 次へボタン: currentPage次へ + )} +
+ )} ) : (
ログインしてください