Skip to content

Commit 65edc8e

Browse files
committed
feat: add AnimatedLogo component with sound effect on hover
1 parent 74e9dbe commit 65edc8e

File tree

11 files changed

+148
-33
lines changed

11 files changed

+148
-33
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- **🔄 Smart Connection Check:** Refresh function re-validates Supabase connection before loading prompts
1414
- **✨ Loading States:** Visual feedback with spinning icon and disabled button during refresh operation
1515
- **📢 User Feedback:** Toast notifications for refresh success, failure, and connection issues
16+
- **🤖 Animated Robot Logo:** Added cute hover animation and robot sound effect to the Promptzy logo
17+
- **🎵 Interactive Sound:** Robot logo plays a fun sound effect when hovered for enhanced user experience
18+
- **✨ Bouncy Animation:** Logo bounces, rotates, and glows with purple shadow on hover
1619

1720
### Changed
1821
- **🎨 Header Layout:** Refresh button positioned between logo and settings for easy access

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# ✨ Promptzy 🎯
22

33
<p align="center">
4-
<img src="https://res.cloudinary.com/di7ctlowx/image/upload/v1748393462/icon_lzh8zy.png" alt="Promptzy Logo" width="200" />
4+
<img src="https://res.cloudinary.com/di7ctlowx/image/upload/v1748393462/icon_lzh8zy.png" alt="Promptzy Logo" width="250" height="250" />
55
</p>
66

77
**Promptzy** - A modern, cute web application for managing and organizing your AI prompts, with tagging, search, and cloud storage.
88

99
<div align="center">
1010

1111
![License](https://img.shields.io/badge/license-MIT-blue.svg)
12-
![Version](https://img.shields.io/badge/version-1.3.1-green.svg)
12+
![Version](https://img.shields.io/badge/version-1.3.2-green.svg)
1313
![NPM](https://img.shields.io/npm/v/@pinkpixel/promptzy?color=red)
1414
![React](https://img.shields.io/badge/React-19.1.0-61DAFB?logo=react)
1515
![TypeScript](https://img.shields.io/badge/TypeScript-5.8.3-3178C6?logo=typescript)
@@ -35,7 +35,9 @@
3535

3636
## 🖥️ Screenshots
3737

38-
*Coming soon*
38+
<p align="center">
39+
<img src="https://res.cloudinary.com/di7ctlowx/image/upload/v1748492164/dashboard_c6krgr.png" alt="Screenshot" width="800" />
40+
</p>
3941

4042
## 🛠️ Installation
4143

dashboard.png

51.6 KB
Loading

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pinkpixel/promptzy",
3-
"version": "1.3.1",
3+
"version": "1.3.2",
44
"description": "Promptzy - A modern, cute web application for managing and organizing your AI prompts, with tagging, search, and cloud storage.",
55
"type": "module",
66
"main": "dist/index.html",

public/robot-sound.mp3

179 KB
Binary file not shown.

src/components/AnimatedLogo.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React, { useRef, useState } from "react";
2+
3+
interface AnimatedLogoProps {
4+
className?: string;
5+
}
6+
7+
const AnimatedLogo: React.FC<AnimatedLogoProps> = ({ className = "" }) => {
8+
const audioRef = useRef<HTMLAudioElement | null>(null);
9+
const [isPlaying, setIsPlaying] = useState(false);
10+
11+
const handleMouseEnter = async () => {
12+
if (isPlaying) return; // Prevent overlapping sounds
13+
14+
try {
15+
// Create a new audio instance each time to avoid conflicts
16+
const audio = new Audio('/robot-sound.mp3');
17+
audioRef.current = audio;
18+
19+
// Set volume to a reasonable level
20+
audio.volume = 0.3;
21+
22+
setIsPlaying(true);
23+
24+
// Play the sound
25+
await audio.play();
26+
27+
// Reset playing state when sound ends
28+
audio.addEventListener('ended', () => {
29+
setIsPlaying(false);
30+
});
31+
32+
} catch (error) {
33+
console.log("Could not play robot sound:", error);
34+
setIsPlaying(false);
35+
}
36+
};
37+
38+
return (
39+
<div
40+
className={`robot-logo-container ${className}`}
41+
onMouseEnter={handleMouseEnter}
42+
>
43+
<img
44+
src="/favicon.png"
45+
alt="Promptzy Robot Logo"
46+
className="robot-logo w-10 h-10 sm:w-12 sm:h-12 cursor-pointer select-none"
47+
draggable={false}
48+
/>
49+
</div>
50+
);
51+
};
52+
53+
export default AnimatedLogo;

src/components/Header.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState } from "react";
22
import { Button } from "@/components/ui/button";
33
import { Plus, Settings, RefreshCw } from "lucide-react";
44
import SettingsDialog from "@/components/SettingsDialog";
5+
import AnimatedLogo from "@/components/AnimatedLogo";
56

67
interface HeaderProps {
78
onAddPrompt: () => void;
@@ -15,7 +16,7 @@ const Header: React.FC<HeaderProps> = ({ onAddPrompt, onRefreshPrompts, isRefres
1516
return (
1617
<header className="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-6 sm:mb-8 gap-4 sm:gap-0">
1718
<div className="flex items-center gap-2">
18-
<img src="/favicon.png" alt="Logo" className="w-10 h-10 sm:w-12 sm:h-12" />
19+
<AnimatedLogo />
1920
<h1 className="text-2xl sm:text-3xl font-bold">Promptzy</h1>
2021
</div>
2122
<div className="flex gap-2 w-full sm:w-auto">

src/index.css

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,32 @@
66
:root {
77
--background: 240 10% 3.9%;
88
--foreground: 0 0% 98%;
9-
9+
1010
--card: 240 10% 3.9%;
1111
--card-foreground: 0 0% 98%;
12-
12+
1313
--popover: 240 10% 3.9%;
1414
--popover-foreground: 0 0% 98%;
15-
15+
1616
--primary: 252 79% 65%;
1717
--primary-foreground: 0 0% 98%;
18-
18+
1919
--secondary: 240 3.7% 15.9%;
2020
--secondary-foreground: 0 0% 98%;
21-
21+
2222
--muted: 240 3.7% 15.9%;
2323
--muted-foreground: 240 5% 64.9%;
24-
24+
2525
--accent: 240 3.7% 15.9%;
2626
--accent-foreground: 0 0% 98%;
27-
27+
2828
--destructive: 0 62.8% 30.6%;
2929
--destructive-foreground: 0 0% 98%;
30-
30+
3131
--border: 240 3.7% 15.9%;
3232
--input: 240 3.7% 15.9%;
3333
--ring: 252 79% 65%;
34-
34+
3535
--radius: 0.75rem;
3636
}
3737
}
@@ -40,11 +40,11 @@
4040
* {
4141
@apply border-border selection:bg-purple-300/20 selection:text-white;
4242
}
43-
43+
4444
body {
4545
@apply bg-background text-foreground antialiased;
4646
}
47-
47+
4848
.glass {
4949
@apply bg-white/5 backdrop-blur-lg border border-white/10 rounded-2xl;
5050
}
@@ -53,28 +53,65 @@
5353
@apply bg-gradient-to-br from-secondary to-secondary/80;
5454
@apply transition-all duration-300;
5555
}
56-
56+
5757
.prompt-card:hover {
5858
@apply from-secondary/90 to-secondary/60;
5959
}
60-
60+
6161
.tag {
6262
@apply bg-purple-300/20 text-purple-300 text-xs px-2 py-1 rounded-full;
6363
@apply transition-all duration-200 hover:bg-purple-300/30;
6464
}
65-
65+
6666
.tag-active {
6767
@apply bg-purple-300 text-black;
6868
}
69-
69+
7070
.btn-hover-effect {
7171
@apply relative overflow-hidden;
7272
}
73-
73+
74+
/* Robot Logo Animations */
75+
.robot-logo-container {
76+
@apply transition-transform duration-300 ease-in-out;
77+
}
78+
79+
.robot-logo-container:hover {
80+
animation: robotBounce 0.6s ease-in-out;
81+
}
82+
83+
.robot-logo {
84+
@apply transition-all duration-300 ease-in-out;
85+
filter: drop-shadow(0 0 0 transparent);
86+
}
87+
88+
.robot-logo-container:hover .robot-logo {
89+
filter: drop-shadow(0 0 8px rgba(126, 105, 171, 0.6));
90+
transform: scale(1.1);
91+
}
92+
93+
@keyframes robotBounce {
94+
0% { transform: translateY(0) rotate(0deg) scale(1); }
95+
25% { transform: translateY(-8px) rotate(-5deg) scale(1.05); }
96+
50% { transform: translateY(-4px) rotate(3deg) scale(1.1); }
97+
75% { transform: translateY(-6px) rotate(-2deg) scale(1.05); }
98+
100% { transform: translateY(0) rotate(0deg) scale(1); }
99+
}
100+
101+
/* Add a subtle pulse effect for extra cuteness */
102+
.robot-logo-container:hover {
103+
animation: robotBounce 0.6s ease-in-out, robotPulse 2s ease-in-out infinite;
104+
}
105+
106+
@keyframes robotPulse {
107+
0%, 100% { transform: scale(1); }
108+
50% { transform: scale(1.02); }
109+
}
110+
74111
.btn-hover-effect:after {
75112
@apply content-[''] absolute inset-0 bg-white/0 transition-colors duration-300 pointer-events-none;
76113
}
77-
114+
78115
.btn-hover-effect:hover:after {
79116
@apply bg-white/10;
80117
}

src/lib/supabasePromptStore.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,11 @@ export const getCurrentUserId = async (): Promise<string> => {
166166
};
167167

168168
export const getPromptsFromSupabase = async (): Promise<Prompt[]> => {
169-
const client = supabaseClient;
169+
// Create a fresh client to ensure we have the latest credentials
170+
const client = createClient(getSupabaseCredentials().supabaseUrl, getSupabaseCredentials().supabaseKey);
170171

171172
try {
172-
console.log("Fetching prompts from Supabase...");
173+
console.log("Fetching prompts from Supabase with fresh client...");
173174
const tableReady = await ensurePromptsTable(client);
174175
if (!tableReady) {
175176
console.error("Prompts table is not available");

0 commit comments

Comments
 (0)