diff options
Diffstat (limited to 'src/client/pages')
| -rw-r--r-- | src/client/pages/DeckDetailPage.tsx | 144 | ||||
| -rw-r--r-- | src/client/pages/HomePage.tsx | 106 | ||||
| -rw-r--r-- | src/client/pages/LoginPage.tsx | 25 | ||||
| -rw-r--r-- | src/client/pages/NotFoundPage.tsx | 32 | ||||
| -rw-r--r-- | src/client/pages/StudyPage.tsx | 75 |
5 files changed, 96 insertions, 286 deletions
diff --git a/src/client/pages/DeckDetailPage.tsx b/src/client/pages/DeckDetailPage.tsx index cb1e3fb..5a3c14e 100644 --- a/src/client/pages/DeckDetailPage.tsx +++ b/src/client/pages/DeckDetailPage.tsx @@ -1,3 +1,13 @@ +import { + faChevronLeft, + faCirclePlay, + faFile, + faPen, + faPlus, + faSpinner, + faTrash, +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useCallback, useEffect, useState } from "react"; import { Link, useParams } from "wouter"; import { ApiClientError, apiClient } from "../api"; @@ -144,20 +154,11 @@ export function DeckDetailPage() { href="/" className="inline-flex items-center gap-2 text-muted hover:text-slate transition-colors text-sm" > - <svg + <FontAwesomeIcon + icon={faChevronLeft} className="w-4 h-4" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M15 19l-7-7 7-7" - /> - </svg> + /> Back to Decks </Link> </div> @@ -168,26 +169,11 @@ export function DeckDetailPage() { {/* Loading State */} {isLoading && ( <div className="flex items-center justify-center py-12"> - <svg - className="animate-spin h-8 w-8 text-primary" - viewBox="0 0 24 24" + <FontAwesomeIcon + icon={faSpinner} + className="h-8 w-8 text-primary animate-spin" aria-hidden="true" - > - <circle - className="opacity-25" - cx="12" - cy="12" - r="10" - stroke="currentColor" - strokeWidth="4" - fill="none" - /> - <path - className="opacity-75" - fill="currentColor" - d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" - /> - </svg> + /> </div> )} @@ -227,26 +213,11 @@ export function DeckDetailPage() { href={`/decks/${deckId}/study`} className="inline-flex items-center gap-2 bg-success hover:bg-success/90 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 active:scale-[0.98] shadow-sm hover:shadow-md" > - <svg + <FontAwesomeIcon + icon={faCirclePlay} className="w-5 h-5" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" - /> - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" - /> - </svg> + /> Study Now </Link> </div> @@ -262,20 +233,11 @@ export function DeckDetailPage() { onClick={() => setIsCreateModalOpen(true)} className="inline-flex items-center gap-2 bg-primary hover:bg-primary-dark text-white font-medium py-2 px-4 rounded-lg transition-all duration-200 active:scale-[0.98]" > - <svg + <FontAwesomeIcon + icon={faPlus} className="w-5 h-5" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M12 4v16m8-8H4" - /> - </svg> + /> Add Card </button> </div> @@ -284,20 +246,11 @@ export function DeckDetailPage() { {cards.length === 0 && ( <div className="text-center py-12 bg-white rounded-xl border border-border/50"> <div className="w-14 h-14 mx-auto mb-4 bg-ivory rounded-xl flex items-center justify-center"> - <svg + <FontAwesomeIcon + icon={faFile} className="w-7 h-7 text-muted" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={1.5} - d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" - /> - </svg> + /> </div> <h3 className="font-display text-lg font-medium text-slate mb-2"> No cards yet @@ -310,20 +263,11 @@ export function DeckDetailPage() { onClick={() => setIsCreateModalOpen(true)} className="inline-flex items-center gap-2 bg-primary hover:bg-primary-dark text-white font-medium py-2 px-4 rounded-lg transition-all duration-200" > - <svg + <FontAwesomeIcon + icon={faPlus} className="w-5 h-5" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M12 4v16m8-8H4" - /> - </svg> + /> Add Your First Card </button> </div> @@ -386,20 +330,11 @@ export function DeckDetailPage() { className="p-2 text-muted hover:text-slate hover:bg-ivory rounded-lg transition-colors" title="Edit card" > - <svg + <FontAwesomeIcon + icon={faPen} className="w-4 h-4" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" - /> - </svg> + /> </button> <button type="button" @@ -407,20 +342,11 @@ export function DeckDetailPage() { className="p-2 text-muted hover:text-error hover:bg-error/5 rounded-lg transition-colors" title="Delete card" > - <svg + <FontAwesomeIcon + icon={faTrash} className="w-4 h-4" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" - /> - </svg> + /> </button> </div> </div> diff --git a/src/client/pages/HomePage.tsx b/src/client/pages/HomePage.tsx index fcae971..b7b2c29 100644 --- a/src/client/pages/HomePage.tsx +++ b/src/client/pages/HomePage.tsx @@ -1,3 +1,11 @@ +import { + faBoxOpen, + faPen, + faPlus, + faSpinner, + faTrash, +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useCallback, useEffect, useState } from "react"; import { Link } from "wouter"; import { ApiClientError, apiClient } from "../api"; @@ -95,20 +103,11 @@ export function HomePage() { onClick={() => setIsCreateModalOpen(true)} className="inline-flex items-center gap-2 bg-primary hover:bg-primary-dark text-white font-medium py-2 px-4 rounded-lg transition-all duration-200 active:scale-[0.98] shadow-sm hover:shadow-md" > - <svg + <FontAwesomeIcon + icon={faPlus} className="w-5 h-5" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M12 4v16m8-8H4" - /> - </svg> + /> New Deck </button> </div> @@ -116,26 +115,11 @@ export function HomePage() { {/* Loading State */} {isLoading && ( <div className="flex items-center justify-center py-12"> - <svg - className="animate-spin h-8 w-8 text-primary" - viewBox="0 0 24 24" + <FontAwesomeIcon + icon={faSpinner} + className="h-8 w-8 text-primary animate-spin" aria-hidden="true" - > - <circle - className="opacity-25" - cx="12" - cy="12" - r="10" - stroke="currentColor" - strokeWidth="4" - fill="none" - /> - <path - className="opacity-75" - fill="currentColor" - d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" - /> - </svg> + /> </div> )} @@ -160,20 +144,11 @@ export function HomePage() { {!isLoading && !error && decks.length === 0 && ( <div className="text-center py-16 animate-fade-in"> <div className="w-16 h-16 mx-auto mb-4 bg-ivory rounded-2xl flex items-center justify-center"> - <svg + <FontAwesomeIcon + icon={faBoxOpen} className="w-8 h-8 text-muted" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={1.5} - d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" - /> - </svg> + /> </div> <h3 className="font-display text-lg font-medium text-slate mb-2"> No decks yet @@ -186,20 +161,11 @@ export function HomePage() { onClick={() => setIsCreateModalOpen(true)} className="inline-flex items-center gap-2 bg-primary hover:bg-primary-dark text-white font-medium py-2.5 px-5 rounded-lg transition-all duration-200" > - <svg + <FontAwesomeIcon + icon={faPlus} className="w-5 h-5" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M12 4v16m8-8H4" - /> - </svg> + /> Create Your First Deck </button> </div> @@ -237,20 +203,11 @@ export function HomePage() { className="p-2 text-muted hover:text-slate hover:bg-ivory rounded-lg transition-colors" title="Edit deck" > - <svg + <FontAwesomeIcon + icon={faPen} className="w-4 h-4" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" - /> - </svg> + /> </button> <button type="button" @@ -258,20 +215,11 @@ export function HomePage() { className="p-2 text-muted hover:text-error hover:bg-error/5 rounded-lg transition-colors" title="Delete deck" > - <svg + <FontAwesomeIcon + icon={faTrash} className="w-4 h-4" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" - /> - </svg> + /> </button> </div> </div> diff --git a/src/client/pages/LoginPage.tsx b/src/client/pages/LoginPage.tsx index 89dd053..835c73e 100644 --- a/src/client/pages/LoginPage.tsx +++ b/src/client/pages/LoginPage.tsx @@ -1,3 +1,5 @@ +import { faSpinner } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { type FormEvent, useEffect, useState } from "react"; import { useLocation } from "wouter"; import { ApiClientError, useAuth } from "../stores"; @@ -111,26 +113,11 @@ export function LoginPage() { > {isSubmitting ? ( <span className="flex items-center justify-center gap-2"> - <svg - className="animate-spin h-4 w-4" - viewBox="0 0 24 24" + <FontAwesomeIcon + icon={faSpinner} + className="h-4 w-4 animate-spin" aria-hidden="true" - > - <circle - className="opacity-25" - cx="12" - cy="12" - r="10" - stroke="currentColor" - strokeWidth="4" - fill="none" - /> - <path - className="opacity-75" - fill="currentColor" - d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" - /> - </svg> + /> Signing in... </span> ) : ( diff --git a/src/client/pages/NotFoundPage.tsx b/src/client/pages/NotFoundPage.tsx index 72531c1..c94340e 100644 --- a/src/client/pages/NotFoundPage.tsx +++ b/src/client/pages/NotFoundPage.tsx @@ -1,3 +1,5 @@ +import { faFaceSadTear, faHouse } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Link } from "wouter"; export function NotFoundPage() { @@ -5,20 +7,11 @@ export function NotFoundPage() { <div className="min-h-screen bg-cream flex items-center justify-center px-4"> <div className="text-center animate-fade-in"> <div className="w-20 h-20 mx-auto mb-6 bg-ivory rounded-2xl flex items-center justify-center"> - <svg + <FontAwesomeIcon + icon={faFaceSadTear} className="w-10 h-10 text-muted" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={1.5} - d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" - /> - </svg> + /> </div> <h1 className="font-display text-6xl font-bold text-ink mb-2">404</h1> <h2 className="font-display text-xl font-medium text-slate mb-4"> @@ -31,20 +24,11 @@ export function NotFoundPage() { href="/" className="inline-flex items-center gap-2 bg-primary hover:bg-primary-dark text-white font-medium py-2.5 px-5 rounded-lg transition-all duration-200" > - <svg + <FontAwesomeIcon + icon={faHouse} className="w-5 h-5" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" - /> - </svg> + /> Go Home </Link> </div> diff --git a/src/client/pages/StudyPage.tsx b/src/client/pages/StudyPage.tsx index 16c1a1c..5bd31c0 100644 --- a/src/client/pages/StudyPage.tsx +++ b/src/client/pages/StudyPage.tsx @@ -1,3 +1,10 @@ +import { + faCheck, + faChevronLeft, + faCircleCheck, + faSpinner, +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useCallback, useEffect, useRef, useState } from "react"; import { Link, useParams } from "wouter"; import { ApiClientError, apiClient } from "../api"; @@ -245,20 +252,11 @@ export function StudyPage() { href={`/decks/${deckId}`} className="inline-flex items-center gap-2 text-muted hover:text-slate transition-colors text-sm" > - <svg + <FontAwesomeIcon + icon={faChevronLeft} className="w-4 h-4" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M15 19l-7-7 7-7" - /> - </svg> + /> Back to Deck </Link> </div> @@ -269,26 +267,11 @@ export function StudyPage() { {/* Loading State */} {isLoading && ( <div className="flex-1 flex items-center justify-center"> - <svg - className="animate-spin h-8 w-8 text-primary" - viewBox="0 0 24 24" + <FontAwesomeIcon + icon={faSpinner} + className="h-8 w-8 text-primary animate-spin" aria-hidden="true" - > - <circle - className="opacity-25" - cx="12" - cy="12" - r="10" - stroke="currentColor" - strokeWidth="4" - fill="none" - /> - <path - className="opacity-75" - fill="currentColor" - d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" - /> - </svg> + /> </div> )} @@ -335,20 +318,11 @@ export function StudyPage() { > <div className="text-center py-12 px-6 bg-white rounded-2xl border border-border/50 shadow-card max-w-sm w-full"> <div className="w-16 h-16 mx-auto mb-4 bg-success/10 rounded-2xl flex items-center justify-center"> - <svg + <FontAwesomeIcon + icon={faCheck} className="w-8 h-8 text-success" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M5 13l4 4L19 7" - /> - </svg> + /> </div> <h2 className="font-display text-xl font-medium text-slate mb-2"> All caught up! @@ -374,20 +348,11 @@ export function StudyPage() { > <div className="text-center py-12 px-6 bg-white rounded-2xl border border-border/50 shadow-lg max-w-sm w-full animate-scale-in"> <div className="w-20 h-20 mx-auto mb-6 bg-success/10 rounded-full flex items-center justify-center"> - <svg + <FontAwesomeIcon + icon={faCircleCheck} className="w-10 h-10 text-success" - fill="none" - stroke="currentColor" - viewBox="0 0 24 24" aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" - /> - </svg> + /> </div> <h2 className="font-display text-2xl font-semibold text-ink mb-2"> Session Complete! |
