Skip to content

Commit 2fab361

Browse files
committed
floating
1 parent 3243121 commit 2fab361

File tree

4 files changed

+5277
-2348
lines changed

4 files changed

+5277
-2348
lines changed

dashboard/ai-analytics/src/app/components/RootLayoutContent.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useTinybirdToken } from '@/providers/TinybirdProvider';
55
import { useModal } from '../context/ModalContext';
66
import { useKeyboardShortcut } from '@/hooks/useKeyboardShortcut';
77
import CostPredictionModal from './CostPredictionModal';
8+
import { FloatingNotification } from '@/components/ui/floating-notification';
89

910
interface RootLayoutContentProps {
1011
children: ReactNode;
@@ -23,6 +24,12 @@ export function RootLayoutContent({ children, initialToken, initialOrgName }: Ro
2324
<>
2425
{children}
2526
<ModalController filters={{}} />
27+
<FloatingNotification
28+
links={{
29+
github: 'https://github.com/tinybirdco/ai-analytics-template',
30+
telegram: 'https://t.me/tinybirdco',
31+
}}
32+
/>
2633
</>
2734
);
2835
}

dashboard/ai-analytics/src/app/globals.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ select::placeholder {
227227
opacity: 0.5;
228228
}
229229

230-
.settings-button {
230+
.settings-button, .floating-notification-button {
231231
display: flex;
232232
flex-direction: row;
233233
align-items: center;
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
'use client'
2+
3+
import { useState, useRef, useEffect } from 'react'
4+
import { cn } from '@/lib/utils'
5+
import { Github, X, Send } from 'lucide-react'
6+
7+
interface FloatingNotificationProps {
8+
className?: string
9+
title?: string
10+
links?: {
11+
github?: string
12+
telegram?: string
13+
close?: () => void
14+
}
15+
}
16+
17+
export function FloatingNotification({
18+
className,
19+
title = 'Learn more about this template:',
20+
links = {},
21+
}: FloatingNotificationProps) {
22+
const [isCollapsed, setIsCollapsed] = useState(false)
23+
const [position, setPosition] = useState({ x: 20, y: 20 })
24+
const [isDragging, setIsDragging] = useState(false)
25+
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 })
26+
const containerRef = useRef<HTMLDivElement>(null)
27+
28+
const handleMouseDown = (e: React.MouseEvent) => {
29+
if (containerRef.current) {
30+
const rect = containerRef.current.getBoundingClientRect()
31+
setDragOffset({
32+
x: e.clientX - rect.left,
33+
y: e.clientY - rect.top,
34+
})
35+
setIsDragging(true)
36+
}
37+
}
38+
39+
useEffect(() => {
40+
const handleMouseMove = (e: MouseEvent) => {
41+
if (isDragging) {
42+
setPosition({
43+
x: e.clientX - dragOffset.x,
44+
y: e.clientY - dragOffset.y,
45+
})
46+
}
47+
}
48+
49+
const handleMouseUp = () => {
50+
setIsDragging(false)
51+
}
52+
53+
if (isDragging) {
54+
document.addEventListener('mousemove', handleMouseMove)
55+
document.addEventListener('mouseup', handleMouseUp)
56+
}
57+
58+
return () => {
59+
document.removeEventListener('mousemove', handleMouseMove)
60+
document.removeEventListener('mouseup', handleMouseUp)
61+
}
62+
}, [isDragging, dragOffset])
63+
64+
return (
65+
<div
66+
ref={containerRef}
67+
className={cn(
68+
'fixed flex items-center gap-6 bg-[#262626] shadow-lg border-l-[3px] border-l-[#27F795] pl-4',
69+
isCollapsed ? 'w-auto' : 'w-[500px]',
70+
className
71+
)}
72+
style={{
73+
left: `${position.x}px`,
74+
top: `${position.y}px`,
75+
cursor: isDragging ? 'grabbing' : 'grab',
76+
}}
77+
onMouseDown={handleMouseDown}
78+
>
79+
<div className="flex items-center gap-6">
80+
<div className="text-sm text-muted-foreground"></div>
81+
{!isCollapsed && (
82+
<div className="text-sm text-muted-foreground !-ml-2">{title}</div>
83+
)}
84+
</div>
85+
86+
{!isCollapsed && (
87+
<div className="flex items-center gap-2">
88+
{links.telegram && (
89+
<a
90+
href={links.telegram}
91+
target="_blank"
92+
rel="noopener noreferrer"
93+
className="rounded-md p-2 text-muted-foreground transition-colors hover:bg-transparent hover:text-[var(--accent)] active:text-white"
94+
>
95+
<Send className="h-4 w-4" />
96+
</a>
97+
)}
98+
{links.github && (
99+
<a
100+
href={links.github}
101+
target="_blank"
102+
rel="noopener noreferrer"
103+
className="rounded-md p-2 text-muted-foreground transition-colors hover:bg-transparent hover:text-[var(--accent)] active:text-white"
104+
>
105+
<Github className="h-4 w-4" />
106+
</a>
107+
)}
108+
<button
109+
onClick={() => setIsCollapsed(!isCollapsed)}
110+
className="floating-notification-button text-muted-foreground transition-colors hover:bg-[#27F795] hover:text-[#262626] active:bg-[#267A52] active:border-none active:text-[#FFFFFF]"
111+
>
112+
{isCollapsed ? '+' : <X className="h-4 w-4" />}
113+
</button>
114+
</div>
115+
)}
116+
{isCollapsed && (
117+
<button
118+
onClick={() => setIsCollapsed(!isCollapsed)}
119+
className="floating-notification-button text-muted-foreground transition-colors hover:bg-[#27F795] hover:text-[#262626] active:bg-[#267A52] active:border-none active:text-[#FFFFFF]"
120+
>
121+
<div className="h-4 w-4 flex items-center justify-center">+</div>
122+
</button>
123+
)}
124+
</div>
125+
)
126+
}

0 commit comments

Comments
 (0)