@xwadex/fesd 0.0.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.
Files changed (47) hide show
  1. package/20240328-video4-setting.png +0 -0
  2. package/CHANGELOG.md +41 -0
  3. package/README.md +25 -0
  4. package/dist/assets/fesd-bundle.css +9 -0
  5. package/dist/assets/fesd-bundle.js +9800 -0
  6. package/dist/assets/fesd-bundle.js.map +1 -0
  7. package/index.html +25 -0
  8. package/package.json +23 -0
  9. package/prepros.config +883 -0
  10. package/src/fesd/anchor4/anchor4.js +179 -0
  11. package/src/fesd/aost4/_aost4.sass +64 -0
  12. package/src/fesd/aost4/aost4.js +138 -0
  13. package/src/fesd/article4/article4.js +280 -0
  14. package/src/fesd/article4/article4.md +1 -0
  15. package/src/fesd/category-slider/_category-slider.sass +33 -0
  16. package/src/fesd/category-slider/category-slider.js +332 -0
  17. package/src/fesd/collapse4/collapse4.js +159 -0
  18. package/src/fesd/detect4/detect4.js +70 -0
  19. package/src/fesd/dropdown4/_dropdown4.sass +185 -0
  20. package/src/fesd/dropdown4/cityData.js +830 -0
  21. package/src/fesd/dropdown4/dropdown4.js +647 -0
  22. package/src/fesd/image-preview/_image-preview.sass +26 -0
  23. package/src/fesd/image-preview/image-preview.js +209 -0
  24. package/src/fesd/image-validate/_image-validate.sass +21 -0
  25. package/src/fesd/image-validate/image-validate.js +84 -0
  26. package/src/fesd/marquee4/_marquee4.sass +45 -0
  27. package/src/fesd/marquee4/marquee4.js +371 -0
  28. package/src/fesd/modal4/_modal4.sass +134 -0
  29. package/src/fesd/modal4/modal4.js +236 -0
  30. package/src/fesd/modal4/modernModal.js +182 -0
  31. package/src/fesd/multipurpose4/_multipurpose4.sass +282 -0
  32. package/src/fesd/multipurpose4/multipurpose4.js +562 -0
  33. package/src/fesd/ripple4/_ripple4.sass +44 -0
  34. package/src/fesd/ripple4/ripple4.js +138 -0
  35. package/src/fesd/share4/share4.js +191 -0
  36. package/src/fesd/shared/shared.js +59 -0
  37. package/src/fesd/shared/utils.js +98 -0
  38. package/src/fesd/tab4/_tab4.sass +25 -0
  39. package/src/fesd/tab4/tab4.js +473 -0
  40. package/src/fesd/video4/README.md +3 -0
  41. package/src/fesd/video4/_video4.sass +117 -0
  42. package/src/fesd/video4/video4.js +237 -0
  43. package/src/fesd/video4/videoPlayer.js +195 -0
  44. package/src/fesd.js +53 -0
  45. package/src/fesd.sass +29 -0
  46. package/src/fesdDB.js +282 -0
  47. package/vite.config.js +37 -0
