refactor(ai-chat): enhance ShinyText component and integrate into AIChainOfThought and WelcomeScreen

- Updated the `ShinyText` component to support children and customizable shimmer width, improving flexibility in usage.
- Refactored styles for the `ShinyText` component to enhance the shine animation effect.
- Integrated the `ShinyText` component into the `AIChainOfThought` and `WelcomeScreen` components, ensuring consistent visual styling across the AI chat interface.

These changes aim to improve the visual appeal and maintainability of the components within the AI chat module.

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
Innei 2025-09-25 14:30:45 +08:00
parent cafdc42916
commit 413fb986ff
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
4 changed files with 35 additions and 40 deletions

View File

@ -71,7 +71,7 @@ export const AIChainOfThought: React.FC<AIChainOfThoughtProps> = React.memo(
{!currentChainReasoningIsFinished ? (
<span className="flex items-center gap-2">
Thinking:{" "}
<ShinyText className="font-medium" text={currentReasoningTitle ?? ""} />
<ShinyText className="font-medium">{currentReasoningTitle ?? ""}</ShinyText>
</span>
) : (
"Finished Thinking"

View File

@ -102,6 +102,7 @@ const DefaultWelcomeHeader = ({ description }: { description: string }) => (
<h1 className="text-text flex items-center justify-center gap-2 text-2xl font-semibold">
<Folo className="size-11" /> AI
</h1>
<p className="text-text-secondary text-balance text-sm">{description}</p>
</div>
</m.div>

View File

@ -1,29 +1,39 @@
import { clsx } from "@follow/utils"
import * as React from "react"
import { cn } from "@follow/utils"
import type { ComponentPropsWithoutRef, CSSProperties, FC } from "react"
import styles from "./index.module.css"
interface ShinyTextProps {
text: string
disabled?: boolean
speed?: number
className?: string
export interface AnimatedShinyTextProps extends ComponentPropsWithoutRef<"span"> {
shimmerWidth?: number
}
export const ShinyText: React.FC<ShinyTextProps> = ({
text,
disabled = false,
speed = 2,
className = "",
export const ShinyText: FC<AnimatedShinyTextProps> = ({
children,
className,
shimmerWidth = 100,
...props
}) => {
const animationDuration = `${speed}s`
return (
<div
className={clsx(styles["shiny-text"], disabled ? styles["disabled"] : "", className)}
style={{ animationDuration }}
<span
style={
{
"--shiny-width": `${shimmerWidth}px`,
} as CSSProperties
}
className={cn(
"text-text-secondary mx-auto max-w-md",
// Shine effect
"bg-clip-text bg-no-repeat [background-position:0_0] [background-size:var(--shiny-width)_100%] [transition:background-position_1s_cubic-bezier(.6,.6,0,1)_infinite]",
// Shine gradient
"bg-gradient-to-r from-transparent via-black/90 via-50% to-transparent dark:via-white/80",
styles["shiny-text"],
className,
)}
{...props}
>
{text}
</div>
{children}
</span>
)
}

View File

@ -1,28 +1,12 @@
.shiny-text {
@apply text-text-secondary;
background-image: linear-gradient(
150deg,
rgba(255, 255, 255, 0) 40%,
rgba(255, 255, 255, 0.8) 50%,
rgba(255, 255, 255, 0) 60%
);
background-size: 200% 100%;
-webkit-background-clip: text;
background-clip: text;
display: inline-block;
animation: shine 5s linear infinite;
animation: shiny-text 3s infinite;
}
@keyframes shine {
@keyframes shiny-text {
0% {
background-position: 100%;
background-position: calc(-100% - var(--shiny-width)) 0;
}
100% {
background-position: -100%;
background-position: calc(100% + var(--shiny-width)) 0;
}
}
.shiny-text.disabled {
animation: none;
}