Spaces:
Paused
Paused
Commit
·
9f0412d
1
Parent(s):
a65b5e7
fix duplicate space modal
Browse files- .claude/settings.local.json +5 -1
- headless-ui-transition.md +310 -0
- ui/package-lock.json +5 -4
- ui/package.json +1 -1
- ui/src/components/DuplicateSpaceModal.tsx +2 -7
.claude/settings.local.json
CHANGED
@@ -5,7 +5,11 @@
|
|
5 |
"Bash(mkdir:*)",
|
6 |
"Bash(curl:*)",
|
7 |
"Bash(git lfs track:*)",
|
8 |
-
"Bash(git add:*)"
|
|
|
|
|
|
|
|
|
9 |
],
|
10 |
"deny": [],
|
11 |
"ask": []
|
|
|
5 |
"Bash(mkdir:*)",
|
6 |
"Bash(curl:*)",
|
7 |
"Bash(git lfs track:*)",
|
8 |
+
"Bash(git add:*)",
|
9 |
+
"Bash(git commit:*)",
|
10 |
+
"Bash(git push:*)",
|
11 |
+
"Bash(find:*)",
|
12 |
+
"Bash(git rm:*)"
|
13 |
],
|
14 |
"deny": [],
|
15 |
"ask": []
|
headless-ui-transition.md
ADDED
@@ -0,0 +1,310 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Transition
|
2 |
+
==========
|
3 |
+
|
4 |
+
Control the transition styles of conditionally rendered elements, including nested child transitions, using CSS classes.
|
5 |
+
|
6 |
+
PreviewCode
|
7 |
+
|
8 |
+
[](#installation)Installation
|
9 |
+
-----------------------------
|
10 |
+
|
11 |
+
To get started, install Headless UI via npm:
|
12 |
+
|
13 |
+
npm install @headlessui/react
|
14 |
+
|
15 |
+
[](#basic-example)Basic example
|
16 |
+
-------------------------------
|
17 |
+
|
18 |
+
To transition a conditionally rendered element, wrap it in the `Transition` component and use the `show` prop to indicate whether it is open or closed.
|
19 |
+
|
20 |
+
Then, use native CSS transition styles to apply an animation, specifying the element's closed styles by targeting the `data-closed` attribute that the `Transition` component exposes.
|
21 |
+
|
22 |
+
import { Transition } from '@headlessui/react'
|
23 |
+
import { useState } from 'react'
|
24 |
+
|
25 |
+
function Example() {
|
26 |
+
const [open, setOpen] = useState(false)
|
27 |
+
|
28 |
+
return (
|
29 |
+
<>
|
30 |
+
<button onClick={() => setOpen((open) => !open)}>Toggle</button>
|
31 |
+
<Transition show={open}>
|
32 |
+
<div className="transition duration-300 ease-in data-closed:opacity-0">I will fade in and out</div>
|
33 |
+
</Transition>
|
34 |
+
</>
|
35 |
+
)
|
36 |
+
}
|
37 |
+
|
38 |
+
Styles defined with the `data-closed` attribute will be used as the starting point when transitioning in as well as the ending point when transitioning out.
|
39 |
+
|
40 |
+
For more complex transitions, you can also use the `data-enter`, `data-leave`, and `data-transition` attributes to apply styles at the different stages of the transition.
|
41 |
+
|
42 |
+
[](#examples)Examples
|
43 |
+
---------------------
|
44 |
+
|
45 |
+
### [](#different-enter-leave-transitions)Different enter/leave transitions
|
46 |
+
|
47 |
+
Use the `data-enter` and `data-leave` attributes to apply different transition styles when entering and leaving:
|
48 |
+
|
49 |
+
import { Transition } from '@headlessui/react'
|
50 |
+
import clsx from 'clsx'
|
51 |
+
import { useState } from 'react'
|
52 |
+
|
53 |
+
function Example() {
|
54 |
+
const [open, setOpen] = useState(false)
|
55 |
+
|
56 |
+
return (
|
57 |
+
<div className="relative">
|
58 |
+
<button onClick={() => setOpen((open) => !open)}>Toggle</button>
|
59 |
+
<Transition show={open}>
|
60 |
+
<div
|
61 |
+
className={clsx([
|
62 |
+
// Base styles
|
63 |
+
'absolute w-48 border transition ease-in-out',
|
64 |
+
// Shared closed styles
|
65 |
+
'data-closed:opacity-0',
|
66 |
+
// Entering styles
|
67 |
+
'data-enter:duration-100 data-enter:data-closed:-translate-x-full',
|
68 |
+
// Leaving styles
|
69 |
+
'data-leave:duration-300 data-leave:data-closed:translate-x-full',
|
70 |
+
])}
|
71 |
+
>
|
72 |
+
I will enter from the left and leave to the right
|
73 |
+
</div>
|
74 |
+
</Transition>
|
75 |
+
</div>
|
76 |
+
)
|
77 |
+
}
|
78 |
+
|
79 |
+
This example combines the `data-enter` and `data-closed` attributes to specify the starting point of the enter transition, and combines the `data-leave` and `data-closed` attributes to specify the ending point of the leave transition.
|
80 |
+
|
81 |
+
It also uses the `data-enter` and `data-leave` attributes to specify different enter and leave durations.
|
82 |
+
|
83 |
+
### [](#coordinating-multiple-transitions)Coordinating multiple transitions
|
84 |
+
|
85 |
+
Sometimes you need to transition multiple elements with different animations but all based on the same state. For example, say the user clicks a button to open a sidebar that slides over the screen, and you also need to fade-in a backdrop at the same time.
|
86 |
+
|
87 |
+
You can do this by wrapping the related elements with a parent `Transition` component, and wrapping each child that needs its own transition styles with a `TransitionChild` component, which will automatically communicate with the parent `Transition` and inherit the parent's `open` state.
|
88 |
+
|
89 |
+
import { Transition, TransitionChild } from '@headlessui/react'
|
90 |
+
import { useState } from 'react'
|
91 |
+
|
92 |
+
function Example() {
|
93 |
+
const [open, setOpen] = useState(false)
|
94 |
+
|
95 |
+
return (
|
96 |
+
<>
|
97 |
+
<button onClick={() => setOpen(true)}>Open</button>
|
98 |
+
{/* The `show` prop controls all nested `TransitionChild` components. */}
|
99 |
+
<Transition show={open}> {/* Backdrop */}
|
100 |
+
<TransitionChild> <div
|
101 |
+
className="fixed inset-0 bg-black/30 transition duration-300 data-closed:opacity-0"
|
102 |
+
onClick={() => setOpen(false)}
|
103 |
+
/>
|
104 |
+
</TransitionChild>
|
105 |
+
{/* Slide-in sidebar */}
|
106 |
+
<TransitionChild> <div className="fixed inset-y-0 left-0 w-64 bg-white transition duration-300 data-closed:-translate-x-full">
|
107 |
+
{/* ... */}
|
108 |
+
</div> </TransitionChild> </Transition>
|
109 |
+
</>
|
110 |
+
)
|
111 |
+
}
|
112 |
+
|
113 |
+
|
114 |
+
The `TransitionChild` component has the exact same API as the `Transition` component, but with no `show` prop, since the `show` value is controlled by the parent.
|
115 |
+
|
116 |
+
Parent `Transition` components will always automatically wait for all children to finish transitioning before unmounting, so you don't need to manage any of that timing yourself.
|
117 |
+
|
118 |
+
### [](#transitioning-on-initial-mount)Transitioning on initial mount
|
119 |
+
|
120 |
+
If you want an element to transition the very first time it's rendered, set the `appear` prop to `true`.
|
121 |
+
|
122 |
+
This is useful if you want something to transition in on initial page load, or when its parent is conditionally rendered.
|
123 |
+
|
124 |
+
import { Transition } from '@headlessui/react'
|
125 |
+
import { useState } from 'react'
|
126 |
+
|
127 |
+
function Example() {
|
128 |
+
const [open, setOpen] = useState(true)
|
129 |
+
|
130 |
+
return (
|
131 |
+
<>
|
132 |
+
<button onClick={() => setOpen((open) => !open)}>Toggle</button>
|
133 |
+
<Transition show={open} appear={true}> <div className="transition duration-300 ease-in data-closed:opacity-0">I will fade in on initial render</div>
|
134 |
+
</Transition>
|
135 |
+
</>
|
136 |
+
)
|
137 |
+
}
|
138 |
+
|
139 |
+
|
140 |
+
[](#component-api)Component API
|
141 |
+
-------------------------------
|
142 |
+
|
143 |
+
### [](#transition)Transition
|
144 |
+
|
145 |
+
Prop
|
146 |
+
|
147 |
+
Default
|
148 |
+
|
149 |
+
Description
|
150 |
+
|
151 |
+
`as`
|
152 |
+
|
153 |
+
`Fragment`
|
154 |
+
|
155 |
+
`String | Component`
|
156 |
+
|
157 |
+
The element or component the transition should render as.
|
158 |
+
|
159 |
+
`show`
|
160 |
+
|
161 |
+
—
|
162 |
+
|
163 |
+
`Boolean`
|
164 |
+
|
165 |
+
Whether the children should be shown or hidden.
|
166 |
+
|
167 |
+
`appear`
|
168 |
+
|
169 |
+
`false`
|
170 |
+
|
171 |
+
`Boolean`
|
172 |
+
|
173 |
+
Whether the transition should run on initial mount.
|
174 |
+
|
175 |
+
`unmount`
|
176 |
+
|
177 |
+
`true`
|
178 |
+
|
179 |
+
`Boolean`
|
180 |
+
|
181 |
+
Whether the element should be unmounted or hidden based on the show state.
|
182 |
+
|
183 |
+
`beforeEnter`
|
184 |
+
|
185 |
+
—
|
186 |
+
|
187 |
+
`() => void`
|
188 |
+
|
189 |
+
Callback which is called before we start the enter transition.
|
190 |
+
|
191 |
+
`afterEnter`
|
192 |
+
|
193 |
+
—
|
194 |
+
|
195 |
+
`() => void`
|
196 |
+
|
197 |
+
Callback which is called after we finished the enter transition.
|
198 |
+
|
199 |
+
`beforeLeave`
|
200 |
+
|
201 |
+
—
|
202 |
+
|
203 |
+
`() => void`
|
204 |
+
|
205 |
+
Callback which is called before we start the leave transition.
|
206 |
+
|
207 |
+
`afterLeave`
|
208 |
+
|
209 |
+
—
|
210 |
+
|
211 |
+
`() => void`
|
212 |
+
|
213 |
+
Callback which is called after we finished the leave transition.
|
214 |
+
|
215 |
+
### [](#transition-child)TransitionChild
|
216 |
+
|
217 |
+
Prop
|
218 |
+
|
219 |
+
Default
|
220 |
+
|
221 |
+
Description
|
222 |
+
|
223 |
+
`as`
|
224 |
+
|
225 |
+
`Fragment`
|
226 |
+
|
227 |
+
`String | Component`
|
228 |
+
|
229 |
+
The element or component the transition child should render as.
|
230 |
+
|
231 |
+
`appear`
|
232 |
+
|
233 |
+
`false`
|
234 |
+
|
235 |
+
`Boolean`
|
236 |
+
|
237 |
+
Whether the transition should run on initial mount.
|
238 |
+
|
239 |
+
`unmount`
|
240 |
+
|
241 |
+
`true`
|
242 |
+
|
243 |
+
`Boolean`
|
244 |
+
|
245 |
+
Whether the element should be unmounted or hidden based on the show state.
|
246 |
+
|
247 |
+
`beforeEnter`
|
248 |
+
|
249 |
+
—
|
250 |
+
|
251 |
+
`() => void`
|
252 |
+
|
253 |
+
Callback which is called before we start the enter transition.
|
254 |
+
|
255 |
+
`afterEnter`
|
256 |
+
|
257 |
+
—
|
258 |
+
|
259 |
+
`() => void`
|
260 |
+
|
261 |
+
Callback which is called after we finished the enter transition.
|
262 |
+
|
263 |
+
`beforeLeave`
|
264 |
+
|
265 |
+
—
|
266 |
+
|
267 |
+
`() => void`
|
268 |
+
|
269 |
+
Callback which is called before we start the leave transition.
|
270 |
+
|
271 |
+
`afterLeave`
|
272 |
+
|
273 |
+
—
|
274 |
+
|
275 |
+
`() => void`
|
276 |
+
|
277 |
+
Callback which is called after we finished the leave transition.
|
278 |
+
|
279 |
+
### [](#data-attributes)Data attributes
|
280 |
+
|
281 |
+
Attribute
|
282 |
+
|
283 |
+
Description
|
284 |
+
|
285 |
+
`data-closed`
|
286 |
+
|
287 |
+
Present before transitioning in, and when transitioning out.
|
288 |
+
|
289 |
+
`data-enter`
|
290 |
+
|
291 |
+
Present when transitioning in.
|
292 |
+
|
293 |
+
`data-leave`
|
294 |
+
|
295 |
+
Present when transitioning out.
|
296 |
+
|
297 |
+
`data-transition`
|
298 |
+
|
299 |
+
Present when transitioning in or out.
|
300 |
+
|
301 |
+
[](#styled-examples)Styled examples
|
302 |
+
-----------------------------------
|
303 |
+
|
304 |
+
If you're interested in predesigned [Tailwind CSS component examples](https://tailwindui.com/components) using Headless UI, check out **Tailwind Plus** — a collection of beautifully designed and expertly crafted components built by us.
|
305 |
+
|
306 |
+
It's a great way to support our work on open-source projects like this and makes it possible for us to improve them and keep them well-maintained.
|
307 |
+
|
308 |
+
[Explore more predesigned examples →](https://tailwindcss.com/plus)
|
309 |
+
|
310 |
+
[](https://tailwindcss.com/plus)
|
ui/package-lock.json
CHANGED
@@ -31,7 +31,7 @@
|
|
31 |
"@types/node": "^20",
|
32 |
"@types/react": "^19",
|
33 |
"@types/react-dom": "^19",
|
34 |
-
"concurrently": "^9.
|
35 |
"postcss": "^8",
|
36 |
"prettier": "^3.5.1",
|
37 |
"prettier-basic": "^1.0.0",
|
@@ -2007,10 +2007,11 @@
|
|
2007 |
"license": "MIT"
|
2008 |
},
|
2009 |
"node_modules/concurrently": {
|
2010 |
-
"version": "9.
|
2011 |
-
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.
|
2012 |
-
"integrity": "sha512-
|
2013 |
"dev": true,
|
|
|
2014 |
"dependencies": {
|
2015 |
"chalk": "^4.1.2",
|
2016 |
"lodash": "^4.17.21",
|
|
|
31 |
"@types/node": "^20",
|
32 |
"@types/react": "^19",
|
33 |
"@types/react-dom": "^19",
|
34 |
+
"concurrently": "^9.2.0",
|
35 |
"postcss": "^8",
|
36 |
"prettier": "^3.5.1",
|
37 |
"prettier-basic": "^1.0.0",
|
|
|
2007 |
"license": "MIT"
|
2008 |
},
|
2009 |
"node_modules/concurrently": {
|
2010 |
+
"version": "9.2.0",
|
2011 |
+
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.0.tgz",
|
2012 |
+
"integrity": "sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==",
|
2013 |
"dev": true,
|
2014 |
+
"license": "MIT",
|
2015 |
"dependencies": {
|
2016 |
"chalk": "^4.1.2",
|
2017 |
"lodash": "^4.17.21",
|
ui/package.json
CHANGED
@@ -35,7 +35,7 @@
|
|
35 |
"@types/node": "^20",
|
36 |
"@types/react": "^19",
|
37 |
"@types/react-dom": "^19",
|
38 |
-
"concurrently": "^9.
|
39 |
"postcss": "^8",
|
40 |
"prettier": "^3.5.1",
|
41 |
"prettier-basic": "^1.0.0",
|
|
|
35 |
"@types/node": "^20",
|
36 |
"@types/react": "^19",
|
37 |
"@types/react-dom": "^19",
|
38 |
+
"concurrently": "^9.2.0",
|
39 |
"postcss": "^8",
|
40 |
"prettier": "^3.5.1",
|
41 |
"prettier-basic": "^1.0.0",
|
ui/src/components/DuplicateSpaceModal.tsx
CHANGED
@@ -29,14 +29,12 @@ export default function DuplicateSpaceModal() {
|
|
29 |
return (
|
30 |
<Dialog open={isOpen} onClose={() => {}} className="relative z-50" static>
|
31 |
<DialogBackdrop
|
32 |
-
transition
|
33 |
-
className="fixed inset-0 bg-black/50 backdrop-saturate-150 transition-opacity data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in"
|
34 |
/>
|
35 |
|
36 |
<div className="fixed inset-0 z-10 w-screen overflow-y-auto">
|
37 |
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
38 |
<DialogPanel
|
39 |
-
transition
|
40 |
className="relative transform overflow-hidden rounded-2xl bg-gradient-to-b from-gray-800 to-gray-900 text-left shadow-2xl transition-all data-closed:translate-y-4 data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in sm:my-8 sm:w-full sm:max-w-md data-closed:sm:translate-y-0 data-closed:sm:scale-95 border border-gray-700"
|
41 |
>
|
42 |
<div className="absolute inset-0 bg-gradient-to-br from-blue-600/10 via-transparent to-orange-600/10 pointer-events-none" />
|
@@ -48,7 +46,7 @@ export default function DuplicateSpaceModal() {
|
|
48 |
</div>
|
49 |
|
50 |
<h3 className="text-2xl font-bold text-white mb-3 bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-transparent">
|
51 |
-
|
52 |
</h3>
|
53 |
|
54 |
<div className="space-y-3 text-gray-300">
|
@@ -68,9 +66,6 @@ export default function DuplicateSpaceModal() {
|
|
68 |
onClick={handleDuplicate}
|
69 |
className="w-full inline-flex items-center justify-center gap-2 rounded-xl bg-gradient-to-r from-orange-500 to-yellow-500 px-6 py-3 text-base font-semibold text-white shadow-lg hover:from-orange-600 hover:to-yellow-600 transform hover:scale-[1.02] transition-all duration-200"
|
70 |
>
|
71 |
-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
72 |
-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7v8a2 2 0 002 2h6m0-6v6m0-6l-3-3m3 3l3-3" />
|
73 |
-
</svg>
|
74 |
Duplicate this Space
|
75 |
</button>
|
76 |
|
|
|
29 |
return (
|
30 |
<Dialog open={isOpen} onClose={() => {}} className="relative z-50" static>
|
31 |
<DialogBackdrop
|
32 |
+
className="fixed inset-0 bg-black/50 backdrop-blur-[2px] backdrop-saturate-150 transition-opacity data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in"
|
|
|
33 |
/>
|
34 |
|
35 |
<div className="fixed inset-0 z-10 w-screen overflow-y-auto">
|
36 |
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
37 |
<DialogPanel
|
|
|
38 |
className="relative transform overflow-hidden rounded-2xl bg-gradient-to-b from-gray-800 to-gray-900 text-left shadow-2xl transition-all data-closed:translate-y-4 data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in sm:my-8 sm:w-full sm:max-w-md data-closed:sm:translate-y-0 data-closed:sm:scale-95 border border-gray-700"
|
39 |
>
|
40 |
<div className="absolute inset-0 bg-gradient-to-br from-blue-600/10 via-transparent to-orange-600/10 pointer-events-none" />
|
|
|
46 |
</div>
|
47 |
|
48 |
<h3 className="text-2xl font-bold text-white mb-3 bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-transparent">
|
49 |
+
This is a space template
|
50 |
</h3>
|
51 |
|
52 |
<div className="space-y-3 text-gray-300">
|
|
|
66 |
onClick={handleDuplicate}
|
67 |
className="w-full inline-flex items-center justify-center gap-2 rounded-xl bg-gradient-to-r from-orange-500 to-yellow-500 px-6 py-3 text-base font-semibold text-white shadow-lg hover:from-orange-600 hover:to-yellow-600 transform hover:scale-[1.02] transition-all duration-200"
|
68 |
>
|
|
|
|
|
|
|
69 |
Duplicate this Space
|
70 |
</button>
|
71 |
|