feat(desktop): integrate MagneticHoverEffect into MarkdownLink and EntryTitle components
- Replaced standard anchor tags with MagneticHoverEffect for enhanced visual feedback on hover. - Removed custom mouse event handlers from EntryTitle, simplifying the component's code while maintaining hover effects. These changes improve user interaction and visual appeal across the affected components. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
d9ca464590
commit
feba117ba3
|
|
@ -1,3 +1,4 @@
|
|||
import { MagneticHoverEffect } from "@follow/components/ui/effect/MagneticHoverEffect.js"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
|
|
@ -31,9 +32,10 @@ export const MarkdownLink = (props: LinkProps) => {
|
|||
return (
|
||||
<Tooltip delayDuration={0}>
|
||||
<TooltipTrigger asChild>
|
||||
<a
|
||||
<MagneticHoverEffect
|
||||
as="a"
|
||||
draggable="false"
|
||||
className="follow-link--underline text-foreground font-semibold no-underline"
|
||||
className="text-foreground before:!bg-accent/50 font-semibold no-underline"
|
||||
href={populatedFullHref}
|
||||
title={props.title}
|
||||
target="_blank"
|
||||
|
|
@ -44,7 +46,7 @@ export const MarkdownLink = (props: LinkProps) => {
|
|||
{typeof props.children === "string" && (
|
||||
<i className="i-mgc-arrow-right-up-cute-re size-[0.9em] translate-y-[2px] opacity-70" />
|
||||
)}
|
||||
</a>
|
||||
</MagneticHoverEffect>
|
||||
</TooltipTrigger>
|
||||
{!!props.href && (
|
||||
<TooltipPortal>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { cn, formatEstimatedMins, formatTimeToSeconds } from "@follow/utils/utils"
|
||||
import { useCallback, useMemo, useRef } from "react"
|
||||
import { MagneticHoverEffect } from "@follow/components/ui/effect/MagneticHoverEffect.js"
|
||||
import { formatEstimatedMins, formatTimeToSeconds } from "@follow/utils/utils"
|
||||
import { useMemo } from "react"
|
||||
|
||||
import { useUISettingKey } from "~/atoms/settings/ui"
|
||||
import { useWhoami } from "~/atoms/user"
|
||||
|
|
@ -69,32 +70,6 @@ export const EntryTitle = ({ entryId, compact }: EntryLinkProps) => {
|
|||
return formatEstimatedMins(Math.floor(durationInSeconds / 60))
|
||||
}, [audioAttachment])
|
||||
|
||||
const titleRef = useRef<HTMLAnchorElement>(null)
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
if (!titleRef.current) return
|
||||
titleRef.current.style.transition = "transform 0.2s cubic-bezier(0.33, 1, 0.68, 1)"
|
||||
}
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
if (!titleRef.current) return
|
||||
titleRef.current.style.transform = "translate(0px, 0px)"
|
||||
titleRef.current.style.transition = "transform 0.4s cubic-bezier(0.33, 1, 0.68, 1)"
|
||||
}
|
||||
|
||||
const handleMouseMove = useCallback((e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
if (!titleRef.current) return
|
||||
const rect = titleRef.current.getBoundingClientRect()
|
||||
|
||||
const centerX = rect.left + rect.width / 2
|
||||
const centerY = rect.top + rect.height / 2
|
||||
|
||||
const distanceX = (e.clientX - centerX) * 0.05
|
||||
const distanceY = (e.clientY - centerY) * 0.05
|
||||
|
||||
titleRef.current.style.transform = `translate(${distanceX}px, ${distanceY}px)`
|
||||
}, [])
|
||||
|
||||
if (!entry) return null
|
||||
|
||||
return compact ? (
|
||||
|
|
@ -123,26 +98,19 @@ export const EntryTitle = ({ entryId, compact }: EntryLinkProps) => {
|
|||
<FeedIcon fallback feed={feed || inbox} entry={entry.entries} size={16} />
|
||||
{getPreferredTitle(feed || inbox, entry.entries)}
|
||||
</a>
|
||||
<a
|
||||
<MagneticHoverEffect
|
||||
as="a"
|
||||
href={populatedFullHref ?? "#"}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
ref={titleRef}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onMouseMove={handleMouseMove}
|
||||
className={cn(
|
||||
"cursor-link relative select-text break-words text-2xl font-medium leading-normal",
|
||||
"inline-block transition-all duration-200 ease-out",
|
||||
"before:absolute before:-inset-x-2 before:inset-y-0 before:rounded-xl before:bg-black/[0.03] before:opacity-0 before:transition-opacity hover:before:opacity-100 dark:before:bg-white/[0.07]",
|
||||
)}
|
||||
className={"select-text break-words text-2xl font-medium leading-normal"}
|
||||
>
|
||||
<EntryTranslation
|
||||
source={entry.entries.title}
|
||||
target={translation.data?.title}
|
||||
className="select-text hyphens-auto"
|
||||
/>
|
||||
</a>
|
||||
</MagneticHoverEffect>
|
||||
</div>
|
||||
|
||||
{/* Meta Information with improved layout */}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
import { cn } from "@follow/utils/utils"
|
||||
import * as React from "react"
|
||||
import { useCallback, useRef } from "react"
|
||||
|
||||
type MagneticHoverEffectProps<T extends React.ElementType> = {
|
||||
as?: T
|
||||
children: React.ReactNode
|
||||
} & Omit<React.ComponentPropsWithoutRef<T>, "as" | "children">
|
||||
|
||||
export const MagneticHoverEffect = <T extends React.ElementType = "div">({
|
||||
as,
|
||||
children,
|
||||
...rest
|
||||
}: MagneticHoverEffectProps<T>) => {
|
||||
const Component = as || "div"
|
||||
|
||||
const itemRef = useRef<HTMLElement>(null)
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
if (!itemRef.current) return
|
||||
itemRef.current.style.transition = "transform 0.2s cubic-bezier(0.33, 1, 0.68, 1)"
|
||||
}
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
if (!itemRef.current) return
|
||||
itemRef.current.style.transform = "translate(0px, 0px)"
|
||||
itemRef.current.style.transition = "transform 0.4s cubic-bezier(0.33, 1, 0.68, 1)"
|
||||
}
|
||||
|
||||
const handleMouseMove = useCallback((e: React.MouseEvent<HTMLElement>) => {
|
||||
if (!itemRef.current) return
|
||||
const rect = itemRef.current.getBoundingClientRect()
|
||||
|
||||
const centerX = rect.left + rect.width / 2
|
||||
const centerY = rect.top + rect.height / 2
|
||||
|
||||
const distanceX = (e.clientX - centerX) * 0.05
|
||||
const distanceY = (e.clientY - centerY) * 0.05
|
||||
|
||||
itemRef.current.style.transform = `translate(${distanceX}px, ${distanceY}px)`
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Component
|
||||
ref={itemRef as any}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onMouseMove={handleMouseMove}
|
||||
{...rest}
|
||||
className={cn(
|
||||
"relative !cursor-none",
|
||||
"inline-block transition-all duration-200 ease-out",
|
||||
"before:absolute before:-inset-x-2 before:inset-y-0 before:z-[-1] before:origin-center before:scale-[0.92] before:rounded-xl before:bg-black/[0.03] before:opacity-0 before:backdrop-blur before:transition-all before:duration-200 hover:before:scale-100 hover:before:opacity-100 dark:before:bg-white/[0.10]",
|
||||
rest.className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</Component>
|
||||
)
|
||||
}
|
||||
Loading…
Reference in New Issue