marqy 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/core-COOoOGpB.js +21 -0
- package/dist/core-COOoOGpB.js.map +1 -0
- package/dist/core-CuZGUfsl.cjs +2 -0
- package/dist/core-CuZGUfsl.cjs.map +1 -0
- package/dist/index.cjs.js +2 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.esm.js +5 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/marqy.css +4 -0
- package/dist/react.cjs.js +2 -0
- package/dist/react.cjs.js.map +1 -0
- package/dist/react.d.ts +15 -0
- package/dist/react.esm.js +60 -0
- package/dist/react.esm.js.map +1 -0
- package/dist/svelte.cjs.js +2 -0
- package/dist/svelte.cjs.js.map +1 -0
- package/dist/svelte.d.ts +7 -0
- package/dist/svelte.esm.js +54 -0
- package/dist/svelte.esm.js.map +1 -0
- package/dist/vanilla.cjs.js +2 -0
- package/dist/vanilla.cjs.js.map +1 -0
- package/dist/vanilla.d.ts +32 -0
- package/dist/vanilla.esm.js +96 -0
- package/dist/vanilla.esm.js.map +1 -0
- package/dist/vue.cjs.js +2 -0
- package/dist/vue.cjs.js.map +1 -0
- package/dist/vue.d.ts +45 -0
- package/dist/vue.esm.js +70 -0
- package/dist/vue.esm.js.map +1 -0
- package/package.json +81 -19
- package/.claude/settings.local.json +0 -13
- package/.prettierrc +0 -6
- package/.vscode/settings.json +0 -3
- package/dist/marqy.d.ts +0 -9
- package/dist/marqy.esm.js +0 -2
- package/dist/marqy.esm.js.map +0 -1
- package/dist/marqy.js +0 -2
- package/dist/marqy.js.map +0 -1
- package/dist/marqy.umd.js +0 -2
- package/dist/marqy.umd.js.map +0 -1
- package/examples/.astro/content-assets.mjs +0 -1
- package/examples/.astro/content-modules.mjs +0 -1
- package/examples/.astro/content.d.ts +0 -154
- package/examples/.astro/data-store.json +0 -1
- package/examples/.astro/fonts/font-akkurat-mono-500-normal-40f4e0ea0b54adc5.woff2 +0 -0
- package/examples/.astro/fonts/font-akkurat-mono-700-normal-b9f40f1447b587bd.woff +0 -0
- package/examples/.astro/fonts/font-grtsk-300-normal-8ef14ca23be6893c.woff2 +0 -0
- package/examples/.astro/fonts/font-grtsk-400-normal-13ba8954073ee64a.woff2 +0 -0
- package/examples/.astro/fonts/font-grtsk-500-normal-d214468daf16245f.woff2 +0 -0
- package/examples/.astro/fonts/font-grtsk-wide-500-normal-6f8c2658b9c2ba8e.woff2 +0 -0
- package/examples/.astro/fonts/font-grtsk-wide-700-normal-17406f09c7b68ca3.woff2 +0 -0
- package/examples/.astro/fonts.d.ts +0 -4
- package/examples/.astro/settings.json +0 -5
- package/examples/.astro/types.d.ts +0 -3
- package/examples/.yarnrc +0 -1
- package/examples/astro.config.mjs +0 -101
- package/examples/package.json +0 -30
- package/examples/public/apple-touch-icon.png +0 -0
- package/examples/public/favicon.ico +0 -0
- package/examples/public/favicon.svg +0 -4
- package/examples/public/marqy-logo.svg +0 -35
- package/examples/src/assets/baggu.jpg +0 -0
- package/examples/src/assets/bluesky.jpg +0 -0
- package/examples/src/assets/clams-lol.jpg +0 -0
- package/examples/src/assets/coconut-club-2.jpg +0 -0
- package/examples/src/assets/coconut-club.jpg +0 -0
- package/examples/src/assets/lucci.jpg +0 -0
- package/examples/src/assets/phila-museum.jpg +0 -0
- package/examples/src/assets/red-rooster.jpg +0 -0
- package/examples/src/assets/sanity.jpg +0 -0
- package/examples/src/assets/usal.jpg +0 -0
- package/examples/src/assets/vacation.jpg +0 -0
- package/examples/src/components/CopyButton.tsx +0 -26
- package/examples/src/components/Divider.tsx +0 -3
- package/examples/src/components/Footer.astro +0 -7
- package/examples/src/components/InUse.astro +0 -89
- package/examples/src/components/InUseExamples.tsx +0 -60
- package/examples/src/components/MarqyCredits.tsx +0 -33
- package/examples/src/components/MarqyHero.tsx +0 -77
- package/examples/src/components/MarqyInteractiveDemo.tsx +0 -46
- package/examples/src/components/MarqyPlayground.tsx +0 -496
- package/examples/src/components/MarqySpeedDemo.tsx +0 -34
- package/examples/src/components/MarqyVerticalDemo.tsx +0 -44
- package/examples/src/components/Playground.astro +0 -11
- package/examples/src/components/QuickStart.astro +0 -59
- package/examples/src/components/SectionHeadline.tsx +0 -41
- package/examples/src/components/Tile.tsx +0 -32
- package/examples/src/content.config.ts +0 -3
- package/examples/src/fonts/Akkurat-Mono-Bold.woff +0 -0
- package/examples/src/fonts/Akkurat-Mono.woff +0 -0
- package/examples/src/fonts/Akkurat-Mono.woff2 +0 -0
- package/examples/src/fonts/Grtsk-Peta-Light.woff +0 -0
- package/examples/src/fonts/Grtsk-Peta-Light.woff2 +0 -0
- package/examples/src/fonts/Grtsk-Peta-Medium.woff +0 -0
- package/examples/src/fonts/Grtsk-Peta-Medium.woff2 +0 -0
- package/examples/src/fonts/Grtsk-Peta-Regular.woff +0 -0
- package/examples/src/fonts/Grtsk-Peta-Regular.woff2 +0 -0
- package/examples/src/fonts/Grtsk-Tera-Bold.woff +0 -0
- package/examples/src/fonts/Grtsk-Tera-Bold.woff2 +0 -0
- package/examples/src/fonts/Grtsk-Tera-Medium.woff +0 -0
- package/examples/src/fonts/Grtsk-Tera-Medium.woff2 +0 -0
- package/examples/src/layouts/layout.astro +0 -107
- package/examples/src/lib/cn.ts +0 -16
- package/examples/src/lib/helpers.ts +0 -13
- package/examples/src/lib/hooks/useCopyText.ts +0 -47
- package/examples/src/pages/index.astro +0 -56
- package/examples/src/styles/_base.css +0 -155
- package/examples/src/styles/_components.css +0 -123
- package/examples/src/styles/_utilities.css +0 -23
- package/examples/src/styles/app.css +0 -397
- package/examples/tsconfig.json +0 -3
- package/examples/yarn.lock +0 -3316
- package/marqy.css +0 -131
- package/src/marqy.tsx +0 -97
- package/tsconfig.json +0 -9
|
@@ -1,496 +0,0 @@
|
|
|
1
|
-
import React, { forwardRef, useState, useEffect, useRef } from 'react'
|
|
2
|
-
import { gsap } from 'gsap'
|
|
3
|
-
import { Marqy } from 'marqy'
|
|
4
|
-
import { RadioGroup } from '@base-ui-components/react/radio-group'
|
|
5
|
-
import { Radio } from '@base-ui-components/react/radio'
|
|
6
|
-
import { Slider } from '@base-ui-components/react/slider'
|
|
7
|
-
import { Switch } from '@base-ui-components/react/switch'
|
|
8
|
-
import { ResizableBox } from 'react-resizable'
|
|
9
|
-
import useDimensions from 'react-cool-dimensions'
|
|
10
|
-
|
|
11
|
-
import { cn } from '../lib/cn'
|
|
12
|
-
import Divider from './Divider'
|
|
13
|
-
|
|
14
|
-
const DIRECTIONS = ['left', 'right', 'up', 'down'] as const
|
|
15
|
-
type Direction = (typeof DIRECTIONS)[number]
|
|
16
|
-
|
|
17
|
-
type DragHandleProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
18
|
-
handleAxis?: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const DragHandle = forwardRef<HTMLDivElement, DragHandleProps>((props, ref) => {
|
|
22
|
-
const { handleAxis, ...restProps } = props
|
|
23
|
-
return (
|
|
24
|
-
<div
|
|
25
|
-
ref={ref}
|
|
26
|
-
className={cn(
|
|
27
|
-
'flex justify-center items-center absolute bg-purple rounded-2 z-4 cursor-grab active:cursor-grabbing text-center',
|
|
28
|
-
{
|
|
29
|
-
// Y-axis
|
|
30
|
-
'w-55 h-8 -translate-y-1/2 -translate-x-1/2 after:absolute after:h-px after:w-20 after:bg-black/30':
|
|
31
|
-
handleAxis === 'n' || handleAxis === 's',
|
|
32
|
-
'top-0 left-1/2': handleAxis === 'n',
|
|
33
|
-
'top-full left-1/2': handleAxis === 's',
|
|
34
|
-
|
|
35
|
-
// X-axis
|
|
36
|
-
'h-55 w-8 -translate-y-1/2 -translate-x-1/2 after:absolute after:w-px after:h-20 after:bg-black/30':
|
|
37
|
-
handleAxis === 'w' || handleAxis === 'e',
|
|
38
|
-
'left-0 top-1/2': handleAxis === 'w',
|
|
39
|
-
'left-full top-1/2': handleAxis === 'e',
|
|
40
|
-
},
|
|
41
|
-
)}
|
|
42
|
-
{...restProps}
|
|
43
|
-
/>
|
|
44
|
-
)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
export default function MarqyPlayground() {
|
|
48
|
-
const $marqyContainer = useRef<HTMLDivElement>(null)
|
|
49
|
-
const { observe, height, width } = useDimensions<HTMLDivElement>({
|
|
50
|
-
useBorderBoxSize: true,
|
|
51
|
-
})
|
|
52
|
-
const [itemCount, setItemCount] = useState<number>(0)
|
|
53
|
-
const [duration, setDuration] = useState('')
|
|
54
|
-
|
|
55
|
-
const DEFAULT_TEXT = 'marqy'
|
|
56
|
-
const [size, setSize] = useState({ width: width - 40, height: -40 })
|
|
57
|
-
const [isResizing, setIsResizing] = useState(false)
|
|
58
|
-
const [text, setText] = useState(DEFAULT_TEXT)
|
|
59
|
-
const [direction, setDirection] = useState<Direction>('left')
|
|
60
|
-
const [speed, setSpeed] = useState(1)
|
|
61
|
-
const [pauseOnHover, setPauseOnHover] = useState(false)
|
|
62
|
-
const [manual, setManual] = useState(false)
|
|
63
|
-
const [showXRay, setShowXRay] = useState(false)
|
|
64
|
-
|
|
65
|
-
const [gsapEnabled, setGsapEnabled] = useState(false)
|
|
66
|
-
|
|
67
|
-
const isVertical = direction === 'up' || direction === 'down'
|
|
68
|
-
const overlayClass = 'after:absolute after:inset-y-0 after:bg-black/80'
|
|
69
|
-
|
|
70
|
-
useEffect(() => {
|
|
71
|
-
const container = $marqyContainer.current
|
|
72
|
-
const $content = gsap.utils.toArray<HTMLElement>(
|
|
73
|
-
'[data-marqy-content]',
|
|
74
|
-
container,
|
|
75
|
-
)
|
|
76
|
-
if (!container || !$content.length) return
|
|
77
|
-
|
|
78
|
-
if (!gsapEnabled) {
|
|
79
|
-
// Only kill stale tweens — don't touch inline styles, CSS owns the transform
|
|
80
|
-
gsap.killTweensOf($content)
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
let tween: gsap.core.Tween | null = null
|
|
85
|
-
|
|
86
|
-
const buildTween = () => {
|
|
87
|
-
const dur = parseFloat($content[0].dataset.marqyStatic ?? '')
|
|
88
|
-
if (!dur) return
|
|
89
|
-
|
|
90
|
-
gsap.killTweensOf(tween)
|
|
91
|
-
tween?.kill()
|
|
92
|
-
gsap.killTweensOf($content)
|
|
93
|
-
gsap.set($content, { xPercent: 0, yPercent: 0 })
|
|
94
|
-
|
|
95
|
-
if (direction === 'down') {
|
|
96
|
-
// CSS marqyD: translate from -100% → 0
|
|
97
|
-
gsap.set($content, { yPercent: -100 })
|
|
98
|
-
tween = gsap.to($content, {
|
|
99
|
-
yPercent: 0,
|
|
100
|
-
ease: 'none',
|
|
101
|
-
duration: dur,
|
|
102
|
-
repeat: -1,
|
|
103
|
-
})
|
|
104
|
-
} else if (direction === 'up') {
|
|
105
|
-
// CSS marqyU: translate from 0 → -100%
|
|
106
|
-
tween = gsap.to($content, {
|
|
107
|
-
yPercent: -100,
|
|
108
|
-
ease: 'none',
|
|
109
|
-
duration: dur,
|
|
110
|
-
repeat: -1,
|
|
111
|
-
})
|
|
112
|
-
} else {
|
|
113
|
-
tween = gsap.to($content, {
|
|
114
|
-
xPercent: direction === 'left' ? -100 : 100,
|
|
115
|
-
ease: 'none',
|
|
116
|
-
duration: dur,
|
|
117
|
-
repeat: -1,
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// If cursor is already inside the container (e.g. enabled via button click),
|
|
122
|
-
// immediately apply the paused state so hover works without needing a re-enter
|
|
123
|
-
if (pauseOnHover && container.matches(':hover')) {
|
|
124
|
-
gsap.set(tween, { timeScale: 0 })
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// attrObserver handles speed/dimension changes without a full effect re-run
|
|
129
|
-
const attrObserver = new MutationObserver(buildTween)
|
|
130
|
-
attrObserver.observe($content[0], {
|
|
131
|
-
attributes: true,
|
|
132
|
-
attributeFilter: ['data-marqy-static'],
|
|
133
|
-
})
|
|
134
|
-
buildTween()
|
|
135
|
-
|
|
136
|
-
const slowDown = () => {
|
|
137
|
-
if (!tween) return
|
|
138
|
-
gsap.to(tween, {
|
|
139
|
-
timeScale: 0,
|
|
140
|
-
duration: 1.5,
|
|
141
|
-
ease: 'power3.out',
|
|
142
|
-
overwrite: 'auto',
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
const speedUp = () => {
|
|
146
|
-
if (!tween) return
|
|
147
|
-
gsap.to(tween, {
|
|
148
|
-
timeScale: 1,
|
|
149
|
-
duration: 0.75,
|
|
150
|
-
ease: 'power3.out',
|
|
151
|
-
overwrite: 'auto',
|
|
152
|
-
})
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (pauseOnHover) {
|
|
156
|
-
container.addEventListener('mouseenter', slowDown)
|
|
157
|
-
container.addEventListener('mouseleave', speedUp)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return () => {
|
|
161
|
-
attrObserver.disconnect()
|
|
162
|
-
gsap.killTweensOf(tween)
|
|
163
|
-
tween?.kill()
|
|
164
|
-
gsap.killTweensOf($content)
|
|
165
|
-
// clearProps lets CSS animation take over cleanly when GSAP is disabled
|
|
166
|
-
gsap.set($content, { clearProps: 'transform,xPercent,yPercent' })
|
|
167
|
-
container.removeEventListener('mouseenter', slowDown)
|
|
168
|
-
container.removeEventListener('mouseleave', speedUp)
|
|
169
|
-
}
|
|
170
|
-
}, [gsapEnabled, direction, isVertical, pauseOnHover])
|
|
171
|
-
|
|
172
|
-
function onResize(
|
|
173
|
-
_: any,
|
|
174
|
-
{ size }: { size: { width: number; height: number } },
|
|
175
|
-
) {
|
|
176
|
-
setSize({ width: size.width, height: size.height })
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
useEffect(() => {
|
|
180
|
-
const el = $marqyContainer.current
|
|
181
|
-
if (!el) return
|
|
182
|
-
|
|
183
|
-
const read = () => {
|
|
184
|
-
const firstContent = el.querySelector<HTMLElement>('[data-marqy-content]')
|
|
185
|
-
setDuration(firstContent?.style.animationDuration ?? '')
|
|
186
|
-
setItemCount(
|
|
187
|
-
firstContent?.querySelectorAll('[data-marqy-item]').length ?? 0,
|
|
188
|
-
)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const observer = new MutationObserver(read)
|
|
192
|
-
observer.observe(el, {
|
|
193
|
-
subtree: true,
|
|
194
|
-
attributes: true,
|
|
195
|
-
attributeFilter: ['style'],
|
|
196
|
-
childList: true,
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
return () => observer.disconnect()
|
|
200
|
-
}, [])
|
|
201
|
-
|
|
202
|
-
useEffect(() => {
|
|
203
|
-
setSize({ width: width - 40, height: height - 40 })
|
|
204
|
-
}, [isVertical, width, height])
|
|
205
|
-
|
|
206
|
-
return (
|
|
207
|
-
<div className={cn('relative grid grid-cols-8 gap-20 sm:gap-40')}>
|
|
208
|
-
{/* Controls */}
|
|
209
|
-
<div
|
|
210
|
-
className={cn(
|
|
211
|
-
'relative col-span-8 md:col-span-4 backdrop-blur-md z-1 rounded-5',
|
|
212
|
-
'after:-left-40 after:-right-40 after:-z-1',
|
|
213
|
-
overlayClass,
|
|
214
|
-
)}
|
|
215
|
-
>
|
|
216
|
-
<div
|
|
217
|
-
ref={observe}
|
|
218
|
-
className="flex flex-col gap-20 bg-white/10 p-20 rounded-5"
|
|
219
|
-
>
|
|
220
|
-
{/* Text */}
|
|
221
|
-
<div className="relative flex justify-between items-center gap-10">
|
|
222
|
-
<h3 className="text-p1 sr-only">Text</h3>
|
|
223
|
-
<input
|
|
224
|
-
value={text}
|
|
225
|
-
onChange={(e) => setText(e.target.value)}
|
|
226
|
-
className="rounded-4 h-40 pr-75 bg-white/10 font-headline font-bold text-15 uppercase text-white px-10 py-0 focus:outline-none"
|
|
227
|
-
/>
|
|
228
|
-
|
|
229
|
-
<button
|
|
230
|
-
disabled={text === DEFAULT_TEXT}
|
|
231
|
-
onClick={() => setText(DEFAULT_TEXT)}
|
|
232
|
-
className="disabled:cursor-not-allowed clean-btn cursor-pointer rounded-3 flex items-center justify-center absolute right-10 h-20 w-55 bg-white/20 text-white disabled:text-white/40 disabled:bg-white/10"
|
|
233
|
-
>
|
|
234
|
-
<span className="text-p0 uppercase tracking-10">Reset</span>
|
|
235
|
-
</button>
|
|
236
|
-
</div>
|
|
237
|
-
|
|
238
|
-
{/* Direction */}
|
|
239
|
-
<div className="flex justify-between items-center gap-x-20 border-t border-white/10 pt-20">
|
|
240
|
-
<h3 className="text-p1">direction</h3>
|
|
241
|
-
<RadioGroup
|
|
242
|
-
value={direction}
|
|
243
|
-
onValueChange={(val) => setDirection(val as Direction)}
|
|
244
|
-
className="flex gap-5"
|
|
245
|
-
>
|
|
246
|
-
{DIRECTIONS.map((dir) => (
|
|
247
|
-
<label key={dir} className="flex items-center cursor-pointer">
|
|
248
|
-
<Radio.Root
|
|
249
|
-
value={dir}
|
|
250
|
-
nativeButton
|
|
251
|
-
render={<button />}
|
|
252
|
-
className="clean-btn cursor-pointer rounded-3 data-checked:animate-flicker-opacity hover:bg-white/20 bg-white/10 min-w-55 h-20 flex items-center justify-center data-checked:bg-neon data-checked:text-black transition-colors"
|
|
253
|
-
>
|
|
254
|
-
<span className="text-p0 uppercase tracking-10">{dir}</span>
|
|
255
|
-
</Radio.Root>
|
|
256
|
-
</label>
|
|
257
|
-
))}
|
|
258
|
-
</RadioGroup>
|
|
259
|
-
</div>
|
|
260
|
-
|
|
261
|
-
{/* Speed */}
|
|
262
|
-
<div className="flex flex-col gap-10 border-t border-white/10 pt-20">
|
|
263
|
-
<div className="flex items-center justify-between gap-x-20">
|
|
264
|
-
<h3 className="text-p1">speed</h3>
|
|
265
|
-
|
|
266
|
-
<div className="flex-1 flex items-center justify-end gap-x-10">
|
|
267
|
-
<Slider.Root
|
|
268
|
-
value={speed}
|
|
269
|
-
onValueChange={(val) => setSpeed(val as number)}
|
|
270
|
-
min={0.1}
|
|
271
|
-
max={3}
|
|
272
|
-
step={0.1}
|
|
273
|
-
thumbAlignment="edge-client-only"
|
|
274
|
-
className="flex flex-col w-full max-w-215"
|
|
275
|
-
>
|
|
276
|
-
<Slider.Control className="flex items-center h-20 w-full data-dragging:cursor-grabbing">
|
|
277
|
-
<Slider.Track className="h-20 bg-white/10 rounded-3 w-full relative">
|
|
278
|
-
<Slider.Indicator>
|
|
279
|
-
<span className="absolute inset-3 rounded-2 bg-white/50" />
|
|
280
|
-
</Slider.Indicator>
|
|
281
|
-
<Slider.Thumb className="flex focus:outline-none cursor-grab px-3">
|
|
282
|
-
<span className="w-25 h-14 rounded-2 bg-white" />
|
|
283
|
-
</Slider.Thumb>
|
|
284
|
-
</Slider.Track>
|
|
285
|
-
</Slider.Control>
|
|
286
|
-
</Slider.Root>
|
|
287
|
-
<span className="text-p0 shrink-0 tabular-nums text-neon">
|
|
288
|
-
{speed.toFixed(1)}
|
|
289
|
-
</span>
|
|
290
|
-
</div>
|
|
291
|
-
</div>
|
|
292
|
-
</div>
|
|
293
|
-
|
|
294
|
-
{/* Boolean props */}
|
|
295
|
-
<div className="flex flex-col gap-10 pb-10">
|
|
296
|
-
{[
|
|
297
|
-
{
|
|
298
|
-
name: 'pauseOnHover',
|
|
299
|
-
label: 'pauseOnHover',
|
|
300
|
-
value: pauseOnHover,
|
|
301
|
-
onChange: setPauseOnHover,
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
name: 'manual',
|
|
305
|
-
label: 'manual',
|
|
306
|
-
subLabel: 'GSAP',
|
|
307
|
-
value: manual,
|
|
308
|
-
onChange: (checked: boolean) => {
|
|
309
|
-
setManual(checked)
|
|
310
|
-
setGsapEnabled(checked)
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
name: 'xray',
|
|
315
|
-
label: 'x-ray mode',
|
|
316
|
-
value: showXRay,
|
|
317
|
-
onChange: setShowXRay,
|
|
318
|
-
},
|
|
319
|
-
].map(({ name, label, subLabel, value, onChange }) => (
|
|
320
|
-
<label
|
|
321
|
-
key={name}
|
|
322
|
-
className="flex items-center justify-between cursor-pointer border-t border-white/10 pt-20"
|
|
323
|
-
>
|
|
324
|
-
<span className="text-p1 flex items-center gap-x-10">
|
|
325
|
-
{label}
|
|
326
|
-
{subLabel && (
|
|
327
|
-
<span className="text-neon text-p0 uppercase bg-neon/20 rounded-2 p-5 tracking-10">
|
|
328
|
-
{subLabel}
|
|
329
|
-
</span>
|
|
330
|
-
)}
|
|
331
|
-
</span>
|
|
332
|
-
<Switch.Root
|
|
333
|
-
checked={value}
|
|
334
|
-
onCheckedChange={onChange}
|
|
335
|
-
className={cn(
|
|
336
|
-
'w-55 h-20 rounded-3 bg-white/10 relative transition-colors',
|
|
337
|
-
{
|
|
338
|
-
'data-checked:bg-neon': name !== 'xray',
|
|
339
|
-
'data-checked:bg-purple': name === 'xray',
|
|
340
|
-
},
|
|
341
|
-
)}
|
|
342
|
-
>
|
|
343
|
-
<Switch.Thumb className="w-25 h-14 rounded-2 bg-white absolute top-3 left-3 data-checked:translate-x-24 transition-all data-checked:bg-black" />
|
|
344
|
-
</Switch.Root>
|
|
345
|
-
</label>
|
|
346
|
-
))}
|
|
347
|
-
</div>
|
|
348
|
-
</div>
|
|
349
|
-
</div>
|
|
350
|
-
|
|
351
|
-
{/* Preview */}
|
|
352
|
-
<div className="overflow-hidden col-span-8 md:col-span-4 isolate rounded-5 flex justify-center items-center p-20">
|
|
353
|
-
<ResizableBox
|
|
354
|
-
width={size.width}
|
|
355
|
-
height={size.height}
|
|
356
|
-
draggableOpts={{ grid: [20, 20] }}
|
|
357
|
-
axis={isVertical ? 'y' : 'x'}
|
|
358
|
-
resizeHandles={isVertical ? ['n', 's'] : ['w', 'e']}
|
|
359
|
-
minConstraints={isVertical ? [width, 80] : [220, height]}
|
|
360
|
-
maxConstraints={[width - 40, height - 40]}
|
|
361
|
-
handle={<DragHandle />}
|
|
362
|
-
onResize={onResize}
|
|
363
|
-
onResizeStart={() => setIsResizing(true)}
|
|
364
|
-
onResizeStop={() => setIsResizing(false)}
|
|
365
|
-
className={cn(
|
|
366
|
-
'absolute border border-purple rounded-5 flex flex-col',
|
|
367
|
-
{
|
|
368
|
-
'cursor-grabbing': isResizing,
|
|
369
|
-
},
|
|
370
|
-
)}
|
|
371
|
-
>
|
|
372
|
-
<span
|
|
373
|
-
className={cn(
|
|
374
|
-
'absolute bottom-full mb-px h-200 z-1 before:absolute before:inset-0 before:bg-white/10 before:z-1 after:absolute after:inset-0 after:bg-black/85',
|
|
375
|
-
{
|
|
376
|
-
'-inset-x-px': !isVertical,
|
|
377
|
-
'-inset-x-21': isVertical,
|
|
378
|
-
},
|
|
379
|
-
)}
|
|
380
|
-
/>
|
|
381
|
-
<span
|
|
382
|
-
className={cn(
|
|
383
|
-
'absolute top-full mt-px h-200 z-1 before:absolute before:inset-0 before:bg-white/10 before:z-1 after:absolute after:inset-0 after:bg-black/85',
|
|
384
|
-
{
|
|
385
|
-
'-inset-x-px': !isVertical,
|
|
386
|
-
'-inset-x-21': isVertical,
|
|
387
|
-
},
|
|
388
|
-
)}
|
|
389
|
-
/>
|
|
390
|
-
|
|
391
|
-
<span
|
|
392
|
-
className={cn(
|
|
393
|
-
'absolute right-full mr-px w-[50vw] z-1 before:absolute before:inset-0 before:bg-white/10 before:z-1 after:absolute after:inset-0 after:bg-black/85',
|
|
394
|
-
{
|
|
395
|
-
'-inset-y-21': !isVertical,
|
|
396
|
-
'-inset-y-px': isVertical,
|
|
397
|
-
},
|
|
398
|
-
)}
|
|
399
|
-
/>
|
|
400
|
-
<span
|
|
401
|
-
className={cn(
|
|
402
|
-
'absolute left-full ml-px w-[50vw] z-1 before:absolute before:inset-0 before:bg-white/10 before:z-1 after:absolute after:inset-0 after:bg-black/85',
|
|
403
|
-
{
|
|
404
|
-
'-inset-y-21': !isVertical,
|
|
405
|
-
'-inset-y-px': isVertical,
|
|
406
|
-
},
|
|
407
|
-
)}
|
|
408
|
-
/>
|
|
409
|
-
|
|
410
|
-
<div
|
|
411
|
-
ref={$marqyContainer}
|
|
412
|
-
style={
|
|
413
|
-
{ '--height': `${size.height - 2}px` } as React.CSSProperties
|
|
414
|
-
}
|
|
415
|
-
className={cn(
|
|
416
|
-
'relative flex flex-col items-center justify-center grow',
|
|
417
|
-
)}
|
|
418
|
-
>
|
|
419
|
-
<Marqy
|
|
420
|
-
direction={direction}
|
|
421
|
-
speed={speed}
|
|
422
|
-
pauseOnHover={pauseOnHover}
|
|
423
|
-
manual={manual || gsapEnabled}
|
|
424
|
-
className={cn('select-none', {
|
|
425
|
-
'h-(--height) grow': isVertical,
|
|
426
|
-
'overflow-visible! [&_[data-marqy-content]:last-child]:text-purple/20 [&_[data-marqy-content]:last-child]:[-webkit-text-stroke:1px_var(--color-purple)]':
|
|
427
|
-
showXRay,
|
|
428
|
-
})}
|
|
429
|
-
>
|
|
430
|
-
<p className="flex justify-center text-h1 text-60 py-20 uppercase whitespace-pre text-center">
|
|
431
|
-
{text?.trim() && (
|
|
432
|
-
<>
|
|
433
|
-
{!isVertical && (
|
|
434
|
-
<Divider value={direction === 'left' ? ' ← ' : ' → '} />
|
|
435
|
-
)}
|
|
436
|
-
{isVertical && (
|
|
437
|
-
<span className="opacity-40 shrink-0">
|
|
438
|
-
{direction === 'up' ? '↑' : '↓'}
|
|
439
|
-
</span>
|
|
440
|
-
)}
|
|
441
|
-
<span className="text-ellipsis overflow-hidden">
|
|
442
|
-
{text}
|
|
443
|
-
</span>
|
|
444
|
-
{isVertical && (
|
|
445
|
-
<span className="opacity-40 shrink-0">
|
|
446
|
-
{direction === 'up' ? '↑' : '↓'}
|
|
447
|
-
</span>
|
|
448
|
-
)}
|
|
449
|
-
</>
|
|
450
|
-
)}
|
|
451
|
-
</p>
|
|
452
|
-
</Marqy>
|
|
453
|
-
|
|
454
|
-
{!text?.trim() && (
|
|
455
|
-
<div className="absolute inset-0 flex justify-center items-center select-none">
|
|
456
|
-
<p className="text-h1 text-h1 uppercase text-white/20">
|
|
457
|
-
not_defined
|
|
458
|
-
</p>
|
|
459
|
-
</div>
|
|
460
|
-
)}
|
|
461
|
-
|
|
462
|
-
<span className="select-none backdrop-blur-sm flex gap-x-5 absolute top-0 left-0 text-p0 m-10 text-purple bg-purple/20 p-5 rounded-3">
|
|
463
|
-
<span className="text-purple/50 uppercase">duration</span>
|
|
464
|
-
{duration?.trim() ? duration : 'NA'}
|
|
465
|
-
</span>
|
|
466
|
-
<span className="select-none backdrop-blur-sm flex gap-x-5 absolute top-0 right-0 text-p0 m-10 text-purple bg-purple/20 p-5 rounded-3">
|
|
467
|
-
<span className="text-purple/50 uppercase">reps</span>
|
|
468
|
-
{itemCount}
|
|
469
|
-
</span>
|
|
470
|
-
|
|
471
|
-
{manual && (
|
|
472
|
-
<button
|
|
473
|
-
onClick={() => setGsapEnabled((v) => !v)}
|
|
474
|
-
className={cn(
|
|
475
|
-
'clean-btn cursor-pointer select-none backdrop-blur-sm absolute bottom-0 left-0 m-10 p-5 rounded-3',
|
|
476
|
-
gsapEnabled
|
|
477
|
-
? 'text-neon/50 bg-neon/20'
|
|
478
|
-
: 'text-black/50 bg-neon',
|
|
479
|
-
)}
|
|
480
|
-
>
|
|
481
|
-
<span className="flex gap-x-5 text-p0 uppercase">
|
|
482
|
-
{gsapEnabled ? 'Disable' : 'Enable'}
|
|
483
|
-
<span
|
|
484
|
-
className={cn(gsapEnabled ? 'text-neon' : 'text-black')}
|
|
485
|
-
>
|
|
486
|
-
GSAP
|
|
487
|
-
</span>
|
|
488
|
-
</span>
|
|
489
|
-
</button>
|
|
490
|
-
)}
|
|
491
|
-
</div>
|
|
492
|
-
</ResizableBox>
|
|
493
|
-
</div>
|
|
494
|
-
</div>
|
|
495
|
-
)
|
|
496
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Marqy } from 'marqy'
|
|
2
|
-
|
|
3
|
-
import Divider from './Divider'
|
|
4
|
-
|
|
5
|
-
export default function MarqySpeedDemo() {
|
|
6
|
-
return (
|
|
7
|
-
<section>
|
|
8
|
-
<Marqy speed={0.2} direction="right" className="border-t">
|
|
9
|
-
<p className="uppercase py-20 text-p1 whitespace-pre">
|
|
10
|
-
<Divider />
|
|
11
|
-
BPM_0.5: Chillwave
|
|
12
|
-
</p>
|
|
13
|
-
</Marqy>
|
|
14
|
-
<Marqy speed={0.5} direction="right" className="border-t">
|
|
15
|
-
<p className="uppercase py-20 text-p1 whitespace-pre">
|
|
16
|
-
<Divider />
|
|
17
|
-
BPM_1: House
|
|
18
|
-
</p>
|
|
19
|
-
</Marqy>
|
|
20
|
-
<Marqy speed={1.5} direction="right" className="border-t">
|
|
21
|
-
<p className="uppercase py-20 text-p1 whitespace-pre">
|
|
22
|
-
<Divider />
|
|
23
|
-
BPM_1.5: Techno
|
|
24
|
-
</p>
|
|
25
|
-
</Marqy>
|
|
26
|
-
<Marqy speed={3} direction="right" className="border-t">
|
|
27
|
-
<p className="uppercase py-20 text-p1 whitespace-pre">
|
|
28
|
-
<Divider />
|
|
29
|
-
BPM_3: Dubstep
|
|
30
|
-
</p>
|
|
31
|
-
</Marqy>
|
|
32
|
-
</section>
|
|
33
|
-
)
|
|
34
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { Marqy } from 'marqy'
|
|
2
|
-
|
|
3
|
-
function Char({ value }: { value: string }) {
|
|
4
|
-
return (
|
|
5
|
-
<span className="w-1/5 aspect-square text-jumbo text-[8vw] bg-white flex items-center justify-center">
|
|
6
|
-
{value}
|
|
7
|
-
</span>
|
|
8
|
-
)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default function MarqyInteractiveDemo() {
|
|
12
|
-
return (
|
|
13
|
-
<section className="flex flex-col sm:flex-row p-20 border-t gap-px">
|
|
14
|
-
<Marqy
|
|
15
|
-
speed={1}
|
|
16
|
-
direction="up"
|
|
17
|
-
className="bg-white text-black text-center min-h-[calc(10vw+2rem)] max-h-[calc((10vw+2rem)*2)] h-[calc(10vw+2rem)] overflow-hidden"
|
|
18
|
-
>
|
|
19
|
-
<p className="flex w-full gap-px bg-black text-center border-t select-none">
|
|
20
|
-
<Char value="↑" />
|
|
21
|
-
<Char value="↑" />
|
|
22
|
-
<Char value="↑" />
|
|
23
|
-
<Char value="↑" />
|
|
24
|
-
<Char value="↑" />
|
|
25
|
-
<Char value="↑" />
|
|
26
|
-
</p>
|
|
27
|
-
</Marqy>
|
|
28
|
-
<Marqy
|
|
29
|
-
speed={1}
|
|
30
|
-
direction="down"
|
|
31
|
-
className="bg-white text-black text-center min-h-[calc(10vw+2rem)] max-h-[calc((10vw+2rem)*2)] h-[calc(10vw+2rem)] overflow-hidden"
|
|
32
|
-
>
|
|
33
|
-
<p className="flex w-full gap-px bg-black text-center border-t select-none">
|
|
34
|
-
<Char value="↓" />
|
|
35
|
-
<Char value="↓" />
|
|
36
|
-
<Char value="↓" />
|
|
37
|
-
<Char value="↓" />
|
|
38
|
-
<Char value="↓" />
|
|
39
|
-
<Char value="↓" />
|
|
40
|
-
</p>
|
|
41
|
-
</Marqy>
|
|
42
|
-
</section>
|
|
43
|
-
)
|
|
44
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import SectionHeadline from '../components/SectionHeadline'
|
|
3
|
-
import MarqyPlayground from './MarqyPlayground'
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
<section class="md:p-40 relative overflow-hidden">
|
|
7
|
-
<SectionHeadline text="Playground" client:load />
|
|
8
|
-
<div class="p-20 md:px-80 md:py-0">
|
|
9
|
-
<MarqyPlayground client:only="react" />
|
|
10
|
-
</div>
|
|
11
|
-
</section>
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { Code } from 'astro:components'
|
|
3
|
-
import SectionHeadline from '../components/SectionHeadline'
|
|
4
|
-
import CopyButton from '../components/CopyButton'
|
|
5
|
-
|
|
6
|
-
const installCode = `yarn add marqy`
|
|
7
|
-
|
|
8
|
-
const usageCode = `import { Marqy } from 'marqy'
|
|
9
|
-
import 'marqy/dist/marqy.css'
|
|
10
|
-
|
|
11
|
-
<Marqy speed={1} direction="left" pauseOnHover>
|
|
12
|
-
<span>Your content here</span>
|
|
13
|
-
</Marqy>`
|
|
14
|
-
|
|
15
|
-
const props = [
|
|
16
|
-
{ name: 'speed', type: 'number', default: '0.5', description: 'Scroll speed multiplier' },
|
|
17
|
-
{ name: 'direction', type: "'left' | 'right' | 'up' | 'down'", default: "'left'", description: 'Direction of scroll' },
|
|
18
|
-
{ name: 'pauseOnHover', type: 'boolean', default: 'false', description: 'Pauses the animation on hover' },
|
|
19
|
-
{ name: 'manual', type: 'boolean', default: 'false', description: 'Renders without applying CSS animations' },
|
|
20
|
-
{ name: 'children', type: 'React.ReactNode', default: '—', description: 'Content to repeat inside the marqy' },
|
|
21
|
-
]
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
<section class="md:p-40 relative overflow-hidden transform-[translateZ(0)] border-t">
|
|
25
|
-
<SectionHeadline text="Quick Start" client:load />
|
|
26
|
-
<div class="grid grid-cols-2 gap-20 sm:gap-40 p-20 md:px-80 md:py-0 items-center">
|
|
27
|
-
<div class="flex flex-col gap-20 sm:gap-40 col-span-2 lg:col-span-1">
|
|
28
|
-
<div>
|
|
29
|
-
<div class="flex justify-between mb-10 items-center bg-white text-black pl-10 rounded-5">
|
|
30
|
-
<p class="text-h3 uppercase">Install</p>
|
|
31
|
-
<CopyButton text={installCode} client:load />
|
|
32
|
-
</div>
|
|
33
|
-
<Code code={installCode} lang="sh" theme="css-variables" />
|
|
34
|
-
</div>
|
|
35
|
-
<div>
|
|
36
|
-
<div class="flex justify-between mb-10 items-center bg-white text-black pl-10 rounded-5">
|
|
37
|
-
<p class="text-h3 uppercase">Usage</p>
|
|
38
|
-
<CopyButton text={usageCode} client:load />
|
|
39
|
-
</div>
|
|
40
|
-
<Code code={usageCode} lang="jsx" theme="css-variables" />
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
<div class="col-span-2 lg:col-span-1">
|
|
44
|
-
<!-- <p class="text-p1 border-b pb-10">Props</p> -->
|
|
45
|
-
<div class="@container flex flex-col divide-y divide-white/20">
|
|
46
|
-
{props.map((prop) => (
|
|
47
|
-
<div class="grid grid-cols-[15ch_1fr] @min-[50rem]:grid-cols-[12ch_1fr_auto] gap-10 pt-10 first:pt-0 pb-20 items-start">
|
|
48
|
-
<code class="font-mono font-bold text-neon">{prop.name}</code>
|
|
49
|
-
<div class="flex flex-col gap-y-8 items-start">
|
|
50
|
-
<code class="font-mono text-white/60 text-end @min-[50rem]:text-start">{prop.type}</code>
|
|
51
|
-
{prop.default !== '—' && <span class="shrink-0 uppercase text-p0 bg-white/15 p-5 rounded-5"> Default: <code class="normal-case text-white/60">{prop.default}</code></span>}
|
|
52
|
-
</div>
|
|
53
|
-
<span class="col-span-2 @min-[50rem]:col-span-1 inline-flex items-center justify-between gap-x-10 font-sans">{prop.description}</span>
|
|
54
|
-
</div>
|
|
55
|
-
))}
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
</section>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { Marqy } from 'marqy'
|
|
2
|
-
|
|
3
|
-
import { cn } from '../lib/cn'
|
|
4
|
-
|
|
5
|
-
export default function SectionHeadline({ text }: { text: string }) {
|
|
6
|
-
return (
|
|
7
|
-
<>
|
|
8
|
-
<h2
|
|
9
|
-
className={cn(
|
|
10
|
-
'md:absolute md:top-1/2 md:left-0 md:w-lvh md:transform-[rotate(-90deg)_translateX(-50%)] origin-top-left border-b py-20 z-2 bg-black',
|
|
11
|
-
)}
|
|
12
|
-
>
|
|
13
|
-
<Marqy speed={1} direction="left">
|
|
14
|
-
<span className="text-jumbo text-15 sm:text-40 px-20">{text}</span>
|
|
15
|
-
</Marqy>
|
|
16
|
-
</h2>
|
|
17
|
-
|
|
18
|
-
<h2
|
|
19
|
-
aria-hidden="true"
|
|
20
|
-
className={cn(
|
|
21
|
-
'hidden md:block',
|
|
22
|
-
'absolute top-1/2 right-0 w-lvh transform-[rotate(90deg)_translateX(50%)] origin-top-right border-b py-20 z-2 bg-black',
|
|
23
|
-
)}
|
|
24
|
-
>
|
|
25
|
-
<Marqy speed={1} direction="left">
|
|
26
|
-
<span className="text-jumbo text-15 sm:text-40 px-20">{text}</span>
|
|
27
|
-
</Marqy>
|
|
28
|
-
</h2>
|
|
29
|
-
|
|
30
|
-
{/* <h2
|
|
31
|
-
className={cn(
|
|
32
|
-
'w-lvh fixed right-0 top-0 origin-top-left transform-[translateY(-100%)_rotate(90deg)] border-b py-20 z-2 bg-black',
|
|
33
|
-
)}
|
|
34
|
-
>
|
|
35
|
-
<Marqy speed={1} direction="left">
|
|
36
|
-
<span className="text-jumbo text-40 px-20">{text}</span>
|
|
37
|
-
</Marqy>
|
|
38
|
-
</h2> */}
|
|
39
|
-
</>
|
|
40
|
-
)
|
|
41
|
-
}
|