@adstage/web-sdk 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/LICENSE +21 -0
- package/README.md +70 -0
- package/dist/index.cjs.js +2304 -0
- package/dist/index.d.ts +416 -0
- package/dist/index.esm.js +2288 -0
- package/dist/index.standalone.js +2331 -0
- package/examples/README.md +33 -0
- package/examples/banner-ads.html +512 -0
- package/examples/index.html +338 -0
- package/examples/native-ads.html +634 -0
- package/examples/react-app/README.md +70 -0
- package/examples/react-app/index.html +13 -0
- package/examples/react-app/package-lock.json +3042 -0
- package/examples/react-app/package.json +26 -0
- package/examples/react-app/pnpm-lock.yaml +1857 -0
- package/examples/react-app/public/index.standalone.js +2331 -0
- package/examples/react-app/src/App.tsx +226 -0
- package/examples/react-app/src/index.css +37 -0
- package/examples/react-app/src/main.tsx +10 -0
- package/examples/react-app/tsconfig.json +25 -0
- package/examples/react-app/tsconfig.node.json +10 -0
- package/examples/react-app/vite.config.ts +15 -0
- package/examples/react-nextjs/app/globals.css +200 -0
- package/examples/react-nextjs/app/layout.tsx +27 -0
- package/examples/react-nextjs/app/page.tsx +258 -0
- package/examples/react-nextjs/next.config.js +9 -0
- package/examples/react-nextjs/package.json +22 -0
- package/examples/react-nextjs/pnpm-lock.yaml +343 -0
- package/examples/react-nextjs/tsconfig.json +34 -0
- package/examples/text-ads.html +597 -0
- package/examples/video-ads.html +739 -0
- package/package.json +83 -0
- package/src/global.d.ts +20 -0
- package/src/index.ts +350 -0
- package/src/managers/device-info-collector.ts +127 -0
- package/src/managers/event-tracker.ts +131 -0
- package/src/managers/fade-slider-manager.ts +276 -0
- package/src/managers/impression-tracker.ts +88 -0
- package/src/managers/slider-manager.ts +405 -0
- package/src/react/components/AdErrorBoundary.tsx +75 -0
- package/src/react/components/AdSlot.tsx +144 -0
- package/src/react/components/BannerAd.tsx +24 -0
- package/src/react/components/InterstitialAd.tsx +24 -0
- package/src/react/components/NativeAd.tsx +24 -0
- package/src/react/components/TextAd.tsx +24 -0
- package/src/react/components/VideoAd.tsx +24 -0
- package/src/react/components/index.ts +8 -0
- package/src/react/hooks/index.ts +4 -0
- package/src/react/hooks/useAdSlot.ts +83 -0
- package/src/react/hooks/useAdStage.ts +14 -0
- package/src/react/hooks/useAdTracking.ts +61 -0
- package/src/react/index.ts +4 -0
- package/src/react/providers/AdStageProvider.tsx +86 -0
- package/src/react/providers/index.ts +2 -0
- package/src/renderers/banner-renderer.ts +35 -0
- package/src/renderers/base-renderer.ts +207 -0
- package/src/renderers/index.ts +71 -0
- package/src/renderers/interstitial-renderer.ts +70 -0
- package/src/renderers/native-renderer.ts +35 -0
- package/src/renderers/text-renderer.ts +94 -0
- package/src/renderers/video-renderer.ts +63 -0
- package/src/types/advertisement.ts +197 -0
- package/src/types/api.ts +173 -0
- package/src/types/config.ts +174 -0
- package/src/types/events.ts +60 -0
- package/src/types/index.ts +6 -0
- package/src/utils/dom-utils.ts +237 -0
- package/src/utils/sdk-utils.ts +134 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# API Key 설정 가이드
|
|
2
|
+
|
|
3
|
+
이 예제들을 실행하기 전에 API 키를 설정해야 합니다.
|
|
4
|
+
|
|
5
|
+
## React App 예제
|
|
6
|
+
`sdk/examples/react-app/.env` 파일의 API 키를 설정하세요:
|
|
7
|
+
```
|
|
8
|
+
REACT_APP_ADSTAGE_API_KEY=your_api_key_here
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Next.js 예제
|
|
12
|
+
`sdk/examples/react-nextjs/.env` 파일의 API 키를 설정하세요:
|
|
13
|
+
```
|
|
14
|
+
NEXT_PUBLIC_ADSTAGE_API_KEY=your_api_key_here
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 실행 방법
|
|
18
|
+
|
|
19
|
+
### React App 예제
|
|
20
|
+
```bash
|
|
21
|
+
cd sdk/examples/react-app
|
|
22
|
+
pnpm install
|
|
23
|
+
pnpm start
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Next.js 예제
|
|
27
|
+
```bash
|
|
28
|
+
cd sdk/examples/react-nextjs
|
|
29
|
+
pnpm install
|
|
30
|
+
pnpm dev
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
보안상 .env 파일은 Git에 커밋되지 않습니다. 실제 API 키는 AdStage 대시보드에서 발급받으세요.
|
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="ko">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>배너 광고 예제 - AdStage SDK</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
|
16
|
+
line-height: 1.6;
|
|
17
|
+
color: #333;
|
|
18
|
+
background: #f8f9fa;
|
|
19
|
+
padding: 20px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.container {
|
|
23
|
+
max-width: 1200px;
|
|
24
|
+
margin: 0 auto;
|
|
25
|
+
background: white;
|
|
26
|
+
border-radius: 12px;
|
|
27
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.header {
|
|
32
|
+
background: linear-gradient(135deg, #667eea, #764ba2);
|
|
33
|
+
color: white;
|
|
34
|
+
padding: 30px;
|
|
35
|
+
text-align: center;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.header h1 {
|
|
39
|
+
font-size: 2rem;
|
|
40
|
+
margin-bottom: 10px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.header p {
|
|
44
|
+
opacity: 0.9;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.nav {
|
|
48
|
+
background: #f8f9fa;
|
|
49
|
+
padding: 15px 30px;
|
|
50
|
+
border-bottom: 1px solid #dee2e6;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.back-link {
|
|
54
|
+
color: #667eea;
|
|
55
|
+
text-decoration: none;
|
|
56
|
+
font-weight: 500;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.back-link:hover {
|
|
60
|
+
text-decoration: underline;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.content {
|
|
64
|
+
padding: 30px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.section {
|
|
68
|
+
margin-bottom: 40px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.section h2 {
|
|
72
|
+
color: #495057;
|
|
73
|
+
margin-bottom: 20px;
|
|
74
|
+
padding-bottom: 10px;
|
|
75
|
+
border-bottom: 2px solid #667eea;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.ad-grid {
|
|
79
|
+
display: grid;
|
|
80
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
81
|
+
gap: 30px;
|
|
82
|
+
margin-bottom: 30px;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.ad-container {
|
|
86
|
+
border: 2px solid #e9ecef;
|
|
87
|
+
border-radius: 12px;
|
|
88
|
+
padding: 20px;
|
|
89
|
+
background: #f8f9fa;
|
|
90
|
+
transition: all 0.3s ease;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.ad-container:hover {
|
|
94
|
+
border-color: #667eea;
|
|
95
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.ad-container h3 {
|
|
99
|
+
margin-bottom: 15px;
|
|
100
|
+
color: #667eea;
|
|
101
|
+
font-size: 1.1rem;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.ad-slot {
|
|
105
|
+
background: white;
|
|
106
|
+
border: 2px dashed #dee2e6;
|
|
107
|
+
border-radius: 8px;
|
|
108
|
+
padding: 20px;
|
|
109
|
+
text-align: center;
|
|
110
|
+
min-height: 120px;
|
|
111
|
+
display: flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
justify-content: center;
|
|
114
|
+
position: relative;
|
|
115
|
+
transition: all 0.3s ease;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.ad-slot:hover {
|
|
119
|
+
border-color: #667eea;
|
|
120
|
+
background: #f8f9ff;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.ad-slot.loading::before {
|
|
124
|
+
content: "📡 광고 로딩 중...";
|
|
125
|
+
color: #6c757d;
|
|
126
|
+
font-size: 0.9rem;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.ad-slot.loaded::before {
|
|
130
|
+
content: "✅ 광고 로딩 완료";
|
|
131
|
+
color: #28a745;
|
|
132
|
+
font-size: 0.9rem;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.ad-slot.error::before {
|
|
136
|
+
content: "❌ 광고 로딩 실패";
|
|
137
|
+
color: #dc3545;
|
|
138
|
+
font-size: 0.9rem;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.ad-info {
|
|
142
|
+
margin-top: 15px;
|
|
143
|
+
padding: 10px;
|
|
144
|
+
background: #e9ecef;
|
|
145
|
+
border-radius: 6px;
|
|
146
|
+
font-size: 0.9rem;
|
|
147
|
+
color: #6c757d;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.controls {
|
|
151
|
+
display: flex;
|
|
152
|
+
gap: 10px;
|
|
153
|
+
margin-top: 15px;
|
|
154
|
+
flex-wrap: wrap;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.btn {
|
|
158
|
+
padding: 8px 16px;
|
|
159
|
+
border: none;
|
|
160
|
+
border-radius: 6px;
|
|
161
|
+
background: #667eea;
|
|
162
|
+
color: white;
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
font-size: 0.9rem;
|
|
165
|
+
transition: background 0.3s ease;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.btn:hover {
|
|
169
|
+
background: #5a67d8;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.btn.secondary {
|
|
173
|
+
background: #6c757d;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.btn.secondary:hover {
|
|
177
|
+
background: #5a6268;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.status {
|
|
181
|
+
margin-top: 30px;
|
|
182
|
+
padding: 20px;
|
|
183
|
+
background: #e7f3ff;
|
|
184
|
+
border-left: 4px solid #0066cc;
|
|
185
|
+
border-radius: 4px;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.code-example {
|
|
189
|
+
background: #2d3748;
|
|
190
|
+
color: #e2e8f0;
|
|
191
|
+
padding: 20px;
|
|
192
|
+
border-radius: 8px;
|
|
193
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
194
|
+
font-size: 0.9rem;
|
|
195
|
+
overflow-x: auto;
|
|
196
|
+
margin: 15px 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.large-banner {
|
|
200
|
+
min-height: 250px;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.medium-banner {
|
|
204
|
+
min-height: 200px;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.small-banner {
|
|
208
|
+
min-height: 120px;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.log {
|
|
212
|
+
background: #f8f9fa;
|
|
213
|
+
border: 1px solid #dee2e6;
|
|
214
|
+
border-radius: 6px;
|
|
215
|
+
padding: 15px;
|
|
216
|
+
max-height: 200px;
|
|
217
|
+
overflow-y: auto;
|
|
218
|
+
font-family: monospace;
|
|
219
|
+
font-size: 0.8rem;
|
|
220
|
+
margin-top: 15px;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.log-entry {
|
|
224
|
+
margin-bottom: 5px;
|
|
225
|
+
padding: 2px 5px;
|
|
226
|
+
border-radius: 3px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.log-entry.info {
|
|
230
|
+
background: #d4edda;
|
|
231
|
+
color: #155724;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.log-entry.warn {
|
|
235
|
+
background: #fff3cd;
|
|
236
|
+
color: #856404;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.log-entry.error {
|
|
240
|
+
background: #f8d7da;
|
|
241
|
+
color: #721c24;
|
|
242
|
+
}
|
|
243
|
+
</style>
|
|
244
|
+
</head>
|
|
245
|
+
<body>
|
|
246
|
+
<div class="container">
|
|
247
|
+
<div class="header">
|
|
248
|
+
<h1>🖼️ 배너 광고 예제</h1>
|
|
249
|
+
<p>다양한 크기와 형태의 배너 광고 표시</p>
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
<div class="nav">
|
|
253
|
+
<a href="index.html" class="back-link">← 메인 페이지로 돌아가기</a>
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
<div class="content">
|
|
257
|
+
<div class="section">
|
|
258
|
+
<h2>🎯 라이브 배너 광고</h2>
|
|
259
|
+
|
|
260
|
+
<div class="ad-grid">
|
|
261
|
+
<div class="ad-container">
|
|
262
|
+
<h3>대형 배너 (728x90)</h3>
|
|
263
|
+
<div class="ad-slot large-banner loading"
|
|
264
|
+
id="large-banner"
|
|
265
|
+
adstage="large-banner"
|
|
266
|
+
ad-type="BANNER"
|
|
267
|
+
data-size="728x90">
|
|
268
|
+
</div>
|
|
269
|
+
<div class="ad-info">
|
|
270
|
+
슬롯 ID: large-banner<br>
|
|
271
|
+
크기: 728x90 (Leaderboard)<br>
|
|
272
|
+
위치: 페이지 상단
|
|
273
|
+
</div>
|
|
274
|
+
<div class="controls">
|
|
275
|
+
<button class="btn" onclick="refreshAd('large-banner')">🔄 새로고침</button>
|
|
276
|
+
<button class="btn secondary" onclick="hideAd('large-banner')">👁️ 숨기기</button>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
|
|
280
|
+
<div class="ad-container">
|
|
281
|
+
<h3>중형 배너 (320x100)</h3>
|
|
282
|
+
<div class="ad-slot medium-banner loading"
|
|
283
|
+
id="medium-banner"
|
|
284
|
+
adstage="medium-banner"
|
|
285
|
+
ad-type="BANNER"
|
|
286
|
+
data-size="320x100">
|
|
287
|
+
</div>
|
|
288
|
+
<div class="ad-info">
|
|
289
|
+
슬롯 ID: medium-banner<br>
|
|
290
|
+
크기: 320x100 (Mobile Banner)<br>
|
|
291
|
+
위치: 콘텐츠 중간
|
|
292
|
+
</div>
|
|
293
|
+
<div class="controls">
|
|
294
|
+
<button class="btn" onclick="refreshAd('medium-banner')">🔄 새로고침</button>
|
|
295
|
+
<button class="btn secondary" onclick="hideAd('medium-banner')">👁️ 숨기기</button>
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
|
|
299
|
+
<div class="ad-container">
|
|
300
|
+
<h3>소형 배너 (300x50)</h3>
|
|
301
|
+
<div class="ad-slot small-banner loading"
|
|
302
|
+
id="small-banner"
|
|
303
|
+
adstage="small-banner"
|
|
304
|
+
ad-type="BANNER"
|
|
305
|
+
data-size="300x50">
|
|
306
|
+
</div>
|
|
307
|
+
<div class="ad-info">
|
|
308
|
+
슬롯 ID: small-banner<br>
|
|
309
|
+
크기: 300x50 (Mobile Banner)<br>
|
|
310
|
+
위치: 페이지 하단
|
|
311
|
+
</div>
|
|
312
|
+
<div class="controls">
|
|
313
|
+
<button class="btn" onclick="refreshAd('small-banner')">🔄 새로고침</button>
|
|
314
|
+
<button class="btn secondary" onclick="hideAd('small-banner')">👁️ 숨기기</button>
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<div class="ad-container">
|
|
319
|
+
<h3>동적 배너 (유동 크기)</h3>
|
|
320
|
+
<div class="ad-slot medium-banner loading"
|
|
321
|
+
id="dynamic-banner"
|
|
322
|
+
adstage="dynamic-banner"
|
|
323
|
+
ad-type="BANNER"
|
|
324
|
+
data-size="responsive">
|
|
325
|
+
</div>
|
|
326
|
+
<div class="ad-info">
|
|
327
|
+
슬롯 ID: dynamic-banner<br>
|
|
328
|
+
크기: 반응형 (Responsive)<br>
|
|
329
|
+
위치: 동적 콘텐츠 영역
|
|
330
|
+
</div>
|
|
331
|
+
<div class="controls">
|
|
332
|
+
<button class="btn" onclick="refreshAd('dynamic-banner')">🔄 새로고침</button>
|
|
333
|
+
<button class="btn secondary" onclick="hideAd('dynamic-banner')">👁️ 숨기기</button>
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
<div class="section">
|
|
340
|
+
<h2>⚡ 전체 제어</h2>
|
|
341
|
+
<div class="controls">
|
|
342
|
+
<button class="btn" onclick="refreshAllAds()">🔄 모든 광고 새로고침</button>
|
|
343
|
+
<button class="btn secondary" onclick="hideAllAds()">👁️ 모든 광고 숨기기</button>
|
|
344
|
+
<button class="btn" onclick="showAllAds()">👀 모든 광고 보이기</button>
|
|
345
|
+
<button class="btn secondary" onclick="clearLog()">🧹 로그 지우기</button>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
<div class="section">
|
|
350
|
+
<h2>📝 구현 코드</h2>
|
|
351
|
+
<div class="code-example">
|
|
352
|
+
<!-- HTML: 배너 광고 슬롯 -->
|
|
353
|
+
<div adstage="large-banner" ad-type="BANNER" data-size="728x90"></div>
|
|
354
|
+
|
|
355
|
+
<script type="module">
|
|
356
|
+
import AdStageSDK, { AdType } from '../dist/index.standalone.js';
|
|
357
|
+
|
|
358
|
+
// SDK 초기화
|
|
359
|
+
const sdk = AdStageSDK.init({
|
|
360
|
+
apiKey: 'YOUR_API_KEY',
|
|
361
|
+
debug: true
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// 수동 광고 로드 (선택사항)
|
|
365
|
+
sdk.loadAd('large-banner', AdType.BANNER);
|
|
366
|
+
</script>
|
|
367
|
+
</div>
|
|
368
|
+
</div>
|
|
369
|
+
|
|
370
|
+
<div class="status" id="status">
|
|
371
|
+
SDK 초기화 중...
|
|
372
|
+
</div>
|
|
373
|
+
|
|
374
|
+
<div class="log" id="log">
|
|
375
|
+
<div class="log-entry info">페이지 로드 시작...</div>
|
|
376
|
+
</div>
|
|
377
|
+
</div>
|
|
378
|
+
</div>
|
|
379
|
+
|
|
380
|
+
<script type="module">
|
|
381
|
+
import AdStageSDK, { AdType } from './dist/index.standalone.js';
|
|
382
|
+
|
|
383
|
+
const statusEl = document.getElementById('status');
|
|
384
|
+
const logEl = document.getElementById('log');
|
|
385
|
+
|
|
386
|
+
function addLog(message, type = 'info') {
|
|
387
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
388
|
+
const logEntry = document.createElement('div');
|
|
389
|
+
logEntry.className = `log-entry ${type}`;
|
|
390
|
+
logEntry.textContent = `[${timestamp}] ${message}`;
|
|
391
|
+
logEl.appendChild(logEntry);
|
|
392
|
+
logEl.scrollTop = logEl.scrollHeight;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function updateAdSlotStatus(slotId, status) {
|
|
396
|
+
const slot = document.getElementById(slotId);
|
|
397
|
+
if (slot) {
|
|
398
|
+
slot.className = slot.className.replace(/\b(loading|loaded|error)\b/g, '');
|
|
399
|
+
slot.classList.add(status);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// 전역 함수들
|
|
404
|
+
window.refreshAd = function(slotId) {
|
|
405
|
+
addLog(`광고 새로고침 요청: ${slotId}`, 'info');
|
|
406
|
+
updateAdSlotStatus(slotId, 'loading');
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
window.adstageSDK.refreshSlot(slotId);
|
|
410
|
+
addLog(`광고 새로고침 성공: ${slotId}`, 'info');
|
|
411
|
+
setTimeout(() => updateAdSlotStatus(slotId, 'loaded'), 1000);
|
|
412
|
+
} catch (error) {
|
|
413
|
+
addLog(`광고 새로고침 실패: ${slotId} - ${error.message}`, 'error');
|
|
414
|
+
updateAdSlotStatus(slotId, 'error');
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
window.hideAd = function(slotId) {
|
|
419
|
+
const slot = document.getElementById(slotId);
|
|
420
|
+
if (slot) {
|
|
421
|
+
slot.style.display = 'none';
|
|
422
|
+
addLog(`광고 숨김: ${slotId}`, 'info');
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
window.showAd = function(slotId) {
|
|
427
|
+
const slot = document.getElementById(slotId);
|
|
428
|
+
if (slot) {
|
|
429
|
+
slot.style.display = 'flex';
|
|
430
|
+
addLog(`광고 표시: ${slotId}`, 'info');
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
window.refreshAllAds = function() {
|
|
435
|
+
const slots = ['large-banner', 'medium-banner', 'small-banner', 'dynamic-banner'];
|
|
436
|
+
slots.forEach(slotId => {
|
|
437
|
+
setTimeout(() => refreshAd(slotId), Math.random() * 2000);
|
|
438
|
+
});
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
window.hideAllAds = function() {
|
|
442
|
+
const slots = ['large-banner', 'medium-banner', 'small-banner', 'dynamic-banner'];
|
|
443
|
+
slots.forEach(hideAd);
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
window.showAllAds = function() {
|
|
447
|
+
const slots = ['large-banner', 'medium-banner', 'small-banner', 'dynamic-banner'];
|
|
448
|
+
slots.forEach(showAd);
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
window.clearLog = function() {
|
|
452
|
+
logEl.innerHTML = '<div class="log-entry info">로그가 지워졌습니다.</div>';
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
try {
|
|
456
|
+
addLog('AdStage SDK 초기화 시작...', 'info');
|
|
457
|
+
|
|
458
|
+
// SDK 초기화
|
|
459
|
+
const sdk = AdStageSDK.init({
|
|
460
|
+
apiKey: '7dfddcfda637fbb73225bac3731688b80b90675942fe9f2057a88e2379aba2a4',
|
|
461
|
+
debug: true
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
// 전역 참조 저장
|
|
465
|
+
window.adstageSDK = sdk;
|
|
466
|
+
|
|
467
|
+
statusEl.innerHTML = '✅ SDK 초기화 완료 - 실제 배너 광고 로딩 중...';
|
|
468
|
+
statusEl.style.background = '#d4edda';
|
|
469
|
+
statusEl.style.borderColor = '#28a745';
|
|
470
|
+
|
|
471
|
+
addLog('SDK 초기화 완료', 'info');
|
|
472
|
+
addLog('실제 API에서 광고 로딩 시작...', 'info');
|
|
473
|
+
|
|
474
|
+
// 실제 API에서 광고 자동 로드
|
|
475
|
+
await sdk.autoLoadSlots();
|
|
476
|
+
|
|
477
|
+
// 광고 슬롯들에 클릭 이벤트 추가
|
|
478
|
+
document.querySelectorAll('.ad-slot').forEach(slot => {
|
|
479
|
+
const slotId = slot.getAttribute('adstage');
|
|
480
|
+
const adSize = slot.getAttribute('data-size');
|
|
481
|
+
|
|
482
|
+
// 클릭 이벤트
|
|
483
|
+
slot.addEventListener('click', function() {
|
|
484
|
+
addLog(`배너 광고 클릭: ${slotId} (${adSize})`, 'info');
|
|
485
|
+
|
|
486
|
+
// 시각적 피드백
|
|
487
|
+
this.style.background = '#e3f2fd';
|
|
488
|
+
setTimeout(() => {
|
|
489
|
+
this.style.background = 'white';
|
|
490
|
+
}, 300);
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
// 로딩 완료 상태로 업데이트
|
|
494
|
+
setTimeout(() => {
|
|
495
|
+
updateAdSlotStatus(slotId, 'loaded');
|
|
496
|
+
addLog(`실제 배너 광고 로드 완료: ${slotId}`, 'info');
|
|
497
|
+
}, Math.random() * 3000 + 1000);
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
addLog('🎯 실제 API 광고 로딩 완료 - beta-api.adstage.app', 'info');
|
|
501
|
+
console.log('배너 광고 예제 페이지 로드 완료');
|
|
502
|
+
|
|
503
|
+
} catch (error) {
|
|
504
|
+
console.error('SDK 초기화 오류:', error);
|
|
505
|
+
addLog(`SDK 초기화 실패: ${error.message}`, 'error');
|
|
506
|
+
statusEl.innerHTML = '❌ SDK 초기화 실패: ' + error.message;
|
|
507
|
+
statusEl.style.background = '#f8d7da';
|
|
508
|
+
statusEl.style.borderColor = '#dc3545';
|
|
509
|
+
}
|
|
510
|
+
</script>
|
|
511
|
+
</body>
|
|
512
|
+
</html>
|