feat: add surprise-me

This commit is contained in:
Henry Li
2026-02-06 14:04:15 +08:00
parent 254efe7391
commit 26e078df7d
5 changed files with 122 additions and 0 deletions

View File

@@ -51,6 +51,7 @@
"ai": "^6.0.33",
"best-effort-json-parser": "^1.2.1",
"better-auth": "^1.3",
"canvas-confetti": "^1.9.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",

View File

@@ -116,6 +116,9 @@ importers:
better-auth:
specifier: ^1.3
version: 1.4.12(next@16.1.4(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vue@3.5.26(typescript@5.9.3))
canvas-confetti:
specifier: ^1.9.4
version: 1.9.4
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
@@ -2577,6 +2580,9 @@ packages:
caniuse-lite@1.0.30001764:
resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==}
canvas-confetti@1.9.4:
resolution: {integrity: sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==}
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@@ -7513,6 +7519,8 @@ snapshots:
caniuse-lite@1.0.30001764: {}
canvas-confetti@1.9.4: {}
ccount@2.0.1: {}
chalk@4.1.2:

View File

@@ -0,0 +1,49 @@
"use client";
import React, { type MouseEventHandler } from "react";
import confetti from "canvas-confetti";
import { Button } from "@/components/ui/button";
interface ConfettiButtonProps extends React.ComponentProps<typeof Button> {
angle?: number;
particleCount?: number;
startVelocity?: number;
spread?: number;
onClick?: MouseEventHandler<HTMLButtonElement>;
}
export function ConfettiButton({
className,
children,
angle = 90,
particleCount = 75,
startVelocity = 35,
spread = 70,
onClick,
...props
}: ConfettiButtonProps) {
const handleClick: MouseEventHandler<HTMLButtonElement> = (event) => {
const target = event.currentTarget;
if (target) {
const rect = target.getBoundingClientRect();
confetti({
particleCount,
startVelocity,
angle,
spread,
origin: {
x: (rect.left + rect.width / 2) / window.innerWidth,
y: (rect.top + rect.height / 2) / window.innerHeight,
},
});
}
onClick?.(event);
};
return (
<Button onClick={handleClick} className={className} {...props}>
{children}
</Button>
);
}

View File

@@ -7,6 +7,7 @@ import {
LightbulbIcon,
PaperclipIcon,
PlusIcon,
SparklesIcon,
ZapIcon,
} from "lucide-react";
import { useSearchParams } from "next/navigation";
@@ -30,6 +31,7 @@ import {
usePromptInputController,
type PromptInputMessage,
} from "@/components/ai-elements/prompt-input";
import { ConfettiButton } from "@/components/ui/confetti-button";
import {
DropdownMenuGroup,
DropdownMenuLabel,
@@ -386,6 +388,14 @@ function SuggestionList() {
);
return (
<Suggestions className="w-fit">
<ConfettiButton
className="text-muted-foreground cursor-pointer rounded-full px-4 text-xs font-normal"
variant="outline"
size="sm"
onClick={() => handleSuggestionClick("Surprise me")}
>
<SparklesIcon className="size-4" /> Surprise
</ConfettiButton>
{t.inputBox.suggestions.map((suggestion) => (
<Suggestion
key={suggestion.suggestion}