cult-ui
Display
Feedback
Layout

floating-panel

A headless, composable floating panel component.

animated
button
dialog
effect
flex
form
hover
list
modal
motion
positioning
select
text
transform
transition

Source Code

Files
floating-panel-examples
1"use client"
2 
3import React from "react"
4import { Image as ImageIcon, Paintbrush, Plus, X } from "lucide-react"
5import { AnimatePresence, motion } from "motion/react"
6 
7import {
8  FloatingPanelBody,
9  FloatingPanelButton,
10  FloatingPanelCloseButton,
11  FloatingPanelContent,
12  FloatingPanelFooter,
13  FloatingPanelForm,
14  FloatingPanelHeader,
15  FloatingPanelLabel,
16  FloatingPanelRoot,
17  FloatingPanelSubmitButton,
18  FloatingPanelTextarea,
19  FloatingPanelTrigger,
20} from "../ui/floating-panel"
21 
22function FloatingPanelInput() {
23  const handleSubmit = (note: string) => {
24    console.log("Submitted note:", note)
25  }
26 
27  return (
28    <FloatingPanelRoot>
29      <FloatingPanelTrigger
30        title="Add Note"
31        className="flex items-center space-x-2 px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors"
32      >
33        <span>Add Note</span>
34      </FloatingPanelTrigger>
35      <FloatingPanelContent className="w-80">
36        <FloatingPanelForm onSubmit={handleSubmit}>
37          <FloatingPanelBody>
38            <FloatingPanelLabel htmlFor="note-input">Note</FloatingPanelLabel>
39            <FloatingPanelTextarea id="note-input" className="min-h-[100px]" />
40          </FloatingPanelBody>
41          <FloatingPanelFooter>
42            <FloatingPanelCloseButton />
43            <FloatingPanelSubmitButton />
44          </FloatingPanelFooter>
45        </FloatingPanelForm>
46      </FloatingPanelContent>
47    </FloatingPanelRoot>
48  )
49}
50 
51const ColorPickerFloatingPanel = () => {
52  const colors = [
53    "#FF5733",
54    "#33FF57",
55    "#3357FF",
56    "#FF33F1",
57    "#33FFF1",
58    "#F1FF33",
59  ]
60 
61  return (
62    <FloatingPanelRoot>
63      <FloatingPanelTrigger
64        title="Choose Color"
65        className="flex items-center space-x-2 px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/90 transition-colors"
66      >
67        <span>Choose Color</span>
68      </FloatingPanelTrigger>
69      <FloatingPanelContent className="w-64">
70        <FloatingPanelBody>
71          <div className="grid grid-cols-3 gap-2">
72            <AnimatePresence>
73              {colors.map((color) => (
74                <motion.button
75                  key={color}
76                  className="w-12 h-12 rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"
77                  style={{ backgroundColor: color }}
78                  onClick={() => console.log(`Selected color: ${color}`)}
79                  whileHover={{ scale: 1.1 }}
80                  whileTap={{ scale: 0.9 }}
81                  initial={{ opacity: 0, scale: 0.8 }}
82                  animate={{ opacity: 1, scale: 1 }}
83                  exit={{ opacity: 0, scale: 0.8 }}
84                  transition={{ duration: 0.2 }}
85                />
86              ))}
87            </AnimatePresence>
88          </div>
89        </FloatingPanelBody>
90        <FloatingPanelFooter>
91          <FloatingPanelCloseButton />
92        </FloatingPanelFooter>
93      </FloatingPanelContent>
94    </FloatingPanelRoot>
95  )
96}
97 
98const QuickActionsFloatingPanel = () => {
99  const actions = [
100    {
101      icon: <Plus className="w-4 h-4" />,
102      label: "New File",
103      action: () => console.log("New File"),
104    },
105    {
106      icon: <ImageIcon className="w-4 h-4" />,
107      label: "Upload Image",
108      action: () => console.log("Upload Image"),
109    },
110    {
111      icon: <Paintbrush className="w-4 h-4" />,
112      label: "Edit Colors",
113      action: () => console.log("Edit Colors"),
114    },
115  ]
116 
117  return (
118    <FloatingPanelRoot>
119      <FloatingPanelTrigger
120        title="Quick Actions"
121        className="flex items-center space-x-2 px-4 py-2 bg-accent text-accent-foreground rounded-md hover:bg-accent/90 transition-colors"
122      >
123        <span>Quick Actions</span>
124      </FloatingPanelTrigger>
125      <FloatingPanelContent className="w-56">
126        <FloatingPanelBody>
127          <AnimatePresence>
128            {actions.map((action, index) => (
129              <motion.div
130                key={index}
131                initial={{ opacity: 0, y: -10 }}
132                animate={{ opacity: 1, y: 0 }}
133                exit={{ opacity: 0, y: 10 }}
134                transition={{ delay: index * 0.1 }}
135              >
136                <FloatingPanelButton
137                  onClick={action.action}
138                  className="w-full flex items-center space-x-2 px-2 py-1 rounded-md hover:bg-muted transition-colors"
139                >
140                  {action.icon}
141                  <span>{action.label}</span>
142                </FloatingPanelButton>
143              </motion.div>
144            ))}
145          </AnimatePresence>
146        </FloatingPanelBody>
147        <FloatingPanelFooter>
148          <FloatingPanelCloseButton />
149        </FloatingPanelFooter>
150      </FloatingPanelContent>
151    </FloatingPanelRoot>
152  )
153}
154 
155const ImagePreviewFloatingPanel = () => {
156  return (
157    <FloatingPanelRoot>
158      <FloatingPanelTrigger
159        title="Preview Image"
160        className="flex items-center space-x-2 px-4 py-2 bg-muted text-muted-foreground rounded-md hover:bg-muted/90 transition-colors"
161      >
162        <span>Preview Image</span>
163      </FloatingPanelTrigger>
164      <FloatingPanelContent className="w-80">
165        <FloatingPanelBody>
166          <motion.img
167            src="/placeholder.svg?height=200&width=300"
168            alt="Preview"
169            className="w-full h-auto rounded-md"
170            initial={{ opacity: 0, scale: 0.9 }}
171            animate={{ opacity: 1, scale: 1 }}
172            transition={{ duration: 0.3 }}
173          />
174          <motion.p
175            className="mt-2 text-sm text-muted-foreground"
176            initial={{ opacity: 0, y: 10 }}
177            animate={{ opacity: 1, y: 0 }}
178            transition={{ delay: 0.2, duration: 0.3 }}
179          >
180            Image preview description goes here.
181          </motion.p>
182        </FloatingPanelBody>
183        <FloatingPanelFooter>
184          <FloatingPanelCloseButton />
185          <FloatingPanelButton
186            onClick={() => console.log("Download clicked")}
187            className="px-3 py-1 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors"
188          >
189            Download
190          </FloatingPanelButton>
191        </FloatingPanelFooter>
192      </FloatingPanelContent>
193    </FloatingPanelRoot>
194  )
195}
196 
197export function FloatingPanelExamples() {
198  return (
199    <div className="p-8 space-y-8">
200      <h1 className="text-3xl font-bold mb-4">FloatingPanel Examples</h1>
201      <div className="flex flex-col md:flex-row flex-wrap gap-4">
202        <FloatingPanelInput />
203        <ColorPickerFloatingPanel />
204        <QuickActionsFloatingPanel />
205        <ImagePreviewFloatingPanel />
206      </div>
207    </div>
208  )
209}