@@ -0,0 +1,473 @@
1
+ import SHARED from '../shared/shared';
2
+ import { isElement } from '../shared/utils';
3
+
4
+ // 第六版
5
+ class Tab4 extends HTMLElement {
6
+ // 定義組件的初始狀態
7
+ constructor(el, option) {
8
+ super();
9
+ }
10
+ // 當組件的屬性被更改時會被呼叫
11
+ static get observedAttributes() {
12
+ return ['t4-active'];
13
+ }
14
+ attributeChangedCallback(attr, oldVal, newVal) {
15
+ if (attr === 't4-active') {
16
+ // change function
17
+ if (oldVal !== newVal) {
18
+ this.#stateChange(newVal);
19
+ }
20
+ }
21
+ }
22
+ connectedCallback() {
23
+ // 防呆
24
+ if (!this.classList.contains('t4-initialize')) {
25
+ this.#create();
26
+ }
27
+ }
28
+ #create() {
29
+ const name = this.getAttribute('t4-name');
30
+ const { SETTINGS } = fesdDB.tab4;
31
+ // 防呆!
32
+ if (document.querySelectorAll(`tab-el[t4-name=${name}]`).length > 1) {
33
+ console.warn(name, '名字有重複喔!!!');
34
+ }
35
+
36
+ this.t = {
37
+ tabs: [],
38
+ name: name,
39
+ tabPanels: [...this.children],
40
+ activeTab: '',
41
+ stepOutput: SETTINGS.stepOutput,
42
+ recordUrl: this.getAttribute('t4-url') || SETTINGS.recordUrl,
43
+ type: this.getAttribute('t4-type') || SETTINGS.type,
44
+ display: this.getAttribute('t4-display') || SETTINGS.display,
45
+ defaultPage: this.getAttribute('t4-defaultPage') || SETTINGS.defaultPage,
46
+ anchor: this.getAttribute('t4-anchor'),
47
+ gap: this.getAttribute('t4-gap') || SETTINGS.anchorGap,
48
+ transition: {
49
+ duration: this.getAttribute('t4-duration') || SETTINGS.transition.duration,
50
+ timing: this.getAttribute('t4-timing') || SETTINGS.transition.timing,
51
+ delay: this.getAttribute('t4-delay') || SETTINGS.transition.delay,
52
+ },
53
+ tabGroup: this.getAttribute('t4-group') || SETTINGS.tabGroup,
54
+ };
55
+ this.__events__ = {};
56
+ this.t.tabs = this.#tabSet();
57
+ this.t.step = document.querySelector(`[t4-control="${this.t.name}"]${this.t.stepOutput}`);
58
+
59
+ this.#init();
60
+ }
61
+
62
+ #init() {
63
+ // 初始化設定
64
+ this.t.activeTab = this.t.defaultPage;
65
+ if (this.t.display === 'swiper') {
66
+ this.#createSwiper();
67
+ }
68
+ if (this.t.recordUrl) {
69
+ const params = new URLSearchParams(document.location.search);
70
+ const val = params.get(this.t.name);
71
+ const matchingTabs = document.querySelectorAll(`[t4-name="${this.t.name}"] [t4-id="${val}"]`);
72
+
73
+ // 如果網址中有對應的參數,載入對應的頁籤
74
+ if (val && matchingTabs.length === 1) {
75
+ this.t.activeTab = val
76
+ } else {
77
+ console.warn(`沒有${val}這頁喔!!`);
78
+ }
79
+ }
80
+ this.setActiveTab(this.t.activeTab);
81
+ // 設定防呆
82
+ this.classList.add('t4-initialize');
83
+ this.#resizeTab();
84
+ }
85
+ // 第一關 判斷數量以及id設定
86
+ #tabSet() {
87
+ const { t } = this;
88
+ const tabs = Array.from(document.querySelectorAll(`[t4-control="${t.name}"][t4-role="tab"]`));
89
+ // 防呆
90
+ if (t.type === 'normal' && t.tabGroup === 'true') {
91
+ // 是頁籤且是群組 判斷數量是否相符
92
+ if (t.tabPanels.length !== tabs.length) {
93
+ console.warn('按鈕與內容數量不同喔', t.tabPanels.length, tabs.length);
94
+ }
95
+ }
96
+ if (t.tabGroup === 'true') {
97
+ // 流水號
98
+ t.tabPanels.forEach((el, index) => el.setAttribute('t4-id', index));
99
+ } else {
100
+ // 單一頁籤
101
+ t.tabPanels.forEach(el => {
102
+ if (!el.getAttribute('t4-id')) {
103
+ console.warn(el, '請幫我設定id!!');
104
+ }
105
+ });
106
+ }
107
+ return tabs;
108
+ }
109
+ // 第二關 id命名提醒
110
+ #getTabIndex(id) {
111
+ const { t } = this;
112
+ const tabPanelsWithId = t.tabPanels.filter(panel => panel.getAttribute('t4-id') === id);
113
+ // 防呆!
114
+ if (tabPanelsWithId.length > 1) {
115
+ console.warn('有兩個相同id設定', tabPanelsWithId);
116
+ }
117
+
118
+ // 取得頁籤本人
119
+ const tabPanel = tabPanelsWithId[0];
120
+ if (tabPanel) {
121
+ const tabIndex = t.tabPanels.indexOf(tabPanel);
122
+ return tabIndex;
123
+ } else {
124
+ console.warn(`找不到t4-id為${id}的頁籤`);
125
+ return 0;
126
+ }
127
+ }
128
+
129
+ #createSwiper() {
130
+ const swiperContainer = document.createElement('div');
131
+ swiperContainer.classList.add('swiper-container');
132
+
133
+ const swiperWrapper = document.createElement('div');
134
+ swiperWrapper.classList.add('swiper-wrapper');
135
+
136
+ this.t.tabPanels.forEach(slide => {
137
+ swiperWrapper.appendChild(slide.cloneNode(true));
138
+ });
139
+
140
+ // 更新 t.tabPanels
141
+ this.t.tabPanels = [...swiperWrapper.children];
142
+
143
+ swiperContainer.appendChild(swiperWrapper);
144
+ this.innerHTML = ''; // 清空原有的內容
145
+ this.appendChild(swiperContainer);
146
+ // 執行 Swiper 效果的相關初始化
147
+ this.#initSwiper();
148
+ }
149
+ #initSwiper() {
150
+ const sContainer = this.querySelector('.swiper-container');
151
+ const sWrapper = this.querySelector('.swiper-wrapper');
152
+ const tabPanels = this.t.tabPanels;
153
+
154
+ // 設定容器和 wrapper 的樣式
155
+ sContainer.style.overflow = 'hidden';
156
+ sWrapper.style.display = 'flex';
157
+
158
+ // 設定 wrapper 的寬度
159
+ const totalWidth = tabPanels.length * 100 + '%';
160
+ sWrapper.style.width = totalWidth;
161
+ }
162
+
163
+ #addUrl(panel) {
164
+ const { t } = this;
165
+
166
+ if (t.recordUrl === 'true') {
167
+ const params = new URLSearchParams(document.location.search);
168
+ params.set(t.name, panel);
169
+ const newUrl = `${window.location.pathname}?${params.toString()}`;
170
+
171
+ // 使用 replaceState 修改瀏覽器歷史記錄
172
+ history.replaceState({ t4Id: panel }, '', newUrl);
173
+ }
174
+ }
175
+
176
+ // 執行函式
177
+ // 移動至指定位置
178
+ #eventAnchor() {
179
+ const gap = parseInt(this.t.gap, 10);
180
+ const pageYOffset = window.pageYOffset;
181
+ const targetOffset = this.getBoundingClientRect().top;
182
+ const changeOffset = targetOffset + pageYOffset - gap;
183
+ this.#goAnchor(changeOffset);
184
+ }
185
+ // 移動
186
+ #goAnchor(val) {
187
+ window.scrollTo({
188
+ top: val,
189
+ behavior: 'smooth',
190
+ });
191
+ }
192
+ // 步驟狀態
193
+ #step(val) {
194
+ let current = parseInt(val, 10) + 1;
195
+ this.t.step.textContent = `${current}`;
196
+ this.t.step.setAttribute('now-page', current);
197
+ }
198
+ // next 按鈕狀態
199
+ #btnNextState(newPage) {
200
+ const next = document.querySelectorAll(`[t4-role="next"][t4-control="${this.t.name}"]`);
201
+
202
+ const isSinglePage = this.t.tabPanels.length === 1;
203
+ const isLastPage = newPage === this.t.tabPanels.length - 1;
204
+
205
+ next.forEach(btn => {
206
+ if (isSinglePage || isLastPage) {
207
+ btn.setAttribute('disabled', '');
208
+ } else {
209
+ btn.removeAttribute('disabled');
210
+ }
211
+ });
212
+ }
213
+ // prev 按鈕狀態
214
+ #btnPrevState(newPage) {
215
+ const prev = document.querySelectorAll(`[t4-role="prev"][t4-control="${this.t.name}"]`);
216
+
217
+ const isSinglePage = this.t.tabPanels.length === 1;
218
+ const isFirstPage = newPage === 0;
219
+
220
+ prev.forEach(btn => {
221
+ if (isSinglePage || isFirstPage) {
222
+ btn.setAttribute('disabled', '');
223
+ } else {
224
+ btn.removeAttribute('disabled');
225
+ }
226
+ });
227
+ }
228
+ // 頁籤狀態
229
+ #tabState(newPage, tabId) {
230
+ if (this.t.tabGroup === 'true') {
231
+ this.t.tabs.forEach((tab, i) => {
232
+ if (i == newPage) {
233
+ tab.setAttribute('aria-selected', true);
234
+ } else {
235
+ tab.setAttribute('aria-selected', false);
236
+ }
237
+ });
238
+ } else {
239
+ // 自訂 id 的話...
240
+ this.t.tabs.forEach((tab, i) => {
241
+ if (tab.getAttribute('t4-id') === tabId) {
242
+ tab.setAttribute('aria-selected', true);
243
+ } else {
244
+ tab.setAttribute('aria-selected', false);
245
+ }
246
+ });
247
+ }
248
+ }
249
+ // 第三關各種元件判斷 及 執行
250
+ #isTrue(fun, val, val2) {
251
+ switch (fun) {
252
+ case 'step':
253
+ if (isElement(this.t.step)) {
254
+ this.#step(val);
255
+ }
256
+ break;
257
+ case 'eventAnchor':
258
+ if (this.t.anchor) {
259
+ this.#eventAnchor();
260
+ }
261
+ break;
262
+ case 'tabState':
263
+ // 流程沒有按鈕 客制的話....
264
+ if (this.t.type == 'normal') {
265
+ // 頁籤按鈕狀態
266
+ this.#tabState(val, val2);
267
+ }
268
+ break;
269
+ case 'btnState':
270
+ this.#btnNextState(val);
271
+ this.#btnPrevState(val);
272
+ break;
273
+ case 'tabUrl':
274
+ if (this.t.recordUrl === 'true') {
275
+ this.#addUrl(val);
276
+ }
277
+ break;
278
+ default:
279
+ console.warn('請增加判斷,謝謝');
280
+ break;
281
+ }
282
+ }
283
+ // 消失動畫
284
+ #animationHide(index) {
285
+ const { t } = this;
286
+ const { duration, timing, delay } = this.t.transition;
287
+ const tabPanel = t.tabPanels[index];
288
+ // 動畫 消失 動畫 出現 搭配 settimeout 使用
289
+ tabPanel.classList.add('hide');
290
+ switch (t.display) {
291
+ case 'fade':
292
+ tabPanel.style.cssText = 'display: none; opacity: 0;';
293
+ break;
294
+ case 'slide':
295
+ tabPanel.style.cssText = 'display: none; opacity: 0; max-height: unset;';
296
+ break;
297
+ case 'swiper':
298
+ break;
299
+ default:
300
+ tabPanel.style.display = 'none';
301
+ break;
302
+ }
303
+ }
304
+ // 出現動畫
305
+ #animationShow(index) {
306
+ const { duration, timing, delay } = this.t.transition;
307
+ const tabPanel = this.t.tabPanels[index];
308
+ let timer;
309
+
310
+ tabPanel.classList.remove('hide');
311
+ tabPanel.style.transition = `opacity ${duration}ms ${timing} ${delay}ms`;
312
+ tabPanel.style.display = 'block';
313
+
314
+ switch (this.t.display) {
315
+ case 'fade':
316
+ tabPanel.style.opacity = '0';
317
+ timer = setTimeout(() => {
318
+ clearTimeout(timer);
319
+ tabPanel.style.opacity = '1';
320
+ }, 100);
321
+ break;
322
+ case 'slide':
323
+ console.warn(this.t.display, '抱歉,好像壞掉了...');
324
+ const clientHeight = tabPanel.offsetHeight;
325
+ tabPanel.style.opacity = '1';
326
+ tabPanel.style.maxHeight = '0';
327
+ timer = setTimeout(() => {
328
+ clearTimeout(timer);
329
+ tabPanel.style.maxHeight = clientHeight + 'px';
330
+ }, 100);
331
+ break;
332
+ case 'swiper':
333
+ tabPanel.style.opacity = '1';
334
+ const sWrapper = this.querySelector('.swiper-wrapper');
335
+ const slideWidth = this.t.tabPanels[0].offsetWidth;
336
+ const translateValue = -index * slideWidth;
337
+
338
+ sWrapper.style.transition = `transform ${duration}ms ${timing} ${delay}ms`;
339
+ sWrapper.style.transform = `translateX(${translateValue}px)`;
340
+ break;
341
+ default:
342
+ console.warn(this.t.display, '沒有這個效果請自己想辦法!!!!');
343
+ break;
344
+ }
345
+ }
346
+ // 狀態
347
+ #stateChange(tabId) {
348
+ const newTabIndex = this.#getTabIndex(tabId);
349
+ // 通知狀態改變
350
+ this.#isTrue('step', newTabIndex);
351
+ this.#isTrue('btnState', newTabIndex);
352
+ this.#isTrue('tabState', newTabIndex, tabId);
353
+ this.#isTrue('tabUrl', tabId);
354
+ // 觸發自定義事件
355
+ this.emit('change');
356
+ }
357
+ // resize
358
+ #resizeTab() {
359
+ const _this_ = this;
360
+ window.addEventListener(
361
+ 'resize',
362
+ debounce(() => {
363
+ _this_.update();
364
+ }, 1000),
365
+ );
366
+ }
367
+
368
+ // ------------- 我是分隔線呦 -------------
369
+ // 頁籤切換
370
+ tabClick(clickedTab) {
371
+ const { t } = this;
372
+ // 防呆!! 為了保證數量多餘頁籤時仍可正常執行
373
+ const indexOf = t.tabs.indexOf(clickedTab) % t.tabPanels.length;
374
+ const newTabId = t.tabGroup === 'true' ? String(indexOf) : clickedTab.getAttribute('t4-id');
375
+
376
+ // 通知頁籤切換
377
+ this.setActiveTab(newTabId);
378
+
379
+ // 錨點滑動動畫
380
+ setTimeout(() => {
381
+ this.#isTrue('eventAnchor');
382
+ }, t.transition.duration);
383
+ }
384
+ // 外部呼叫方法 $0.setActiveTab(0)
385
+ setActiveTab(id) {
386
+ const { t } = this;
387
+ const defaultID = id === '' ? t.tabPanels[0].getAttribute('t4-id') : id;
388
+ t.activeTab = defaultID;
389
+ this.setAttribute('t4-active', defaultID);
390
+
391
+ const newTabIndex = this.#getTabIndex(defaultID);
392
+
393
+ t.tabPanels.forEach((panel, i) => {
394
+ i === newTabIndex ? this.#animationShow(i) : this.#animationHide(i);
395
+ });
396
+ }
397
+ // 外部呼叫方法 $0.goNext()
398
+ goNext() {
399
+ const tabIndex = this.#getTabIndex(this.t.activeTab);
400
+ const nextPage = Math.min(this.t.tabPanels.length - 1, tabIndex + 1);
401
+ const nextPageId = this.t.tabPanels[nextPage].getAttribute('t4-id');
402
+ this.setActiveTab(nextPageId);
403
+ }
404
+ // 外部呼叫方法 $0.goPrev()
405
+ goPrev() {
406
+ const tabIndex = this.#getTabIndex(this.t.activeTab);
407
+ const prevPage = Math.max(0, tabIndex - 1);
408
+ const prevPageId = this.t.tabPanels[prevPage].getAttribute('t4-id');
409
+ this.setActiveTab(prevPageId);
410
+ }
411
+ // 外部呼叫方法 $0.update()
412
+ update() {
413
+ this.t.tabs = this.#tabSet();
414
+ // 事件重綁
415
+ changeEvent();
416
+ console.log('tab update!!!!');
417
+ }
418
+ }
419
+
420
+ function debounce(func, time = 1000) {
421
+ let timer;
422
+ return function (event) {
423
+ if (timer) clearTimeout(timer);
424
+ timer = setTimeout(func, time, event);
425
+ };
426
+ }
427
+
428
+ // 綁定點擊事件
429
+ function changeEvent() {
430
+ const targetElements = document.querySelectorAll('[t4-control]');
431
+
432
+ document.addEventListener('click', function (event) {
433
+ let isTarget = false;
434
+ for (const targetElement of targetElements) {
435
+ if (targetElement.contains(event.target) || event.target.closest('[t4-control]') === targetElement) {
436
+ isTarget = true;
437
+ break;
438
+ }
439
+ }
440
+ if (isTarget) {
441
+ // event.target 是目標元素或其子層
442
+ const tabControl = event.target.closest('[t4-control]');
443
+ const tabElName = tabControl.getAttribute('t4-control');
444
+ const tabEls = document.querySelectorAll(`tab-el[t4-name="${tabElName}"]`);
445
+ const role = tabControl.getAttribute('t4-role');
446
+ tabEls.forEach(el => {
447
+ switch (role) {
448
+ case 'tab':
449
+ el.tabClick(tabControl);
450
+ break;
451
+ case 'next':
452
+ el.goNext(tabControl);
453
+ break;
454
+ case 'prev':
455
+ el.goPrev(tabControl);
456
+ break;
457
+ default:
458
+ console.warn('你是誰??', tabControl);
459
+ break;
460
+ }
461
+ });
462
+ }
463
+ });
464
+ }
465
+ changeEvent();
466
+
467
+ Object.assign(Tab4.prototype, SHARED);
468
+
469
+ // if (!customElements.get('tab-el')) {
470
+ // customElements.define('tab-el', Tab4);
471
+ // }
472
+
473
+ export default Tab4;
@@ -0,0 +1,3 @@
1
+ ## youku video id 包含 == / autoplay 目前沒有作用
2
+ ## vimeo 需要 video id & video hash
3
+
@@ -0,0 +1,117 @@
1
+ [video-template]
2
+ .modal-wrapper
3
+ padding: 0 40px
4
+ .modal-content
5
+ max-width: 1280px
6
+ width: 100%
7
+ background-color: transparent
8
+ .close-button
9
+ position: absolute
10
+ top: -30px
11
+ right: -30px
12
+ display: flex
13
+ align-items: center
14
+ justify-content: center
15
+ width: 30px
16
+ height: 30px
17
+ transform: rotate(45deg)
18
+ z-index: 1
19
+ cursor: pointer
20
+ &:before,
21
+ &:after
22
+ content: ''
23
+ position: absolute
24
+ top: 50%
25
+ left: 50%
26
+ transform: translate3d(-50%,-50%,0)
27
+ background-color: #fff
28
+ &:before
29
+ width: 3px
30
+ height: 20px
31
+ &:after
32
+ width: 20px
33
+ height: 3px
34
+
35
+ video-player
36
+ .player-container
37
+ position: relative
38
+ .player-wrapper
39
+ &::before
40
+ display: block
41
+ padding-bottom: 56.25%
42
+ content: ''
43
+ iframe
44
+ position: absolute
45
+ top: 0
46
+ left: 0
47
+ bottom: 0
48
+ right: 0
49
+ width: 100%
50
+ height: 100%
51
+
52
+ .video4-cover
53
+ position: relative
54
+ .playButton
55
+ position: absolute
56
+ top: 50%
57
+ left: 50%
58
+ display: flex
59
+ align-items: center
60
+ justify-content: center
61
+ width: min(24%, 50px)
62
+ height: 0
63
+ padding-bottom: min(24%,50px)
64
+ background-size: cover
65
+ box-shadow: 4px 4px 25px rgba(0, 0, 0, 0.5)
66
+ border-radius: 50%
67
+ transform: translate3d(-50%, -50%, 0)
68
+ z-index: 2
69
+ cursor: pointer
70
+ &::after
71
+ content: ''
72
+ position: absolute
73
+ top: 0
74
+ left: 0
75
+ width: 100%
76
+ height: 100%
77
+ border-radius: 100%
78
+ background-color: #fff
79
+ &::before
80
+ content: ''
81
+ position: absolute
82
+ top: 50%
83
+ left: 50%
84
+ width: 0
85
+ height: 0
86
+ border-style: solid
87
+ border-width: 6px 0 6px 12px
88
+ border-color: transparent transparent transparent #000
89
+ transform: translate3d(-50%,-50%,0)
90
+ z-index: 1
91
+ &:hover
92
+ + .overlay
93
+ background-color: rgba(0, 0, 0, 0.8)
94
+
95
+ .overlay
96
+ position: absolute
97
+ top: 0
98
+ left: 0
99
+ width: 100%
100
+ height: 100%
101
+ background-color: rgba(0, 0, 0, 0.4)
102
+ transition: background-color 0.5s
103
+ z-index: 1
104
+
105
+ &.onPage
106
+ iframe
107
+ width: 100%
108
+ height: 100%
109
+ position: absolute
110
+ top: 0
111
+ left: 0
112
+ z-index: 2
113
+
114
+ @media all and (orientation:landscape)
115
+ [video-template]
116
+ .modal-content
117
+ max-width: 133.33vh