feat: chat reactions
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* The column that holds the header, page and footer.
|
||||
*
|
||||
* Exists as a client component for one reason: the bottom padding that
|
||||
* reserves space for the mobile tab bar has to disappear wherever the tab bar
|
||||
* does, and that decision depends on the route. Left in the server layout, the
|
||||
* padding would survive the bar and leave a 64px gap under a chat composer.
|
||||
*/
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useHidesAppChrome } from "@/lib/use-chrome-visibility";
|
||||
|
||||
export function AppShell({ children }: { children: React.ReactNode }) {
|
||||
const noTabBar = useHidesAppChrome();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-1 flex-col md:pl-16",
|
||||
// Matches SiteBottomNav's own visibility exactly.
|
||||
noTabBar ? "pb-0" : "pb-16 md:pb-0",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
useChatUnread,
|
||||
} from "@/components/layout/nav-unread-badge";
|
||||
import { useAuth } from "@/components/auth/auth-provider";
|
||||
import { useHidesAppChrome } from "@/lib/use-chrome-visibility";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type Item = {
|
||||
@@ -31,6 +32,7 @@ type Item = {
|
||||
|
||||
export function SiteBottomNav() {
|
||||
const pathname = usePathname();
|
||||
const hidden = useHidesAppChrome();
|
||||
const { user } = useAuth();
|
||||
// Read here rather than inside the badge so the count can also reach the
|
||||
// link's accessible name — the badge itself is decorative.
|
||||
@@ -97,6 +99,9 @@ export function SiteBottomNav() {
|
||||
return pathname === item.href || pathname.startsWith(`${item.href}/`);
|
||||
}
|
||||
|
||||
// A chat thread owns the bottom edge — its composer lives there.
|
||||
if (hidden) return null;
|
||||
|
||||
return (
|
||||
<nav
|
||||
aria-label="Primary"
|
||||
|
||||
@@ -26,6 +26,7 @@ import Link from "next/link";
|
||||
import { ReadingSettings } from "@/components/reading-settings";
|
||||
import { NotificationBell } from "@/components/layout/notification-bell";
|
||||
import { useAuth } from "@/components/auth/auth-provider";
|
||||
import { useHidesAppChrome } from "@/lib/use-chrome-visibility";
|
||||
|
||||
export function SiteHeader() {
|
||||
const { user, loading } = useAuth();
|
||||
@@ -33,6 +34,10 @@ export function SiteHeader() {
|
||||
// auth check we treat `loading` as anonymous so the gear doesn't flash
|
||||
// in and out — once auth resolves, it hides for signed-in users.
|
||||
const showMobileGear = !loading && !user;
|
||||
// A chat thread has its own header — back button, name, avatar — so the
|
||||
// wordmark bar would stack a second title above it.
|
||||
const hidden = useHidesAppChrome();
|
||||
if (hidden) return null;
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-30 bg-background/60 backdrop-blur-md">
|
||||
|
||||
@@ -17,6 +17,7 @@ import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { Menu } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useHidesAppChrome } from "@/lib/use-chrome-visibility";
|
||||
import {
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
@@ -43,6 +44,10 @@ export function MobileNavToggle({
|
||||
items: ReadonlyArray<NavItem>;
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
// A thread already has a back button in its own header; a hamburger beside
|
||||
// it offers a second, conflicting way out.
|
||||
const hidden = useHidesAppChrome();
|
||||
if (hidden) return null;
|
||||
|
||||
return (
|
||||
<Drawer open={open} onOpenChange={setOpen} direction="left">
|
||||
|
||||
Reference in New Issue
Block a user