Citation
tool-ui/citationFreeBlock
Display source references with attribution.
See it running
Open the demo on tool-ui
www.tool-ui.com/components/citationInstall it
npx shadcn@latest add https://www.tool-ui.com/r/citation.jsonSource
1"use client";23import * as React from "react";4import type { LucideIcon } from "lucide-react";5import {6 FileText,7 Globe,8 Code2,9 Newspaper,10 Database,11 File,12 ExternalLink,13} from "lucide-react";14import { cn, Popover, PopoverContent, PopoverTrigger } from "./_adapter";1516import { openSafeNavigationHref, sanitizeHref } from "../shared/media";17import type {18 SerializableCitation,19 CitationType,20 CitationVariant,21} from "./schema";2223const FALLBACK_LOCALE = "en-US";2425const TYPE_ICONS: Record<CitationType, LucideIcon> = {26 webpage: Globe,27 document: FileText,28 article: Newspaper,29 api: Database,30 code: Code2,31 other: File,32};3334function extractDomain(url: string): string | undefined {35 try {36 const urlObj = new URL(url);37 return urlObj.hostname.replace(/^www\./, "");38 } catch {39 return undefined;40 }41}4243function formatDate(isoString: string, locale: string): string {44 try {45 const date = new Date(isoString);46 return date.toLocaleDateString(locale, {47 year: "numeric",48 month: "short",49 });50 } catch {51 return isoString;52 }53}5455function useHoverPopover(delay = 100) {56 const [open, setOpen] = React.useState(false);57 const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);5859 const handleMouseEnter = React.useCallback(() => {60 if (timeoutRef.current) clearTimeout(timeoutRef.current);61 timeoutRef.current = setTimeout(() => setOpen(true), delay);62 }, [delay]);6364 const handleMouseLeave = React.useCallback(() => {65 if (timeoutRef.current) clearTimeout(timeoutRef.current);66 timeoutRef.current = setTimeout(() => setOpen(false), delay);67 }, [delay]);6869 React.useEffect(() => {70 return () => {71 if (timeoutRef.current) clearTimeout(timeoutRef.current);72 };73 }, []);7475 return { open, setOpen, handleMouseEnter, handleMouseLeave };76}7778export interface CitationProps extends SerializableCitation {79 variant?: CitationVariant;80 className?: string;81 onNavigate?: (href: string, citation: SerializableCitation) => void;82}8384export function Citation(props: CitationProps) {85 const { variant = "default", className, onNavigate, ...serializable } = props;8687 const {88 id,89 href: rawHref,90 title,91 snippet,92 domain: providedDomain,93 favicon,94 author,95 publishedAt,96 type = "webpage",97 locale: providedLocale,98 } = serializable;99100 const locale = providedLocale ?? FALLBACK_LOCALE;101 const sanitizedHref = sanitizeHref(rawHref);102// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from tool-ui
All 27 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Approval Cardapproval-card | tool-ui | Blocks | Free | 2 deps · 11 files | |
| Audioaudio | tool-ui | Blocks | Free | 2 deps · 9 files | |
| Chartchart | tool-ui | Blocks | Free | 2 deps · 8 files | |
| Code Blockcode-block | tool-ui | Blocks | Free | 3 deps · 11 files | |
| Code Diffcode-diff | tool-ui | Blocks | Free | 3 deps · 10 files | |
| Data Tabledata-table | tool-ui | Blocks | Free | 1 dep · 17 files | |
| Geo Mapgeo-map | tool-ui | Blocks | Free | 4 deps · 12 files | |
| Imageimage | tool-ui | Blocks | Free | 1 dep · 14 files |
