New: Ui Redesign (#1)
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m6s
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m6s
Reviewed-on: #1
This commit is contained in:
parent
009d1eb065
commit
bd071b3906
22 changed files with 464 additions and 524 deletions
|
|
@ -90,9 +90,9 @@ export default function DeckStudyPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto w-full py-2 md:py-4">
|
||||
<div className="mx-auto w-full max-w-5xl py-1 md:py-3">
|
||||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 mb-6">
|
||||
<div className="mb-7 flex flex-col items-start justify-between gap-4 rounded-2xl border border-border-light bg-bg-surface/70 p-4 shadow-[var(--shadow-card)] sm:p-5 md:flex-row md:items-center">
|
||||
<div>
|
||||
<button
|
||||
onClick={() => router.push(`/${classSlug}/flashcards`)}
|
||||
|
|
@ -103,7 +103,8 @@ export default function DeckStudyPage() {
|
|||
</svg>
|
||||
Back to decks
|
||||
</button>
|
||||
<h1 className="text-xl font-bold text-text-heading">{deck.name}</h1>
|
||||
<p className="text-xs font-bold uppercase tracking-[0.16em] text-primary">Flashcard session</p>
|
||||
<h1 className="editorial-title mt-1 text-3xl text-text-heading">{deck.name}</h1>
|
||||
{deck.description && (
|
||||
<p className="text-sm text-text-secondary mt-1">{deck.description}</p>
|
||||
)}
|
||||
|
|
@ -126,7 +127,7 @@ export default function DeckStudyPage() {
|
|||
<div className="flex items-center gap-2 md:gap-4 ml-auto">
|
||||
<ShareMenu targetType="DECK" contentId={deck.id} classSlug={classSlug} />
|
||||
|
||||
<div className="flex bg-bg-surface-alt rounded-lg p-0.5 border border-border-light">
|
||||
<div className="flex rounded-xl border border-border-light bg-bg-surface-alt p-1">
|
||||
<button
|
||||
onClick={() => setView("study")}
|
||||
className={`px-4 py-2 rounded-md text-sm font-medium transition-all duration-200 cursor-pointer ${
|
||||
|
|
|
|||
|
|
@ -76,8 +76,8 @@ function SortableDeckCard({ deck, onEdit, onDelete, classSlug }: any) {
|
|||
const progressLabel = getProgressLabel(deck);
|
||||
|
||||
return (
|
||||
<div ref={setNodeRef} style={style} className="group flex flex-col bg-bg-surface rounded-xl border border-border-light shadow-[var(--shadow-card)] hover:shadow-[var(--shadow-card-hover)] hover:border-primary/20 transition-all duration-300 h-full">
|
||||
<div className="p-4 flex flex-col flex-1 h-full">
|
||||
<div ref={setNodeRef} style={style} className="group flex h-full flex-col rounded-2xl border border-border-light bg-bg-surface shadow-[var(--shadow-card)] transition-all duration-300 hover:-translate-y-0.5 hover:border-primary/25 hover:shadow-[var(--shadow-card-hover)]">
|
||||
<div className="flex h-full flex-1 flex-col p-5">
|
||||
<div className="flex items-start gap-2">
|
||||
<div {...attributes} {...listeners} className="mt-1 cursor-grab active:cursor-grabbing text-text-muted hover:text-text-heading">
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
|
|
@ -85,7 +85,7 @@ function SortableDeckCard({ deck, onEdit, onDelete, classSlug }: any) {
|
|||
</svg>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-semibold text-text-heading mb-1">{deck.name}</h3>
|
||||
<h3 className="mb-1 text-lg font-extrabold text-text-heading">{deck.name}</h3>
|
||||
{deck.description && <p className="text-sm text-text-secondary mb-3 line-clamp-2">{deck.description}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -369,15 +369,15 @@ export default function FlashcardsPage() {
|
|||
const activeDeck = decks.find(d => d.id === activeId);
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 pb-20">
|
||||
<div className="pb-20">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-xl font-semibold text-text-heading">Flashcard Decks</h2>
|
||||
<div className="flex items-center gap-3">
|
||||
<button onClick={() => setIsCreatingGroup(true)} className="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg bg-bg-surface-alt text-text-heading font-medium border border-border-light hover:bg-border transition-all duration-200 shadow-sm cursor-pointer">
|
||||
<div className="mb-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div><p className="text-xs font-bold uppercase tracking-[0.16em] text-primary">Collection</p><h2 className="editorial-title mt-1 text-3xl text-text-heading">Flashcard decks</h2></div>
|
||||
<div className="grid grid-cols-2 gap-3 sm:flex">
|
||||
<button onClick={() => setIsCreatingGroup(true)} className="inline-flex min-h-12 items-center justify-center gap-2 rounded-xl border border-border-light bg-bg-surface px-4 font-bold text-text-heading shadow-sm transition-colors hover:bg-bg-surface-alt">
|
||||
Add Group
|
||||
</button>
|
||||
<button onClick={() => setShowImport(true)} className="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg bg-primary text-white font-medium hover:bg-primary-hover transition-all duration-200 shadow-sm cursor-pointer">
|
||||
<button onClick={() => setShowImport(true)} className="inline-flex min-h-12 items-center justify-center gap-2 rounded-xl bg-primary px-4 font-bold text-white shadow-sm transition-colors hover:bg-primary-hover">
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
||||
</svg>
|
||||
|
|
@ -387,7 +387,7 @@ export default function FlashcardsPage() {
|
|||
</div>
|
||||
|
||||
{isCreatingGroup && (
|
||||
<div className="mb-6 p-4 bg-bg-surface rounded-xl border border-primary/20 shadow-sm flex items-center gap-3">
|
||||
<div className="animate-slide-up mb-6 flex flex-col gap-3 rounded-2xl border border-primary/20 bg-bg-surface p-5 shadow-sm sm:flex-row sm:items-center">
|
||||
<input
|
||||
autoFocus
|
||||
type="text"
|
||||
|
|
@ -407,8 +407,8 @@ export default function FlashcardsPage() {
|
|||
|
||||
{editingId && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40 backdrop-blur-sm">
|
||||
<div className="bg-bg-surface rounded-xl p-6 w-full max-w-md shadow-lg border border-border">
|
||||
<h3 className="text-lg font-semibold text-text-heading mb-4">Edit Deck</h3>
|
||||
<div className="w-full max-w-md rounded-3xl border border-border bg-bg-surface p-6 shadow-[var(--shadow-modal)]">
|
||||
<h3 className="editorial-title mb-4 text-2xl text-text-heading">Edit deck</h3>
|
||||
<input
|
||||
type="text"
|
||||
value={editName}
|
||||
|
|
@ -443,7 +443,7 @@ export default function FlashcardsPage() {
|
|||
<DndContext sensors={sensors} collisionDetection={pointerWithin} onDragStart={handleDragStart} onDragOver={handleDragOver} onDragEnd={handleDragEnd}>
|
||||
<div className="space-y-8">
|
||||
{groupedDecks.map(group => (
|
||||
<div key={group.id} className="bg-bg-surface-alt/30 p-4 rounded-xl border border-border-light">
|
||||
<div key={group.id} className="rounded-2xl border border-border-light bg-bg-surface/70 p-4 shadow-[var(--shadow-card)] sm:p-5">
|
||||
<div className={`flex items-center justify-between ${collapsedGroups[group.id] ? "" : "mb-4"}`}>
|
||||
{editingGroupId === group.id ? (
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
@ -456,7 +456,7 @@ export default function FlashcardsPage() {
|
|||
<button onClick={() => toggleGroup(group.id)} className="p-1 rounded text-text-muted hover:text-text-heading hover:bg-bg-surface transition-colors cursor-pointer" title={collapsedGroups[group.id] ? "Expand" : "Collapse"}>
|
||||
<svg className={`w-5 h-5 transition-transform duration-200 ${collapsedGroups[group.id] ? '-rotate-90' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
|
||||
</button>
|
||||
<h3 className="text-lg font-semibold text-text-heading">{group.name}</h3>
|
||||
<h3 className="text-lg font-extrabold text-text-heading">{group.name}</h3>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -484,7 +484,7 @@ export default function FlashcardsPage() {
|
|||
))}
|
||||
|
||||
{/* Uncategorized */}
|
||||
<div className="bg-bg-surface-alt/30 p-4 rounded-xl border border-border-light">
|
||||
<div className="rounded-2xl border border-border-light bg-bg-surface/70 p-4 shadow-[var(--shadow-card)] sm:p-5">
|
||||
<div className={`flex items-center gap-2 ${collapsedGroups["uncategorized"] ? "" : "mb-4"}`}>
|
||||
<button onClick={() => toggleGroup("uncategorized")} className="p-1 rounded text-text-muted hover:text-text-heading hover:bg-bg-surface transition-colors cursor-pointer" title={collapsedGroups["uncategorized"] ? "Expand" : "Collapse"}>
|
||||
<svg className={`w-5 h-5 transition-transform duration-200 ${collapsedGroups["uncategorized"] ? '-rotate-90' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export default async function ClassLayout(props: LayoutProps<"/[classSlug]">) {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<div className="app-page">
|
||||
{/* Dynamic Header & Tabs */}
|
||||
<ClassHeader classSlug={classSlug} className={classData.name} />
|
||||
|
||||
|
|
|
|||
|
|
@ -124,9 +124,9 @@ export default function QuizStudyPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto w-full py-2 md:py-4">
|
||||
<div className="mx-auto w-full max-w-5xl py-1 md:py-3">
|
||||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row items-start justify-between gap-4 mb-6">
|
||||
<div className="mb-7 flex flex-col items-start justify-between gap-4 rounded-2xl border border-border-light bg-bg-surface/70 p-4 shadow-[var(--shadow-card)] sm:p-5 md:flex-row">
|
||||
<div>
|
||||
<button
|
||||
onClick={() => router.push(`/${classSlug}/quizzes`)}
|
||||
|
|
@ -142,7 +142,7 @@ export default function QuizStudyPage() {
|
|||
onClick={() => setShowTopics(!showTopics)}
|
||||
className="flex items-center gap-2 group cursor-pointer text-left focus:outline-none mb-2"
|
||||
>
|
||||
<h1 className="text-3xl font-bold font-serif text-text-heading group-hover:text-primary transition-colors">
|
||||
<h1 className="editorial-title text-3xl text-text-heading transition-colors group-hover:text-primary sm:text-4xl">
|
||||
{quiz.name}
|
||||
</h1>
|
||||
<svg
|
||||
|
|
@ -180,7 +180,7 @@ export default function QuizStudyPage() {
|
|||
<ShareMenu targetType="QUIZ" contentId={quiz.id} classSlug={classSlug} />
|
||||
|
||||
{attempts.length > 0 && (
|
||||
<div className="flex bg-bg-surface-alt rounded-lg p-0.5 border border-border-light">
|
||||
<div className="flex rounded-xl border border-border-light bg-bg-surface-alt p-1">
|
||||
<button
|
||||
onClick={() => setView("history")}
|
||||
className={`px-4 py-2 rounded-md text-sm font-medium transition-all duration-200 cursor-pointer ${
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ function SortableQuizCard({ quiz, onEdit, onDelete, classSlug }: any) {
|
|||
};
|
||||
|
||||
return (
|
||||
<div ref={setNodeRef} style={style} className="group bg-bg-surface rounded-xl border border-border-light shadow-[var(--shadow-card)] hover:shadow-[var(--shadow-card-hover)] hover:border-primary/20 transition-all duration-300">
|
||||
<div className="p-4 flex flex-col flex-1 h-full">
|
||||
<div ref={setNodeRef} style={style} className="group rounded-2xl border border-border-light bg-bg-surface shadow-[var(--shadow-card)] transition-all duration-300 hover:-translate-y-0.5 hover:border-primary/25 hover:shadow-[var(--shadow-card-hover)]">
|
||||
<div className="flex h-full flex-1 flex-col p-5">
|
||||
<div className="flex items-start gap-2">
|
||||
<div {...attributes} {...listeners} className="mt-1 cursor-grab active:cursor-grabbing text-text-muted hover:text-text-heading">
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
|
|
@ -63,7 +63,7 @@ function SortableQuizCard({ quiz, onEdit, onDelete, classSlug }: any) {
|
|||
</svg>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-semibold text-text-heading mb-1">{quiz.name}</h3>
|
||||
<h3 className="mb-1 text-lg font-extrabold text-text-heading">{quiz.name}</h3>
|
||||
{quiz.description && <p className="text-sm text-text-secondary mb-3 line-clamp-2">{quiz.description}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -343,15 +343,15 @@ export default function QuizzesPage() {
|
|||
const activeQuiz = quizzes.find(q => q.id === activeId);
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 pb-20">
|
||||
<div className="pb-20">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-xl font-semibold text-text-heading">Quizzes</h2>
|
||||
<div className="flex items-center gap-3">
|
||||
<button onClick={() => setIsCreatingGroup(true)} className="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg bg-bg-surface-alt text-text-heading font-medium border border-border-light hover:bg-border transition-all duration-200 shadow-sm cursor-pointer">
|
||||
<div className="mb-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div><p className="text-xs font-bold uppercase tracking-[0.16em] text-primary">Practice</p><h2 className="editorial-title mt-1 text-3xl text-text-heading">Practice quizzes</h2></div>
|
||||
<div className="grid grid-cols-2 gap-3 sm:flex">
|
||||
<button onClick={() => setIsCreatingGroup(true)} className="inline-flex min-h-12 items-center justify-center gap-2 rounded-xl border border-border-light bg-bg-surface px-4 font-bold text-text-heading shadow-sm transition-colors hover:bg-bg-surface-alt">
|
||||
Add Group
|
||||
</button>
|
||||
<button onClick={() => setShowImport(true)} className="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg bg-primary text-white font-medium hover:bg-primary-hover transition-all duration-200 shadow-sm cursor-pointer">
|
||||
<button onClick={() => setShowImport(true)} className="inline-flex min-h-12 items-center justify-center gap-2 rounded-xl bg-primary px-4 font-bold text-white shadow-sm transition-colors hover:bg-primary-hover">
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
||||
</svg>
|
||||
|
|
@ -361,7 +361,7 @@ export default function QuizzesPage() {
|
|||
</div>
|
||||
|
||||
{isCreatingGroup && (
|
||||
<div className="mb-6 p-4 bg-bg-surface rounded-xl border border-primary/20 shadow-sm flex items-center gap-3">
|
||||
<div className="animate-slide-up mb-6 flex flex-col gap-3 rounded-2xl border border-primary/20 bg-bg-surface p-5 shadow-sm sm:flex-row sm:items-center">
|
||||
<input
|
||||
autoFocus
|
||||
type="text"
|
||||
|
|
@ -382,8 +382,8 @@ export default function QuizzesPage() {
|
|||
{/* Editing quiz modal/inline - simplified as a modal-like overlay for simplicity when editing */}
|
||||
{editingId && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40 backdrop-blur-sm">
|
||||
<div className="bg-bg-surface rounded-xl p-6 w-full max-w-md shadow-lg border border-border">
|
||||
<h3 className="text-lg font-semibold text-text-heading mb-4">Edit Quiz</h3>
|
||||
<div className="w-full max-w-md rounded-3xl border border-border bg-bg-surface p-6 shadow-[var(--shadow-modal)]">
|
||||
<h3 className="editorial-title mb-4 text-2xl text-text-heading">Edit quiz</h3>
|
||||
<input
|
||||
type="text"
|
||||
value={editName}
|
||||
|
|
@ -418,7 +418,7 @@ export default function QuizzesPage() {
|
|||
<DndContext sensors={sensors} collisionDetection={pointerWithin} onDragStart={handleDragStart} onDragOver={handleDragOver} onDragEnd={handleDragEnd}>
|
||||
<div className="space-y-8">
|
||||
{groupedQuizzes.map(group => (
|
||||
<div key={group.id} className="bg-bg-surface-alt/30 p-4 rounded-xl border border-border-light">
|
||||
<div key={group.id} className="rounded-2xl border border-border-light bg-bg-surface/70 p-4 shadow-[var(--shadow-card)] sm:p-5">
|
||||
<div className={`flex items-center justify-between ${collapsedGroups[group.id] ? "" : "mb-4"}`}>
|
||||
{editingGroupId === group.id ? (
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
@ -431,7 +431,7 @@ export default function QuizzesPage() {
|
|||
<button onClick={() => toggleGroup(group.id)} className="p-1 rounded text-text-muted hover:text-text-heading hover:bg-bg-surface transition-colors cursor-pointer" title={collapsedGroups[group.id] ? "Expand" : "Collapse"}>
|
||||
<svg className={`w-5 h-5 transition-transform duration-200 ${collapsedGroups[group.id] ? '-rotate-90' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
|
||||
</button>
|
||||
<h3 className="text-lg font-semibold text-text-heading">{group.name}</h3>
|
||||
<h3 className="text-lg font-extrabold text-text-heading">{group.name}</h3>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -459,7 +459,7 @@ export default function QuizzesPage() {
|
|||
))}
|
||||
|
||||
{/* Uncategorized */}
|
||||
<div className="bg-bg-surface-alt/30 p-4 rounded-xl border border-border-light">
|
||||
<div className="rounded-2xl border border-border-light bg-bg-surface/70 p-4 shadow-[var(--shadow-card)] sm:p-5">
|
||||
<div className={`flex items-center gap-2 ${collapsedGroups["uncategorized"] ? "" : "mb-4"}`}>
|
||||
<button onClick={() => toggleGroup("uncategorized")} className="p-1 rounded text-text-muted hover:text-text-heading hover:bg-bg-surface transition-colors cursor-pointer" title={collapsedGroups["uncategorized"] ? "Expand" : "Collapse"}>
|
||||
<svg className={`w-5 h-5 transition-transform duration-200 ${collapsedGroups["uncategorized"] ? '-rotate-90' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue