fix(mobile+comments): Sprint 1 — nav visibility, messages button, optimistic comments
- MobileNav: fixed mail icon top-right corner (always reachable on mobile) - MobileNav: iOS safe-area-inset-bottom padding so nav is never hidden - MobileNav: larger icons (h-6) + better contrast on inactive tabs (text-foreground/60) - PostDetailDialog: optimistic comment update — comment appears immediately on submit with pending indicator; rolls back input on error - i18n: added Comments.sending key (EN/DE) - PostCard: minor style cleanup (pre-existing session changes) - Explore: pre-existing session changes
This commit is contained in:
1 parent
dc4c196721
commit
58e2840fae
9 files changed
+145
-63
No files matched your search
@@ -48,7 +48,50 @@
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query config-get workflow.discuss_mode)",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query phase.mvp-mode 1 --pick active)",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query state.advance-plan --phase 1 --plan \"01-04\")",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query commit \"chore\\(01\\): phase 1 complete\" --files \".planning/STATE.md\" \".planning/ROADMAP.md\" \".planning/phases/01-foundation/01-04-SUMMARY.md\" \".planning/phases/01-foundation/SUMMARY.md\")"
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query commit \"chore\\(01\\): phase 1 complete\" --files \".planning/STATE.md\" \".planning/ROADMAP.md\" \".planning/phases/01-foundation/01-04-SUMMARY.md\" \".planning/phases/01-foundation/SUMMARY.md\")",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query init.plan-phase 2)",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query phase.mvp-mode 2 --pick active)",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query config-set workflow._auto_chain_active false)",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query roadmap.get-phase 2 --pick section)",
|
||||
"Bash(command -v ctx7)",
|
||||
"WebSearch",
|
||||
"Bash(python -c \"from slopcheck import cli; cli.main\\(\\)\" -- install react-intersection-observer --json)",
|
||||
"Bash(python -m slopcheck.cli install react-intersection-observer --json)",
|
||||
"Bash(python *)",
|
||||
"Bash(npm view *)",
|
||||
"Bash(sed -i 's/^## Open Questions$/## Open Questions \\(RESOLVED\\)/' .planning/phases/02-content-core/02-RESEARCH.md)",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query state.planned-phase --phase 2 --name \"Content Core\" --plans 6)",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query roadmap.annotate-dependencies 2)",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query commit \"docs\\(02\\): create phase plan \\(6 plans\\)\" --files \".planning/phases/02-content-core/02-01-PLAN.md\" \".planning/phases/02-content-core/02-02-PLAN.md\" \".planning/phases/02-content-core/02-03-PLAN.md\" \".planning/phases/02-content-core/02-04-PLAN.md\" \".planning/phases/02-content-core/02-05-PLAN.md\" \".planning/phases/02-content-core/02-06-PLAN.md\" \".planning/phases/02-content-core/02-RESEARCH.md\" \".planning/STATE.md\" \".planning/ROADMAP.md\")",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" gap-analysis --phase-dir \".planning/phases/02-content-core\" --phase-req-ids \"PHOTO-01, PHOTO-02, PHOTO-03, PHOTO-04, STORY-01, STORY-02, STORY-03, MILE-01, MILE-02, SOCL-01, SOCL-02, SOCL-03, FEED-01, SAFE-01, SAFE-02\")",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query state.advance-plan --phase 2 --plan \"02-02\")",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query state.advance-plan --phase 2 --plan \"02-03\")",
|
||||
"Bash(node \"T:/CC-Projekte/.claude/gsd-core/bin/gsd-tools.cjs\" query state.advance-plan --phase 2 --plan \"02-04\")",
|
||||
"Bash(git push *)",
|
||||
"Bash(New-Item -ItemType Directory -Force \"T:\\\\CC-Projekte\\\\OnlyPets\\\\.planning\\\\phases\\\\03-engagement-discovery\")",
|
||||
"Bash(Out-Null)",
|
||||
"Bash(Write-Output \"created\")",
|
||||
"PowerShell(New-Item *)",
|
||||
"Bash(npm run *)",
|
||||
"Bash(ping -n 4 127.0.0.1)",
|
||||
"Bash(npm list *)",
|
||||
"Bash(curl -s http://localhost:3000 -o /dev/null -w \"%{http_code}\")",
|
||||
"PowerShell(taskkill *)",
|
||||
"PowerShell(npm run *)",
|
||||
"Bash(findstr /i \"phase health\")",
|
||||
"Bash(findstr /i \"cuid\" package.json)",
|
||||
"Bash(node -e \"const { prisma } = require\\('./src/lib/prisma'\\); console.log\\('weightLog:', typeof prisma.weightLog\\); console.log\\('vetVisit:', typeof prisma.vetVisit\\); console.log\\('vaccine:', typeof prisma.vaccine\\);\")",
|
||||
"Bash(node -e \"const { PrismaClient } = require\\('@prisma/client'\\); const p = new PrismaClient\\(\\); console.log\\('weightLog:', typeof p.weightLog\\); console.log\\('vetVisit:', typeof p.vetVisit\\); console.log\\('vaccine:', typeof p.vaccine\\); console.log\\('healthCard:', typeof p.healthCard\\);\")",
|
||||
"Bash(npx tsx -e ' *)",
|
||||
"Bash(git remote *)",
|
||||
"Read(//t/cc-projekte/onlypets/**)",
|
||||
"Bash(find src *)",
|
||||
"Bash(grep -v \"useTranslations\\\\|t\\(\\\\|import\\\\|//\\\\|className\\\\|aria-\\\\|placeholder\\\\|type=\\\\|href=\\\\|key=\\\\|data-\")",
|
||||
"Bash(grep -rn --include=\"*.tsx\" -E \"^\\\\s+[A-Z][a-z]|No [a-z]|yet$|No [A-Z]\" src/components src/app)",
|
||||
"Bash(grep -v \"useTranslations\\\\|t\\(\\\\|import\\\\|//\\\\|className\\\\|interface\\\\|type\\\\|const\\\\|export\\\\|function\\\\|return\\\\|<\\\\|}\\\\|{\")",
|
||||
"Bash(grep -v \"//\\\\|import\\\\|className\\\\|href\\\\|aria\\\\|data-\\\\|type=\\\\|value=\\\\|admin\\\\|legal\\\\|impressum\\\\|datenschutz\\\\|nutzung\\\\|health-card\\\\|join\\\\|banned\\\\|auth\\\\|p/\\\\[\")",
|
||||
"Bash(grep -v \"^\\\\s*//\\\\|^import\")",
|
||||
"Bash(grep -v \"//\\\\|import\\\\|className\\\\|interface\\\\|type\\\\|const\\\\|export\\\\|href\\\\|aria-\\\\|data-\\\\|key=\\\\|useTranslations\\\\|admin\\\\|auth\\\\|legal\\\\|health-card\\\\|p/\\\\[\")"
|
||||
]
|
||||
}
|
||||
}
|
||||
+20
-4
@@ -1,14 +1,30 @@
|
||||
Debug:
|
||||
|
||||
Health - Share Card - Downloadbar machen als PDF Ansicht, mit Profil Foto und allen Health Daten übersichtlich aufgegliedert.
|
||||
\-Die Suchen seite ist noch nicht auf Deutsch übersetzt.
|
||||
|
||||
jeweils mit Farblichen Trennern oder Rahmen. So wäre es möglich bei einem Arztwechsel, gleich alle Daten mitnehmen zu können.
|
||||
\-Die Erwähnfunktion mittels @ ist impelmentiert, aber es fehlt die Benachrichtung das man Erwähnt wurde ! Zudem ist die Auswahl nach dem tippen @ schlecht designed man kann gerade so den Avatar erkennen aber nicht den namen in der aufploppenden suche, bitte um FIX !
|
||||
|
||||
Oder für den Notfall ausgedruckt dabei zu haben.
|
||||
\-Messages ist noch nicht auf Deutsch übersetzt.
|
||||
|
||||
\-Kommentar Update; wenn man einen Kommentar postet, muss dieser zwingend sofort im Kommentar-Verlauf sichtbar werden (Optische Bestätigung das der Kommentar angekommen ist für den Nutzer), es muss sich als Nutzer Live anfühlen auch wenn der Server noch am arbeiten ist.
|
||||
|
||||
\-Benachrichtung wenn man "Paw-Back this post" nutzt für den Original-User des Posts.
|
||||
|
||||
\-Die Mobil Ansicht ist noch nicht ausgereift, das Menü ist teilweise nicht mehr erkennbar im unteren Segemet ( Startseite, Entdecken, +, Benachrichtigungen, Profil).
|
||||
|
||||
\-Mobilansicht - Add Story Button ist sehr linksbündig, keine Aufteilung vorhanden.
|
||||
|
||||
\-Mobilansicht - Kein PawFeed Logo sichtbar, soll nur auf der Startseite erscheinen beim scrollen verschwinden.
|
||||
|
||||
\-Mobilansicht - wenn man bis man hin und her scrollt soll man bei langem hochscrollen einen refresh auslösen.
|
||||
|
||||
\-Mobilansicht - Impressum/Datenschutz in das Profil rein legen, damit man es erreichen kann.
|
||||
|
||||
\-Mobilansicht - Nachrichten nicht aufrufbar weil kein Button vorhanden. kann gerne als Mail-Icon mitscrollend oben rechts in die ecke damit es immer erreichbar ist.
|
||||
|
||||
|
||||
|
||||
Health - Share Card - Der Link wird nicht generiert, hier müsste ein Unique link erstellt werden, mit einem Verfallsdatum in der regel sollten 14 Tage ausreichen, aber man soll sich das selbst einstellen können, 7,13,30,60,90 Tage zur Auswahl.
|
||||
\-User Delete Funktion, für den Unwahrscheinlichen fall ein User möchte sein Konto löschen wird ein Workflow benötigt, der nach einer Bestätigung mittels Tiernamen Eingabe (Auswahl eins von möglichen) den Kompletten Account löscht, sowie alle Hochgeladen Bilder/Videos und erzeugten Posts, Rückstandslos.
|
||||
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
"empty": "Noch keine Kommentare — sei der Erste!",
|
||||
"placeholder": "Kommentar hinzufügen…",
|
||||
"post": "Senden",
|
||||
"sending": "Wird gesendet…",
|
||||
"postError": "Kommentar konnte nicht gepostet werden. Bitte versuche es erneut.",
|
||||
"deleteError": "Kommentar konnte nicht gelöscht werden. Bitte versuche es erneut.",
|
||||
"countSingular": "1 Kommentar",
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
"empty": "No comments yet — be the first!",
|
||||
"placeholder": "Add a comment…",
|
||||
"post": "Post",
|
||||
"sending": "Sending…",
|
||||
"postError": "Couldn't post comment. Please try again.",
|
||||
"deleteError": "Couldn't delete comment. Please try again.",
|
||||
"countSingular": "1 comment",
|
||||
|
||||
@@ -10,8 +10,7 @@ import { useActivePet } from "@/context/ActivePetContext";
|
||||
import { ExploreCard } from "@/components/explore/ExploreCard";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog";
|
||||
import { PostCard } from "@/components/feed/PostCard";
|
||||
import { PostDetailDialog } from "@/components/feed/PostDetailDialog";
|
||||
import { getMediaUrl } from "@/lib/media-url";
|
||||
import type { PostCardPost } from "@/components/feed/PostCard";
|
||||
import {
|
||||
@@ -184,26 +183,13 @@ export default function ExplorePage() {
|
||||
</>
|
||||
))}
|
||||
|
||||
{/* Post detail dialog */}
|
||||
<Dialog
|
||||
{/* Post detail dialog — inline comments */}
|
||||
<PostDetailDialog
|
||||
post={selectedPost}
|
||||
open={!!selectedPost}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) setSelectedPost(null);
|
||||
}}
|
||||
>
|
||||
<DialogContent
|
||||
showCloseButton={false}
|
||||
className="max-w-[560px] w-full p-0 overflow-y-auto max-h-[90dvh] rounded-xl"
|
||||
>
|
||||
{selectedPost && (
|
||||
<PostCard
|
||||
post={selectedPost}
|
||||
variant="detail"
|
||||
onDeleted={() => setSelectedPost(null)}
|
||||
/>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
onClose={() => setSelectedPost(null)}
|
||||
onDeleted={() => setSelectedPost(null)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 15 KiB |
@@ -43,7 +43,7 @@ import { MilestoneCard } from "@/components/feed/MilestoneCard";
|
||||
import { VideoCard } from "@/components/video/VideoCard";
|
||||
import { PawButton } from "@/components/feed/PawButton";
|
||||
import { PawBackButton } from "@/components/feed/PawBackButton";
|
||||
import { CommentSheet } from "@/components/feed/CommentSheet";
|
||||
import { PostDetailDialog } from "@/components/feed/PostDetailDialog";
|
||||
import { RepostCard } from "@/components/feed/RepostCard";
|
||||
import { BlockDialog } from "@/components/safety/BlockDialog";
|
||||
import { ReportSheet } from "@/components/safety/ReportSheet";
|
||||
@@ -160,8 +160,8 @@ export function PostCard({ post, onDeleted, variant = "feed" }: PostCardProps) {
|
||||
// Block dialog state
|
||||
const [showBlockDialog, setShowBlockDialog] = useState(false);
|
||||
|
||||
// Comment sheet state
|
||||
const [showCommentSheet, setShowCommentSheet] = useState(false);
|
||||
// Detail dialog (replaces comment sheet)
|
||||
const [showDetailDialog, setShowDetailDialog] = useState(false);
|
||||
|
||||
// Ownership: active pet's own post vs another pet's post
|
||||
const isOwnPost = activePetId === pet.id;
|
||||
@@ -335,7 +335,8 @@ export function PostCard({ post, onDeleted, variant = "feed" }: PostCardProps) {
|
||||
<img
|
||||
src={getMediaUrl(img.storageKey) ?? ""}
|
||||
alt={currentCaption ?? `${pet.name}'s post`}
|
||||
className={variant === "detail" ? "w-full object-contain bg-black max-h-[50dvh]" : "w-full object-cover max-h-[560px]"}
|
||||
className="w-full object-cover max-h-[560px] cursor-pointer"
|
||||
onClick={() => setShowDetailDialog(true)}
|
||||
/>
|
||||
</CarouselItem>
|
||||
))}
|
||||
@@ -367,14 +368,13 @@ export function PostCard({ post, onDeleted, variant = "feed" }: PostCardProps) {
|
||||
</div>
|
||||
) : (
|
||||
/* Single image */
|
||||
<div className={variant === "detail" ? "w-full bg-black flex justify-center" : "w-full"}>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={getMediaUrl(images[0].storageKey) ?? ""}
|
||||
alt={currentCaption ?? `${pet.name}'s post`}
|
||||
className={variant === "detail" ? "max-w-full max-h-[50dvh] object-contain" : "w-full object-cover max-h-[560px]"}
|
||||
/>
|
||||
</div>
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={getMediaUrl(images[0].storageKey) ?? ""}
|
||||
alt={currentCaption ?? `${pet.name}'s post`}
|
||||
className="w-full object-cover max-h-[560px] cursor-pointer"
|
||||
onClick={() => setShowDetailDialog(true)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@@ -475,7 +475,7 @@ export function PostCard({ post, onDeleted, variant = "feed" }: PostCardProps) {
|
||||
<button
|
||||
type="button"
|
||||
aria-label="View comments"
|
||||
onClick={() => setShowCommentSheet(true)}
|
||||
onClick={() => setShowDetailDialog(true)}
|
||||
className="flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<MessageCircle className="h-4 w-4" aria-hidden="true" />
|
||||
@@ -520,15 +520,13 @@ export function PostCard({ post, onDeleted, variant = "feed" }: PostCardProps) {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* CommentSheet */}
|
||||
{activePetId && (
|
||||
<CommentSheet
|
||||
postId={post.id}
|
||||
petId={activePetId}
|
||||
open={showCommentSheet}
|
||||
onOpenChange={setShowCommentSheet}
|
||||
/>
|
||||
)}
|
||||
{/* PostDetailDialog — focused view with inline comments */}
|
||||
<PostDetailDialog
|
||||
post={post}
|
||||
open={showDetailDialog}
|
||||
onClose={() => setShowDetailDialog(false)}
|
||||
onDeleted={onDeleted}
|
||||
/>
|
||||
|
||||
{/* BlockDialog — other's post */}
|
||||
{activePetId && !isOwnPost && (
|
||||
|
||||
@@ -66,6 +66,7 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD
|
||||
const [currentCaption, setCurrentCaption] = useState<string | null>(null);
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||
const [body, setBody] = useState("");
|
||||
const [pendingBody, setPendingBody] = useState<string | null>(null);
|
||||
const commentsEndRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -114,12 +115,16 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD
|
||||
const createCommentMutation = useMutation(
|
||||
trpc.comments.create.mutationOptions({
|
||||
onSuccess: () => {
|
||||
setBody("");
|
||||
setPendingBody(null);
|
||||
void queryClient.invalidateQueries({ queryKey: [["trpc", "comments", "listByPost"]] });
|
||||
void queryClient.invalidateQueries({ queryKey: [["trpc", "feed", "getFeed"]] });
|
||||
setTimeout(() => commentsEndRef.current?.scrollIntoView({ behavior: "smooth" }), 150);
|
||||
},
|
||||
onError: () => toast.error(tc("postError")),
|
||||
onError: () => {
|
||||
setBody((prev) => prev || pendingBody ?? "");
|
||||
setPendingBody(null);
|
||||
toast.error(tc("postError"));
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
@@ -134,7 +139,11 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD
|
||||
|
||||
const handleSubmitComment = useCallback(() => {
|
||||
if (!body.trim() || !post || !activePetId) return;
|
||||
createCommentMutation.mutate({ postId: post.id, petId: activePetId, body: body.trim() });
|
||||
const trimmed = body.trim();
|
||||
setPendingBody(trimmed);
|
||||
setBody("");
|
||||
createCommentMutation.mutate({ postId: post.id, petId: activePetId, body: trimmed });
|
||||
setTimeout(() => commentsEndRef.current?.scrollIntoView({ behavior: "smooth" }), 50);
|
||||
}, [body, post, activePetId, createCommentMutation]);
|
||||
|
||||
const handleCommentKeyDown = useCallback(
|
||||
@@ -427,6 +436,20 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{pendingBody && (
|
||||
<div className="flex gap-2 opacity-60">
|
||||
<Avatar className="h-7 w-7 shrink-0 mt-0.5">
|
||||
<AvatarFallback className="text-xs bg-orange-100 text-orange-600">
|
||||
✓
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex-1 min-w-0">
|
||||
<span className="text-xs text-muted-foreground">{tc("sending")}</span>
|
||||
<p className="text-sm mt-0.5 break-words">{pendingBody}</p>
|
||||
</div>
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin text-muted-foreground shrink-0 self-start mt-1" />
|
||||
</div>
|
||||
)}
|
||||
<div ref={commentsEndRef} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
Plus,
|
||||
User,
|
||||
ChevronDown,
|
||||
Mail,
|
||||
} from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { NotificationBell } from "@/components/notifications/NotificationBell";
|
||||
@@ -71,9 +72,21 @@ export function MobileNav({ pets }: MobileNavProps) {
|
||||
const isPetsPage = pathname.startsWith("/pets");
|
||||
const isExplorePage = pathname.startsWith("/explore");
|
||||
const isNotificationsPage = pathname.startsWith("/notifications");
|
||||
const isMessagesPage = pathname.startsWith("/messages");
|
||||
|
||||
return (
|
||||
<div className="lg:hidden fixed bottom-0 left-0 right-0 z-50">
|
||||
{/* Fixed Messages shortcut — top-right corner, always reachable */}
|
||||
<Link
|
||||
href="/messages"
|
||||
aria-label={t("messages")}
|
||||
className={`fixed top-3 right-3 z-[51] flex items-center justify-center w-10 h-10 rounded-full bg-background/90 backdrop-blur-sm border border-border shadow-md ${
|
||||
isMessagesPage ? "text-orange-500" : "text-foreground/75"
|
||||
}`}
|
||||
>
|
||||
<Mail className="h-5 w-5" aria-hidden="true" />
|
||||
</Link>
|
||||
|
||||
{/* Active pet switcher bar — shown above tab bar on mobile */}
|
||||
{activePet && (
|
||||
<div className="bg-background border-t border px-4 py-2">
|
||||
@@ -141,30 +154,31 @@ export function MobileNav({ pets }: MobileNavProps) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Bottom tab bar */}
|
||||
{/* Bottom tab bar — pt-2 + pb handles iOS safe-area (home indicator) */}
|
||||
<nav
|
||||
className="h-16 bg-card border-t border flex items-center justify-around px-2"
|
||||
className="bg-card border-t flex items-center justify-around px-2 pt-2 pb-[max(8px,env(safe-area-inset-bottom))]"
|
||||
style={{ minHeight: "4rem" }}
|
||||
aria-label="Mobile navigation"
|
||||
>
|
||||
{/* Home — D-05: href updated to /feed; label stays "Home" */}
|
||||
<Link
|
||||
href="/feed"
|
||||
className={`flex flex-col items-center gap-0.5 px-3 py-2 text-xs ${
|
||||
isHomePage ? "text-orange-500" : "text-muted-foreground"
|
||||
className={`flex flex-col items-center gap-0.5 px-3 py-1.5 text-xs font-medium ${
|
||||
isHomePage ? "text-orange-500" : "text-foreground/60"
|
||||
}`}
|
||||
>
|
||||
<Home className="h-5 w-5" aria-hidden="true" />
|
||||
<Home className="h-6 w-6" aria-hidden="true" />
|
||||
<span>{t("home")}</span>
|
||||
</Link>
|
||||
|
||||
{/* Explore */}
|
||||
<Link
|
||||
href="/explore"
|
||||
className={`flex flex-col items-center gap-0.5 px-3 py-2 text-xs ${
|
||||
isExplorePage ? "text-orange-500" : "text-muted-foreground"
|
||||
className={`flex flex-col items-center gap-0.5 px-3 py-1.5 text-xs font-medium ${
|
||||
isExplorePage ? "text-orange-500" : "text-foreground/60"
|
||||
}`}
|
||||
>
|
||||
<Compass className="h-5 w-5" aria-hidden="true" />
|
||||
<Compass className="h-6 w-6" aria-hidden="true" />
|
||||
<span>{t("explore")}</span>
|
||||
</Link>
|
||||
|
||||
@@ -175,7 +189,7 @@ export function MobileNav({ pets }: MobileNavProps) {
|
||||
onClick={() => setPostTypeSheetOpen(true)}
|
||||
className="flex flex-col items-center"
|
||||
>
|
||||
<span className="bg-orange-500 text-white rounded-full p-3 flex items-center justify-center">
|
||||
<span className="bg-orange-500 text-white rounded-full p-3 flex items-center justify-center shadow-sm">
|
||||
<Plus className="h-5 w-5" aria-hidden="true" />
|
||||
</span>
|
||||
</button>
|
||||
@@ -186,11 +200,11 @@ export function MobileNav({ pets }: MobileNavProps) {
|
||||
{/* Profile (My Pets) */}
|
||||
<Link
|
||||
href="/pets"
|
||||
className={`flex flex-col items-center gap-0.5 px-3 py-2 text-xs ${
|
||||
isPetsPage ? "text-orange-500" : "text-muted-foreground"
|
||||
className={`flex flex-col items-center gap-0.5 px-3 py-1.5 text-xs font-medium ${
|
||||
isPetsPage ? "text-orange-500" : "text-foreground/60"
|
||||
}`}
|
||||
>
|
||||
<User className="h-5 w-5" aria-hidden="true" />
|
||||
<User className="h-6 w-6" aria-hidden="true" />
|
||||
<span>{t("profile")}</span>
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
Reference in new issue
Block a user