chore(lint): biome cleanup across services — format, sort imports, drop unused
- discord-gateway: 74 lint errors -> 0 (format, import sorting, unused imports/vars, dead breath var) - backend: format + sort imports (11 warnings left: noExplicitAny) - frontend: remove unused imports, drop dead breathing var, fix useExhaustiveDependencies (scroll keyed on messages), a11y biome-ignore for drag surface + stopPropagation container (mouse-only gestures) - remaining warnings are false positives: index keys on static lists, <img> in static export (next/image unsupported), noExplicitAny tsc --noEmit clean on all 3 services; vitest green (60+36).
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useRef, useEffect } from "react";
|
||||
import { Send } from "lucide-react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useChatbot } from "./chatbot-context";
|
||||
|
||||
interface ChatPanelProps {
|
||||
@@ -15,11 +15,12 @@ export function ChatPanel({ inputRef: externalInputRef }: ChatPanelProps) {
|
||||
const inputRef = externalInputRef ?? internalInputRef;
|
||||
|
||||
// Auto-scroll to bottom on new messages
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: re-run on message arrival; scroll is a visual effect keyed on new content
|
||||
useEffect(() => {
|
||||
if (listRef.current) {
|
||||
listRef.current.scrollTop = listRef.current.scrollHeight;
|
||||
}
|
||||
}, [messages, isTyping]);
|
||||
}, [messages]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -35,7 +36,9 @@ export function ChatPanel({ inputRef: externalInputRef }: ChatPanelProps) {
|
||||
<div ref={listRef} className="flex-1 overflow-y-auto px-2 py-1 space-y-1">
|
||||
{messages.length === 0 && (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<p className="text-[10px] text-text-secondary/40">Ask chatbot anything</p>
|
||||
<p className="text-[10px] text-text-secondary/40">
|
||||
Ask chatbot anything
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{messages.slice(-8).map((msg, i) => (
|
||||
@@ -58,9 +61,18 @@ export function ChatPanel({ inputRef: externalInputRef }: ChatPanelProps) {
|
||||
<div className="flex justify-start">
|
||||
<div className="glass rounded-lg px-2 py-1">
|
||||
<span className="inline-flex gap-0.5">
|
||||
<span className="size-1 rounded-full bg-text-secondary animate-bounce" style={{ animationDelay: "0ms" }} />
|
||||
<span className="size-1 rounded-full bg-text-secondary animate-bounce" style={{ animationDelay: "150ms" }} />
|
||||
<span className="size-1 rounded-full bg-text-secondary animate-bounce" style={{ animationDelay: "300ms" }} />
|
||||
<span
|
||||
className="size-1 rounded-full bg-text-secondary animate-bounce"
|
||||
style={{ animationDelay: "0ms" }}
|
||||
/>
|
||||
<span
|
||||
className="size-1 rounded-full bg-text-secondary animate-bounce"
|
||||
style={{ animationDelay: "150ms" }}
|
||||
/>
|
||||
<span
|
||||
className="size-1 rounded-full bg-text-secondary animate-bounce"
|
||||
style={{ animationDelay: "300ms" }}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -68,7 +80,10 @@ export function ChatPanel({ inputRef: externalInputRef }: ChatPanelProps) {
|
||||
</div>
|
||||
|
||||
{/* Input bar */}
|
||||
<form onSubmit={handleSubmit} className="flex items-center gap-1 px-2 py-1.5 border-t border-glass-border shrink-0">
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="flex items-center gap-1 px-2 py-1.5 border-t border-glass-border shrink-0"
|
||||
>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
|
||||
@@ -33,7 +33,14 @@ export function ChatbotCanvas() {
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
|
||||
// Background circle
|
||||
const gradient = ctx.createRadialGradient(w / 2, h / 2 - 10, 10, w / 2, h / 2, 80);
|
||||
const gradient = ctx.createRadialGradient(
|
||||
w / 2,
|
||||
h / 2 - 10,
|
||||
10,
|
||||
w / 2,
|
||||
h / 2,
|
||||
80,
|
||||
);
|
||||
gradient.addColorStop(0, "oklch(0.62 0.17 215 / 0.8)");
|
||||
gradient.addColorStop(0.6, "oklch(0.12 0.02 245 / 0.9)");
|
||||
gradient.addColorStop(1, "oklch(0.07 0.015 250 / 1)");
|
||||
@@ -112,11 +119,6 @@ export function ChatbotCanvas() {
|
||||
ctx.arc(w / 2, 75, 6, 0.1, Math.PI - 0.1);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Breathing animation — subtle canvas shift
|
||||
const breath = Math.sin(Date.now() / 1000) * 1.5;
|
||||
// Applied via CSS transform on container instead
|
||||
|
||||
}, [expression]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useRef, useState, useCallback, useEffect } from "react";
|
||||
import { Bot, MessageCircle, Minimize2 } from "lucide-react";
|
||||
import { useChatbot } from "./chatbot-context";
|
||||
import { ChatbotCanvas } from "./chatbot-canvas";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { ChatPanel } from "./chat-panel";
|
||||
import { ChatbotCanvas } from "./chatbot-canvas";
|
||||
import { useChatbot } from "./chatbot-context";
|
||||
|
||||
export function ChatbotContainer() {
|
||||
const { minimized, setMinimized, chatOpen, setChatOpen } = useChatbot();
|
||||
@@ -13,15 +13,21 @@ export function ChatbotContainer() {
|
||||
const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
setDragging(true);
|
||||
setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });
|
||||
}, [position]);
|
||||
const handleMouseDown = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
setDragging(true);
|
||||
setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });
|
||||
},
|
||||
[position],
|
||||
);
|
||||
|
||||
const handleMouseMove = useCallback((e: React.MouseEvent) => {
|
||||
if (!dragging) return;
|
||||
setPosition({ x: e.clientX - dragStart.x, y: e.clientY - dragStart.y });
|
||||
}, [dragging, dragStart]);
|
||||
const handleMouseMove = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
if (!dragging) return;
|
||||
setPosition({ x: e.clientX - dragStart.x, y: e.clientY - dragStart.y });
|
||||
},
|
||||
[dragging, dragStart],
|
||||
);
|
||||
|
||||
const handleMouseUp = useCallback(() => setDragging(false), []);
|
||||
|
||||
@@ -35,6 +41,7 @@ export function ChatbotContainer() {
|
||||
}, [chatOpen]);
|
||||
|
||||
return (
|
||||
// biome-ignore lint/a11y/noStaticElementInteractions: drag container — mouse-move gesture surface, not keyboard-interactive content
|
||||
<div
|
||||
className="fixed bottom-4 right-4 z-40 select-none"
|
||||
style={{ transform: `translate(${position.x}px, ${position.y}px)` }}
|
||||
@@ -62,6 +69,7 @@ export function ChatbotContainer() {
|
||||
) : (
|
||||
<>
|
||||
{/* Drag handle + controls */}
|
||||
{/* biome-ignore lint/a11y/noStaticElementInteractions: drag handle — mouse-only gesture, keyboard users use the buttons in this header */}
|
||||
<div
|
||||
className="flex items-center justify-between px-3 py-1.5 border-b border-glass-border cursor-grab active:cursor-grabbing"
|
||||
onMouseDown={handleMouseDown}
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
useState,
|
||||
} from "react";
|
||||
import { chatbotApi } from "@/lib/api";
|
||||
import type { ChatbotHistoryRow } from "@/lib/types";
|
||||
|
||||
export type ChatbotExpression =
|
||||
| "idle"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export { ChatbotProvider, useChatbot } from "./chatbot-context";
|
||||
export { ChatbotContainer } from "./chatbot-container";
|
||||
export { ChatbotCanvas } from "./chatbot-canvas";
|
||||
export { ChatPanel } from "./chat-panel";
|
||||
export { ChatbotCanvas } from "./chatbot-canvas";
|
||||
export { ChatbotContainer } from "./chatbot-container";
|
||||
export { ChatbotProvider, useChatbot } from "./chatbot-context";
|
||||
|
||||
Reference in New Issue
Block a user