Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf5d3dd8

Browse files
authored
Merge pull request#747 from freakdaniel/stack
Refactor Stack: Content Flexibility, Autoplay and Layout Sync
2 parents3c9d40f +54e72c9 commitf5d3dd8

File tree

10 files changed

+631
-233
lines changed

10 files changed

+631
-233
lines changed

‎src/constants/Categories.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const NEW = [
99
'Floating Lines',
1010
'Light Pillar'
1111
];
12-
exportconstUPDATED=['Profile Card','Logo Loop','Animated Content','Fade Content'];
12+
exportconstUPDATED=['Profile Card','Logo Loop','Animated Content','Fade Content','Stack'];
1313

1414
// Used for main sidebar navigation
1515
exportconstCATEGORIES=[

‎src/constants/Information.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ export const componentMetadata = {
673673
},
674674
'Components/Stack':{
675675
videoUrl:'/assets/video/stack.webm',
676-
description:'Layered stack with swipe animations and smooth transitions.',
676+
description:'Layered stack with swipe animations, autoplay and smooth transitions.',
677677
category:'Components',
678678
name:'Stack',
679679
docsUrl:'https://reactbits.dev/components/stack',

‎src/constants/code/Components/stackCode.js‎

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,27 @@ export const stack = {
99
usage:`import Stack from './Stack'
1010
1111
const images = [
12-
{ id: 1, img:"https://images.unsplash.com/photo-1480074568708-e7b720bb3f09?q=80&w=500&auto=format" },
13-
{ id: 2, img:"https://images.unsplash.com/photo-1449844908441-8829872d2607?q=80&w=500&auto=format" },
14-
{ id: 3, img:"https://images.unsplash.com/photo-1452626212852-811d58933cae?q=80&w=500&auto=format" },
15-
{ id: 4, img:"https://images.unsplash.com/photo-1572120360610-d971b9d7767c?q=80&w=500&auto=format" }
12+
"https://images.unsplash.com/photo-1480074568708-e7b720bb3f09?q=80&w=500&auto=format",
13+
"https://images.unsplash.com/photo-1449844908441-8829872d2607?q=80&w=500&auto=format",
14+
"https://images.unsplash.com/photo-1452626212852-811d58933cae?q=80&w=500&auto=format",
15+
"https://images.unsplash.com/photo-1572120360610-d971b9d7767c?q=80&w=500&auto=format"
1616
];
17-
18-
<Stack
19-
randomRotation={true}
20-
sensitivity={180}
21-
sendToBackOnClick={false}
22-
cardDimensions={{ width: 200, height: 200 }}
23-
cardsData={images}
24-
/>`,
17+
18+
<div style={{ width: 208, height: 208 }}>
19+
<Stack
20+
randomRotation={true}
21+
sensitivity={180}
22+
sendToBackOnClick={true}
23+
cards={images.map((src, i) => (
24+
<img
25+
key={i}
26+
src={src}
27+
alt={\`card-\${i + 1}\`}
28+
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
29+
/>
30+
))}
31+
/>
32+
</div>`,
2533
code,
2634
css,
2735
tailwind,
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,32 @@
11
.stack-container {
22
position: relative;
3+
width:100%;
4+
height:100%;
35
perspective:600px;
46
}
57

68
.card-rotate {
79
position: absolute;
10+
inset:0;
811
cursor: grab;
912
}
1013

14+
.card-rotate-disabled {
15+
position: absolute;
16+
inset:0;
17+
cursor: pointer;
18+
}
19+
1120
.card {
12-
border-radius:20px;
13-
border:5px solid#fff;
21+
border-radius:1rem;
1422
overflow: hidden;
23+
width:100%;
24+
height:100%;
1525
}
1626

1727
.card-image {
18-
pointer-events: none;
1928
width:100%;
2029
height:100%;
2130
object-fit: cover;
31+
pointer-events: none;
2232
}
Lines changed: 125 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import{motion,useMotionValue,useTransform}from'motion/react';
2-
import{useState}from'react';
2+
import{useState,useEffect}from'react';
33
import'./Stack.css';
44

5-
functionCardRotate({ children, onSendToBack, sensitivity}){
5+
functionCardRotate({ children, onSendToBack, sensitivity, disableDrag=false}){
66
constx=useMotionValue(0);
77
consty=useMotionValue(0);
88
constrotateX=useTransform(y,[-100,100],[60,-60]);
@@ -17,6 +17,17 @@ function CardRotate({ children, onSendToBack, sensitivity }) {
1717
}
1818
}
1919

20+
if(disableDrag){
21+
return(
22+
<motion.div
23+
className="card-rotate-disabled"
24+
style={{x:0,y:0}}
25+
>
26+
{children}
27+
</motion.div>
28+
);
29+
}
30+
2031
return(
2132
<motion.div
2233
className="card-rotate"
@@ -35,70 +46,144 @@ function CardRotate({ children, onSendToBack, sensitivity }) {
3546
exportdefaultfunctionStack({
3647
randomRotation=false,
3748
sensitivity=200,
38-
cardDimensions={width:208,height:208},
39-
cardsData=[],
49+
cards=[],
4050
animationConfig={stiffness:260,damping:20},
41-
sendToBackOnClick=false
51+
sendToBackOnClick=false,
52+
autoplay=false,
53+
autoplayDelay=3000,
54+
pauseOnHover=false,
55+
mobileClickOnly=false,
56+
mobileBreakpoint=768,
4257
}){
43-
const[cards,setCards]=useState(
44-
cardsData.length
45-
?cardsData
46-
:[
47-
{id:1,img:'https://images.unsplash.com/photo-1480074568708-e7b720bb3f09?q=80&w=500&auto=format'},
48-
{id:2,img:'https://images.unsplash.com/photo-1449844908441-8829872d2607?q=80&w=500&auto=format'},
49-
{id:3,img:'https://images.unsplash.com/photo-1452626212852-811d58933cae?q=80&w=500&auto=format'},
50-
{id:4,img:'https://images.unsplash.com/photo-1572120360610-d971b9d7767c?q=80&w=500&auto=format'}
51-
]
58+
const[isMobile,setIsMobile]=useState(false);
59+
const[isPaused,setIsPaused]=useState(false);
60+
61+
useEffect(()=>{
62+
constcheckMobile=()=>{
63+
setIsMobile(window.innerWidth<mobileBreakpoint);
64+
};
65+
66+
checkMobile();
67+
window.addEventListener('resize',checkMobile);
68+
return()=>window.removeEventListener('resize',checkMobile);
69+
},[mobileBreakpoint]);
70+
71+
constshouldDisableDrag=mobileClickOnly&&isMobile;
72+
constshouldEnableClick=sendToBackOnClick||shouldDisableDrag;
73+
74+
const[stack,setStack]=useState(
75+
()=>{
76+
if(cards.length){
77+
returncards.map((content,index)=>({id:index+1, content}));
78+
}else{
79+
return[
80+
{
81+
id:1,
82+
content:(
83+
<img
84+
src="https://images.unsplash.com/photo-1480074568708-e7b720bb3f09?q=80&w=500&auto=format"
85+
alt="card-1"
86+
className="card-image"
87+
/>
88+
),
89+
},
90+
{
91+
id:2,
92+
content:(
93+
<img
94+
src="https://images.unsplash.com/photo-1449844908441-8829872d2607?q=80&w=500&auto=format"
95+
alt="card-2"
96+
className="card-image"
97+
/>
98+
),
99+
},
100+
{
101+
id:3,
102+
content:(
103+
<img
104+
src="https://images.unsplash.com/photo-1452626212852-811d58933cae?q=80&w=500&auto=format"
105+
alt="card-3"
106+
className="card-image"
107+
/>
108+
),
109+
},
110+
{
111+
id:4,
112+
content:(
113+
<img
114+
src="https://images.unsplash.com/photo-1572120360610-d971b9d7767c?q=80&w=500&auto=format"
115+
alt="card-4"
116+
className="card-image"
117+
/>
118+
),
119+
},
120+
];
121+
}
122+
}
52123
);
53124

54-
constsendToBack=id=>{
55-
setCards(prev=>{
56-
constnewCards=[...prev];
57-
constindex=newCards.findIndex(card=>card.id===id);
58-
const[card]=newCards.splice(index,1);
59-
newCards.unshift(card);
60-
returnnewCards;
125+
useEffect(()=>{
126+
if(cards.length){
127+
setStack(cards.map((content,index)=>({id:index+1, content})));
128+
}
129+
},[cards]);
130+
131+
constsendToBack=(id)=>{
132+
setStack((prev)=>{
133+
constnewStack=[...prev];
134+
constindex=newStack.findIndex((card)=>card.id===id);
135+
const[card]=newStack.splice(index,1);
136+
newStack.unshift(card);
137+
returnnewStack;
61138
});
62139
};
63140

141+
useEffect(()=>{
142+
if(autoplay&&stack.length>1&&!isPaused){
143+
constinterval=setInterval(()=>{
144+
consttopCardId=stack[stack.length-1].id;
145+
sendToBack(topCardId);
146+
},autoplayDelay);
147+
148+
return()=>clearInterval(interval);
149+
}
150+
},[autoplay,autoplayDelay,stack,isPaused]);
151+
64152
return(
65153
<div
66154
className="stack-container"
67-
style={{
68-
width:cardDimensions.width,
69-
height:cardDimensions.height,
70-
perspective:600
71-
}}
155+
onMouseEnter={()=>pauseOnHover&&setIsPaused(true)}
156+
onMouseLeave={()=>pauseOnHover&&setIsPaused(false)}
72157
>
73-
{cards.map((card,index)=>{
158+
{stack.map((card,index)=>{
74159
constrandomRotate=randomRotation ?Math.random()*10-5 :0;
75-
76160
return(
77-
<CardRotatekey={card.id}onSendToBack={()=>sendToBack(card.id)}sensitivity={sensitivity}>
161+
<CardRotate
162+
key={card.id}
163+
onSendToBack={()=>sendToBack(card.id)}
164+
sensitivity={sensitivity}
165+
disableDrag={shouldDisableDrag}
166+
>
78167
<motion.div
79168
className="card"
80-
onClick={()=>sendToBackOnClick&&sendToBack(card.id)}
169+
onClick={()=>shouldEnableClick&&sendToBack(card.id)}
81170
animate={{
82-
rotateZ:(cards.length-index-1)*4+randomRotate,
83-
scale:1+index*0.06-cards.length*0.06,
84-
transformOrigin:'90% 90%'
171+
rotateZ:(stack.length-index-1)*4+randomRotate,
172+
scale:1+index*0.06-stack.length*0.06,
173+
transformOrigin:'90% 90%',
85174
}}
86175
initial={false}
87176
transition={{
88177
type:'spring',
89178
stiffness:animationConfig.stiffness,
90-
damping:animationConfig.damping
91-
}}
92-
style={{
93-
width:cardDimensions.width,
94-
height:cardDimensions.height
179+
damping:animationConfig.damping,
95180
}}
96181
>
97-
<imgsrc={card.img}alt={`card-${card.id}`}className="card-image"/>
182+
{card.content}
98183
</motion.div>
99184
</CardRotate>
100185
);
101186
})}
102187
</div>
103188
);
104-
}
189+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp