update sound design

update form design
This commit is contained in:
2026-05-09 14:05:32 +02:00
parent b2891feea4
commit e909095495
15 changed files with 73 additions and 42 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@avocadi/ui",
"type": "module",
"version": "0.2.18",
"version": "0.3.0",
"description": "ui elements for avocadi",
"private": false,
"files": [
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+7 -2
View File
@@ -64,10 +64,15 @@ function Button({
className={cn(buttonVariants({ variant, size, className }))}
onClick={(e) => {
onClick?.(e);
play({ id: "click1" });
}}
onMouseUp={() => {
play({ id: "clickSmall" });
}}
onMouseDown={() => {
play({ id: "clickSmall" });
}}
onMouseEnter={(e) => {
play({ id: "click2" });
play({ id: "hover" });
onMouseEnter?.(e);
}}
{...props}
+28 -1
View File
@@ -5,6 +5,7 @@ import { type HTMLMotionProps, motion } from "motion/react";
import { forwardRef, type HTMLAttributes, type ReactNode } from "react";
import { cn } from "@/lib/utils";
import { CardDepthProvider, useCardDepth } from "./card-context";
import useInterfaceSound from "./hooks/useInterfaceSound";
import {
defaultTransitionCard,
defaultVariantsCard,
@@ -51,9 +52,26 @@ const Card = forwardRef<HTMLDivElement, CommonCardProps>(
const Comp = asChild ? Slot : "div";
const { play } = useInterfaceSound();
return (
<CardDepthProvider>
<Comp
onMouseEnter={() => {
if (interactive) {
play({ id: "hover" });
}
}}
onMouseDown={() => {
if (interactive) {
play({ id: "clickSmall" });
}
}}
onMouseUp={() => {
if (interactive) {
play({ id: "clickSmall" });
}
}}
ref={ref}
style={{ borderRadius: `${radius}rem`, ...style }}
className={cn(cardVariants({ interactive, className, padding }))}
@@ -70,11 +88,20 @@ const MCard = motion.create(Card);
export const AnimatedCard: React.FC<
CommonCardProps & HTMLMotionProps<"div">
> = (props) => {
> = ({ interactive, ...props }) => {
return (
<MCard
variants={defaultVariantsCard}
transition={defaultTransitionCard}
{...(interactive && {
whileHover: {
scale: 1.05,
},
whileTap: {
scale: 0.95,
},
})}
interactive={interactive}
{...props}
/>
);
+1 -1
View File
@@ -16,7 +16,7 @@ function Checkbox({
<CheckboxPrimitive.Root
onCheckedChange={(checked) => {
if (onCheckedChange) onCheckedChange(checked);
play({ id: "click2" });
play({ id: "clickSmall" });
}}
data-slot="checkbox"
className={cn(
+1 -1
View File
@@ -45,7 +45,7 @@ const InputNumber = React.forwardRef<HTMLInputElement, Props>(
value={draft}
onFocus={(e) => {
setFocused(true);
play({ id: "click2" });
play({ id: "clickSmall" });
onFocus?.(e);
}}
onChange={(e) => {
+2 -2
View File
@@ -11,11 +11,11 @@ const InputText = React.forwardRef<
return (
<input
onFocus={() => {
play({ id: "click2" });
play({ id: "clickSmall" });
}}
type={type}
className={cn(
"flex h-input-height w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"flex h-input-height w-full rounded-input border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className,
)}
ref={ref}
+4 -4
View File
@@ -15,9 +15,9 @@ function Select({
<SelectPrimitive.Root
onOpenChange={(open) => {
if (open) {
play({ id: "click3" });
play({ id: "clickSmall" });
} else {
play({ id: "click4" });
play({ id: "clickSmall" });
}
}}
data-slot="select"
@@ -53,7 +53,7 @@ function SelectTrigger({
className={cn(
"border-main data-placeholder:text-secondary [&_svg:not([class*='text-'])]:text-secondary focus-visible:border-ring",
"focus-visible:ring-main/50 aria-invalid:ring-error/20 dark:aria-invalid:ring-error/40 aria-invalid:border-error",
"dark:bg-neutral-accent/30 dark:hover:bg-neutral-accent/50 flex w-fit items-center justify-between gap-2 rounded-full",
"dark:bg-neutral-accent/30 dark:hover:bg-neutral-accent/50 flex w-fit items-center justify-between gap-2 rounded-input",
"border bg-transparent px-4 py-2 text-sm text-main whitespace-nowrap shadow-xs transition-[color,box-shadow,background-color] outline-none",
"focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-input-height data-[size=sm]:h-8",
"*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center",
@@ -133,7 +133,7 @@ function SelectItem({
return (
<SelectPrimitive.Item
onMouseEnter={() => play({ id: "click2" })}
onMouseEnter={() => play({ id: "hover" })}
data-slot="select-item"
className={cn(
"focus:bg-main/25 text-main/75 focus:text-main [&_svg:not([class*='text-'])]:text-main transition-colors",
+21 -30
View File
@@ -1,41 +1,32 @@
import { useSound } from "use-sound";
import z from "zod";
import soundSpriteButtons from "../assets/sounds/762132__ienba__ui-buttons.wav";
import soundSprite from "../assets/sounds/842498__newlocknew__uimvmt_game-user-interface-sound-set.mp3";
const UiSoundSetSprites = z.enum([
"smooth1",
"smooth2",
"lobbyCreated",
"gameStart",
]);
import clickSmallSound from "../assets/sounds/clickSmall.wav";
import hoverSound from "../assets/sounds/hover.wav";
import uploadSuccessSound from "../assets/sounds/uploadSuccess.wav";
const UiButtonSprites = z.enum(["click1", "click2", "click3", "click4"]);
export const InterfaceSounds = z.enum(["clickSmall", "hover", "uploadSuccess"]);
export default function useInterfaceSound() {
const [playSprite1] = useSound(soundSprite, {
sprite: {
smooth1: [0, 1200],
smooth2: [7800, 1400],
lobbyCreated: [53800, 3500],
gameStart: [62000, 4000],
},
});
const [playHover] = useSound(hoverSound);
const [playSprite2] = useSound(soundSpriteButtons, {
sprite: {
click1: [0, 1000],
click2: [2750, 1000],
click3: [5200, 1000],
click4: [7700, 1000],
},
});
const [playClickSmall] = useSound(clickSmallSound);
const play = ({ id }: { id: string }) => {
if (UiSoundSetSprites.safeParse(id).success) {
playSprite1({ id });
} else if (UiButtonSprites.safeParse(id).success) {
playSprite2({ id });
const [playUploadSuccess] = useSound(uploadSuccessSound);
const play = ({ id }: { id: z.output<typeof InterfaceSounds> }) => {
switch (id) {
case "clickSmall":
playClickSmall();
break;
case "hover":
playHover();
break;
case "uploadSuccess":
playUploadSuccess();
break;
default:
break;
}
};
+6
View File
@@ -3,6 +3,7 @@
import { stagger, type Transition } from "motion";
import { motion, type Variants } from "motion/react";
import type { FC } from "react";
import useInterfaceSound from "@/hooks/useInterfaceSound";
import { cn, getRandomInt } from "@/lib/utils";
const variants: {
@@ -46,6 +47,8 @@ export const LogoText: FC<{
"transition-colors",
);
const { play } = useInterfaceSound();
return (
<motion.svg
variants={variants.container}
@@ -53,6 +56,9 @@ export const LogoText: FC<{
transition={{
delayChildren: stagger(0.1, { from: "center" }),
}}
onClick={() => {
play({ id: "clickSmall" });
}}
{...(animateOnGestures && { whileHover: "hover", whileTap: "active" })}
className="overflow-visible"
width="100%"
+2
View File
@@ -49,6 +49,8 @@
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--radius-2xl: calc(var(--radius) + 12px);
--radius-input: calc(var(--radius) + 4px);
}
@theme {