Fix top nagivation flickering, add 404 page
This commit is contained in:
		
							parent
							
								
									ae30e8d4a8
								
							
						
					
					
						commit
						b43abafa1c
					
				| @ -1,17 +1,17 @@ | |||||||
|  | import Head from "next/head"; | ||||||
| import { PropsWithChildren } from "react"; | import { PropsWithChildren } from "react"; | ||||||
| import { Navigation } from "../Navigation"; |  | ||||||
| 
 | 
 | ||||||
| export interface PageProps { | export interface PageProps { | ||||||
|   className?: string; |   title: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function Page({ className, children }: PropsWithChildren<PageProps>) { | export function Page({ title, children }: PropsWithChildren<PageProps>) { | ||||||
|   return ( |   return ( | ||||||
|     <div className="page"> |     <> | ||||||
|       <header> |       <Head> | ||||||
|         <Navigation /> |         <title>{title}</title> | ||||||
|       </header> |       </Head> | ||||||
|       <main className={className}>{children}</main> |       {children} | ||||||
|     </div> |     </> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								src/pages/404.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/pages/404.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | import type { NextPage } from "next"; | ||||||
|  | import { PageWithError } from "../views/PageWithError"; | ||||||
|  | 
 | ||||||
|  | const PageTitle = "Flash Card App - 404"; | ||||||
|  | 
 | ||||||
|  | const Page404: NextPage = () => { | ||||||
|  |   return <PageWithError title={PageTitle} message="404 - content not found" />; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default Page404; | ||||||
| @ -1,7 +1,17 @@ | |||||||
| import "../styles/globals.css"; | import "../styles/globals.css"; | ||||||
| import "../styles/components.css"; | import "../styles/components.css"; | ||||||
| import type { AppProps } from "next/app"; | import type { AppProps } from "next/app"; | ||||||
|  | import { Navigation } from "../components"; | ||||||
| 
 | 
 | ||||||
| export default function MyApp({ Component, pageProps }: AppProps) { | export default function MyApp({ Component, pageProps }: AppProps) { | ||||||
|   return <Component {...pageProps} />; |   return ( | ||||||
|  |     <div className="page"> | ||||||
|  |       <header> | ||||||
|  |         <Navigation /> | ||||||
|  |       </header> | ||||||
|  |       <main> | ||||||
|  |         <Component {...pageProps} /> | ||||||
|  |       </main> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,6 +8,10 @@ import { useExpressionSetQueryId } from "../../hooks/useExpressionSetQueryId"; | |||||||
| import { useExpressionsInSet } from "../../hooks/useExpressionsInSet"; | import { useExpressionsInSet } from "../../hooks/useExpressionsInSet"; | ||||||
| import { PageWithError } from "../../views/PageWithError/PageWithError"; | import { PageWithError } from "../../views/PageWithError/PageWithError"; | ||||||
| 
 | 
 | ||||||
|  | function pageTitle(name?: string) { | ||||||
|  |   return `Flash Card App - ${name || "Sets"}`; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const ExpressionSetDetailsPage: NextPage = () => { | const ExpressionSetDetailsPage: NextPage = () => { | ||||||
|   const expression_set_id = useExpressionSetQueryId(); |   const expression_set_id = useExpressionSetQueryId(); | ||||||
|   const expression_set = useExpressionSet(expression_set_id); |   const expression_set = useExpressionSet(expression_set_id); | ||||||
| @ -15,13 +19,15 @@ const ExpressionSetDetailsPage: NextPage = () => { | |||||||
| 
 | 
 | ||||||
|   // Fallback for expression set not found
 |   // Fallback for expression set not found
 | ||||||
|   if (!expression_set) { |   if (!expression_set) { | ||||||
|     return <PageWithError message="Expression set not found" />; |     return ( | ||||||
|  |       <PageWithError title={pageTitle()} message="Expression set not found" /> | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Fallback for expression set empty
 |   // Fallback for expression set empty
 | ||||||
|   if (expressions.length === 0) |   if (expressions.length === 0) | ||||||
|     return ( |     return ( | ||||||
|       <Page> |       <Page title={pageTitle(expression_set.name)}> | ||||||
|         <div className="page-with-padding scroll"> |         <div className="page-with-padding scroll"> | ||||||
|           <ExpressionSetInfo |           <ExpressionSetInfo | ||||||
|             id={expression_set.id!} |             id={expression_set.id!} | ||||||
| @ -35,7 +41,7 @@ const ExpressionSetDetailsPage: NextPage = () => { | |||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Page> |     <Page title={pageTitle(expression_set.name)}> | ||||||
|       <div className="page-with-bottom-navigation"> |       <div className="page-with-bottom-navigation"> | ||||||
|         <section className="padding-small scroll"> |         <section className="padding-small scroll"> | ||||||
|           <ExpressionSetInfo |           <ExpressionSetInfo | ||||||
|  | |||||||
| @ -8,15 +8,19 @@ import { useExpressionsInSet } from "../../hooks/useExpressionsInSet"; | |||||||
| import { IndexedExpressionSet } from "../../model"; | import { IndexedExpressionSet } from "../../model"; | ||||||
| import { PageWithError } from "../../views/PageWithError"; | import { PageWithError } from "../../views/PageWithError"; | ||||||
| 
 | 
 | ||||||
|  | const PageTitle = "Flash Card App - Sets"; | ||||||
|  | 
 | ||||||
| const ExpressionSetListPage: NextPage = () => { | const ExpressionSetListPage: NextPage = () => { | ||||||
|   const expression_sets = useExpressionSets(); |   const expression_sets = useExpressionSets(); | ||||||
| 
 | 
 | ||||||
|   if (!expression_sets?.length) { |   if (!expression_sets?.length) { | ||||||
|     return <PageWithError message="No expression sets found" />; |     return ( | ||||||
|  |       <PageWithError title={PageTitle} message="No expression sets found" /> | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Page> |     <Page title={PageTitle}> | ||||||
|       <div className="page-with-padding content-list scroll"> |       <div className="page-with-padding content-list scroll"> | ||||||
|         {expression_sets.map(({ id, name, description }) => ( |         {expression_sets.map(({ id, name, description }) => ( | ||||||
|           <ExpressionSetLink |           <ExpressionSetLink | ||||||
|  | |||||||
| @ -16,6 +16,8 @@ import { | |||||||
| import { sample } from "../../util/array-utils"; | import { sample } from "../../util/array-utils"; | ||||||
| import { PageWithError } from "../../views/PageWithError/PageWithError"; | import { PageWithError } from "../../views/PageWithError/PageWithError"; | ||||||
| 
 | 
 | ||||||
|  | const PageTitle = "Flash Card App - Practice"; | ||||||
|  | 
 | ||||||
| // Do random selection here so we don't keep flipping states with interaction
 | // Do random selection here so we don't keep flipping states with interaction
 | ||||||
| const ExpressionPracticePage: NextPage = () => { | const ExpressionPracticePage: NextPage = () => { | ||||||
|   // Query info
 |   // Query info
 | ||||||
| @ -36,10 +38,17 @@ const ExpressionPracticePage: NextPage = () => { | |||||||
| 
 | 
 | ||||||
|   // Fallback views for expression set content not found
 |   // Fallback views for expression set content not found
 | ||||||
|   if (!expression_set_id) { |   if (!expression_set_id) { | ||||||
|     return <PageWithError message="Expression set not found" />; |     return ( | ||||||
|  |       <PageWithError title={PageTitle} message="Expression set not found" /> | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
|   if (!expression) { |   if (!expression) { | ||||||
|     return <PageWithError message="No expressions left in this set" />; |     return ( | ||||||
|  |       <PageWithError | ||||||
|  |         title={PageTitle} | ||||||
|  |         message="No expressions left in this set" | ||||||
|  |       /> | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
| @ -63,7 +72,7 @@ function ExpressionCardPracticeView({ | |||||||
| }: ExpressionCardPracticeViewProps) { | }: ExpressionCardPracticeViewProps) { | ||||||
|   const [revealed, setRevealed] = useState(false); |   const [revealed, setRevealed] = useState(false); | ||||||
|   return ( |   return ( | ||||||
|     <Page> |     <Page title={PageTitle}> | ||||||
|       <div className="page-with-bottom-navigation"> |       <div className="page-with-bottom-navigation"> | ||||||
|         <section className="padding-small scroll"> |         <section className="padding-small scroll"> | ||||||
|           <ExpressionCard |           <ExpressionCard | ||||||
| @ -120,26 +129,25 @@ function DemoteExpressionButton({ expression_id }: ExpressionIdProps) { | |||||||
|   const { query, pathname, push } = useRouter(); |   const { query, pathname, push } = useRouter(); | ||||||
|   const expression_set_id = useExpressionSetQueryId(); |   const expression_set_id = useExpressionSetQueryId(); | ||||||
|   const handleClick = useCallback(() => { |   const handleClick = useCallback(() => { | ||||||
|     () => { |     if (expression_set_id === 1) { | ||||||
|       if (expression_set_id === 1) { |       const filter_ids = query["filter-ids"] | ||||||
|         const filter_ids = query["filter-ids"] |         ? `${query["filter-ids"]} ${expression_id}` | ||||||
|           ? `${query["filter-ids"]} ${expression_id}` |         : `${expression_id}`; | ||||||
|           : `${expression_id}`; |       push({ | ||||||
|         push({ |         pathname, | ||||||
|           pathname, |         query: { | ||||||
|           query: { |           ...query, | ||||||
|             ...query, |           "filter-ids": filter_ids, | ||||||
|             "filter-ids": filter_ids, |         }, | ||||||
|           }, |       }); | ||||||
|         }); |     } else { | ||||||
|       } else { |       assignExpressionToSet({ | ||||||
|         assignExpressionToSet({ |         expression_id, | ||||||
|           expression_id, |         expression_set_id: Math.max(1, expression_set_id - 1), | ||||||
|           expression_set_id: Math.max(1, expression_set_id - 1), |       }); | ||||||
|         }); |     } | ||||||
|       } |   }, [expression_id, expression_set_id, pathname, push, query]); | ||||||
|     }; | 
 | ||||||
|   }, [expression_id, expression_set_id, pathname, query, push]); |  | ||||||
|   return ( |   return ( | ||||||
|     <button |     <button | ||||||
|       className="navigation-item bottom text-navigation grow" |       className="navigation-item bottom text-navigation grow" | ||||||
|  | |||||||
| @ -1,8 +1,10 @@ | |||||||
| import type { NextPage } from "next"; | import type { NextPage } from "next"; | ||||||
| import { Page } from "../components/Page"; | import { Page } from "../components/Page"; | ||||||
| 
 | 
 | ||||||
|  | const PageTitle = "Flash Card App"; | ||||||
|  | 
 | ||||||
| const Home: NextPage = () => { | const Home: NextPage = () => { | ||||||
|   return <Page />; |   return <Page title={PageTitle} />; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default Home; | export default Home; | ||||||
|  | |||||||
| @ -1,12 +1,13 @@ | |||||||
| import { Page } from "../../components/Page"; | import { Page } from "../../components/Page"; | ||||||
| 
 | 
 | ||||||
| export interface PageWithErrorProps { | export interface PageWithErrorProps { | ||||||
|  |   title: string; | ||||||
|   message: string; |   message: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function PageWithError({ message }: PageWithErrorProps) { | export function PageWithError({ title, message }: PageWithErrorProps) { | ||||||
|   return ( |   return ( | ||||||
|     <Page> |     <Page title={title}> | ||||||
|       <div className="page-with-padding"> |       <div className="page-with-padding"> | ||||||
|         <p className="text-meta">{message}</p> |         <p className="text-meta">{message}</p> | ||||||
|       </div> |       </div> | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user