|
3 | 3 | import { useState } from 'react' |
4 | 4 | import { cn } from '@sim/emcn' |
5 | 5 | import { motion, useReducedMotion } from 'framer-motion' |
| 6 | +import { ResponsiveDesignStage } from '@/app/(landing)/components/shared/responsive-design-stage' |
6 | 7 | import styles from '@/app/(landing)/files/components/feature-graphics/file-library-graphic.module.css' |
7 | 8 |
|
8 | 9 | /** |
@@ -72,53 +73,68 @@ export function InteractiveLibraryFolder({ |
72 | 73 | : { type: 'spring' as const, stiffness: 120, damping: 14 } |
73 | 74 |
|
74 | 75 | return ( |
75 | | - <button |
76 | | - type='button' |
77 | | - className={cn(styles.folderButton, className)} |
78 | | - aria-label={`${name}, ${count}`} |
79 | | - aria-pressed={open} |
80 | | - onPointerEnter={(event) => { |
81 | | - if (event.pointerType !== 'touch') setHovered(true) |
82 | | - }} |
83 | | - onPointerLeave={() => setHovered(false)} |
84 | | - onFocus={() => setHovered(true)} |
85 | | - onBlur={() => setHovered(false)} |
86 | | - onClick={() => setOpen((value) => !value)} |
87 | | - onKeyDown={(event) => { |
88 | | - if (event.key === 'Escape') setOpen(false) |
89 | | - }} |
90 | | - > |
91 | | - <span aria-hidden='true' className={styles.folderScene}> |
92 | | - <span className={styles.folderBack} /> |
93 | | - {CARDS.map((card, index) => ( |
94 | | - <motion.span |
95 | | - key={card.x} |
96 | | - className={styles.folderPaper} |
97 | | - animate={{ |
98 | | - x: open ? card.openX : card.x, |
99 | | - y: open ? card.openY : hovered ? card.hoverY : card.y, |
100 | | - rotate: open ? card.openRotate : hovered ? card.hoverRotate : card.rotate, |
101 | | - }} |
102 | | - transition={{ ...transition, delay: reducedMotion ? 0 : (2 - index) * 0.05 }} |
103 | | - > |
104 | | - <span className={styles.paperTitle} /> |
105 | | - <span className={styles.paperLines} /> |
106 | | - </motion.span> |
107 | | - ))} |
108 | | - <motion.span |
109 | | - className={styles.folderFlap} |
110 | | - animate={{ rotateX: open ? -55 : hovered ? -45 : -15 }} |
111 | | - transition={transition} |
| 76 | + <div className={cn('relative min-h-0 min-w-0', className)}> |
| 77 | + <ResponsiveDesignStage |
| 78 | + width={350} |
| 79 | + height={340} |
| 80 | + maxScale={Number.POSITIVE_INFINITY} |
| 81 | + className='-translate-y-3 absolute inset-0 items-end overflow-visible [contain:none]' |
| 82 | + contentClassName='origin-bottom' |
| 83 | + > |
| 84 | + <button |
| 85 | + type='button' |
| 86 | + className={styles.folderButton} |
| 87 | + aria-label={`${name}, ${count}`} |
| 88 | + aria-pressed={open} |
| 89 | + onPointerEnter={(event) => { |
| 90 | + if (event.pointerType !== 'touch') setHovered(true) |
| 91 | + }} |
| 92 | + onPointerLeave={() => setHovered(false)} |
| 93 | + onFocus={() => setHovered(true)} |
| 94 | + onBlur={() => setHovered(false)} |
| 95 | + onClick={() => setOpen((value) => !value)} |
| 96 | + onKeyDown={(event) => { |
| 97 | + if (event.key === 'Escape') setOpen(false) |
| 98 | + }} |
112 | 99 | > |
113 | | - <svg className='absolute inset-0 size-full' viewBox='0 0 321 241' fill='none'> |
114 | | - <path d={FLAP_PATH} fill='var(--surface-3)' stroke='var(--border)' strokeWidth='2' /> |
115 | | - </svg> |
116 | | - <span className={styles.folderLabel}> |
117 | | - <span>{name}</span> |
118 | | - <span>{count}</span> |
| 100 | + <span aria-hidden='true' className={styles.folderScene}> |
| 101 | + <span className={styles.folderBack} /> |
| 102 | + {CARDS.map((card, index) => ( |
| 103 | + <motion.span |
| 104 | + key={card.x} |
| 105 | + className={styles.folderPaper} |
| 106 | + animate={{ |
| 107 | + x: open ? card.openX : card.x, |
| 108 | + y: open ? card.openY : hovered ? card.hoverY : card.y, |
| 109 | + rotate: open ? card.openRotate : hovered ? card.hoverRotate : card.rotate, |
| 110 | + }} |
| 111 | + transition={{ ...transition, delay: reducedMotion ? 0 : (2 - index) * 0.05 }} |
| 112 | + > |
| 113 | + <span className={styles.paperTitle} /> |
| 114 | + <span className={styles.paperLines} /> |
| 115 | + </motion.span> |
| 116 | + ))} |
| 117 | + <motion.span |
| 118 | + className={styles.folderFlap} |
| 119 | + animate={{ rotateX: open ? -55 : hovered ? -45 : -15 }} |
| 120 | + transition={transition} |
| 121 | + > |
| 122 | + <svg className='absolute inset-0 size-full' viewBox='0 0 321 241' fill='none'> |
| 123 | + <path |
| 124 | + d={FLAP_PATH} |
| 125 | + fill='var(--surface-3)' |
| 126 | + stroke='var(--border)' |
| 127 | + strokeWidth='2' |
| 128 | + /> |
| 129 | + </svg> |
| 130 | + <span className={styles.folderLabel}> |
| 131 | + <span>{name}</span> |
| 132 | + <span>{count}</span> |
| 133 | + </span> |
| 134 | + </motion.span> |
119 | 135 | </span> |
120 | | - </motion.span> |
121 | | - </span> |
122 | | - </button> |
| 136 | + </button> |
| 137 | + </ResponsiveDesignStage> |
| 138 | + </div> |
123 | 139 | ) |
124 | 140 | } |
0 commit comments