1+ import React , { useState , useEffect } from 'react' ;
2+ import { useParams } from 'react-router-dom' ;
3+ import '../../styles/notebook.css' ;
4+ import { CaretLeft , CaretRight } from '@phosphor-icons/react' ;
5+
6+ const Page = ( { content, pageNumber, title } ) => {
7+ return (
8+ < div className = "page" >
9+ < div className = "page-inner" >
10+ < div className = "notebook-header" > { title } </ div >
11+ < div className = "page-content" >
12+ < p > { content } </ p >
13+ </ div >
14+ < div className = "notebook-footer" > Page { pageNumber } </ div >
15+ </ div >
16+ </ div >
17+ ) ;
18+ } ;
19+
20+ const NotebookCover = ( { title, author, date } ) => {
21+ return (
22+ < div className = "page notebook-cover" >
23+ < div className = "page-inner" >
24+ < h2 > { title } </ h2 >
25+ { author && < p className = "author" > { author } </ p > }
26+ { date && < p className = "date" > { date } </ p > }
27+ </ div >
28+ </ div >
29+ ) ;
30+ } ;
31+
32+ const NotebookViewerPage = ( ) => {
33+ const { notebookId } = useParams ( ) ;
34+ const [ notebook , setNotebook ] = useState ( null ) ;
35+ const [ currentPage , setCurrentPage ] = useState ( 0 ) ;
36+ const [ isMobile , setIsMobile ] = useState ( window . innerWidth < 768 ) ;
37+
38+ useEffect ( ( ) => {
39+ fetch ( `/notebooks/${ notebookId } .json` )
40+ . then ( response => response . json ( ) )
41+ . then ( data => setNotebook ( data ) )
42+ . catch ( error => console . error ( 'Error fetching notebook:' , error ) ) ;
43+
44+ const handleResize = ( ) => {
45+ setIsMobile ( window . innerWidth < 768 ) ;
46+ } ;
47+ window . addEventListener ( 'resize' , handleResize ) ;
48+ return ( ) => window . removeEventListener ( 'resize' , handleResize ) ;
49+ } , [ notebookId ] ) ;
50+
51+ const handleNextPage = ( ) => {
52+ if ( notebook ) {
53+ const pageIncrement = isMobile ? 1 : 2 ;
54+ setCurrentPage ( prev => Math . min ( prev + pageIncrement , notebook . pages . length + 1 ) ) ;
55+ }
56+ } ;
57+
58+ const handlePrevPage = ( ) => {
59+ const pageDecrement = isMobile ? 1 : 2 ;
60+ setCurrentPage ( prev => Math . max ( prev - pageDecrement , 0 ) ) ;
61+ } ;
62+
63+ if ( ! notebook ) {
64+ return < div > Loading notebook...</ div > ;
65+ }
66+
67+ const renderPages = ( ) => {
68+ if ( currentPage === 0 ) {
69+ return < NotebookCover title = { notebook . title } author = { notebook . author } date = { notebook . date } /> ;
70+ }
71+ if ( currentPage > notebook . pages . length ) {
72+ return < NotebookCover title = "The End" /> ;
73+ }
74+
75+ if ( isMobile ) {
76+ return < Page content = { notebook . pages [ currentPage - 1 ] } pageNumber = { currentPage } title = { notebook . title } /> ;
77+ }
78+
79+ return (
80+ < div style = { { display : 'flex' , width : '100%' } } >
81+ < Page content = { notebook . pages [ currentPage - 1 ] } pageNumber = { currentPage } title = { notebook . title } />
82+ { currentPage < notebook . pages . length && (
83+ < Page content = { notebook . pages [ currentPage ] } pageNumber = { currentPage + 1 } title = { notebook . title } />
84+ ) }
85+ </ div >
86+ ) ;
87+ } ;
88+
89+ return (
90+ < div className = "notebook-container" >
91+ < div className = "book" >
92+ { currentPage > 0 && (
93+ < div className = "clickable-edge left" onClick = { handlePrevPage } >
94+ < CaretLeft size = { 32 } />
95+ </ div >
96+ ) }
97+ { renderPages ( ) }
98+ { notebook && currentPage < notebook . pages . length + 1 && (
99+ < div className = "clickable-edge right" onClick = { handleNextPage } >
100+ < CaretRight size = { 32 } />
101+ </ div >
102+ ) }
103+ </ div >
104+ { notebook && (
105+ < div className = "slider-container" >
106+ < input
107+ type = "range"
108+ min = "0"
109+ max = { notebook . pages . length + 1 }
110+ value = { currentPage }
111+ onChange = { ( e ) => setCurrentPage ( parseInt ( e . target . value , 10 ) ) }
112+ className = "slider"
113+ />
114+ < div className = "page-number-display" >
115+ Page { currentPage } of { notebook . pages . length + 1 }
116+ </ div >
117+ </ div >
118+ ) }
119+ </ div >
120+ ) ;
121+ } ;
122+
123+ export default NotebookViewerPage ;
0 commit comments