Skip to content

Commit f622933

Browse files
docs: Add CodeSandbox examples for vanilla JS and React
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e4f8a12 commit f622933

File tree

9 files changed

+643
-0
lines changed

9 files changed

+643
-0
lines changed

codesandbox/react/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>CloudImage 360 View - React Example</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>

codesandbox/react/package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "cloudimage-360-react-example",
3+
"private": true,
4+
"version": "1.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc && vite build",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
"js-cloudimage-360-view": "^4.1.0-beta.0",
13+
"react": "^18.2.0",
14+
"react-dom": "^18.2.0"
15+
},
16+
"devDependencies": {
17+
"@types/react": "^18.2.0",
18+
"@types/react-dom": "^18.2.0",
19+
"@vitejs/plugin-react": "^4.2.0",
20+
"typescript": "^5.3.0",
21+
"vite": "^5.0.0"
22+
}
23+
}

codesandbox/react/src/App.css

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
* {
2+
box-sizing: border-box;
3+
}
4+
5+
body {
6+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
7+
margin: 0;
8+
padding: 0;
9+
background: #f5f5f5;
10+
}
11+
12+
.app {
13+
min-height: 100vh;
14+
display: flex;
15+
flex-direction: column;
16+
}
17+
18+
header {
19+
text-align: center;
20+
padding: 30px 20px 20px;
21+
background: white;
22+
border-bottom: 1px solid #e0e0e0;
23+
}
24+
25+
header h1 {
26+
margin: 0 0 10px 0;
27+
color: #333;
28+
font-size: 28px;
29+
}
30+
31+
header p {
32+
margin: 0;
33+
color: #666;
34+
font-size: 16px;
35+
}
36+
37+
main {
38+
flex: 1;
39+
padding: 30px 20px;
40+
max-width: 1200px;
41+
margin: 0 auto;
42+
width: 100%;
43+
display: flex;
44+
flex-direction: column;
45+
gap: 40px;
46+
}
47+
48+
.example {
49+
background: white;
50+
border-radius: 12px;
51+
padding: 20px;
52+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
53+
}
54+
55+
.example h2 {
56+
margin: 0 0 15px 0;
57+
color: #333;
58+
font-size: 18px;
59+
}
60+
61+
.controls {
62+
display: flex;
63+
gap: 10px;
64+
margin-top: 15px;
65+
flex-wrap: wrap;
66+
}
67+
68+
button {
69+
padding: 8px 16px;
70+
border: none;
71+
border-radius: 6px;
72+
background: #007bff;
73+
color: white;
74+
cursor: pointer;
75+
font-size: 14px;
76+
transition: background 0.2s;
77+
}
78+
79+
button:hover {
80+
background: #0056b3;
81+
}
82+
83+
button.active {
84+
background: #28a745;
85+
}
86+
87+
.features {
88+
display: flex;
89+
gap: 8px;
90+
margin-top: 15px;
91+
flex-wrap: wrap;
92+
}
93+
94+
.feature-tag {
95+
background: #e9ecef;
96+
color: #495057;
97+
padding: 4px 10px;
98+
border-radius: 4px;
99+
font-size: 12px;
100+
}
101+
102+
.frame-indicator {
103+
margin-top: 10px;
104+
padding: 8px 12px;
105+
background: #f8f9fa;
106+
border-radius: 6px;
107+
font-size: 14px;
108+
color: #495057;
109+
}
110+
111+
.event-log {
112+
margin-top: 10px;
113+
padding: 10px 12px;
114+
background: #f8f9fa;
115+
border-radius: 6px;
116+
font-size: 13px;
117+
color: #495057;
118+
min-height: 40px;
119+
}
120+
121+
footer {
122+
text-align: center;
123+
padding: 20px;
124+
background: white;
125+
border-top: 1px solid #e0e0e0;
126+
display: flex;
127+
justify-content: center;
128+
gap: 15px;
129+
align-items: center;
130+
}
131+
132+
footer a {
133+
color: #007bff;
134+
text-decoration: none;
135+
}
136+
137+
footer a:hover {
138+
text-decoration: underline;
139+
}
140+
141+
footer span {
142+
color: #ccc;
143+
}

