fix: Resolve multiple mobile UX issues including swiping and header layouts
All checks were successful
Automated Container Build / build-and-push (push) Successful in 50s
All checks were successful
Automated Container Build / build-and-push (push) Successful in 50s
This commit is contained in:
parent
4ea58da3cd
commit
7d2c466e9b
4 changed files with 74 additions and 29 deletions
|
|
@ -92,7 +92,7 @@ export default function DeckStudyPage() {
|
|||
return (
|
||||
<div className="max-w-4xl mx-auto w-full py-2 md:py-4">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 mb-6">
|
||||
<div>
|
||||
<button
|
||||
onClick={() => router.push(`/${classSlug}/flashcards`)}
|
||||
|
|
|
|||
65
src/app/shared/[classSlug]/[type]/[token]/SharedViewer.tsx
Normal file
65
src/app/shared/[classSlug]/[type]/[token]/SharedViewer.tsx
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { FlashcardViewer } from "@/components/flashcards/FlashcardViewer";
|
||||
import { QuizViewer } from "@/components/quizzes/QuizViewer";
|
||||
|
||||
interface SharedViewerProps {
|
||||
type: string;
|
||||
data: any;
|
||||
}
|
||||
|
||||
export function SharedViewer({ type, data }: SharedViewerProps) {
|
||||
const [restartKey, setRestartKey] = useState(0);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 mb-8">
|
||||
<div className="text-left">
|
||||
<h1 className="text-2xl font-bold text-text-heading mb-2">
|
||||
{data.name}
|
||||
</h1>
|
||||
<p className="text-text-secondary">
|
||||
From class: <span className="font-medium text-text-heading">{data.class.name}</span>
|
||||
</p>
|
||||
{data.description && (
|
||||
<p className="text-sm text-text-secondary mt-2 max-w-2xl">
|
||||
{data.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
onClick={() => setRestartKey(k => k + 1)}
|
||||
className="p-1.5 rounded-lg text-text-muted hover:text-text-heading hover:bg-bg-surface-alt transition-all duration-200 cursor-pointer"
|
||||
title="Restart Session"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{type === "flashcards" ? (
|
||||
<FlashcardViewer
|
||||
key={restartKey}
|
||||
cards={data.cards}
|
||||
deckId={data.id}
|
||||
isShared={true}
|
||||
/>
|
||||
) : (
|
||||
<QuizViewer
|
||||
key={restartKey}
|
||||
quiz={{
|
||||
...data,
|
||||
progress: [], // Start fresh since it's shared
|
||||
}}
|
||||
retakeIds={null}
|
||||
isShared={true}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
import { getShareLink } from "@/services/shareService";
|
||||
import { notFound } from "next/navigation";
|
||||
import { FlashcardViewer } from "@/components/flashcards/FlashcardViewer";
|
||||
import { QuizViewer } from "@/components/quizzes/QuizViewer";
|
||||
import { ThemeToggle } from "@/components/ui/ThemeToggle";
|
||||
import Link from "next/link";
|
||||
import { SharedViewer } from "./SharedViewer";
|
||||
|
||||
interface SharedPageProps {
|
||||
params: Promise<{
|
||||
|
|
@ -52,7 +51,7 @@ export default async function SharedPage(props: SharedPageProps) {
|
|||
<div className="flex items-center gap-4">
|
||||
<ThemeToggle />
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-sm font-medium px-3 py-1 bg-badge-bg text-badge-text rounded-full">
|
||||
<span className="text-sm font-medium px-3 py-1 bg-badge-bg text-badge-text rounded-full hidden sm:inline-block">
|
||||
Read Only
|
||||
</span>
|
||||
<Link
|
||||
|
|
@ -70,29 +69,10 @@ export default async function SharedPage(props: SharedPageProps) {
|
|||
{/* Main Content */}
|
||||
<main className="flex-1 overflow-y-auto">
|
||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<div className="mb-8 text-center">
|
||||
<h1 className="text-2xl font-bold text-text-heading mb-2">
|
||||
{link.deck ? link.deck.name : link.quizSet?.name}
|
||||
</h1>
|
||||
<p className="text-text-secondary">
|
||||
From class: <span className="font-medium text-text-heading">{link.deck ? link.deck.class.name : link.quizSet?.class.name}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{type === "flashcards" && link.deck && (
|
||||
<FlashcardViewer cards={link.deck.cards} deckId={link.deck.id} isShared={true} />
|
||||
)}
|
||||
|
||||
{type === "quizzes" && link.quizSet && (
|
||||
<QuizViewer
|
||||
quiz={{
|
||||
...link.quizSet,
|
||||
progress: [], // Start fresh since it's shared
|
||||
}}
|
||||
retakeIds={null}
|
||||
isShared={true}
|
||||
/>
|
||||
)}
|
||||
<SharedViewer
|
||||
type={type}
|
||||
data={type === "flashcards" ? link.deck : link.quizSet}
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ export function FlashcardViewer({ cards, deckId, isShared = false, initialProgre
|
|||
|
||||
// Touch handlers for swipe
|
||||
function handleTouchStart(e: React.TouchEvent) {
|
||||
if (!isFlipped) return;
|
||||
if (!hasFlippedOnce) return;
|
||||
dragRef.current = {
|
||||
startX: e.touches[0].clientX,
|
||||
currentX: e.touches[0].clientX,
|
||||
|
|
@ -350,7 +350,7 @@ export function FlashcardViewer({ cards, deckId, isShared = false, initialProgre
|
|||
</ReactMarkdown>
|
||||
</div>
|
||||
<p className="mt-6 text-xs text-text-muted">
|
||||
Tap or press Space to flip
|
||||
Tap <span className="hidden md:inline">or press Space </span>to flip
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue