forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBetaWelcomeModal.tsx
More file actions
189 lines (173 loc) · 8.03 KB
/
Copy pathBetaWelcomeModal.tsx
File metadata and controls
189 lines (173 loc) · 8.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
'use client';
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Sparkles, MessageSquare, Bug, X, ExternalLink } from 'lucide-react';
import { cn } from '@/lib/utils';
import confetti from 'canvas-confetti';
// Discord icon component
function DiscordIcon({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/>
</svg>
);
}
const STORAGE_KEY = 'omi_beta_welcome_seen';
export function BetaWelcomeModal() {
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
// Check if user has already seen the welcome modal
const hasSeenWelcome = localStorage.getItem(STORAGE_KEY);
if (!hasSeenWelcome) {
// Small delay to let the page load first
const timer = setTimeout(() => {
setIsOpen(true);
}, 500);
return () => clearTimeout(timer);
}
}, []);
const handleClose = () => {
// Fire full-page confetti celebration
const duration = 2000;
const end = Date.now() + duration;
const frame = () => {
// Left side
confetti({
particleCount: 3,
angle: 60,
spread: 55,
origin: { x: 0, y: 0.6 },
colors: ['#8B5CF6', '#A78BFA', '#C4B5FD', '#ffffff']
});
// Right side
confetti({
particleCount: 3,
angle: 120,
spread: 55,
origin: { x: 1, y: 0.6 },
colors: ['#8B5CF6', '#A78BFA', '#C4B5FD', '#ffffff']
});
if (Date.now() < end) {
requestAnimationFrame(frame);
}
};
frame();
localStorage.setItem(STORAGE_KEY, 'true');
setIsOpen(false);
};
return (
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-[10000] flex items-center justify-center bg-black/50 p-4"
onClick={handleClose}
>
{/* Modal */}
<motion.div
initial={{ opacity: 0, scale: 0.95, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 20 }}
onClick={(e) => e.stopPropagation()}
className={cn(
'w-full max-w-md bg-bg-secondary rounded-2xl',
'shadow-xl border border-bg-tertiary',
'overflow-hidden'
)}
>
{/* Close button */}
<button
onClick={handleClose}
className="absolute top-4 right-4 p-2 rounded-lg hover:bg-bg-tertiary transition-colors z-10"
>
<X className="w-5 h-5 text-text-tertiary" />
</button>
{/* Header with gradient */}
<div className="relative px-6 pt-8 pb-6 text-center">
<div className="absolute inset-0 bg-gradient-to-b from-purple-primary/10 to-transparent" />
<div className="relative">
<div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-purple-primary/20 mb-4">
<Sparkles className="w-8 h-8 text-purple-primary" />
</div>
<h2 className="text-2xl font-semibold text-text-primary mb-2">
Welcome to Omi Web Beta
</h2>
<p className="text-text-tertiary">
Thanks for being an early adopter!
</p>
</div>
</div>
{/* Content */}
<div className="px-6 pb-6 space-y-4">
{/* Feature list */}
<div className="space-y-3">
<div className="flex items-start gap-3 p-3 rounded-xl bg-bg-tertiary/50">
<div className="flex-shrink-0 w-8 h-8 rounded-lg bg-purple-primary/10 flex items-center justify-center">
<Sparkles className="w-4 h-4 text-purple-primary" />
</div>
<div>
<p className="text-sm font-medium text-text-primary">Early Access Features</p>
<p className="text-xs text-text-tertiary">Features may change as we improve the experience</p>
</div>
</div>
<div className="flex items-start gap-3 p-3 rounded-xl bg-bg-tertiary/50">
<div className="flex-shrink-0 w-8 h-8 rounded-lg bg-purple-primary/10 flex items-center justify-center">
<Bug className="w-4 h-4 text-purple-primary" />
</div>
<div>
<p className="text-sm font-medium text-text-primary">Error Tracking</p>
<p className="text-xs text-text-tertiary">We capture errors to improve stability</p>
</div>
</div>
<div className="flex items-start gap-3 p-3 rounded-xl bg-bg-tertiary/50">
<div className="flex-shrink-0 w-8 h-8 rounded-lg bg-purple-primary/10 flex items-center justify-center">
<MessageSquare className="w-4 h-4 text-purple-primary" />
</div>
<div>
<p className="text-sm font-medium text-text-primary">Your Feedback Matters</p>
<p className="text-xs text-text-tertiary">Help us build the best experience possible</p>
</div>
</div>
</div>
{/* Feedback links */}
<div className="pt-2 space-y-2">
<p className="text-xs text-text-quaternary">Share your feedback:</p>
<div className="flex items-center gap-4">
<a
href="https://feedback.omi.me"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1.5 text-sm text-text-tertiary hover:text-purple-primary transition-colors"
>
<ExternalLink className="w-3.5 h-3.5" />
<span>feedback.omi.me</span>
</a>
<a
href="http://discord.omi.me"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1.5 text-sm text-text-tertiary hover:text-purple-primary transition-colors"
>
<DiscordIcon className="w-3.5 h-3.5" />
<span>Discord</span>
</a>
</div>
</div>
{/* Action button */}
<div className="pt-4">
<button
onClick={handleClose}
className="block w-full py-3 px-4 rounded-xl bg-purple-primary text-white text-center font-medium hover:bg-purple-600 transition-colors"
>
Got it, let's go!
</button>
</div>
</div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
);
}