codesandbox/react/src/App.tsx

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import { useRef, useState } from 'react';
2+
import { CI360Viewer, CI360ViewerRef } from 'js-cloudimage-360-view/react';
3+
import 'js-cloudimage-360-view/css';
4+
5+
// Example 1: Basic viewer with autoplay
6+
function BasicExample() {
7+
return (
8+
<div className="example">
9+
<h2>Basic Example with Autoplay</h2>
10+
<CI360Viewer
11+
folder="https://scaleflex.cloudimg.io/v7/demo/suv-orange-car-360/"
12+
filenameX="orange-{index}.jpg"
13+
amountX={73}
14+
autoplay
15+
fullscreen
16+
bottomCircle
17+
hints
18+
style={{ width: '100%', height: 400 }}
19+
/>
20+
<div className="features">
21+
<span className="feature-tag">Autoplay</span>
22+
<span className="feature-tag">Fullscreen</span>
23+
<span className="feature-tag">73 Frames</span>
24+
</div>
25+
</div>
26+
);
27+
}
28+
29+
// Example 2: Ref control with buttons
30+
function RefControlExample() {
31+
const viewerRef = useRef<CI360ViewerRef>(null);
32+
const [currentFrame, setCurrentFrame] = useState(0);
33+
34+
return (
35+
<div className="example">
36+
<h2>Programmatic Control via Ref</h2>
37+
<CI360Viewer
38+
ref={viewerRef}
39+
folder="https://scaleflex.cloudimg.io/v7/demo/suv-orange-car-360/"
40+
filenameX="orange-{index}.jpg"
41+
amountX={73}
42+
fullscreen
43+
inertia
44+
onSpin={(data) => setCurrentFrame(data.activeImageX)}
45+
style={{ width: '100%', height: 400 }}
46+
/>
47+
<div className="frame-indicator">Current Frame: {currentFrame + 1} / 73</div>
48+
<div className="controls">
49+
<button onClick={() => viewerRef.current?.play()}>Play</button>
50+
<button onClick={() => viewerRef.current?.stop()}>Stop</button>
51+
<button onClick={() => viewerRef.current?.moveLeft(5)}>Rotate Left</button>
52+
<button onClick={() => viewerRef.current?.moveRight(5)}>Rotate Right</button>
53+
<button onClick={() => viewerRef.current?.goToFrame(0)}>Go to Start</button>
54+
<button onClick={() => viewerRef.current?.goToFrame(36)}>Go to Middle</button>
55+
</div>
56+
<div className="features">
57+
<span className="feature-tag">Ref Control</span>
58+
<span className="feature-tag">Inertia</span>
59+
<span className="feature-tag">onSpin Event</span>
60+
</div>
61+
</div>
62+
);
63+
}
64+
65+
// Example 3: Zoom features
66+
function ZoomExample() {
67+
return (
68+
<div className="example">
69+
<h2>Zoom & Magnifier</h2>
70+
<CI360Viewer
71+
folder="https://scaleflex.cloudimg.io/v7/demo/earbuds/"
72+
filenameX="earbuds-{index}.jpg"
73+
amountX={233}
74+
pointerZoom={3}
75+
fullscreen
76+
speed={50}
77+
style={{ width: '100%', height: 400 }}
78+
/>
79+
<div className="features">
80+
<span className="feature-tag">Pointer Zoom (3x)</span>
81+
<span className="feature-tag">233 Frames</span>
82+
<span className="feature-tag">Click to zoom</span>
83+
</div>
84+
</div>
85+
);
86+
}
87+
88+
// Example 4: Event callbacks
89+
function EventsExample() {
90+
const [events, setEvents] = useState<string[]>([]);
91+
92+
const addEvent = (event: string) => {
93+
setEvents((prev) => [...prev.slice(-4), event]);
94+
};
95+
96+
return (
97+
<div className="example">
98+
<h2>Event Callbacks</h2>
99+
<CI360Viewer
100+
folder="https://scaleflex.cloudimg.io/v7/demo/suv-orange-car-360/"
101+
filenameX="orange-{index}.jpg"
102+
amountX={73}
103+
fullscreen
104+
onReady={() => addEvent('onReady')}
105+
onLoad={() => addEvent('onLoad')}
106+
onAutoplayStart={() => addEvent('onAutoplayStart')}
107+
onAutoplayStop={() => addEvent('onAutoplayStop')}
108+
onDragStart={() => addEvent('onDragStart')}
109+
onDragEnd={() => addEvent('onDragEnd')}
110+
onZoomIn={() => addEvent('onZoomIn')}
111+
onZoomOut={() => addEvent('onZoomOut')}
112+
style={{ width: '100%', height: 400 }}
113+
/>
114+
<div className="event-log">
115+
<strong>Events:</strong> {events.length > 0 ? events.join(' → ') : 'Interact to see events'}
116+
</div>
117+
<div className="features">
118+
<span className="feature-tag">onReady</span>
119+
<span className="feature-tag">onLoad</span>
120+
<span className="feature-tag">onDragStart/End</span>
121+
<span className="feature-tag">onZoom</span>
122+
</div>
123+
</div>
124+
);
125+
}
126+
127+
// Example 5: Theme toggle
128+
function ThemeExample() {
129+
const [theme, setTheme] = useState<'light' | 'dark'>('light');
130+
131+
return (
132+
<div className="example">
133+
<h2>Theme Toggle</h2>
134+
<CI360Viewer
135+
folder="https://scaleflex.cloudimg.io/v7/demo/suv-orange-car-360/"
136+
filenameX="orange-{index}.jpg"
137+
amountX={73}
138+
fullscreen
139+
theme={theme}
140+
style={{ width: '100%', height: 400 }}
141+
/>
142+
<div className="controls">
143+
<button
144+
className={theme === 'light' ? 'active' : ''}
145+
onClick={() => setTheme('light')}
146+
>
147+
Light Theme
148+
</button>
149+
<button
150+
className={theme === 'dark' ? 'active' : ''}
151+
onClick={() => setTheme('dark')}
152+
>
153+
Dark Theme
154+
</button>
155+
</div>
156+
<div className="features">
157+
<span className="feature-tag">Light Theme</span>
158+
<span className="feature-tag">Dark Theme</span>
159+
<span className="feature-tag">Dynamic Switch</span>
160+
</div>
161+
</div>
162+
);
163+
}
164+
165+
export default function App() {
166+
return (
167+
<div className="app">
168+
<header>
169+
<h1>CloudImage 360 View - React</h1>
170+
<p>Interactive 360-degree product viewer - Version 4.1.0</p>
171+
</header>
172+
173+
<main>
174+
<BasicExample />
175+
<RefControlExample />
176+
<ZoomExample />
177+
<EventsExample />
178+
<ThemeExample />
179+
</main>
180+
181+
<footer>
182+
<a
183+
href="https://github.com/niceplayer/js-cloudimage-360-view"
184+
target="_blank"
185+
rel="noopener noreferrer"
186+
>
187+
GitHub Repository
188+
</a>
189+
<span>|</span>
190+
<a
191+
href="https://scaleflex.github.io/js-cloudimage-360-view/"
192+
target="_blank"
193+
rel="noopener noreferrer"
194+
>
195+
Documentation
196+
</a>
197+
</footer>
198+
</div>
199+
);
200+
}

codesandbox/react/src/main.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { StrictMode } from 'react';
2+
import { createRoot } from 'react-dom/client';
3+
import App from './App';
4+
import './App.css';
5+
6+
createRoot(document.getElementById('root')!).render(
7+
<StrictMode>
8+
<App />
9+
</StrictMode>
10+
);

0 commit comments

Comments
 (0)