From 26c460f3de8ef90d0da12efbe82c261d016f1e5c Mon Sep 17 00:00:00 2001 From: Francisco Pessano Date: Sat, 12 Jul 2025 01:43:34 -0300 Subject: [PATCH] Update tooltip implementation and add TooltipContent and TooltipTrigger components --- web/package.json | 1 + web/pnpm-lock.yaml | 84 ++++++++++++++++++ web/src/components/VirtualTable.tsx | 20 +++-- web/src/components/ui/tooltip.tsx | 127 +++++++++++++++++++++------- 4 files changed, 196 insertions(+), 36 deletions(-) diff --git a/web/package.json b/web/package.json index 2121a8c..be35f6b 100644 --- a/web/package.json +++ b/web/package.json @@ -11,6 +11,7 @@ "dependencies": { "@astrojs/mdx": "^4.3.0", "@astrojs/react": "^4.3.0", + "@base-ui-components/react": "1.0.0-beta.1", "@radix-ui/react-slot": "^1.2.3", "@tailwindcss/vite": "^4.1.3", "@tanstack/react-virtual": "^3.13.12", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index cfe00b0..ec86927 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@astrojs/react': specifier: ^4.3.0 version: 4.3.0(@types/node@24.0.13)(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(jiti@2.4.2)(lightningcss@1.30.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@base-ui-components/react': + specifier: 1.0.0-beta.1 + version: 1.0.0-beta.1(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': specifier: ^1.2.3 version: 1.2.3(@types/react@19.1.8)(react@19.1.0) @@ -182,6 +185,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.27.6': + resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} @@ -194,6 +201,17 @@ packages: resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==} engines: {node: '>=6.9.0'} + '@base-ui-components/react@1.0.0-beta.1': + resolution: {integrity: sha512-7zmGiz4/+HKnv99lWftItoSMqnj2PdSvt2krh0/GP+Rj0xK0NMnFI/gIVvP7CB2G+k0JPUrRWXjXa3y08oiakg==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + '@capsizecss/unpack@2.4.0': resolution: {integrity: sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==} @@ -356,6 +374,21 @@ packages: cpu: [x64] os: [win32] + '@floating-ui/core@1.7.2': + resolution: {integrity: sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==} + + '@floating-ui/dom@1.7.2': + resolution: {integrity: sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==} + + '@floating-ui/react-dom@2.1.4': + resolution: {integrity: sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -1729,6 +1762,9 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + restructure@3.0.2: resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} @@ -1814,6 +1850,9 @@ packages: style-to-object@1.0.9: resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==} + tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + tailwind-merge@3.3.1: resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} @@ -1991,6 +2030,11 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -2296,6 +2340,8 @@ snapshots: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/runtime@7.27.6': {} + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 @@ -2319,6 +2365,19 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@base-ui-components/react@1.0.0-beta.1(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@babel/runtime': 7.27.6 + '@floating-ui/react-dom': 2.1.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@floating-ui/utils': 0.2.10 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + reselect: 5.1.1 + tabbable: 6.2.0 + use-sync-external-store: 1.5.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.8 + '@capsizecss/unpack@2.4.0': dependencies: blob-to-buffer: 1.2.9 @@ -2410,6 +2469,23 @@ snapshots: '@esbuild/win32-x64@0.25.6': optional: true + '@floating-ui/core@1.7.2': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.2': + dependencies: + '@floating-ui/core': 1.7.2 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/dom': 1.7.2 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@floating-ui/utils@0.2.10': {} + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.4 @@ -4190,6 +4266,8 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 + reselect@5.1.1: {} + restructure@3.0.2: {} retext-latin@4.0.0: @@ -4335,6 +4413,8 @@ snapshots: dependencies: inline-style-parser: 0.2.4 + tabbable@6.2.0: {} + tailwind-merge@3.3.1: {} tailwindcss@4.1.11: {} @@ -4474,6 +4554,10 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + use-sync-external-store@1.5.0(react@19.1.0): + dependencies: + react: 19.1.0 + vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 diff --git a/web/src/components/VirtualTable.tsx b/web/src/components/VirtualTable.tsx index 034f7a7..3cd6fd7 100644 --- a/web/src/components/VirtualTable.tsx +++ b/web/src/components/VirtualTable.tsx @@ -4,7 +4,7 @@ import type { VideoData } from '../types/video'; import { formatDuration, formatDate } from '../utils/csvParser'; import { Badge } from './ui/badge'; import { Button } from './ui/button'; -import { Tooltip } from './ui/tooltip'; +import { Tooltip,TooltipContent, TooltipTrigger } from './ui/tooltip'; interface VirtualTableProps { data: VideoData[]; @@ -74,24 +74,32 @@ export function VirtualTable({ data }: VirtualTableProps) {
{/* Video Info */}
- -

+ + + {video.video_title} + + +

{video.video_title}

+
{video.detailed_subtags.split(',').slice(0, 2).map((tag, i) => ( - {tag.trim()} - ))} {video.detailed_subtags.split(',').length > 2 && ( - + + + {video.detailed_subtags.split(',').slice(2).join(', ')} + + +{video.detailed_subtags.split(',').length - 2} + )}
diff --git a/web/src/components/ui/tooltip.tsx b/web/src/components/ui/tooltip.tsx index 130621d..1d58b66 100644 --- a/web/src/components/ui/tooltip.tsx +++ b/web/src/components/ui/tooltip.tsx @@ -1,36 +1,103 @@ import * as React from "react" +import { Tooltip as BaseTooltip } from "@base-ui-components/react/tooltip" + import { cn } from "@/lib/utils" -interface TooltipProps { - content: string - children: React.ReactNode - className?: string +function TooltipProvider({ + delay = 0, + closeDelay = 0, + ...props +}: React.ComponentProps) { + return ( + + ) } -export function Tooltip({ content, children, className }: TooltipProps) { - const [isVisible, setIsVisible] = React.useState(false) +function Tooltip({ ...props }: React.ComponentProps) { + return ( + + + + ) +} - return ( -
-
setIsVisible(true)} - onMouseLeave={() => setIsVisible(false)} - className="cursor-help" - > - {children} -
- {isVisible && ( -
- {content} -
- )} -
- ) -} \ No newline at end of file +function TooltipTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function TooltipPortal({ + ...props +}: React.ComponentProps) { + return +} + +function TooltipPositioner({ + ...props +}: React.ComponentProps) { + return +} + +function TooltipArrow({ + ...props +}: React.ComponentProps) { + return +} + +function TooltipContent({ + className, + align = "center", + sideOffset = 8, + side = "top", + children, + ...props +}: React.ComponentProps & { + align?: BaseTooltip.Positioner.Props["align"] + side?: BaseTooltip.Positioner.Props["side"] + sideOffset?: BaseTooltip.Positioner.Props["sideOffset"] +}) { + return ( + + + + {children} + + + + + + + + + + ) +} + +export { + Tooltip, + TooltipTrigger, + TooltipContent, + TooltipPortal, + TooltipPositioner, + TooltipArrow, + TooltipProvider, +}