fix: font loading and chat scrolling issues
- fix: Replace corrupted Merriweather fonts with valid WOFF2 files from @fontsource - fix: Use CSS @font-face instead of next/font/local for Merriweather (Next.js 16 compatibility) - fix: Add smart scroll detection to ChatWindow (respects manual scrolling) - feat: Update app title to "Brachnha Insight" - feat: Update app description Co-Authored-By: Claude (glm-4.7) <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
36
src/app/fonts.css
Normal file
36
src/app/fonts.css
Normal file
@@ -0,0 +1,36 @@
|
||||
/* Merriweather Font Faces */
|
||||
@font-face {
|
||||
font-family: 'Merriweather';
|
||||
src: url('/fonts/Merriweather-Light.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Merriweather';
|
||||
src: url('/fonts/Merriweather-Regular.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Merriweather';
|
||||
src: url('/fonts/Merriweather-Bold.woff2') format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Merriweather';
|
||||
src: url('/fonts/Merriweather-Black.woff2') format('woff2');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
:root {
|
||||
--font-merriweather: 'Merriweather', serif;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import localFont from "next/font/local";
|
||||
import "./globals.css";
|
||||
import "./fonts.css";
|
||||
import { OfflineIndicator } from "../components/features/common";
|
||||
import { InstallPrompt } from "../components/features/pwa/install-prompt";
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
@@ -11,20 +12,9 @@ const inter = localFont({
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
const merriweather = localFont({
|
||||
src: [
|
||||
{ path: "../../public/fonts/Merriweather-Light.woff2", weight: "300", style: "normal" },
|
||||
{ path: "../../public/fonts/Merriweather-Regular.woff2", weight: "400", style: "normal" },
|
||||
{ path: "../../public/fonts/Merriweather-Bold.woff2", weight: "700", style: "normal" },
|
||||
{ path: "../../public/fonts/Merriweather-Black.woff2", weight: "900", style: "normal" },
|
||||
],
|
||||
variable: "--font-merriweather",
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Test01 - Local-First Venting",
|
||||
description: "Transform your struggles into personal branding content with AI-powered journaling",
|
||||
title: "Brachnha Insight",
|
||||
description: "Transform what in your mind into a powerful notes",
|
||||
// Story 3.4: PWA metadata
|
||||
manifest: "/manifest.webmanifest", // Next.js 14+ convention
|
||||
themeColor: "#64748B",
|
||||
@@ -52,7 +42,7 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body
|
||||
className={`${inter.variable} ${merriweather.variable} font-sans antialiased`}
|
||||
className={`${inter.variable} font-sans antialiased`}
|
||||
>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { ChatBubble } from './chat-bubble';
|
||||
import { TypingIndicator } from './typing-indicator';
|
||||
import { useChatStore } from '@/store/use-chat';
|
||||
@@ -9,11 +9,39 @@ import { BookOpen, Sparkles } from 'lucide-react';
|
||||
export function ChatWindow() {
|
||||
const { messages, isTyping } = useChatStore();
|
||||
const bottomRef = useRef<HTMLDivElement>(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [isUserScrolling, setIsUserScrolling] = useState(false);
|
||||
|
||||
// Auto-scroll to bottom
|
||||
// Auto-scroll to bottom only when new messages arrive
|
||||
useEffect(() => {
|
||||
if (!isUserScrolling) {
|
||||
bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, [messages, isTyping]);
|
||||
}
|
||||
}, [messages.length, isUserScrolling]);
|
||||
|
||||
// Detect when user is manually scrolling
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
|
||||
const handleScroll = () => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = container;
|
||||
const isAtBottom = scrollHeight - scrollTop - clientHeight < 100;
|
||||
|
||||
// If user scrolls up from bottom, disable auto-scroll
|
||||
if (!isAtBottom && !isUserScrolling) {
|
||||
setIsUserScrolling(true);
|
||||
}
|
||||
|
||||
// If user scrolls back near bottom, re-enable auto-scroll
|
||||
if (isAtBottom && isUserScrolling) {
|
||||
setIsUserScrolling(false);
|
||||
}
|
||||
};
|
||||
|
||||
container.addEventListener('scroll', handleScroll);
|
||||
return () => container.removeEventListener('scroll', handleScroll);
|
||||
}, [isUserScrolling]);
|
||||
|
||||
if (!messages || messages.length === 0) {
|
||||
return (
|
||||
@@ -38,7 +66,7 @@ export function ChatWindow() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full flex-1 overflow-y-auto px-4 py-6 scroll-smooth">
|
||||
<div ref={containerRef} className="h-full flex-1 overflow-y-auto px-4 py-6 scroll-smooth">
|
||||
<div className="max-w-3xl mx-auto space-y-4">
|
||||
{messages.map((msg) => (
|
||||
<ChatBubble key={msg.id} role={msg.role} content={msg.content} />
|
||||
|
||||
Reference in New Issue
Block a user