@c4h/chuci 0.1.0 → 0.2.1
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/CHANGELOG.md +32 -32
- package/LICENSE +20 -20
- package/README.ja.md +143 -143
- package/README.md +224 -224
- package/dist/chuci.js +9068 -6596
- package/dist/chuci.umd.js +165 -166
- package/dist/index.d.ts +1 -0
- package/package.json +36 -33
- package/src/components/swiper/cc-swiper-slide.ts +49 -49
- package/src/components/swiper/cc-swiper-styles.ts +28 -28
- package/src/components/swiper/cc-swiper.ts +379 -361
- package/src/components/swiper/swiper-styles.css +4 -4
- package/src/components/viewer/cc-viewer-3dmodel.ts +491 -491
- package/src/components/viewer/cc-viewer-base.ts +278 -278
- package/src/components/viewer/cc-viewer-gaussian.ts +380 -380
- package/src/components/viewer/cc-viewer-image.ts +189 -189
- package/src/components/viewer/cc-viewer-panorama.ts +85 -85
- package/src/components/viewer/cc-viewer-styles.ts +55 -55
- package/src/components/viewer/cc-viewer-video.ts +109 -109
- package/src/components/viewer/cc-viewer-youtube.ts +75 -75
- package/src/components/viewer/cc-viewer.ts +290 -290
- package/src/index.ts +24 -24
- package/src/types/css-modules.d.ts +1 -1
- package/src/types/global.d.ts +10 -10
- package/src/utils/base-element.ts +76 -76
- package/dist/assets/azumaya_panorama1.png +0 -0
- package/dist/chuci.cjs +0 -4483
- package/dist/index-8VMexD2a.cjs +0 -255
- package/dist/index-kvsisbKS.js +0 -2125
- package/dist/index.html +0 -241
- package/dist/test-image.html +0 -63
|
@@ -1,279 +1,279 @@
|
|
|
1
|
-
import { ChuciElement } from '@/utils/base-element'
|
|
2
|
-
|
|
3
|
-
export abstract class CcViewerBase extends ChuciElement {
|
|
4
|
-
private _showPrevButton = true
|
|
5
|
-
private _showNextButton = true
|
|
6
|
-
protected isShow = false
|
|
7
|
-
protected isLoading = false
|
|
8
|
-
|
|
9
|
-
get showPrevButton() {
|
|
10
|
-
return this._showPrevButton
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
set showPrevButton(value: boolean) {
|
|
14
|
-
this._showPrevButton = value
|
|
15
|
-
this.updateNavigationVisibility()
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
get showNextButton() {
|
|
19
|
-
return this._showNextButton
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
set showNextButton(value: boolean) {
|
|
23
|
-
this._showNextButton = value
|
|
24
|
-
this.updateNavigationVisibility()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Template method pattern - subclasses implement these
|
|
28
|
-
protected abstract doOpen(url: string): void | Promise<void>
|
|
29
|
-
protected abstract doClose(): void
|
|
30
|
-
protected abstract getViewerContent(): string
|
|
31
|
-
|
|
32
|
-
// Common lifecycle methods
|
|
33
|
-
open(url: string): void {
|
|
34
|
-
this.isShow = true
|
|
35
|
-
this.isLoading = true
|
|
36
|
-
|
|
37
|
-
// Call subclass implementation first
|
|
38
|
-
const openPromise = Promise.resolve(this.doOpen(url))
|
|
39
|
-
|
|
40
|
-
// Use microtask to ensure doOpen runs first (even if synchronous)
|
|
41
|
-
Promise.resolve().then(() => {
|
|
42
|
-
// Initial render for loading state
|
|
43
|
-
this.render()
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
// Update after loading completes
|
|
47
|
-
openPromise.then(() => {
|
|
48
|
-
this.isLoading = false
|
|
49
|
-
this.render()
|
|
50
|
-
}).catch(_error => {
|
|
51
|
-
this.isLoading = false
|
|
52
|
-
this.render()
|
|
53
|
-
})
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
close(): void {
|
|
57
|
-
this.cleanupNavigationListeners()
|
|
58
|
-
this.doClose()
|
|
59
|
-
this.isShow = false
|
|
60
|
-
this.isLoading = false
|
|
61
|
-
this.render()
|
|
62
|
-
this.dispatch('close')
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
protected cleanupNavigationListeners() {
|
|
66
|
-
// Remove data-listener-attached attributes so listeners can be re-added
|
|
67
|
-
const prevBtn = this.query('.nav-prev')
|
|
68
|
-
const nextBtn = this.query('.nav-next')
|
|
69
|
-
const closeBtn = this.query('.nav-close')
|
|
70
|
-
|
|
71
|
-
if (prevBtn) prevBtn.removeAttribute('data-listener-attached')
|
|
72
|
-
if (nextBtn) nextBtn.removeAttribute('data-listener-attached')
|
|
73
|
-
if (closeBtn) closeBtn.removeAttribute('data-listener-attached')
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Common render method
|
|
77
|
-
protected render() {
|
|
78
|
-
// Allow subclasses to opt out of common rendering
|
|
79
|
-
if (this.shouldUseCustomRender()) {
|
|
80
|
-
this.customRender()
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const styles = this.css`
|
|
85
|
-
:host {
|
|
86
|
-
--cc-viewer-z-index-each: 1000;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.backdrop {
|
|
90
|
-
justify-content: center;
|
|
91
|
-
align-items: center;
|
|
92
|
-
position: fixed;
|
|
93
|
-
left: 0;
|
|
94
|
-
right: 0;
|
|
95
|
-
top: 0;
|
|
96
|
-
bottom: 0;
|
|
97
|
-
width: 100%;
|
|
98
|
-
height: 100%;
|
|
99
|
-
background-color: rgba(0, 0, 0, 0.9);
|
|
100
|
-
z-index: var(--cc-viewer-z-index-each);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.viewer {
|
|
104
|
-
position: absolute;
|
|
105
|
-
width: 90%;
|
|
106
|
-
height: 85%;
|
|
107
|
-
inset: 0px;
|
|
108
|
-
margin: auto;
|
|
109
|
-
align-self: center;
|
|
110
|
-
background-color: #000;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
${this.getNavigationStyles()}
|
|
114
|
-
${this.getCustomStyles()}
|
|
115
|
-
`
|
|
116
|
-
|
|
117
|
-
const html = `
|
|
118
|
-
${styles}
|
|
119
|
-
<div class="backdrop" style="${this.isShow ? 'visibility: visible' : 'visibility: hidden'}">
|
|
120
|
-
${this.getNavigationButtons()}
|
|
121
|
-
<div class="viewer">
|
|
122
|
-
${this.getViewerContent()}
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
`
|
|
126
|
-
|
|
127
|
-
this.updateShadowRoot(html)
|
|
128
|
-
|
|
129
|
-
// Add listeners after render
|
|
130
|
-
setTimeout(() => {
|
|
131
|
-
this.addNavigationListeners()
|
|
132
|
-
this.onAfterRender()
|
|
133
|
-
}, 0)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Hook for viewers that need completely custom rendering (e.g., image viewer)
|
|
137
|
-
protected shouldUseCustomRender(): boolean {
|
|
138
|
-
return false
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
protected customRender(): void {
|
|
142
|
-
// Override in subclasses that need custom rendering
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Hook methods for subclasses
|
|
146
|
-
protected getCustomStyles(): string {
|
|
147
|
-
return ''
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
protected onAfterRender(): void {
|
|
151
|
-
// Subclasses can override for custom listeners
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
protected navigatePrev() {
|
|
155
|
-
this.dispatch('navigate-prev')
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
protected navigateNext() {
|
|
159
|
-
this.dispatch('navigate-next')
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
protected getNavigationButtons(): string {
|
|
163
|
-
const prevStyle = this.showPrevButton ? '' : 'display: none;'
|
|
164
|
-
const nextStyle = this.showNextButton ? '' : 'display: none;'
|
|
165
|
-
|
|
166
|
-
return `
|
|
167
|
-
<button class="nav-button nav-prev" style="${prevStyle}" aria-label="Previous">
|
|
168
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
169
|
-
<polyline points="15 18 9 12 15 6"></polyline>
|
|
170
|
-
</svg>
|
|
171
|
-
</button>
|
|
172
|
-
<button class="nav-button nav-next" style="${nextStyle}" aria-label="Next">
|
|
173
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
174
|
-
<polyline points="9 18 15 12 9 6"></polyline>
|
|
175
|
-
</svg>
|
|
176
|
-
</button>
|
|
177
|
-
<button class="nav-button nav-close" aria-label="Close">
|
|
178
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
179
|
-
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
180
|
-
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
181
|
-
</svg>
|
|
182
|
-
</button>
|
|
183
|
-
`
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
protected getNavigationStyles(): string {
|
|
187
|
-
return `
|
|
188
|
-
.nav-button {
|
|
189
|
-
position: absolute;
|
|
190
|
-
top: 50%;
|
|
191
|
-
transform: translateY(-50%);
|
|
192
|
-
background: rgba(0, 0, 0, 0.5);
|
|
193
|
-
color: white;
|
|
194
|
-
border: none;
|
|
195
|
-
border-radius: 4px;
|
|
196
|
-
width: 48px;
|
|
197
|
-
height: 48px;
|
|
198
|
-
display: flex;
|
|
199
|
-
align-items: center;
|
|
200
|
-
justify-content: center;
|
|
201
|
-
cursor: pointer;
|
|
202
|
-
transition: background 0.3s;
|
|
203
|
-
z-index:
|
|
204
|
-
pointer-events: auto;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
.nav-button:hover {
|
|
208
|
-
background: rgba(0, 0, 0, 0.7);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
.nav-prev {
|
|
212
|
-
left: 20px;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
.nav-next {
|
|
216
|
-
right: 20px;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.nav-close {
|
|
220
|
-
top: 20px;
|
|
221
|
-
right: 20px;
|
|
222
|
-
transform: none;
|
|
223
|
-
}
|
|
224
|
-
`
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
protected addNavigationListeners() {
|
|
228
|
-
|
|
229
|
-
// Check if this viewer is actually visible
|
|
230
|
-
const backdrop = this.query('.backdrop') as HTMLElement
|
|
231
|
-
if (backdrop && backdrop.style.visibility === 'hidden') {
|
|
232
|
-
return
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
setTimeout(() => {
|
|
236
|
-
const prevBtn = this.query('.nav-prev')
|
|
237
|
-
const nextBtn = this.query('.nav-next')
|
|
238
|
-
const closeBtn = this.query('.nav-close')
|
|
239
|
-
|
|
240
|
-
if (prevBtn && !prevBtn.hasAttribute('data-listener-attached')) {
|
|
241
|
-
prevBtn.setAttribute('data-listener-attached', 'true')
|
|
242
|
-
prevBtn.addEventListener('click', (e) => {
|
|
243
|
-
e.stopPropagation()
|
|
244
|
-
e.preventDefault()
|
|
245
|
-
this.navigatePrev()
|
|
246
|
-
}, true)
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (nextBtn && !nextBtn.hasAttribute('data-listener-attached')) {
|
|
250
|
-
nextBtn.setAttribute('data-listener-attached', 'true')
|
|
251
|
-
nextBtn.addEventListener('click', (e) => {
|
|
252
|
-
e.stopPropagation()
|
|
253
|
-
this.navigateNext()
|
|
254
|
-
})
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (closeBtn && !closeBtn.hasAttribute('data-listener-attached')) {
|
|
258
|
-
closeBtn.setAttribute('data-listener-attached', 'true')
|
|
259
|
-
closeBtn.addEventListener('click', (e) => {
|
|
260
|
-
e.stopPropagation()
|
|
261
|
-
this.close()
|
|
262
|
-
})
|
|
263
|
-
}
|
|
264
|
-
}, 0)
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
protected updateNavigationVisibility() {
|
|
268
|
-
const prevBtn = this.query('.nav-prev')
|
|
269
|
-
const nextBtn = this.query('.nav-next')
|
|
270
|
-
|
|
271
|
-
if (prevBtn) {
|
|
272
|
-
(prevBtn as HTMLElement).style.display = this._showPrevButton ? '' : 'none'
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (nextBtn) {
|
|
276
|
-
(nextBtn as HTMLElement).style.display = this._showNextButton ? '' : 'none'
|
|
277
|
-
}
|
|
278
|
-
}
|
|
1
|
+
import { ChuciElement } from '@/utils/base-element'
|
|
2
|
+
|
|
3
|
+
export abstract class CcViewerBase extends ChuciElement {
|
|
4
|
+
private _showPrevButton = true
|
|
5
|
+
private _showNextButton = true
|
|
6
|
+
protected isShow = false
|
|
7
|
+
protected isLoading = false
|
|
8
|
+
|
|
9
|
+
get showPrevButton() {
|
|
10
|
+
return this._showPrevButton
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
set showPrevButton(value: boolean) {
|
|
14
|
+
this._showPrevButton = value
|
|
15
|
+
this.updateNavigationVisibility()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get showNextButton() {
|
|
19
|
+
return this._showNextButton
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
set showNextButton(value: boolean) {
|
|
23
|
+
this._showNextButton = value
|
|
24
|
+
this.updateNavigationVisibility()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Template method pattern - subclasses implement these
|
|
28
|
+
protected abstract doOpen(url: string): void | Promise<void>
|
|
29
|
+
protected abstract doClose(): void
|
|
30
|
+
protected abstract getViewerContent(): string
|
|
31
|
+
|
|
32
|
+
// Common lifecycle methods
|
|
33
|
+
open(url: string): void {
|
|
34
|
+
this.isShow = true
|
|
35
|
+
this.isLoading = true
|
|
36
|
+
|
|
37
|
+
// Call subclass implementation first
|
|
38
|
+
const openPromise = Promise.resolve(this.doOpen(url))
|
|
39
|
+
|
|
40
|
+
// Use microtask to ensure doOpen runs first (even if synchronous)
|
|
41
|
+
Promise.resolve().then(() => {
|
|
42
|
+
// Initial render for loading state
|
|
43
|
+
this.render()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// Update after loading completes
|
|
47
|
+
openPromise.then(() => {
|
|
48
|
+
this.isLoading = false
|
|
49
|
+
this.render()
|
|
50
|
+
}).catch(_error => {
|
|
51
|
+
this.isLoading = false
|
|
52
|
+
this.render()
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
close(): void {
|
|
57
|
+
this.cleanupNavigationListeners()
|
|
58
|
+
this.doClose()
|
|
59
|
+
this.isShow = false
|
|
60
|
+
this.isLoading = false
|
|
61
|
+
this.render()
|
|
62
|
+
this.dispatch('close')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected cleanupNavigationListeners() {
|
|
66
|
+
// Remove data-listener-attached attributes so listeners can be re-added
|
|
67
|
+
const prevBtn = this.query('.nav-prev')
|
|
68
|
+
const nextBtn = this.query('.nav-next')
|
|
69
|
+
const closeBtn = this.query('.nav-close')
|
|
70
|
+
|
|
71
|
+
if (prevBtn) prevBtn.removeAttribute('data-listener-attached')
|
|
72
|
+
if (nextBtn) nextBtn.removeAttribute('data-listener-attached')
|
|
73
|
+
if (closeBtn) closeBtn.removeAttribute('data-listener-attached')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Common render method
|
|
77
|
+
protected render() {
|
|
78
|
+
// Allow subclasses to opt out of common rendering
|
|
79
|
+
if (this.shouldUseCustomRender()) {
|
|
80
|
+
this.customRender()
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const styles = this.css`
|
|
85
|
+
:host {
|
|
86
|
+
--cc-viewer-z-index-each: 1000;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.backdrop {
|
|
90
|
+
justify-content: center;
|
|
91
|
+
align-items: center;
|
|
92
|
+
position: fixed;
|
|
93
|
+
left: 0;
|
|
94
|
+
right: 0;
|
|
95
|
+
top: 0;
|
|
96
|
+
bottom: 0;
|
|
97
|
+
width: 100%;
|
|
98
|
+
height: 100%;
|
|
99
|
+
background-color: rgba(0, 0, 0, 0.9);
|
|
100
|
+
z-index: var(--cc-viewer-z-index-each);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.viewer {
|
|
104
|
+
position: absolute;
|
|
105
|
+
width: 90%;
|
|
106
|
+
height: 85%;
|
|
107
|
+
inset: 0px;
|
|
108
|
+
margin: auto;
|
|
109
|
+
align-self: center;
|
|
110
|
+
background-color: #000;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
${this.getNavigationStyles()}
|
|
114
|
+
${this.getCustomStyles()}
|
|
115
|
+
`
|
|
116
|
+
|
|
117
|
+
const html = `
|
|
118
|
+
${styles}
|
|
119
|
+
<div class="backdrop" style="${this.isShow ? 'visibility: visible' : 'visibility: hidden'}">
|
|
120
|
+
${this.getNavigationButtons()}
|
|
121
|
+
<div class="viewer">
|
|
122
|
+
${this.getViewerContent()}
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
`
|
|
126
|
+
|
|
127
|
+
this.updateShadowRoot(html)
|
|
128
|
+
|
|
129
|
+
// Add listeners after render
|
|
130
|
+
setTimeout(() => {
|
|
131
|
+
this.addNavigationListeners()
|
|
132
|
+
this.onAfterRender()
|
|
133
|
+
}, 0)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Hook for viewers that need completely custom rendering (e.g., image viewer)
|
|
137
|
+
protected shouldUseCustomRender(): boolean {
|
|
138
|
+
return false
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected customRender(): void {
|
|
142
|
+
// Override in subclasses that need custom rendering
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Hook methods for subclasses
|
|
146
|
+
protected getCustomStyles(): string {
|
|
147
|
+
return ''
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
protected onAfterRender(): void {
|
|
151
|
+
// Subclasses can override for custom listeners
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
protected navigatePrev() {
|
|
155
|
+
this.dispatch('navigate-prev')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
protected navigateNext() {
|
|
159
|
+
this.dispatch('navigate-next')
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
protected getNavigationButtons(): string {
|
|
163
|
+
const prevStyle = this.showPrevButton ? '' : 'display: none;'
|
|
164
|
+
const nextStyle = this.showNextButton ? '' : 'display: none;'
|
|
165
|
+
|
|
166
|
+
return `
|
|
167
|
+
<button class="nav-button nav-prev" style="${prevStyle}" aria-label="Previous">
|
|
168
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
169
|
+
<polyline points="15 18 9 12 15 6"></polyline>
|
|
170
|
+
</svg>
|
|
171
|
+
</button>
|
|
172
|
+
<button class="nav-button nav-next" style="${nextStyle}" aria-label="Next">
|
|
173
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
174
|
+
<polyline points="9 18 15 12 9 6"></polyline>
|
|
175
|
+
</svg>
|
|
176
|
+
</button>
|
|
177
|
+
<button class="nav-button nav-close" aria-label="Close">
|
|
178
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
179
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
180
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
181
|
+
</svg>
|
|
182
|
+
</button>
|
|
183
|
+
`
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
protected getNavigationStyles(): string {
|
|
187
|
+
return `
|
|
188
|
+
.nav-button {
|
|
189
|
+
position: absolute;
|
|
190
|
+
top: 50%;
|
|
191
|
+
transform: translateY(-50%);
|
|
192
|
+
background: rgba(0, 0, 0, 0.5);
|
|
193
|
+
color: white;
|
|
194
|
+
border: none;
|
|
195
|
+
border-radius: 4px;
|
|
196
|
+
width: 48px;
|
|
197
|
+
height: 48px;
|
|
198
|
+
display: flex;
|
|
199
|
+
align-items: center;
|
|
200
|
+
justify-content: center;
|
|
201
|
+
cursor: pointer;
|
|
202
|
+
transition: background 0.3s;
|
|
203
|
+
z-index: calc(var(--cc-viewer-z-index-each, 1000) + 2);
|
|
204
|
+
pointer-events: auto;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.nav-button:hover {
|
|
208
|
+
background: rgba(0, 0, 0, 0.7);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.nav-prev {
|
|
212
|
+
left: 20px;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.nav-next {
|
|
216
|
+
right: 20px;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.nav-close {
|
|
220
|
+
top: 20px;
|
|
221
|
+
right: 20px;
|
|
222
|
+
transform: none;
|
|
223
|
+
}
|
|
224
|
+
`
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
protected addNavigationListeners() {
|
|
228
|
+
|
|
229
|
+
// Check if this viewer is actually visible
|
|
230
|
+
const backdrop = this.query('.backdrop') as HTMLElement
|
|
231
|
+
if (backdrop && backdrop.style.visibility === 'hidden') {
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
setTimeout(() => {
|
|
236
|
+
const prevBtn = this.query('.nav-prev')
|
|
237
|
+
const nextBtn = this.query('.nav-next')
|
|
238
|
+
const closeBtn = this.query('.nav-close')
|
|
239
|
+
|
|
240
|
+
if (prevBtn && !prevBtn.hasAttribute('data-listener-attached')) {
|
|
241
|
+
prevBtn.setAttribute('data-listener-attached', 'true')
|
|
242
|
+
prevBtn.addEventListener('click', (e) => {
|
|
243
|
+
e.stopPropagation()
|
|
244
|
+
e.preventDefault()
|
|
245
|
+
this.navigatePrev()
|
|
246
|
+
}, true)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (nextBtn && !nextBtn.hasAttribute('data-listener-attached')) {
|
|
250
|
+
nextBtn.setAttribute('data-listener-attached', 'true')
|
|
251
|
+
nextBtn.addEventListener('click', (e) => {
|
|
252
|
+
e.stopPropagation()
|
|
253
|
+
this.navigateNext()
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (closeBtn && !closeBtn.hasAttribute('data-listener-attached')) {
|
|
258
|
+
closeBtn.setAttribute('data-listener-attached', 'true')
|
|
259
|
+
closeBtn.addEventListener('click', (e) => {
|
|
260
|
+
e.stopPropagation()
|
|
261
|
+
this.close()
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
}, 0)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
protected updateNavigationVisibility() {
|
|
268
|
+
const prevBtn = this.query('.nav-prev')
|
|
269
|
+
const nextBtn = this.query('.nav-next')
|
|
270
|
+
|
|
271
|
+
if (prevBtn) {
|
|
272
|
+
(prevBtn as HTMLElement).style.display = this._showPrevButton ? '' : 'none'
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (nextBtn) {
|
|
276
|
+
(nextBtn as HTMLElement).style.display = this._showNextButton ? '' : 'none'
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
279
|
}
|