@documental-xyz/core 0.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.
Files changed (114) hide show
  1. package/README.md +424 -0
  2. package/integration.ts +113 -0
  3. package/package.json +83 -0
  4. package/src/admin/admin.astro +29 -0
  5. package/src/assets/scripts/App.js +70 -0
  6. package/src/assets/scripts/EnteringAnimations.js +34 -0
  7. package/src/assets/scripts/MapBoxHandler.js +680 -0
  8. package/src/assets/scripts/ScrollProgressionBar.js +24 -0
  9. package/src/assets/scripts/utils/ScrollObserver.js +166 -0
  10. package/src/assets/styles/config/_breakpoints.scss +37 -0
  11. package/src/assets/styles/config/_colors.scss +8 -0
  12. package/src/assets/styles/config/_config.scss +5 -0
  13. package/src/assets/styles/config/_functions.scss +90 -0
  14. package/src/assets/styles/config/_grrr.configs.scss +7 -0
  15. package/src/assets/styles/config/_mixins.scss +207 -0
  16. package/src/assets/styles/config/_type.scss +175 -0
  17. package/src/assets/styles/config/_vars.scss +16 -0
  18. package/src/assets/styles/globals/_content.scss +47 -0
  19. package/src/assets/styles/globals/_grrr.scss +18 -0
  20. package/src/assets/styles/globals/_html.scss +25 -0
  21. package/src/assets/styles/globals/_lists.scss +19 -0
  22. package/src/assets/styles/globals/_map-anchors.scss +32 -0
  23. package/src/assets/styles/globals/_reset.scss +240 -0
  24. package/src/assets/styles/globals/_reveal-animations.scss +104 -0
  25. package/src/assets/styles/globals/_root.scss +6 -0
  26. package/src/assets/styles/globals/_scroll-progression-bar.scss +8 -0
  27. package/src/assets/styles/main.scss +17 -0
  28. package/src/assets/styles/utils/.gitkeep +0 -0
  29. package/src/assets/styles/utils/grrr/_grrr.scss +433 -0
  30. package/src/assets/styles/utils/list-styles/_list-styles.scss +190 -0
  31. package/src/components/AnimationToggle.astro +19 -0
  32. package/src/components/BigNumbers.astro +83 -0
  33. package/src/components/Button.astro +49 -0
  34. package/src/components/Caption.astro +15 -0
  35. package/src/components/Card.astro +68 -0
  36. package/src/components/Cards.astro +66 -0
  37. package/src/components/CardsCall.astro +125 -0
  38. package/src/components/ChartBar.astro +217 -0
  39. package/src/components/ChartPercentage.astro +137 -0
  40. package/src/components/Column.astro +54 -0
  41. package/src/components/ColumnSticky.astro +129 -0
  42. package/src/components/Columns.astro +139 -0
  43. package/src/components/Compare.astro +266 -0
  44. package/src/components/Cta.astro +242 -0
  45. package/src/components/Gallery.astro +594 -0
  46. package/src/components/Group.astro +140 -0
  47. package/src/components/HtmlEmbed.astro +98 -0
  48. package/src/components/ImageBlock.astro +134 -0
  49. package/src/components/InnerColumns.astro +54 -0
  50. package/src/components/LogosGroup.astro +102 -0
  51. package/src/components/Map.astro +321 -0
  52. package/src/components/MapBox.astro +96 -0
  53. package/src/components/MapView.astro +30 -0
  54. package/src/components/Menu.astro +278 -0
  55. package/src/components/Pullquote.astro +46 -0
  56. package/src/components/Slider.astro +223 -0
  57. package/src/components/Spacer.astro +25 -0
  58. package/src/components/Text.astro +173 -0
  59. package/src/components/TextPlaceholder.astro +98 -0
  60. package/src/components/Timeline.astro +73 -0
  61. package/src/components/TimelineBullet.astro +67 -0
  62. package/src/components/VideoEmbed.astro +99 -0
  63. package/src/content/loader.ts +29 -0
  64. package/src/content/pages/alter-ameacada.md +80 -0
  65. package/src/content/pages/expulsions.md +1447 -0
  66. package/src/content/pages/home.md +346 -0
  67. package/src/content/pages/nhanderekoa-studio-autonoma.md +3113 -0
  68. package/src/content/pages/nhanderekoa-terra-ind/303/255gena-jaragu/303/241.md +3806 -0
  69. package/src/content/pages/nova-landing-page.md +546 -0
  70. package/src/content/pages/territ/303/263rios-de-exce/303/247/303/243o.md +2199 -0
  71. package/src/content/pages/teste-alter-do-chao.md +955 -0
  72. package/src/content/pages/teste-layout.md +1484 -0
  73. package/src/content/pages/thiago.md +93 -0
  74. package/src/content/schema/blog.ts +11 -0
  75. package/src/content/schema/geostorys.ts +13 -0
  76. package/src/content/schema/index.ts +3 -0
  77. package/src/content/schema/pages.ts +494 -0
  78. package/src/content.config.ts +49 -0
  79. package/src/env.d.ts +1 -0
  80. package/src/integration/override-aliases.ts +67 -0
  81. package/src/layouts/components/ButtonLayout.astro +8 -0
  82. package/src/layouts/components/CardLayout.astro +8 -0
  83. package/src/layouts/components/CardsCallLayout.astro +26 -0
  84. package/src/layouts/components/CardsLayout.astro +14 -0
  85. package/src/layouts/components/ChartBarLayout.astro +21 -0
  86. package/src/layouts/components/ChartPercentageLayout.astro +17 -0
  87. package/src/layouts/components/ColumnLayout.astro +11 -0
  88. package/src/layouts/components/ColumnStickyLayout.astro +10 -0
  89. package/src/layouts/components/ColumnsLayout.astro +13 -0
  90. package/src/layouts/components/CompareLayout.astro +22 -0
  91. package/src/layouts/components/CtaLayout.astro +91 -0
  92. package/src/layouts/components/GalleryLayout.astro +24 -0
  93. package/src/layouts/components/GroupLayout.astro +53 -0
  94. package/src/layouts/components/HtmlEmbedLayout.astro +18 -0
  95. package/src/layouts/components/ImageBlockLayout.astro +20 -0
  96. package/src/layouts/components/InnerColumnsLayout.astro +14 -0
  97. package/src/layouts/components/LogosGroupLayout.astro +22 -0
  98. package/src/layouts/components/MapLayout.astro +41 -0
  99. package/src/layouts/components/MapViewLayout.astro +8 -0
  100. package/src/layouts/components/MapboxLayout.astro +248 -0
  101. package/src/layouts/components/PullquoteLayout.astro +13 -0
  102. package/src/layouts/components/SliderLayout.astro +18 -0
  103. package/src/layouts/components/SpacerLayout.astro +8 -0
  104. package/src/layouts/components/TextLayout.astro +17 -0
  105. package/src/layouts/components/TextPlaceholderLayout.astro +7 -0
  106. package/src/layouts/components/TimelineBulletLayout.astro +14 -0
  107. package/src/layouts/components/TimelineLayout.astro +10 -0
  108. package/src/layouts/components/VideoEmbedLayout.astro +28 -0
  109. package/src/layouts/pages/Layout.astro +90 -0
  110. package/src/layouts/pages/PageLayout.astro +200 -0
  111. package/src/lib/collections.ts +1 -0
  112. package/src/routes/[slug].astro +17 -0
  113. package/src/routes/index.astro +5 -0
  114. package/src/vite/yaml-merge-plugin.ts +234 -0
