From 7e822cb73881715f248afcea955f76d59da8689e Mon Sep 17 00:00:00 2001 From: MengXi Date: Wed, 25 Feb 2026 17:26:44 -0800 Subject: [PATCH] feat: replace agentation with draggable help button (#1008) Co-authored-by: Claude Opus 4.6 Co-authored-by: ananaBMaster <68643891+ananaBMaster@users.noreply.github.com> --- .changeset/help-button.md | 5 ++ .husky/pre-push | 2 +- package.json | 1 - pnpm-lock.yaml | 19 ----- src/components/help-button.tsx | 95 ++++++++++++++++++++++++ src/entrypoints/options/main.tsx | 4 +- src/entrypoints/translation-hub/main.tsx | 4 +- 7 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 .changeset/help-button.md create mode 100644 src/components/help-button.tsx diff --git a/.changeset/help-button.md b/.changeset/help-button.md new file mode 100644 index 000000000..36c81f5e6 --- /dev/null +++ b/.changeset/help-button.md @@ -0,0 +1,5 @@ +--- +"@read-frog/extension": patch +--- + +feat: replace agentation dev toolbar with draggable help button diff --git a/.husky/pre-push b/.husky/pre-push index b4e1db200..a42998055 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -18,7 +18,7 @@ fi pnpm exec nx lint pnpm exec nx type-check -pnpm exec nx build +# pnpm exec nx build # Check if SKIP_FREE_API environment variable is set if [ "$SKIP_FREE_API" = "true" ]; then diff --git a/package.json b/package.json index 8d8a42d88..9e2b852b5 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,6 @@ "@vitejs/plugin-react": "^5.1.4", "@vitest/coverage-istanbul": "^4.0.18", "@wxt-dev/module-react": "^1.1.5", - "agentation": "^2.2.1", "autoprefixer": "^10.4.24", "eruda": "^3.4.3", "eslint": "9.39.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aac701094..808cf7124 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -297,9 +297,6 @@ importers: '@wxt-dev/module-react': specifier: ^1.1.5 version: 1.1.5(vite@7.2.2(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))(wxt@0.20.18(@types/node@20.19.25)(eslint@9.39.3(jiti@2.6.1))(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.53.2)(yaml@2.8.2)) - agentation: - specifier: ^2.2.1 - version: 2.2.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) autoprefixer: specifier: ^10.4.24 version: 10.4.24(postcss@8.5.6) @@ -2897,17 +2894,6 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - agentation@2.2.1: - resolution: {integrity: sha512-yV9P1DggI7M3SRaRwLwt+xqE5lXqg5l8xtqCr8KzEkbnH8Wa6eRATU97uKnD7cC8FrsJP62Mmw0Xf5Xi5KV50Q==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - ai@6.0.97: resolution: {integrity: sha512-eZIAcBymwGhBwncRH/v9pillZNMeRCDkc4BwcvwXerXd7sxjVxRis3ZNCNCpP02pVH4NLs81ljm4cElC4vbNcQ==} engines: {node: '>=18'} @@ -10010,11 +9996,6 @@ snapshots: agent-base@7.1.4: {} - agentation@2.2.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4): - optionalDependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - ai@6.0.97(zod@4.3.6): dependencies: '@ai-sdk/gateway': 3.0.53(zod@4.3.6) diff --git a/src/components/help-button.tsx b/src/components/help-button.tsx new file mode 100644 index 000000000..a98c72073 --- /dev/null +++ b/src/components/help-button.tsx @@ -0,0 +1,95 @@ +import { Icon } from "@iconify/react" +import { useCallback, useRef, useState } from "react" +import { cn } from "@/utils/styles/utils" + +type Corner = "bottom-right" | "top-right" + +const STORAGE_KEY = "help-button-corner" +const OFFSET = 16 +const DRAG_THRESHOLD = 5 + +const cornerStyles: Record = { + "bottom-right": { bottom: OFFSET, right: OFFSET, top: "auto", left: "auto" }, + "top-right": { top: OFFSET, right: OFFSET, bottom: "auto", left: "auto" }, +} + +function getStoredCorner(): Corner { + try { + const stored = localStorage.getItem(STORAGE_KEY) + if (stored && stored in cornerStyles) + return stored as Corner + } + catch {} + return "bottom-right" +} + +function getNearestCorner(_x: number, y: number): Corner { + const cy = window.innerHeight / 2 + return y >= cy ? "bottom-right" : "top-right" +} + +export function HelpButton() { + const [corner, setCorner] = useState(getStoredCorner) + const [dragging, setDragging] = useState(false) + const [dragPos, setDragPos] = useState<{ x: number, y: number } | null>(null) + const hasDraggedRef = useRef(false) + + const handleMouseDown = useCallback((e: React.MouseEvent) => { + e.preventDefault() + const startX = e.clientX + const startY = e.clientY + hasDraggedRef.current = false + + function onMouseMove(ev: MouseEvent) { + const dx = ev.clientX - startX + const dy = ev.clientY - startY + + if (!hasDraggedRef.current && Math.sqrt(dx * dx + dy * dy) < DRAG_THRESHOLD) + return + + hasDraggedRef.current = true + setDragging(true) + setDragPos({ x: ev.clientX - 20, y: ev.clientY - 20 }) + } + + function onMouseUp(ev: MouseEvent) { + document.removeEventListener("mousemove", onMouseMove) + document.removeEventListener("mouseup", onMouseUp) + + if (hasDraggedRef.current) { + const newCorner = getNearestCorner(ev.clientX, ev.clientY) + setCorner(newCorner) + localStorage.setItem(STORAGE_KEY, newCorner) + } + else { + window.open("https://github.com/mengxi-ream/read-frog/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen", "_blank") + } + hasDraggedRef.current = false + setDragging(false) + setDragPos(null) + } + + document.addEventListener("mousemove", onMouseMove) + document.addEventListener("mouseup", onMouseUp) + }, []) + + const style: React.CSSProperties = dragging && dragPos + ? { position: "fixed", left: dragPos.x, top: dragPos.y, right: "auto", bottom: "auto", transition: "none" } + : { position: "fixed", ...cornerStyles[corner], transition: "all 300ms ease" } + + return ( + + ) +} diff --git a/src/entrypoints/options/main.tsx b/src/entrypoints/options/main.tsx index 74f08cd7d..09f947720 100644 --- a/src/entrypoints/options/main.tsx +++ b/src/entrypoints/options/main.tsx @@ -1,12 +1,12 @@ import type { Config } from "@/types/config/config" import { QueryClientProvider } from "@tanstack/react-query" -import { Agentation } from "agentation" import { Provider as JotaiProvider } from "jotai" import { useHydrateAtoms } from "jotai/utils" import * as React from "react" import ReactDOM from "react-dom/client" import { HashRouter } from "react-router" import FrogToast from "@/components/frog-toast" +import { HelpButton } from "@/components/help-button" import { ChartThemeProvider } from "@/components/providers/chart-theme-provider" import { ThemeProvider } from "@/components/providers/theme-provider" import { SidebarProvider } from "@/components/ui/base-ui/sidebar" @@ -51,7 +51,7 @@ async function initApp() { - {import.meta.env.DEV && } + diff --git a/src/entrypoints/translation-hub/main.tsx b/src/entrypoints/translation-hub/main.tsx index 7f28643fe..2f8bbadca 100644 --- a/src/entrypoints/translation-hub/main.tsx +++ b/src/entrypoints/translation-hub/main.tsx @@ -1,11 +1,11 @@ import type { Config } from "@/types/config/config" import { QueryClientProvider } from "@tanstack/react-query" -import { Agentation } from "agentation" import { Provider as JotaiProvider } from "jotai" import { useHydrateAtoms } from "jotai/utils" import * as React from "react" import ReactDOM from "react-dom/client" import FrogToast from "@/components/frog-toast" +import { HelpButton } from "@/components/help-button" import { ThemeProvider } from "@/components/providers/theme-provider" import { TooltipProvider } from "@/components/ui/base-ui/tooltip" import { configAtom } from "@/utils/atoms/config" @@ -39,8 +39,8 @@ async function initApp() { - {import.meta.env.DEV && } +