cf-elements 1.0.1 → 1.0.3
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/README.md +3 -1
- package/cf-elements.js +143 -0
- package/package.json +3 -6
- package/bg-styles.css +0 -63
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# cf-elements
|
|
2
2
|
|
|
3
|
-
Zero-dependency
|
|
3
|
+
Zero-dependency markup library that renders ClickFunnels-style HTML with inline styles.
|
|
4
|
+
|
|
5
|
+
It is intended use is for building "ClickFunnels mockups" in LLMs like Claude/ChatGPT/etc, which then can be converted to ClickFunnels ready JSON via the `cf-pagetree-parser` package.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
package/cf-elements.js
CHANGED
|
@@ -70,6 +70,145 @@
|
|
|
70
70
|
}
|
|
71
71
|
})();
|
|
72
72
|
|
|
73
|
+
// ==========================================================================
|
|
74
|
+
// BACKGROUND STYLES - Inject CSS for background image classes
|
|
75
|
+
// ==========================================================================
|
|
76
|
+
|
|
77
|
+
// Inject background styles immediately
|
|
78
|
+
(function injectBgStyles() {
|
|
79
|
+
const style = document.createElement('style');
|
|
80
|
+
style.id = 'cf-bg-styles';
|
|
81
|
+
style.textContent = `
|
|
82
|
+
/* Background style classes - matches ClickFunnels options */
|
|
83
|
+
.bgCover { background-size: cover !important; background-repeat: no-repeat !important; }
|
|
84
|
+
.bgCoverCenter { background-size: cover !important; background-position: center center !important; background-repeat: no-repeat !important; }
|
|
85
|
+
.bgCoverV2 { background-attachment: fixed !important; background-size: cover !important; background-position: center center !important; background-repeat: no-repeat !important; }
|
|
86
|
+
.bgW100 { background-size: 100% auto !important; background-repeat: no-repeat !important; }
|
|
87
|
+
.bgW100H100 { background-size: 100% 100% !important; background-repeat: no-repeat !important; }
|
|
88
|
+
.bgNoRepeat { background-repeat: no-repeat !important; }
|
|
89
|
+
.bgRepeat { background-repeat: repeat !important; }
|
|
90
|
+
.bgRepeatX { background-repeat: repeat-x !important; }
|
|
91
|
+
.bgRepeatY { background-repeat: repeat-y !important; }
|
|
92
|
+
`;
|
|
93
|
+
if (document.head) {
|
|
94
|
+
document.head.appendChild(style);
|
|
95
|
+
} else {
|
|
96
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
97
|
+
document.head.appendChild(style);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
})();
|
|
101
|
+
|
|
102
|
+
// ==========================================================================
|
|
103
|
+
// GOOGLE FONTS - Auto-load fonts from font attributes
|
|
104
|
+
// ==========================================================================
|
|
105
|
+
|
|
106
|
+
// System fonts that don't need to be loaded from Google
|
|
107
|
+
const SYSTEM_FONTS = new Set([
|
|
108
|
+
'sans-serif', 'serif', 'monospace', 'cursive', 'fantasy', 'system-ui',
|
|
109
|
+
'ui-sans-serif', 'ui-serif', 'ui-monospace', 'ui-rounded',
|
|
110
|
+
'arial', 'helvetica', 'times new roman', 'times', 'courier new', 'courier',
|
|
111
|
+
'verdana', 'georgia', 'palatino', 'garamond', 'bookman', 'tahoma',
|
|
112
|
+
'trebuchet ms', 'arial black', 'impact', 'comic sans ms', 'inherit'
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
// Track which fonts have been loaded to avoid duplicates
|
|
116
|
+
const loadedFonts = new Set();
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Extract Google Font names from the document
|
|
120
|
+
* Scans font attributes on cf-* elements and styleguide data
|
|
121
|
+
*/
|
|
122
|
+
function extractFontsFromDocument() {
|
|
123
|
+
const fonts = new Set();
|
|
124
|
+
|
|
125
|
+
// 1. Extract from font attributes on elements
|
|
126
|
+
document.querySelectorAll('[font]').forEach(el => {
|
|
127
|
+
const font = el.getAttribute('font');
|
|
128
|
+
if (font) {
|
|
129
|
+
// Clean and add font name
|
|
130
|
+
const cleanFont = font.replace(/["']/g, '').split(',')[0].trim();
|
|
131
|
+
if (cleanFont && !SYSTEM_FONTS.has(cleanFont.toLowerCase())) {
|
|
132
|
+
fonts.add(cleanFont);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// 2. Extract from styleguide data if present
|
|
138
|
+
const styleguideEl = document.getElementById('cf-styleguide-data');
|
|
139
|
+
if (styleguideEl) {
|
|
140
|
+
try {
|
|
141
|
+
const data = JSON.parse(styleguideEl.textContent);
|
|
142
|
+
if (data.typography) {
|
|
143
|
+
const { headlineFont, subheadlineFont, contentFont } = data.typography;
|
|
144
|
+
[headlineFont, subheadlineFont, contentFont].forEach(font => {
|
|
145
|
+
if (font && !SYSTEM_FONTS.has(font.toLowerCase())) {
|
|
146
|
+
fonts.add(font);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
} catch (e) {
|
|
151
|
+
// Ignore parse errors
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 3. Extract from inline font-family styles in cf-* elements
|
|
156
|
+
document.querySelectorAll('cf-headline, cf-subheadline, cf-paragraph, cf-button').forEach(el => {
|
|
157
|
+
const style = el.getAttribute('style') || '';
|
|
158
|
+
const match = style.match(/font-family:\s*["']?([^"';,]+)/i);
|
|
159
|
+
if (match) {
|
|
160
|
+
const font = match[1].trim();
|
|
161
|
+
if (font && !SYSTEM_FONTS.has(font.toLowerCase())) {
|
|
162
|
+
fonts.add(font);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
return fonts;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Inject Google Fonts stylesheet into document head
|
|
172
|
+
*/
|
|
173
|
+
function injectGoogleFonts(fonts) {
|
|
174
|
+
if (!fonts || fonts.size === 0) return;
|
|
175
|
+
|
|
176
|
+
// Filter out already loaded fonts
|
|
177
|
+
const newFonts = Array.from(fonts).filter(f => !loadedFonts.has(f));
|
|
178
|
+
if (newFonts.length === 0) return;
|
|
179
|
+
|
|
180
|
+
// Mark as loaded
|
|
181
|
+
newFonts.forEach(f => loadedFonts.add(f));
|
|
182
|
+
|
|
183
|
+
// Build Google Fonts URL
|
|
184
|
+
const fontParams = newFonts
|
|
185
|
+
.map(font => font.replace(/ /g, '+'))
|
|
186
|
+
.join('&family=');
|
|
187
|
+
|
|
188
|
+
const url = `https://fonts.googleapis.com/css2?family=${fontParams}:wght@300;400;500;600;700;800;900&display=swap`;
|
|
189
|
+
|
|
190
|
+
// Check if already loaded
|
|
191
|
+
if (document.querySelector(`link[href^="https://fonts.googleapis.com"][href*="${newFonts[0].replace(/ /g, '+')}"]`)) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Inject link tag
|
|
196
|
+
const link = document.createElement('link');
|
|
197
|
+
link.id = 'cf-google-fonts';
|
|
198
|
+
link.rel = 'stylesheet';
|
|
199
|
+
link.href = url;
|
|
200
|
+
document.head.appendChild(link);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Auto-load Google Fonts from document
|
|
205
|
+
* Called before element rendering
|
|
206
|
+
*/
|
|
207
|
+
function loadGoogleFonts() {
|
|
208
|
+
const fonts = extractFontsFromDocument();
|
|
209
|
+
injectGoogleFonts(fonts);
|
|
210
|
+
}
|
|
211
|
+
|
|
73
212
|
// ==========================================================================
|
|
74
213
|
// CONSTANTS & MAPPINGS
|
|
75
214
|
// ==========================================================================
|
|
@@ -4559,6 +4698,7 @@
|
|
|
4559
4698
|
// Auto-initialize when DOM is ready
|
|
4560
4699
|
if (document.readyState === "loading") {
|
|
4561
4700
|
document.addEventListener("DOMContentLoaded", () => {
|
|
4701
|
+
loadGoogleFonts(); // Load fonts before rendering
|
|
4562
4702
|
styleguideManager.init();
|
|
4563
4703
|
brandAssetsManager.init();
|
|
4564
4704
|
initFunnelWind();
|
|
@@ -4571,6 +4711,7 @@
|
|
|
4571
4711
|
} else {
|
|
4572
4712
|
// DOM already ready, use requestAnimationFrame to ensure all elements are parsed
|
|
4573
4713
|
requestAnimationFrame(() => {
|
|
4714
|
+
loadGoogleFonts(); // Load fonts before rendering
|
|
4574
4715
|
styleguideManager.init();
|
|
4575
4716
|
brandAssetsManager.init();
|
|
4576
4717
|
initFunnelWind();
|
|
@@ -4587,12 +4728,14 @@
|
|
|
4587
4728
|
init: initFunnelWind,
|
|
4588
4729
|
initAnimations: initAnimations,
|
|
4589
4730
|
loadAnimateCSS: loadAnimateCSS,
|
|
4731
|
+
loadGoogleFonts: loadGoogleFonts,
|
|
4590
4732
|
initVideoBackgrounds: initVideoBackgrounds,
|
|
4591
4733
|
elements: elements,
|
|
4592
4734
|
StyleguideManager: styleguideManager,
|
|
4593
4735
|
BrandAssetsManager: brandAssetsManager,
|
|
4594
4736
|
initStyleguide: (data) => {
|
|
4595
4737
|
styleguideManager.init(data);
|
|
4738
|
+
loadGoogleFonts(); // Load fonts from styleguide
|
|
4596
4739
|
initFunnelWind();
|
|
4597
4740
|
},
|
|
4598
4741
|
initBrandAssets: (data) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-elements",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Zero-dependency
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "Zero-dependency markup library that generates ClickFunnels compatible HTML with inline styles",
|
|
5
5
|
"main": "cf-elements.js",
|
|
6
6
|
"browser": "cf-elements.js",
|
|
7
7
|
"unpkg": "cf-elements.js",
|
|
@@ -14,12 +14,9 @@
|
|
|
14
14
|
"test": "echo \"No tests yet\""
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
|
-
"web-components",
|
|
18
17
|
"clickfunnels",
|
|
19
18
|
"funnelwind",
|
|
20
|
-
"landing-pages"
|
|
21
|
-
"no-code",
|
|
22
|
-
"inline-styles"
|
|
19
|
+
"landing-pages"
|
|
23
20
|
],
|
|
24
21
|
"author": "BarnumPT",
|
|
25
22
|
"license": "MIT",
|
package/bg-styles.css
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ============================================================================
|
|
3
|
-
* FUNNELWIND - Background Style Classes
|
|
4
|
-
* ============================================================================
|
|
5
|
-
*
|
|
6
|
-
* These classes match ClickFunnels background image styling options.
|
|
7
|
-
* Apply via bg-style attribute on cf-* components.
|
|
8
|
-
*
|
|
9
|
-
* ============================================================================
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/* Cover - fills container, may crop */
|
|
13
|
-
.bgCover {
|
|
14
|
-
background-size: cover !important;
|
|
15
|
-
background-repeat: no-repeat !important;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/* Cover + Centered (default) */
|
|
19
|
-
.bgCoverCenter {
|
|
20
|
-
background-size: cover !important;
|
|
21
|
-
background-position: center center !important;
|
|
22
|
-
background-repeat: no-repeat !important;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/* Parallax - fixed background attachment */
|
|
26
|
-
.bgCoverV2 {
|
|
27
|
-
background-attachment: fixed !important;
|
|
28
|
-
background-size: cover !important;
|
|
29
|
-
background-position: center center !important;
|
|
30
|
-
background-repeat: no-repeat !important;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/* 100% width, auto height */
|
|
34
|
-
.bgW100 {
|
|
35
|
-
background-size: 100% auto !important;
|
|
36
|
-
background-repeat: no-repeat !important;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/* 100% width and height (stretch) */
|
|
40
|
-
.bgW100H100 {
|
|
41
|
-
background-size: 100% 100% !important;
|
|
42
|
-
background-repeat: no-repeat !important;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/* No repeat - original size */
|
|
46
|
-
.bgNoRepeat {
|
|
47
|
-
background-repeat: no-repeat !important;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/* Repeat/tile in both directions */
|
|
51
|
-
.bgRepeat {
|
|
52
|
-
background-repeat: repeat !important;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/* Repeat horizontally only */
|
|
56
|
-
.bgRepeatX {
|
|
57
|
-
background-repeat: repeat-x !important;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/* Repeat vertically only */
|
|
61
|
-
.bgRepeatY {
|
|
62
|
-
background-repeat: repeat-y !important;
|
|
63
|
-
}
|