@@ -0,0 +1,680 @@
1
+ export default class MapBoxHandler {
2
+ constructor() {
3
+ this.transitionScreenPoint = 75;
4
+ this.transitionScreenPointMobile = 65;
5
+ this.mapMobileHeight = 52;
6
+ this.mobileBreakPoint = 992;
7
+
8
+ this.sels = {
9
+ triggers: '[data-map-view]',
10
+ triggersClass: '.map-view',
11
+ anchors: '[data-map-anchor]',
12
+ anchorsHolder: '#map-anchors',
13
+ mapWindows: '.map',
14
+ mapContent: '.map__holder',
15
+ mapFloating: '.map--floating-text',
16
+ mainMap: '#mapbox',
17
+ cloneMap: '#mapbox-clone div',
18
+ captions: '#captions',
19
+ };
20
+ this.labels = {
21
+ displacer: '__displacer__',
22
+ initView: '__initview__',
23
+ };
24
+ this.refs = {
25
+ anchorId: (id = false) =>
26
+ id ? `[data-map-anchor-id="${id}"]` : 'data-map-anchor-id',
27
+ anchorView: (id = false) =>
28
+ id ? `[data-map-anchor="${id}"]` : 'data-map-anchor',
29
+ triggerRef: (id = false) =>
30
+ id ? `[data-ref-id="${id}"]` : 'data-ref-id',
31
+ triggerView: (id = false) =>
32
+ id ? `[data-map-view="${id}"]` : 'data-map-view',
33
+ };
34
+
35
+ window.addEventListener('DOMContentLoaded', this.init.bind(this));
36
+ }
37
+
38
+ async init() {
39
+ this.mapWindows = document.querySelectorAll(this.sels.mapWindows);
40
+
41
+ if (
42
+ typeof window.mapConfig !== 'object' ||
43
+ !window.mapBoxToken ||
44
+ !this.mapWindows.length
45
+ )
46
+ return;
47
+
48
+ this.views = typeof window.mapViews === 'object' ? window.mapViews : false;
49
+ this.views &&
50
+ Object.keys(this.views).forEach((k) => (this.views[k].id = k));
51
+ this.mapAnchors = [];
52
+ this.definedLayers = [...window.mapConfig.layers];
53
+
54
+ const { style, ...initView } = window.mapConfig;
55
+ this.initView = {
56
+ ...initView,
57
+ id: this.labels.initView,
58
+ duration: this.views && Object.values(this.views)[0].duration,
59
+ };
60
+ this.currentView = initView;
61
+
62
+ this.mapHolder = document.querySelector(this.sels.mainMap);
63
+ this.mapHolderClone = document.querySelector(this.sels.cloneMap);
64
+
65
+ this.captionHolder = document.createElement('div');
66
+ this.captionHolder.setAttribute('id', this.sels.captions.replace('#', ''));
67
+
68
+ this.viewObserver = null;
69
+ this.map = null;
70
+ this.mapClone = null;
71
+ this.originalFilters = {};
72
+
73
+ this.countIntersectionEvents = 0;
74
+
75
+ await this.initViewAnchors();
76
+ await this.initMaps();
77
+ this.map.on('load', this.mapsOnLoad.bind(this));
78
+ }
79
+
80
+ async initViewAnchors() {
81
+ await this.setMapWindowDisplacers();
82
+ await this.setMapAnchors();
83
+
84
+ const resizeObserver = new ResizeObserver(
85
+ this.setPosToMapAnchors.bind(this)
86
+ );
87
+ resizeObserver.observe(document.body);
88
+
89
+ return true;
90
+ }
91
+
92
+ async initMaps() {
93
+ mapboxgl.accessToken = window.mapBoxToken;
94
+ this.map = new mapboxgl.Map({
95
+ container: this.mapHolder,
96
+ ...window.mapConfig,
97
+ });
98
+ if (this.getHistoryType() !== 'floating') {
99
+ this.mapClone = new mapboxgl.Map({
100
+ container: this.mapHolderClone,
101
+ ...window.mapConfig,
102
+ });
103
+ } else {
104
+ this.mapHolderClone.remove();
105
+ this.mapHolderClone = false;
106
+ }
107
+ return true;
108
+ }
109
+
110
+ async mapsOnLoad() {
111
+ this.mapHolder.style.opacity = 1;
112
+ this.mapHolderClone && (this.mapHolderClone.style.opacity = 1);
113
+ this.storeOriginalFilters();
114
+ this.defineLayers();
115
+ this.displayLayers(this.initView.layers, true);
116
+ this.adjustFirstViewOnLoad();
117
+ const resizeObserverView = new ResizeObserver(
118
+ this.observeView.bind(
119
+ this,
120
+ this.mapAnchors,
121
+ this.changeViewByEl.bind(this)
122
+ )
123
+ );
124
+ resizeObserverView.observe(document.body);
125
+ }
126
+
127
+ storeOriginalFilters() {
128
+ const style = this.map.getStyle();
129
+ style.layers.forEach(layer => {
130
+ if (layer.filter) {
131
+ this.originalFilters[layer.id] = layer.filter;
132
+ }
133
+ });
134
+ }
135
+
136
+ getOriginalLayerFilter(layerName) {
137
+ return this.originalFilters[layerName] || null;
138
+ }
139
+
140
+ /* Anchors & Observers */
141
+
142
+ async setMapAnchors() {
143
+ this.mapTriggers = document.querySelectorAll(this.sels.triggers);
144
+ const container = document.createElement('div');
145
+ container.setAttribute('id', this.sels.anchorsHolder.replace('#', ''));
146
+ container.setAttribute('aria-hidden', true);
147
+ container.style.position = 'absolute';
148
+ container.style.inset = 0;
149
+ container.style.zIndex = 9999;
150
+ container.style.pointerEvents = 'none';
151
+ this.mapTriggers &&
152
+ this.mapTriggers.forEach((el, i) => {
153
+ const anchor = document.createElement('div');
154
+ el.setAttribute(this.refs.triggerRef(), i);
155
+ anchor.setAttribute(this.refs.anchorId(), i);
156
+ anchor.setAttribute(
157
+ this.refs.anchorView(),
158
+ el.getAttribute(this.refs.triggerView())
159
+ );
160
+ i % 2 === 0 && anchor.classList.add('odd');
161
+ container.appendChild(anchor);
162
+ this.mapAnchors.push(anchor);
163
+ });
164
+ document.body.insertAdjacentElement('afterbegin', container);
165
+ return true;
166
+ }
167
+
168
+ async setPosToMapAnchors() {
169
+ const scrollPos = window.scrollY;
170
+ document.documentElement.style.scrollBehavior = 'unset';
171
+ window.scrollTo({ top: 0, behavior: 'instant' });
172
+
173
+ const getTopDistance = (el) => {
174
+ let distance = 0;
175
+ while (el) {
176
+ distance += el.offsetTop;
177
+ el = el.offsetParent;
178
+ }
179
+ return distance;
180
+ };
181
+
182
+ const getMobileAdjustment = (parent, index, top = false) => {
183
+
184
+ const mobileAdjustment =
185
+ !parent.classList.value.includes(
186
+ this.sels.mapFloating.replace('.', '')
187
+ ) &&
188
+ this.isMobile() &&
189
+ !parent.previousElementSibling?.closest(
190
+ `${this.sels.mapWindows}:not(${this.sels.mapFloating})`
191
+ ) &&
192
+ window.innerHeight;
193
+ return (top && index !== 0) || (!top && index === 0)
194
+ ? mobileAdjustment
195
+ : 0;
196
+ };
197
+
198
+ this.mapWindows &&
199
+ this.mapWindows.forEach((parent) => {
200
+ let mapTriggers = parent.querySelectorAll(this.sels.triggers);
201
+ mapTriggers &&
202
+ mapTriggers.forEach((el, index) => {
203
+ const nextElement = mapTriggers[index + 1];
204
+ const anchorRef = document.querySelector(
205
+ this.refs.anchorId(el.getAttribute(this.refs.triggerRef()))
206
+ );
207
+
208
+ anchorRef.style.top = `${
209
+ getTopDistance(el) + getMobileAdjustment(parent, index, true)
210
+ }px`;
211
+ if (nextElement) {
212
+ const distanceToNext =
213
+ getTopDistance(nextElement) - getTopDistance(el);
214
+ anchorRef.style.height = `${
215
+ distanceToNext + getMobileAdjustment(parent, index)
216
+ }px`;
217
+ } else {
218
+ const parentBottomDistance =
219
+ getTopDistance(parent) + parent.offsetHeight;
220
+ const distanceToParentBottom =
221
+ parentBottomDistance -
222
+ getTopDistance(el) -
223
+ getMobileAdjustment(parent, index, true);
224
+ anchorRef.style.height = `${distanceToParentBottom}px`;
225
+ }
226
+ });
227
+ });
228
+ window.scrollTo({ top: scrollPos, behavior: 'instant' });
229
+ document.documentElement.style.scrollBehavior = null;
230
+ }
231
+
232
+ async setMapWindowDisplacers() {
233
+ let topMapWindows = Array.from(this.mapWindows).filter(
234
+ (el) => !el.querySelector(`${this.sels.triggersClass}:first-child`)
235
+ );
236
+ topMapWindows.length &&
237
+ topMapWindows.forEach((el) =>
238
+ el
239
+ .querySelector(this.sels.mapContent)
240
+ .insertAdjacentHTML(
241
+ 'afterbegin',
242
+ `<div class="${this.sels.triggersClass.replace(
243
+ '.',
244
+ ''
245
+ )}" ${this.refs.triggerView()}="${this.labels.displacer}"></div>`
246
+ )
247
+ );
248
+ return topMapWindows.length;
249
+ }
250
+
251
+ adjustFirstViewOnLoad() {
252
+ const isTop = () => {
253
+ let el = Array.from(this.mapTriggers)[0];
254
+ let pos = el && el.getBoundingClientRect().top;
255
+ let ref =
256
+ el &&
257
+ document.querySelector(
258
+ this.refs.anchorId(el.getAttribute(this.refs.triggerRef()))
259
+ );
260
+ return (
261
+ el &&
262
+ window.scrollY < pos &&
263
+ pos < window.innerHeight * (this.getScreenTransitionPoint() * 0.01) &&
264
+ ref
265
+ );
266
+ };
267
+
268
+ // change to first view if the view is above transition point
269
+ setTimeout(() => {
270
+ const isTopEl = isTop();
271
+ isTopEl && this.changeViewByEl(isTopEl, true);
272
+ }, 80);
273
+ }
274
+
275
+ observeView(els, callback) {
276
+ if (!els || !els.length) return;
277
+ this.viewObserver && this.viewObserver.disconnect();
278
+ this.viewObserver = new IntersectionObserver(
279
+ (entries) => {
280
+ entries.forEach((entry) =>
281
+ callback(entry.target, entry.isIntersecting)
282
+ );
283
+ },
284
+ {
285
+ rootMargin: `${this.getScreenTransitionPoint() * -1}% 0px ${
286
+ (100 - this.getScreenTransitionPoint()) * -1
287
+ }% 0px`,
288
+ threshold: 0,
289
+ }
290
+ );
291
+ els.forEach((element) => this.viewObserver.observe(element));
292
+ }
293
+
294
+ /* Layers management */
295
+
296
+ defineLayers() {
297
+ Object.values(this.views).forEach((view) => {
298
+ if (view.layers) {
299
+ // Normalizar layers - pode vir como string (texto com quebras de linha) ou array
300
+ const normalizedLayers = Array.isArray(view.layers) ? view.layers :
301
+ (typeof view.layers === 'string' ? view.layers.split('\n').map(line => line.trim()).filter(line => line.length > 0) : []);
302
+
303
+ normalizedLayers.forEach((layer) => {
304
+ const layerName = typeof layer === 'string' ? layer : layer.name;
305
+ if (layerName) {
306
+ this.definedLayers.push(layerName);
307
+ }
308
+ });
309
+ }
310
+ });
311
+ }
312
+
313
+ displayLayers(layers = [], show = false) {
314
+ // Processar layers em lote para melhor performance
315
+ const layerUpdates = [];
316
+
317
+ // Normalizar layers - pode vir como string (texto com quebras de linha) ou array
318
+ const normalizedLayers = Array.isArray(layers) ? layers :
319
+ (typeof layers === 'string' ? layers.split('\n').map(line => line.trim()).filter(line => line.length > 0) : []);
320
+
321
+ normalizedLayers.forEach((layer) => {
322
+ const layerName = typeof layer === 'string' ? layer : layer.name;
323
+ if (layerName && this.layerExists(layerName)) {
324
+ layerUpdates.push({
325
+ name: layerName,
326
+ visibility: show ? 'visible' : 'none',
327
+ filter: typeof layer === 'object' ? layer.filter : null,
328
+ });
329
+ }
330
+ });
331
+
332
+ // Aplicar todas as atualizações
333
+ this.applyLayerUpdates(layerUpdates);
334
+ }
335
+
336
+ layerExists(layerName) {
337
+ try {
338
+ return this.map.getLayer(layerName) !== undefined;
339
+ } catch (e) {
340
+ console.warn(`Layer '${layerName}' não encontrada no mapa`);
341
+ return false;
342
+ }
343
+ }
344
+
345
+ applyLayerUpdates(updates) {
346
+ updates.forEach((update) => {
347
+ try {
348
+ this.map.setLayoutProperty(
349
+ update.name,
350
+ 'visibility',
351
+ update.visibility
352
+ );
353
+ this.mapClone &&
354
+ this.mapClone.setLayoutProperty(
355
+ update.name,
356
+ 'visibility',
357
+ update.visibility
358
+ );
359
+
360
+ if (update.filter) {
361
+ this.map.setFilter(update.name, update.filter);
362
+ this.mapClone && this.mapClone.setFilter(update.name, update.filter);
363
+ } else {
364
+ const originalFilter = this.getOriginalLayerFilter(update.name);
365
+ this.map.setFilter(update.name, originalFilter);
366
+ this.mapClone && this.mapClone.setFilter(update.name, originalFilter);
367
+ }
368
+ } catch (e) {
369
+ console.error(`Erro ao atualizar layer '${update.name}':`, e);
370
+ }
371
+ });
372
+ }
373
+
374
+ toggleLayersVisibility(visibleLayers) {
375
+ // Normalizar layers - pode vir como string (texto com quebras de linha) ou array
376
+ const normalizedLayers = Array.isArray(visibleLayers) ? visibleLayers :
377
+ (typeof visibleLayers === 'string' ? visibleLayers.split('\n').map(line => line.trim()).filter(line => line.length > 0) : []);
378
+
379
+ const visibleLayerNames = normalizedLayers.map((layer) =>
380
+ typeof layer === 'string' ? layer : layer.name
381
+ );
382
+ const hideLayers = this.definedLayers.filter(
383
+ (entry) => !visibleLayerNames.includes(entry)
384
+ );
385
+
386
+ // Preparar atualizações para esconder layers
387
+ const hideUpdates = hideLayers.map((layerName) => ({
388
+ name: layerName,
389
+ visibility: 'none',
390
+ filter: null,
391
+ }));
392
+
393
+ // Preparar atualizações para mostrar layers
394
+ const showUpdates = [];
395
+ normalizedLayers.forEach((layer) => {
396
+ const layerName = typeof layer === 'string' ? layer : layer.name;
397
+ if (layerName && this.layerExists(layerName)) {
398
+ showUpdates.push({
399
+ name: layerName,
400
+ visibility: 'visible',
401
+ filter: typeof layer === 'object' ? layer.filter : null,
402
+ });
403
+ }
404
+ });
405
+
406
+ // Aplicar todas as atualizações de uma vez
407
+ this.applyLayerUpdates([...hideUpdates, ...showUpdates]);
408
+ }
409
+
410
+ /* Map Movement */
411
+
412
+ async move(view, refEl = false, fly = true) {
413
+ this.animationStartTime = Date.now();
414
+ const isAnimating = this.map.isMoving() || this.map.isZooming();
415
+ const viewParameters = this.getViewParameters(view);
416
+ const destiny = refEl
417
+ ? { ...viewParameters, offset: this.getDiplacedOffset(refEl) }
418
+ : viewParameters;
419
+
420
+ refEl &&
421
+ setTimeout(() => {
422
+ this.generateCaptionsHTML(
423
+ view.captions,
424
+ refEl.closest(this.sels.mapWindows)
425
+ );
426
+ this.captionHolder.classList.remove('hidden');
427
+ this.countIntersectionEvents = 0;
428
+ }, 20);
429
+ this.toggleLayersVisibility(view.layers);
430
+
431
+ if (destiny.id === this.currentView.id && !isAnimating) {
432
+ destiny.duration = 1500;
433
+ fly = false;
434
+ }
435
+
436
+ this.currentView = view;
437
+ fly
438
+ ? this.mapClone && this.mapClone.flyTo(destiny)
439
+ : this.mapClone && this.mapClone.easeTo(destiny);
440
+ return fly ? this.map.flyTo(destiny) : this.map.easeTo(destiny);
441
+ }
442
+
443
+ changeViewByEl(target, intersection) {
444
+ if (!intersection) {
445
+ if (!this.countIntersectionEvents) {
446
+ this.captionHolder.classList.add('hidden');
447
+ this.maybeBackToInitialView();
448
+ ++this.countIntersectionEvents;
449
+ }
450
+ return false;
451
+ }
452
+
453
+ let viewId = target.getAttribute(this.refs.anchorView());
454
+ let mapTrigger = document.querySelector(
455
+ this.refs.triggerRef(target.getAttribute(this.refs.anchorId()))
456
+ );
457
+
458
+ if (this.views.hasOwnProperty(viewId)) {
459
+ this.move(this.views[viewId], mapTrigger);
460
+ return true;
461
+ }
462
+ if (viewId === this.labels.displacer) {
463
+ const lastAnchor = this.getPreviousAnchorInfo(target);
464
+ lastAnchor
465
+ ? this.move(lastAnchor.view, mapTrigger)
466
+ : this.move(this.initView);
467
+ return true;
468
+ }
469
+
470
+ console.warn('view not found');
471
+ return false;
472
+ }
473
+
474
+ maybeBackToInitialView() {
475
+ const isTop = () => {
476
+ let el = Array.from(this.mapTriggers)[0];
477
+ let pos = el.getBoundingClientRect().top;
478
+ return (
479
+ pos >
480
+ window.innerHeight * (this.getScreenTransitionPoint() * 0.01) && el
481
+ );
482
+ };
483
+ const isTopEl = isTop();
484
+ isTopEl && this.move(this.initView);
485
+ }
486
+
487
+ /* Captions */
488
+
489
+ generateCaptionsHTML(captions, holder) {
490
+ if (!captions) {
491
+ this.captionHolder.innerHTML = '';
492
+ return;
493
+ }
494
+ const infoSvg = `
495
+ <button data-toggle-caption>
496
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
497
+ <rect width="24" height="24" rx="12" fill="#000000"/>
498
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22.5C17.799 22.5 22.5 17.799 22.5 12C22.5 6.20101 17.799 1.5 12 1.5C6.20101 1.5 1.5 6.20101 1.5 12C1.5 17.799 6.20101 22.5 12 22.5ZM12 24C18.6274 24 24 18.6274 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24Z" fill="#FFFFFF"/>
499
+ <path d="M11.3032 17.8065C11.1926 17.8065 11.0986 17.7666 11.0212 17.687C10.9438 17.6074 10.9051 17.5107 10.9051 17.397V9.34364C10.9051 9.22989 10.9438 9.13321 11.0212 9.05359C11.0986 8.97396 11.1926 8.93415 11.3032 8.93415H12.6802C12.8018 8.93415 12.8959 8.97396 12.9622 9.05359C13.0396 9.13321 13.0783 9.22989 13.0783 9.34364V17.397C13.0783 17.5107 13.0396 17.6074 12.9622 17.687C12.8959 17.7666 12.8018 17.8065 12.6802 17.8065H11.3032ZM11.2369 7.46681C11.1263 7.46681 11.0323 7.427 10.9548 7.34737C10.8774 7.26775 10.8387 7.17107 10.8387 7.05732V5.82885C10.8387 5.7151 10.8774 5.61841 10.9548 5.53879C11.0323 5.45917 11.1263 5.41935 11.2369 5.41935H12.7465C12.8682 5.41935 12.9677 5.45917 13.0452 5.53879C13.1226 5.61841 13.1613 5.7151 13.1613 5.82885V7.05732C13.1613 7.17107 13.1226 7.26775 13.0452 7.34737C12.9677 7.427 12.8682 7.46681 12.7465 7.46681H11.2369Z" fill="#FFFFFF"/>
500
+ </svg>
501
+ </button>`;
502
+ this.captionsId = this.sels.captions.replace('#', '');
503
+ this.captionHolder.innerHTML = infoSvg;
504
+
505
+ let container = document.createElement('div');
506
+ if (captions.title) {
507
+ let title = document.createElement('span');
508
+ title.className = `${this.captionsId}__title`;
509
+ title.innerText = captions.title || 'Legenda:';
510
+ container.appendChild(title);
511
+ }
512
+ captions.items &&
513
+ captions.items.length &&
514
+ captions.items.forEach((item) => {
515
+ let itemContainer = document.createElement('span');
516
+ itemContainer.className = `${this.captionsId}__item`;
517
+
518
+ let iconContainer = document.createElement('span');
519
+ iconContainer.innerHTML = item.icon;
520
+ itemContainer.appendChild(iconContainer);
521
+
522
+ let textContainer = document.createElement('span');
523
+ textContainer.innerText = item.text;
524
+ itemContainer.appendChild(textContainer);
525
+
526
+ container.appendChild(itemContainer);
527
+ });
528
+ if (captions.notes) {
529
+ let notes = document.createElement('span');
530
+ notes.className = `${this.captionsId}__notes`;
531
+ notes.innerText = captions.notes;
532
+ container.appendChild(notes);
533
+ }
534
+ this.captionHolder.innerHTML += container.innerHTML;
535
+ holder.insertAdjacentElement('beforeend', this.captionHolder);
536
+ }
537
+
538
+ /* Helpers */
539
+
540
+ isMobile() {
541
+ return window.matchMedia(`(max-width:${this.mobileBreakPoint}px`).matches;
542
+ }
543
+
544
+ getViewParameters(view) {
545
+ let isMobile =
546
+ view &&
547
+ this.isMobile() &&
548
+ view.hasOwnProperty('mobile') &&
549
+ view.mobile &&
550
+ Object.values(view.mobile).length;
551
+ let mobileView = isMobile && { ...view.mobile };
552
+
553
+ // Converter centerLng/centerLat para center se necessário
554
+ let processedView = isMobile ? { ...view, ...mobileView } : view;
555
+ if (processedView.centerLng !== undefined && processedView.centerLat !== undefined) {
556
+ processedView.center = {
557
+ lng: parseFloat(processedView.centerLng),
558
+ lat: parseFloat(processedView.centerLat)
559
+ };
560
+ }
561
+
562
+ return processedView;
563
+ }
564
+
565
+ getDiplacedOffset(el) {
566
+ const parent = el.closest(this.sels.mapWindows);
567
+ const parentClasses = parent.classList.value;
568
+ const offset = { x: 0, y: 0 };
569
+
570
+ if (
571
+ (parentClasses.includes(this.sels.mapFloating.replace('.', '')) &&
572
+ this.isMobile()) ||
573
+ parentClasses.includes('center')
574
+ )
575
+ return Object.values(offset);
576
+
577
+ if (this.isMobile()) {
578
+ offset.y = this.isMobile()
579
+ ? window.innerHeight * ((1 - this.mapMobileHeight) * 0.005)
580
+ : 0;
581
+ } else {
582
+ offset.x = parent
583
+ .querySelector(this.sels.mapContent)
584
+ .getBoundingClientRect().width;
585
+ offset.x *= parentClasses.includes('alignleft')
586
+ ? 0.5
587
+ : parentClasses.includes('alignright')
588
+ ? -0.5
589
+ : 0;
590
+ }
591
+
592
+ return Object.values(offset);
593
+ }
594
+
595
+ getScreenTransitionPoint() {
596
+ const screenPoint = this.isMobile()
597
+ ? this.transitionScreenPointMobile
598
+ : this.transitionScreenPoint;
599
+ return screenPoint;
600
+ }
601
+
602
+ getCurrentAnimationRemaingDuration() {
603
+ let remainingDuration =
604
+ this.getViewParameters(this.currentView).duration -
605
+ (Date.now() - this.animationStartTime);
606
+ return remainingDuration < 0 ? 0 : remainingDuration;
607
+ }
608
+
609
+ getHistoryType() {
610
+ let columnViews = Array.from(this.mapWindows).filter(
611
+ (el) =>
612
+ !el.classList.value.includes(this.sels.mapFloating.replace('.', ''))
613
+ ).length;
614
+ let floatingViews = Array.from(this.mapWindows).filter((el) =>
615
+ el.classList.value.includes(this.sels.mapFloating.replace('.', ''))
616
+ ).length;
617
+ return columnViews && floatingViews
618
+ ? 'mixed'
619
+ : columnViews
620
+ ? 'columns'
621
+ : 'floating';
622
+ }
623
+
624
+ getAnchorInfo(el) {
625
+ if (!el.getAttribute(this.refs.anchorView())) {
626
+ console.warn('Not an anchor');
627
+ return false;
628
+ }
629
+ let view = { ...this.views[el.getAttribute(this.refs.anchorView())] };
630
+ if (view && Object.keys(view).length) {
631
+ let trigger = document.querySelector(
632
+ this.refs.triggerRef(el.getAttribute(this.refs.anchorId()))
633
+ );
634
+ let mapWindow = trigger.closest(this.sels.mapWindows);
635
+ return {
636
+ el: el,
637
+ view: view,
638
+ viewname: el.getAttribute(this.refs.anchorView()),
639
+ anchor: el,
640
+ ref: el.getAttribute(this.refs.anchorId()),
641
+ trigger: trigger,
642
+ mapWindow: mapWindow,
643
+ mapWindowClasses: mapWindow.classList.value,
644
+ };
645
+ }
646
+ return false;
647
+ }
648
+
649
+ getNextAnchorInfo(el) {
650
+ if (!el.getAttribute(this.refs.anchorView())) {
651
+ console.warn('Not an anchor');
652
+ return false;
653
+ }
654
+ let next = false;
655
+ while (el.nextElementSibling && !next) {
656
+ el = el.nextElementSibling;
657
+ next =
658
+ el.getAttribute(this.refs.anchorView()) === this.labels.displacer
659
+ ? false
660
+ : true;
661
+ }
662
+ return next && this.getAnchorInfo(el);
663
+ }
664
+
665
+ getPreviousAnchorInfo(el) {
666
+ if (!el.getAttribute(this.refs.anchorView())) {
667
+ console.warn('Not an anchor');
668
+ return false;
669
+ }
670
+ let next = false;
671
+ while (el.previousElementSibling && !next) {
672
+ el = el.previousElementSibling;
673
+ next =
674
+ el.getAttribute(this.refs.anchorView()) === this.labels.displacer
675
+ ? false
676
+ : true;
677
+ }
678
+ return next && this.getAnchorInfo(el);
679
+ }
680
+ }
@@ -0,0 +1,24 @@
1
+ export default class ScrollProgressionBar {
2
+ constructor() {
3
+ this.addProgressionBar();
4
+ this.onScroll();
5
+ }
6
+
7
+ updateProgressionBar() {
8
+ const scrollPercentage = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
9
+ this.progressionBar.style.width = `${scrollPercentage}%`;
10
+ }
11
+
12
+ addProgressionBar() {
13
+ this.progressionBar = document.createElement('div');
14
+ this.progressionBar.classList.add('scroll-progression-bar');
15
+ this.progressionBar.style.width = '0%';
16
+ document.body.appendChild(this.progressionBar);
17
+ }
18
+
19
+ onScroll() {
20
+ window.addEventListener('scroll', () => {
21
+ this.updateProgressionBar();
22
+ });
23
+ }
24
+ }