@hortonstudio/main 1.9.20 → 1.9.22
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/dist/assets/animations-igIF6V0K.js +3 -0
- package/dist/assets/animations-igIF6V0K.js. +3 -0
- package/dist/assets/animations-igIF6V0K.js.gz +0 -0
- package/dist/assets/animations-igIF6V0K.js.map +1 -0
- package/dist/assets/counter-B9xmgh8V.js +2 -0
- package/dist/assets/counter-B9xmgh8V.js. +2 -0
- package/dist/assets/counter-B9xmgh8V.js.gz +0 -0
- package/dist/assets/counter-B9xmgh8V.js.map +1 -0
- package/dist/assets/cssVariables-n9wQSSYb.js +2 -0
- package/dist/assets/cssVariables-n9wQSSYb.js.map +1 -0
- package/dist/assets/default-CZ6vle49.js +2 -0
- package/dist/assets/default-CZ6vle49.js. +2 -0
- package/dist/assets/default-CZ6vle49.js.gz +0 -0
- package/dist/assets/default-CZ6vle49.js.map +1 -0
- package/dist/assets/modalManager-LtDi9OJz.js +2 -0
- package/dist/assets/modalManager-LtDi9OJz.js. +2 -0
- package/dist/assets/modalManager-LtDi9OJz.js.gz +0 -0
- package/dist/assets/modalManager-LtDi9OJz.js.map +1 -0
- package/dist/assets/normalize-DWI4olFS.js +2 -0
- package/dist/assets/normalize-DWI4olFS.js. +2 -0
- package/dist/assets/normalize-DWI4olFS.js.gz +0 -0
- package/dist/assets/normalize-DWI4olFS.js.map +1 -0
- package/dist/assets/structure--7b3v7AH.js +2 -0
- package/dist/assets/structure--7b3v7AH.js. +2 -0
- package/dist/assets/structure--7b3v7AH.js.gz +0 -0
- package/dist/assets/structure--7b3v7AH.js.map +1 -0
- package/dist/assets/utils-DA-PANmk.js +2 -0
- package/dist/assets/utils-DA-PANmk.js.map +1 -0
- package/dist/bootstrap.js +2 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/main.js +3 -0
- package/dist/main.js. +3 -0
- package/dist/main.js.gz +0 -0
- package/dist/main.js.map +1 -0
- package/package.json +5 -2
- package/.prettierrc +0 -8
- package/eslint.config.js +0 -32
- package/index.ts +0 -275
- package/public/bootstrap.js +0 -16
- package/src/animations/animations.ts +0 -93
- package/src/animations/functions/counter/counter.ts +0 -137
- package/src/config.json +0 -570
- package/src/config.ts +0 -105
- package/src/modules/default/README.md +0 -167
- package/src/modules/default/default.ts +0 -71
- package/src/modules/default/functions/accessibility/README.md +0 -134
- package/src/modules/default/functions/accessibility/accessibility.ts +0 -54
- package/src/modules/default/functions/accordion/README.md +0 -451
- package/src/modules/default/functions/accordion/accordion.ts +0 -189
- package/src/modules/default/functions/comparison/comparison.ts +0 -424
- package/src/modules/default/functions/marquee/marquee.ts +0 -206
- package/src/modules/default/functions/navbar/README.md +0 -393
- package/src/modules/default/functions/navbar/functions/arrow-navigation/arrow-navigation.ts +0 -183
- package/src/modules/default/functions/navbar/functions/dropdown/dropdown.ts +0 -313
- package/src/modules/default/functions/navbar/functions/menu/menu.ts +0 -315
- package/src/modules/default/functions/navbar/navbar.ts +0 -51
- package/src/modules/default/functions/smooth-scroll/README.md +0 -417
- package/src/modules/default/functions/smooth-scroll/smooth-scroll.ts +0 -115
- package/src/modules/default/functions/transition/README.md +0 -328
- package/src/modules/default/functions/transition/transition.ts +0 -290
- package/src/modules/normalize/README.md +0 -172
- package/src/modules/normalize/functions/clickable/README.md +0 -84
- package/src/modules/normalize/functions/clickable/clickable.ts +0 -43
- package/src/modules/normalize/functions/clickable/functions/normalize/README.md +0 -213
- package/src/modules/normalize/functions/clickable/functions/normalize/normalize.ts +0 -68
- package/src/modules/normalize/functions/dupe/README.md +0 -405
- package/src/modules/normalize/functions/dupe/dupe.ts +0 -197
- package/src/modules/normalize/functions/sync/sync.ts +0 -378
- package/src/modules/normalize/normalize.ts +0 -58
- package/src/modules/structure/README.md +0 -190
- package/src/modules/structure/functions/form/README.md +0 -94
- package/src/modules/structure/functions/form/form.ts +0 -54
- package/src/modules/structure/functions/form/functions/honeypot/README.md +0 -77
- package/src/modules/structure/functions/form/functions/honeypot/honeypot.ts +0 -37
- package/src/modules/structure/functions/form/functions/range/README.md +0 -410
- package/src/modules/structure/functions/form/functions/range/range.ts +0 -92
- package/src/modules/structure/functions/form/functions/select/README.md +0 -393
- package/src/modules/structure/functions/form/functions/select/functions/custom-select/custom-select.ts +0 -637
- package/src/modules/structure/functions/form/functions/select/functions/states/states.ts +0 -118
- package/src/modules/structure/functions/form/functions/select/select.ts +0 -48
- package/src/modules/structure/functions/form/functions/test/test.ts +0 -132
- package/src/modules/structure/functions/pagination/README.md +0 -527
- package/src/modules/structure/functions/pagination/pagination.ts +0 -493
- package/src/modules/structure/functions/site-settings/README.md +0 -395
- package/src/modules/structure/functions/site-settings/site-settings.ts +0 -158
- package/src/modules/structure/functions/toc/README.md +0 -82
- package/src/modules/structure/functions/toc/functions/heading-links/heading-links.ts +0 -171
- package/src/modules/structure/functions/toc/functions/progress-bar/progress-bar.ts +0 -101
- package/src/modules/structure/functions/toc/toc.ts +0 -35
- package/src/modules/structure/functions/year-replacement/README.md +0 -55
- package/src/modules/structure/functions/year-replacement/year-replacement.ts +0 -59
- package/src/modules/structure/structure.ts +0 -59
- package/src/utils/attributeSelector.ts +0 -78
- package/src/utils/cssVariables.ts +0 -24
- package/src/utils/gsap.ts +0 -198
- package/src/utils/heightAnimator.ts +0 -130
- package/src/utils/modalManager.ts +0 -150
- package/src/utils.ts +0 -54
- package/tsconfig.json +0 -24
- package/vite.config.js +0 -45
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { querySelectorAll } from '@utils';
|
|
2
|
-
|
|
3
|
-
export function init(config) {
|
|
4
|
-
const cleanup = {
|
|
5
|
-
observers: [],
|
|
6
|
-
handlers: [],
|
|
7
|
-
scrollTimeout: null,
|
|
8
|
-
headings: [],
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const addObserver = (observer) => cleanup.observers.push(observer);
|
|
12
|
-
const addHandler = (element, event, handler, options) => {
|
|
13
|
-
element.addEventListener(event, handler, options);
|
|
14
|
-
cleanup.handlers.push({ element, event, handler, options });
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
function setupRichTextAccessibility(addObserver, addHandler, cleanup) {
|
|
18
|
-
const contentAreas = querySelectorAll(config, 'content');
|
|
19
|
-
const tocLists = querySelectorAll(config, 'list');
|
|
20
|
-
|
|
21
|
-
contentAreas.forEach((contentArea) => {
|
|
22
|
-
// Since there's only 1 content area and 1 TOC list per page, use the first TOC list
|
|
23
|
-
const tocList = tocLists[0];
|
|
24
|
-
|
|
25
|
-
if (!tocList) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (tocList.children.length === 0) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const template = tocList.children[0].cloneNode(true);
|
|
34
|
-
// Remove is-active class from template if it exists
|
|
35
|
-
const templateLink = template.querySelector('a');
|
|
36
|
-
if (templateLink) {
|
|
37
|
-
templateLink.classList.remove('is-active');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Clear all original TOC items
|
|
41
|
-
tocList.innerHTML = '';
|
|
42
|
-
|
|
43
|
-
const h2Headings = contentArea.querySelectorAll('h2');
|
|
44
|
-
|
|
45
|
-
// Add IDs directly to H2 headings (no wrapping)
|
|
46
|
-
h2Headings.forEach((heading) => {
|
|
47
|
-
const sectionId = heading.textContent
|
|
48
|
-
.toLowerCase()
|
|
49
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
50
|
-
.replace(/(^-|-$)/g, '');
|
|
51
|
-
|
|
52
|
-
heading.id = sectionId;
|
|
53
|
-
cleanup.headings.push(heading);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// Create TOC entries
|
|
57
|
-
h2Headings.forEach((heading, index) => {
|
|
58
|
-
const tocItem = template.cloneNode(true);
|
|
59
|
-
const link = tocItem.querySelector('a');
|
|
60
|
-
const sectionId = heading.id;
|
|
61
|
-
link.href = '#' + sectionId;
|
|
62
|
-
|
|
63
|
-
// Bold numbered text
|
|
64
|
-
const number = document.createElement('strong');
|
|
65
|
-
number.textContent = index + 1 + '. ';
|
|
66
|
-
|
|
67
|
-
// Clear the link and add the number + text
|
|
68
|
-
link.innerHTML = '';
|
|
69
|
-
link.appendChild(number);
|
|
70
|
-
link.appendChild(document.createTextNode(heading.textContent));
|
|
71
|
-
|
|
72
|
-
// Add click handler for smooth scrolling
|
|
73
|
-
const clickHandler = (e) => {
|
|
74
|
-
e.preventDefault();
|
|
75
|
-
heading.scrollIntoView({ behavior: 'smooth' });
|
|
76
|
-
};
|
|
77
|
-
addHandler(link, 'click', clickHandler);
|
|
78
|
-
|
|
79
|
-
// Add item to the TOC list
|
|
80
|
-
tocList.appendChild(tocItem);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// Set up IntersectionObserver for active state (Webflow-style)
|
|
84
|
-
const tocLinks = tocList.querySelectorAll('a');
|
|
85
|
-
let currentActive = null;
|
|
86
|
-
|
|
87
|
-
const updateActiveLink = () => {
|
|
88
|
-
const windowHeight = window.innerHeight;
|
|
89
|
-
const trigger = windowHeight * 0.75; // 25% from bottom
|
|
90
|
-
|
|
91
|
-
let newActive = null;
|
|
92
|
-
|
|
93
|
-
// Find the last heading whose top is above the trigger point
|
|
94
|
-
for (let i = h2Headings.length - 1; i >= 0; i--) {
|
|
95
|
-
const rect = h2Headings[i].getBoundingClientRect();
|
|
96
|
-
if (rect.top <= trigger) {
|
|
97
|
-
newActive = h2Headings[i].id;
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Only update if active section changed
|
|
103
|
-
if (newActive !== currentActive) {
|
|
104
|
-
currentActive = newActive;
|
|
105
|
-
|
|
106
|
-
// Remove all is-active
|
|
107
|
-
tocLinks.forEach((link) => link.classList.remove('is-active'));
|
|
108
|
-
|
|
109
|
-
// Add to current
|
|
110
|
-
if (currentActive) {
|
|
111
|
-
const activeLink = Array.from(tocLinks).find(
|
|
112
|
-
(link) => link.getAttribute('href') === `#${currentActive}`
|
|
113
|
-
);
|
|
114
|
-
if (activeLink) {
|
|
115
|
-
activeLink.classList.add('is-active');
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const observerOptions = {
|
|
122
|
-
rootMargin: '0px 0px -75% 0px',
|
|
123
|
-
threshold: 0,
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const observer = new IntersectionObserver(() => {
|
|
127
|
-
updateActiveLink();
|
|
128
|
-
}, observerOptions);
|
|
129
|
-
|
|
130
|
-
// Observe all headings
|
|
131
|
-
h2Headings.forEach((heading) => observer.observe(heading));
|
|
132
|
-
addObserver(observer);
|
|
133
|
-
|
|
134
|
-
// Also update on scroll for smoother tracking
|
|
135
|
-
const scrollHandler = () => {
|
|
136
|
-
if (cleanup.scrollTimeout) clearTimeout(cleanup.scrollTimeout);
|
|
137
|
-
cleanup.scrollTimeout = setTimeout(updateActiveLink, 50);
|
|
138
|
-
};
|
|
139
|
-
addHandler(window, 'scroll', scrollHandler);
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
setupRichTextAccessibility(addObserver, addHandler, cleanup);
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
result: 'toc initialized',
|
|
147
|
-
destroy: () => {
|
|
148
|
-
// Remove IDs from headings
|
|
149
|
-
cleanup.headings.forEach((heading) => {
|
|
150
|
-
heading.removeAttribute('id');
|
|
151
|
-
});
|
|
152
|
-
cleanup.headings.length = 0;
|
|
153
|
-
|
|
154
|
-
// Disconnect all observers
|
|
155
|
-
cleanup.observers.forEach((obs) => obs.disconnect());
|
|
156
|
-
cleanup.observers.length = 0;
|
|
157
|
-
|
|
158
|
-
// Remove all event listeners
|
|
159
|
-
cleanup.handlers.forEach(({ element, event, handler, options }) => {
|
|
160
|
-
element.removeEventListener(event, handler, options);
|
|
161
|
-
});
|
|
162
|
-
cleanup.handlers.length = 0;
|
|
163
|
-
|
|
164
|
-
// Clear scroll timeout
|
|
165
|
-
if (cleanup.scrollTimeout) {
|
|
166
|
-
clearTimeout(cleanup.scrollTimeout);
|
|
167
|
-
cleanup.scrollTimeout = null;
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
};
|
|
171
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Progress Bar Function
|
|
3
|
-
*
|
|
4
|
-
* Creates a scroll-based progress bar that tracks reading progress through content.
|
|
5
|
-
* Uses GSAP ScrollTrigger to animate bar width from 0% to 100% as user scrolls.
|
|
6
|
-
*
|
|
7
|
-
* Structure:
|
|
8
|
-
* <div data-hs-toc="content">
|
|
9
|
-
* <!-- Content to track -->
|
|
10
|
-
* </div>
|
|
11
|
-
*
|
|
12
|
-
* <div data-hs-toc-progress="wrapper">
|
|
13
|
-
* <div data-hs-toc-progress="element"></div>
|
|
14
|
-
* </div>
|
|
15
|
-
*
|
|
16
|
-
* @version 2.0.0
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import { querySelector, querySelectorAll, getGsap, prefersReducedMotion } from '@utils';
|
|
20
|
-
|
|
21
|
-
export async function init(config: any, tocConfig: any) {
|
|
22
|
-
// Skip if user prefers reduced motion
|
|
23
|
-
if (prefersReducedMotion()) {
|
|
24
|
-
return { result: 'progress-bar skipped - prefers-reduced-motion enabled' };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const gsapLib = getGsap('progress-bar');
|
|
28
|
-
if (!gsapLib) {
|
|
29
|
-
return { result: 'progress-bar skipped - GSAP not loaded' };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const { gsap, ScrollTrigger } = gsapLib;
|
|
33
|
-
|
|
34
|
-
if (!ScrollTrigger) {
|
|
35
|
-
console.warn('[progress-bar] GSAP ScrollTrigger plugin not loaded');
|
|
36
|
-
return { result: 'progress-bar skipped - ScrollTrigger not loaded' };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
gsap.registerPlugin(ScrollTrigger);
|
|
40
|
-
|
|
41
|
-
const cleanup = {
|
|
42
|
-
scrollTriggers: [] as any[],
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// Find content area (using toc config since they share the same content)
|
|
46
|
-
const content = querySelector(tocConfig, 'content');
|
|
47
|
-
if (!content) {
|
|
48
|
-
return { result: 'progress-bar skipped - no content element found' };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Find all progress bar wrappers
|
|
52
|
-
const wrappers = querySelectorAll(config, 'wrapper');
|
|
53
|
-
if (wrappers.length === 0) {
|
|
54
|
-
return { result: 'progress-bar skipped - no wrapper elements found' };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
wrappers.forEach((wrapper) => {
|
|
58
|
-
// Show wrapper
|
|
59
|
-
gsap.set(wrapper, { display: 'block' });
|
|
60
|
-
|
|
61
|
-
// Find progress bar elements inside this wrapper
|
|
62
|
-
const progressBars = wrapper.querySelectorAll(
|
|
63
|
-
`[${config.attributes.elements.element.primary.match(/data-hs-toc-progress='element'/)?.[0] || 'data-hs-toc-progress="element"'}]`
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
progressBars.forEach((bar) => {
|
|
67
|
-
// Set initial width to 0%
|
|
68
|
-
gsap.set(bar, { width: '0%' });
|
|
69
|
-
|
|
70
|
-
// Animate from 0% to 100% based on scroll
|
|
71
|
-
gsap.to(bar, {
|
|
72
|
-
width: '100%',
|
|
73
|
-
ease: 'none',
|
|
74
|
-
scrollTrigger: {
|
|
75
|
-
trigger: content,
|
|
76
|
-
start: 'top bottom', // Start when top of content touches bottom of viewport
|
|
77
|
-
end: 'bottom 75%', // End when bottom of content reaches 75% down the viewport
|
|
78
|
-
scrub: true,
|
|
79
|
-
invalidateOnRefresh: true,
|
|
80
|
-
onUpdate: (self) => {
|
|
81
|
-
// Store the scrollTrigger instance for cleanup
|
|
82
|
-
if (!cleanup.scrollTriggers.includes(self)) {
|
|
83
|
-
cleanup.scrollTriggers.push(self);
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
result: `progress-bar initialized (${wrappers.length} instances)`,
|
|
93
|
-
destroy: () => {
|
|
94
|
-
// Kill all scroll triggers
|
|
95
|
-
cleanup.scrollTriggers.forEach((st) => {
|
|
96
|
-
if (st && st.kill) st.kill();
|
|
97
|
-
});
|
|
98
|
-
cleanup.scrollTriggers.length = 0;
|
|
99
|
-
},
|
|
100
|
-
};
|
|
101
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Table of Contents Module
|
|
3
|
-
*
|
|
4
|
-
* Orchestrates TOC functionality including heading links and progress bars.
|
|
5
|
-
* Uses modular functions for different TOC features.
|
|
6
|
-
*
|
|
7
|
-
* @version 2.0.0
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import * as headingLinks from './functions/heading-links/heading-links.ts';
|
|
11
|
-
import * as progressBar from './functions/progress-bar/progress-bar.ts';
|
|
12
|
-
|
|
13
|
-
export async function init(config: any) {
|
|
14
|
-
const results = [];
|
|
15
|
-
|
|
16
|
-
// Initialize heading links (main TOC functionality)
|
|
17
|
-
const headingLinksResult = await headingLinks.init(config);
|
|
18
|
-
results.push(headingLinksResult);
|
|
19
|
-
|
|
20
|
-
// Initialize progress bar (optional)
|
|
21
|
-
if (config['progress-bar']) {
|
|
22
|
-
const progressBarResult = await progressBar.init(config['progress-bar'], config);
|
|
23
|
-
results.push(progressBarResult);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
result: `toc initialized (${results.length} functions)`,
|
|
28
|
-
destroy: () => {
|
|
29
|
-
// Destroy all TOC functions
|
|
30
|
-
if (headingLinksResult?.destroy) {
|
|
31
|
-
headingLinksResult.destroy();
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# **Year Replacement**
|
|
2
|
-
|
|
3
|
-
## **Overview**
|
|
4
|
-
|
|
5
|
-
Automatically replaces `{{year}}` and `{{month}}` placeholders with the current year and month throughout the page.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## **Required Elements**
|
|
10
|
-
|
|
11
|
-
None - works on any text containing placeholders.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## **What It Does**
|
|
16
|
-
|
|
17
|
-
1. Scans all text nodes in document.body
|
|
18
|
-
2. Finds text containing `{{year}}` or `{{month}}`
|
|
19
|
-
3. Replaces `{{year}}` with current year (e.g., "2024")
|
|
20
|
-
4. Replaces `{{month}}` with current month name (e.g., "January")
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## **Usage Example**
|
|
25
|
-
|
|
26
|
-
```html
|
|
27
|
-
<p>Copyright {{year}} Company Name</p>
|
|
28
|
-
<p>Newsletter for {{month}} {{year}}</p>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
**Result (if current date is January 2024):**
|
|
32
|
-
|
|
33
|
-
```html
|
|
34
|
-
<p>Copyright 2024 Company Name</p>
|
|
35
|
-
<p>Newsletter for January 2024</p>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## **Placeholder Syntax**
|
|
41
|
-
|
|
42
|
-
| Placeholder | Replaced With |
|
|
43
|
-
| ----------- | ------------------------- |
|
|
44
|
-
| `{{year}}` | Current year (4 digits) |
|
|
45
|
-
| `{{month}}` | Current month name (full) |
|
|
46
|
-
|
|
47
|
-
**Case insensitive:** `{{YEAR}}` and `{{Year}}` also work.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## **Notes**
|
|
52
|
-
|
|
53
|
-
- One-time text replacement on page load
|
|
54
|
-
- No cleanup needed
|
|
55
|
-
- Updates automatically each year/month
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
export function init(config) {
|
|
2
|
-
function setupYearReplacement() {
|
|
3
|
-
const currentYear = new Date().getFullYear().toString();
|
|
4
|
-
const monthNames = [
|
|
5
|
-
'January',
|
|
6
|
-
'February',
|
|
7
|
-
'March',
|
|
8
|
-
'April',
|
|
9
|
-
'May',
|
|
10
|
-
'June',
|
|
11
|
-
'July',
|
|
12
|
-
'August',
|
|
13
|
-
'September',
|
|
14
|
-
'October',
|
|
15
|
-
'November',
|
|
16
|
-
'December',
|
|
17
|
-
];
|
|
18
|
-
const currentMonth = monthNames[new Date().getMonth()];
|
|
19
|
-
|
|
20
|
-
const yearPlaceholder = config.attributes.placeholders.year;
|
|
21
|
-
const monthPlaceholder = config.attributes.placeholders.month;
|
|
22
|
-
|
|
23
|
-
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {
|
|
24
|
-
acceptNode: (node) => {
|
|
25
|
-
return node.textContent.includes(yearPlaceholder) ||
|
|
26
|
-
node.textContent.includes(monthPlaceholder)
|
|
27
|
-
? NodeFilter.FILTER_ACCEPT
|
|
28
|
-
: NodeFilter.FILTER_SKIP;
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const textNodes = [];
|
|
33
|
-
let node;
|
|
34
|
-
while ((node = walker.nextNode())) {
|
|
35
|
-
textNodes.push(node);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Create regex patterns from config placeholders
|
|
39
|
-
const yearRegex = new RegExp(yearPlaceholder.replace(/[{}]/g, '\\$&'), 'gi');
|
|
40
|
-
const monthRegex = new RegExp(monthPlaceholder.replace(/[{}]/g, '\\$&'), 'gi');
|
|
41
|
-
|
|
42
|
-
textNodes.forEach((textNode) => {
|
|
43
|
-
let newText = textNode.textContent.replace(yearRegex, currentYear);
|
|
44
|
-
newText = newText.replace(monthRegex, currentMonth);
|
|
45
|
-
if (newText !== textNode.textContent) {
|
|
46
|
-
textNode.textContent = newText;
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
setupYearReplacement();
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
result: 'year-replacement initialized',
|
|
55
|
-
destroy: () => {
|
|
56
|
-
// No cleanup needed - this is a one-time text replacement
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Structure Orchestrator
|
|
3
|
-
* Manages visual DOM structure functions in parallel
|
|
4
|
-
*
|
|
5
|
-
* Uses static imports and passes config down to functions
|
|
6
|
-
* @version 2.0.0
|
|
7
|
-
*/
|
|
8
|
-
import config from '@config';
|
|
9
|
-
import { init as yearReplacementInit } from './functions/year-replacement/year-replacement.ts';
|
|
10
|
-
import { init as tocInit } from './functions/toc/toc.ts';
|
|
11
|
-
import { init as paginationInit } from './functions/pagination/pagination.ts';
|
|
12
|
-
import { init as siteSettingsInit } from './functions/site-settings/site-settings.ts';
|
|
13
|
-
import { init as formInit } from './functions/form/form.ts';
|
|
14
|
-
|
|
15
|
-
const CONFIG_ROOT = 'structure';
|
|
16
|
-
|
|
17
|
-
export async function init() {
|
|
18
|
-
const cleanup = { destroyFunctions: [] };
|
|
19
|
-
const moduleConfig = config[CONFIG_ROOT];
|
|
20
|
-
|
|
21
|
-
// Load all functions in parallel - use allSettled for resilient loading
|
|
22
|
-
const results = await Promise.allSettled([
|
|
23
|
-
yearReplacementInit(moduleConfig['year-replacement']),
|
|
24
|
-
tocInit(moduleConfig.toc),
|
|
25
|
-
paginationInit(moduleConfig.pagination),
|
|
26
|
-
siteSettingsInit(moduleConfig['site-settings']),
|
|
27
|
-
formInit(moduleConfig.form),
|
|
28
|
-
]);
|
|
29
|
-
|
|
30
|
-
// Collect destroy functions from successful inits
|
|
31
|
-
results.forEach((result) => {
|
|
32
|
-
if (result.status === 'fulfilled' && result.value?.destroy) {
|
|
33
|
-
cleanup.destroyFunctions.push(result.value.destroy);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// Log summary
|
|
38
|
-
const succeeded = results.filter((r) => r.status === 'fulfilled').length;
|
|
39
|
-
const failed = results.length - succeeded;
|
|
40
|
-
if (failed > 0) {
|
|
41
|
-
console.warn(
|
|
42
|
-
`[structure] ${succeeded}/${results.length} functions loaded successfully. ${failed} failed but won't affect other functions.`
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
result: 'structure initialized',
|
|
48
|
-
destroy: () => {
|
|
49
|
-
cleanup.destroyFunctions.forEach((destroyFn) => {
|
|
50
|
-
try {
|
|
51
|
-
destroyFn();
|
|
52
|
-
} catch (error) {
|
|
53
|
-
console.error('[structure] Error during cleanup:', error);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
cleanup.destroyFunctions.length = 0;
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Attribute Selector Utility
|
|
3
|
-
*
|
|
4
|
-
* Builds CSS selectors from module config.json files to support
|
|
5
|
-
* multiple attribute patterns (primary + aliases) for easy rebranding
|
|
6
|
-
* and backward compatibility.
|
|
7
|
-
*
|
|
8
|
-
* @version 2.0.0
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Builds a CSS selector from config attribute patterns
|
|
13
|
-
* @param {Object} config - Module config.json
|
|
14
|
-
* @param {string} elementKey - Key from config.attributes.elements
|
|
15
|
-
* @returns {string} Combined CSS selector
|
|
16
|
-
*/
|
|
17
|
-
export function getSelector(config, elementKey) {
|
|
18
|
-
const element = config.attributes.elements[elementKey];
|
|
19
|
-
if (!element) {
|
|
20
|
-
console.warn(`[attributeSelector] No config for element: ${elementKey}`);
|
|
21
|
-
return '';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const selectors = [
|
|
25
|
-
`[${element.primary}]`,
|
|
26
|
-
...(element.aliases || []).map((alias) => `[${alias}]`),
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
return selectors.join(', ');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Gets all matching elements for a given element type
|
|
34
|
-
* @param {Object} config - Module config.json
|
|
35
|
-
* @param {string} elementKey - Key from config.attributes.elements
|
|
36
|
-
* @param {Element} root - Root element to search within (default: document)
|
|
37
|
-
* @returns {NodeList} All matching elements
|
|
38
|
-
*/
|
|
39
|
-
export function querySelectorAll(config, elementKey, root: Document | Element = document) {
|
|
40
|
-
const selector = getSelector(config, elementKey);
|
|
41
|
-
return root.querySelectorAll(selector);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Gets first matching element for a given element type
|
|
46
|
-
* @param {Object} config - Module config.json
|
|
47
|
-
* @param {string} elementKey - Key from config.attributes.elements
|
|
48
|
-
* @param {Element} root - Root element to search within (default: document)
|
|
49
|
-
* @returns {Element|null} First matching element or null
|
|
50
|
-
*/
|
|
51
|
-
export function querySelector(config, elementKey, root: Document | Element = document) {
|
|
52
|
-
const selector = getSelector(config, elementKey);
|
|
53
|
-
return root.querySelector(selector);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Logs deprecation warning if using non-primary attributes
|
|
58
|
-
* @param {Element} element - Element to check
|
|
59
|
-
* @param {Object} config - Module config.json
|
|
60
|
-
* @param {string} elementKey - Key from config.attributes.elements
|
|
61
|
-
*/
|
|
62
|
-
export function checkDeprecated(element, config, elementKey) {
|
|
63
|
-
if (!element) return;
|
|
64
|
-
|
|
65
|
-
const elementConfig = config.attributes.elements[elementKey];
|
|
66
|
-
const elementAttrs = element.getAttributeNames();
|
|
67
|
-
|
|
68
|
-
elementConfig.aliases?.forEach((alias) => {
|
|
69
|
-
const attrName = alias.split('=')[0].replace(/[\[\]']/g, '');
|
|
70
|
-
if (elementAttrs.includes(attrName)) {
|
|
71
|
-
console.warn(
|
|
72
|
-
`[${config.module}] Using deprecated attribute "${alias}". ` +
|
|
73
|
-
`Please use "${elementConfig.primary}" instead. ` +
|
|
74
|
-
`Support for deprecated attributes will be removed in v3.0.0`
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CSS Variables Utility
|
|
3
|
-
*
|
|
4
|
-
* Provides the CSS variable prefix for constructing variable names.
|
|
5
|
-
* Uses config from @config for prefix.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* import cssVariables from '@utils/cssVariables';
|
|
9
|
-
* const varName = cssVariables.prefix + 'state';
|
|
10
|
-
* const value = getComputedStyle(el).getPropertyValue(varName);
|
|
11
|
-
* // Returns: "--_hs---state"
|
|
12
|
-
*
|
|
13
|
-
* @version 2.0.0
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import config from '@config';
|
|
17
|
-
|
|
18
|
-
const cssVariables = {
|
|
19
|
-
prefix: config._global.cssVars.prefix,
|
|
20
|
-
state: config._global.cssVars.prefix + config._global.cssVars.state.name,
|
|
21
|
-
clip: config._global.cssVars.prefix + config._global.cssVars.clip.name,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export default cssVariables;
|