goodnocodetools 1.0.0 → 1.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.
- package/README.md +148 -18
- package/dist/global/index.js +1 -158
- package/package.json +17 -17
- package/dist/global/index.js.map +0 -7
package/README.md
CHANGED
|
@@ -1,25 +1,155 @@
|
|
|
1
|
-
#
|
|
1
|
+
# goodnocodetools
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Custom TypeScript scripts for Webflow projects, built with the Finsweet Developer Starter.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 🚀 Quick Start
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### Development
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm install # Install dependencies
|
|
11
|
+
pnpm dev # Start dev server at localhost:3000
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Visit your Webflow site with `?dev=true` to load local scripts:
|
|
15
|
+
```
|
|
16
|
+
https://yoursite.webflow.io?dev=true&debug=true
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Production
|
|
20
|
+
|
|
21
|
+
Scripts are published to npm and served via jsDelivr CDN:
|
|
22
|
+
```
|
|
23
|
+
https://cdn.jsdelivr.net/npm/goodnocodetools@1/dist/global/index.js
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 📦 Available Scripts
|
|
27
|
+
|
|
28
|
+
- **`global/index.js`** (1.2KB) - Site-wide utilities and debug logging
|
|
29
|
+
- **`tools/index.js`** (3.8KB) - /tools page (filters, counter, click trigger)
|
|
30
|
+
- **`vendor/dashboard/index.js`** (1.3KB) - /vendor/dashboard (checkbox sync, add listing)
|
|
31
|
+
- **`vendor/claim-listing/index.js`** (460B) - /vendor/claim-listing (slug capture)
|
|
32
|
+
- **`vendor/thank-you/index.js`** (1.2KB) - /vendor/thank-you (Memberstack save)
|
|
33
|
+
|
|
34
|
+
## 🛠️ Development Workflow
|
|
35
|
+
|
|
36
|
+
See **[WORKFLOW.md](./WORKFLOW.md)** for complete development guide.
|
|
37
|
+
|
|
38
|
+
**Quick reference:**
|
|
39
|
+
```bash
|
|
40
|
+
pnpm dev # Start dev server
|
|
41
|
+
pnpm build # Build production bundles
|
|
42
|
+
pnpm check # TypeScript type checking
|
|
43
|
+
pnpm lint # Check code style
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 🔄 Publishing
|
|
47
|
+
|
|
48
|
+
### Manual Publishing
|
|
49
|
+
```bash
|
|
50
|
+
npm version patch # Bump version (patch/minor/major)
|
|
51
|
+
npm publish # Publish to npm
|
|
52
|
+
git push --tags # Push tags to GitHub
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Automated Publishing (GitHub Actions)
|
|
56
|
+
|
|
57
|
+
See **[GITHUB_ACTIONS_SETUP.md](./GITHUB_ACTIONS_SETUP.md)** for setup instructions.
|
|
58
|
+
|
|
59
|
+
Once configured:
|
|
60
|
+
```bash
|
|
61
|
+
npx changeset # Describe changes
|
|
62
|
+
git add .
|
|
63
|
+
git commit -m "Add new feature"
|
|
64
|
+
git push # Creates "Version Packages" PR
|
|
65
|
+
# Merge PR → auto-publishes to npm
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 📝 Webflow Integration
|
|
8
69
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
70
|
+
Add to **Project Settings > Custom Code > Head**:
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<script>
|
|
74
|
+
(function() {
|
|
75
|
+
const isDev = new URLSearchParams(window.location.search).get('dev') === 'true';
|
|
76
|
+
const baseUrl = isDev
|
|
77
|
+
? 'http://localhost:3000'
|
|
78
|
+
: 'https://cdn.jsdelivr.net/npm/goodnocodetools@1/dist';
|
|
79
|
+
|
|
80
|
+
window.loadScript = function(path) {
|
|
81
|
+
const script = document.createElement('script');
|
|
82
|
+
script.src = baseUrl + '/' + path;
|
|
83
|
+
script.defer = true;
|
|
84
|
+
document.head.appendChild(script);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
window.loadScript('global/index.js');
|
|
88
|
+
})();
|
|
89
|
+
</script>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Add to **Page Settings > Custom Code > Before `</body>`**:
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<!-- /tools page -->
|
|
96
|
+
<script>window.loadScript('tools/index.js');</script>
|
|
97
|
+
|
|
98
|
+
<!-- /vendor/dashboard page -->
|
|
99
|
+
<script>window.loadScript('vendor/dashboard/index.js');</script>
|
|
100
|
+
|
|
101
|
+
<!-- /vendor/claim-listing page -->
|
|
102
|
+
<script>window.loadScript('vendor/claim-listing/index.js');</script>
|
|
103
|
+
|
|
104
|
+
<!-- /vendor/thank-you page -->
|
|
105
|
+
<script>window.loadScript('vendor/thank-you/index.js');</script>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 🔍 Debug Mode
|
|
109
|
+
|
|
110
|
+
Add `?debug=true` to any URL to enable console logging:
|
|
111
|
+
```
|
|
112
|
+
https://yoursite.webflow.io/tools?debug=true
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
All scripts use `window.debug()` for logging, which only outputs when debug mode is enabled.
|
|
116
|
+
|
|
117
|
+
## 📚 Documentation
|
|
118
|
+
|
|
119
|
+
- **[WORKFLOW.md](./WORKFLOW.md)** - Development workflow and daily tasks
|
|
120
|
+
- **[GITHUB_ACTIONS_SETUP.md](./GITHUB_ACTIONS_SETUP.md)** - Automated publishing setup
|
|
121
|
+
|
|
122
|
+
## 🏗️ Project Structure
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
src/
|
|
126
|
+
├── global/ # Site-wide scripts (all pages)
|
|
127
|
+
├── tools/ # /tools page scripts
|
|
128
|
+
├── vendor/ # /vendor/* page scripts
|
|
129
|
+
│ ├── dashboard/
|
|
130
|
+
│ ├── claim-listing/
|
|
131
|
+
│ └── thank-you/
|
|
132
|
+
├── utils/ # Shared utilities
|
|
133
|
+
└── types/ # TypeScript definitions
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 🛡️ Scripts Overview
|
|
137
|
+
|
|
138
|
+
### Global Scripts
|
|
139
|
+
- Debug utilities (`window.debug`, `window.debugError`, `window.debugWarn`)
|
|
140
|
+
- Pricing switch with GSAP animations
|
|
141
|
+
|
|
142
|
+
### Tools Page
|
|
143
|
+
- Filter clear button visibility
|
|
144
|
+
- Click trigger mirroring
|
|
145
|
+
- Results counter with GSAP animation
|
|
146
|
+
|
|
147
|
+
### Vendor Pages
|
|
148
|
+
- **Dashboard:** Checkbox label sync, add listing button with Memberstack
|
|
149
|
+
- **Claim Listing:** Tool slug capture from URL
|
|
150
|
+
- **Thank You:** Save claimed tool to Memberstack member JSON
|
|
151
|
+
|
|
152
|
+
## Reference
|
|
23
153
|
|
|
24
154
|
## Included tools
|
|
25
155
|
|
package/dist/global/index.js
CHANGED
|
@@ -1,158 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
(() => {
|
|
3
|
-
// bin/live-reload.js
|
|
4
|
-
new EventSource(`${"http://localhost:3000"}/esbuild`).addEventListener("change", () => location.reload());
|
|
5
|
-
|
|
6
|
-
// src/utils/pricing-switch.ts
|
|
7
|
-
function initPricingSwitch(options = {}) {
|
|
8
|
-
if (typeof gsap === "undefined") {
|
|
9
|
-
window.debugWarn("[pricing-switch] GSAP not loaded yet, retrying in 100ms");
|
|
10
|
-
setTimeout(() => initPricingSwitch(options), 100);
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
const DEFAULT_STATE = (options.defaultState || "annual").toLowerCase();
|
|
14
|
-
const defaultIsMonthly = DEFAULT_STATE === "monthly";
|
|
15
|
-
const SECTION_SELECTOR = options.sectionSelector || "[data-pricing-section]";
|
|
16
|
-
const CLIP_MONTHLY = "inset(0% 50% 0% 0% round 100rem)";
|
|
17
|
-
const CLIP_ANNUAL = "inset(0% 0% 0% 50% round 100rem)";
|
|
18
|
-
window.debug("[pricing-switch] Initializing with options:", options);
|
|
19
|
-
function showEl(el) {
|
|
20
|
-
if (!el) return;
|
|
21
|
-
el.style.display = "";
|
|
22
|
-
}
|
|
23
|
-
function hideEl(el) {
|
|
24
|
-
if (!el) return;
|
|
25
|
-
el.style.display = "none";
|
|
26
|
-
}
|
|
27
|
-
function blurIn(el, delay = 0) {
|
|
28
|
-
if (!el) return;
|
|
29
|
-
gsap.killTweensOf(el);
|
|
30
|
-
gsap.fromTo(
|
|
31
|
-
el,
|
|
32
|
-
{ autoAlpha: 0, filter: "blur(4px)" },
|
|
33
|
-
{ autoAlpha: 1, filter: "blur(0px)", duration: 0.28, delay, ease: "power1.out" }
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
function swapCard(card, isMonthly) {
|
|
37
|
-
const monthlyWrap = card.querySelector('[data-price="monthly"]');
|
|
38
|
-
const annualWrap = card.querySelector('[data-price="annual"]');
|
|
39
|
-
const monthlyActions = card.querySelector(
|
|
40
|
-
'[data-price-element="actions"][data-price="monthly"]'
|
|
41
|
-
);
|
|
42
|
-
const annualActions = card.querySelector(
|
|
43
|
-
'[data-price-element="actions"][data-price="annual"]'
|
|
44
|
-
);
|
|
45
|
-
if (monthlyWrap && annualWrap) {
|
|
46
|
-
const showWrap = isMonthly ? monthlyWrap : annualWrap;
|
|
47
|
-
const hideWrap = isMonthly ? annualWrap : monthlyWrap;
|
|
48
|
-
hideEl(hideWrap);
|
|
49
|
-
showEl(showWrap);
|
|
50
|
-
const price = showWrap.querySelector('[data-price-element="price"]');
|
|
51
|
-
const term = showWrap.querySelector('[data-price-element="term"]');
|
|
52
|
-
blurIn(price, 0);
|
|
53
|
-
blurIn(term, 0.06);
|
|
54
|
-
}
|
|
55
|
-
if (monthlyActions && annualActions) {
|
|
56
|
-
const showActions = isMonthly ? monthlyActions : annualActions;
|
|
57
|
-
const hideActions = isMonthly ? annualActions : monthlyActions;
|
|
58
|
-
hideEl(hideActions);
|
|
59
|
-
showEl(showActions);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function applyState(sectionEl, isMonthly, animateMask) {
|
|
63
|
-
const darkLabelContainer = sectionEl.querySelector(
|
|
64
|
-
".pricing-switch_label-container.is-dark"
|
|
65
|
-
);
|
|
66
|
-
if (darkLabelContainer) {
|
|
67
|
-
gsap.to(darkLabelContainer, {
|
|
68
|
-
clipPath: isMonthly ? CLIP_MONTHLY : CLIP_ANNUAL,
|
|
69
|
-
duration: animateMask ? 0.4 : 0,
|
|
70
|
-
ease: "power2.inOut"
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
sectionEl.querySelectorAll("[data-price-card]").forEach((card) => {
|
|
74
|
-
swapCard(card, isMonthly);
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
function initSection(sectionEl) {
|
|
78
|
-
const switchButton = sectionEl.querySelector("#payment-switch") || sectionEl.querySelector("[data-payment-switch]");
|
|
79
|
-
const darkLabelContainer = sectionEl.querySelector(
|
|
80
|
-
".pricing-switch_label-container.is-dark"
|
|
81
|
-
);
|
|
82
|
-
if (!switchButton || !darkLabelContainer) {
|
|
83
|
-
window.debugWarn("[pricing-switch] Missing switch button or label container in section");
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const initialIsMonthly = defaultIsMonthly;
|
|
87
|
-
switchButton.setAttribute("aria-checked", initialIsMonthly ? "true" : "false");
|
|
88
|
-
gsap.set(darkLabelContainer, {
|
|
89
|
-
clipPath: initialIsMonthly ? CLIP_MONTHLY : CLIP_ANNUAL
|
|
90
|
-
});
|
|
91
|
-
sectionEl.querySelectorAll("[data-price-card]").forEach((card) => {
|
|
92
|
-
const monthlyWrap = card.querySelector('[data-price="monthly"]');
|
|
93
|
-
const annualWrap = card.querySelector('[data-price="annual"]');
|
|
94
|
-
const monthlyActions = card.querySelector(
|
|
95
|
-
'[data-price-element="actions"][data-price="monthly"]'
|
|
96
|
-
);
|
|
97
|
-
const annualActions = card.querySelector(
|
|
98
|
-
'[data-price-element="actions"][data-price="annual"]'
|
|
99
|
-
);
|
|
100
|
-
if (monthlyWrap && annualWrap) {
|
|
101
|
-
if (initialIsMonthly) {
|
|
102
|
-
showEl(monthlyWrap);
|
|
103
|
-
hideEl(annualWrap);
|
|
104
|
-
} else {
|
|
105
|
-
showEl(annualWrap);
|
|
106
|
-
hideEl(monthlyWrap);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (monthlyActions && annualActions) {
|
|
110
|
-
if (initialIsMonthly) {
|
|
111
|
-
showEl(monthlyActions);
|
|
112
|
-
hideEl(annualActions);
|
|
113
|
-
} else {
|
|
114
|
-
showEl(annualActions);
|
|
115
|
-
hideEl(monthlyActions);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
if (switchButton.dataset.pricingSwitchBound === "true") {
|
|
120
|
-
window.debug("[pricing-switch] Section already initialized, skipping");
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
switchButton.dataset.pricingSwitchBound = "true";
|
|
124
|
-
switchButton.addEventListener("click", function() {
|
|
125
|
-
const wasMonthly = this.getAttribute("aria-checked") === "true";
|
|
126
|
-
this.setAttribute("aria-checked", wasMonthly ? "false" : "true");
|
|
127
|
-
window.debug("[pricing-switch] Toggled to:", wasMonthly ? "annual" : "monthly");
|
|
128
|
-
applyState(sectionEl, !wasMonthly, true);
|
|
129
|
-
});
|
|
130
|
-
window.debug("[pricing-switch] Section initialized");
|
|
131
|
-
}
|
|
132
|
-
const sections = document.querySelectorAll(SECTION_SELECTOR);
|
|
133
|
-
window.debug("[pricing-switch] Found sections:", sections.length);
|
|
134
|
-
sections.forEach(initSection);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// src/global/index.ts
|
|
138
|
-
window.debug = (...args) => {
|
|
139
|
-
new URLSearchParams(location.search).get("debug") === "true" && console.log(...args);
|
|
140
|
-
};
|
|
141
|
-
window.debugError = (...args) => {
|
|
142
|
-
new URLSearchParams(location.search).get("debug") === "true" && console.error(...args);
|
|
143
|
-
};
|
|
144
|
-
window.debugWarn = (...args) => {
|
|
145
|
-
new URLSearchParams(location.search).get("debug") === "true" && console.warn(...args);
|
|
146
|
-
};
|
|
147
|
-
window.Webflow ||= [];
|
|
148
|
-
window.Webflow.push(() => {
|
|
149
|
-
window.debug("Webflow initialized - debug mode active");
|
|
150
|
-
if (document.querySelector("[data-pricing-section]")) {
|
|
151
|
-
initPricingSwitch({
|
|
152
|
-
defaultState: "monthly",
|
|
153
|
-
sectionSelector: "[data-pricing-section]"
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
})();
|
|
158
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";(()=>{function p(o={}){if(typeof gsap>"u"){window.debugWarn("[pricing-switch] GSAP not loaded yet, retrying in 100ms"),setTimeout(()=>p(o),100);return}let f=(o.defaultState||"annual").toLowerCase()==="monthly",S=o.sectionSelector||"[data-pricing-section]",w="inset(0% 50% 0% 0% round 100rem)",h="inset(0% 0% 0% 50% round 100rem)";window.debug("[pricing-switch] Initializing with options:",o);function l(e){e&&(e.style.display="")}function s(e){e&&(e.style.display="none")}function m(e,t=0){e&&(gsap.killTweensOf(e),gsap.fromTo(e,{autoAlpha:0,filter:"blur(4px)"},{autoAlpha:1,filter:"blur(0px)",duration:.28,delay:t,ease:"power1.out"}))}function y(e,t){let a=e.querySelector('[data-price="monthly"]'),i=e.querySelector('[data-price="annual"]'),n=e.querySelector('[data-price-element="actions"][data-price="monthly"]'),c=e.querySelector('[data-price-element="actions"][data-price="annual"]');if(a&&i){let r=t?a:i;s(t?i:a),l(r);let d=r.querySelector('[data-price-element="price"]'),T=r.querySelector('[data-price-element="term"]');m(d,0),m(T,.06)}if(n&&c){let r=t?n:c;s(t?c:n),l(r)}}function b(e,t,a){let i=e.querySelector(".pricing-switch_label-container.is-dark");i&&gsap.to(i,{clipPath:t?w:h,duration:a?.4:0,ease:"power2.inOut"}),e.querySelectorAll("[data-price-card]").forEach(n=>{y(n,t)})}function L(e){let t=e.querySelector("#payment-switch")||e.querySelector("[data-payment-switch]"),a=e.querySelector(".pricing-switch_label-container.is-dark");if(!t||!a){window.debugWarn("[pricing-switch] Missing switch button or label container in section");return}let i=f;if(t.setAttribute("aria-checked",i?"true":"false"),gsap.set(a,{clipPath:i?w:h}),e.querySelectorAll("[data-price-card]").forEach(n=>{let c=n.querySelector('[data-price="monthly"]'),r=n.querySelector('[data-price="annual"]'),u=n.querySelector('[data-price-element="actions"][data-price="monthly"]'),d=n.querySelector('[data-price-element="actions"][data-price="annual"]');c&&r&&(i?(l(c),s(r)):(l(r),s(c))),u&&d&&(i?(l(u),s(d)):(l(d),s(u)))}),t.dataset.pricingSwitchBound==="true"){window.debug("[pricing-switch] Section already initialized, skipping");return}t.dataset.pricingSwitchBound="true",t.addEventListener("click",function(){let n=this.getAttribute("aria-checked")==="true";this.setAttribute("aria-checked",n?"false":"true"),window.debug("[pricing-switch] Toggled to:",n?"annual":"monthly"),b(e,!n,!0)}),window.debug("[pricing-switch] Section initialized")}let g=document.querySelectorAll(S);window.debug("[pricing-switch] Found sections:",g.length),g.forEach(L)}window.debug=(...o)=>{new URLSearchParams(location.search).get("debug")==="true"&&console.log(...o)};window.debugError=(...o)=>{new URLSearchParams(location.search).get("debug")==="true"&&console.error(...o)};window.debugWarn=(...o)=>{new URLSearchParams(location.search).get("debug")==="true"&&console.warn(...o)};window.Webflow||(window.Webflow=[]);window.Webflow.push(()=>{window.debug("Webflow initialized - debug mode active"),document.querySelector("[data-pricing-section]")&&p({defaultState:"monthly",sectionSelector:"[data-pricing-section]"})});})();
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "goodnocodetools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Custom scripts for Webflow projects.",
|
|
5
|
-
"homepage": "https://github.com/liammews/
|
|
5
|
+
"homepage": "https://github.com/liammews/goodnocodetoolsv2#readme",
|
|
6
6
|
"license": "ISC",
|
|
7
7
|
"keywords": [],
|
|
8
8
|
"author": {
|
|
@@ -10,27 +10,15 @@
|
|
|
10
10
|
},
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/liammews/
|
|
13
|
+
"url": "git+https://github.com/liammews/goodnocodetoolsv2.git"
|
|
14
14
|
},
|
|
15
15
|
"bugs": {
|
|
16
|
-
"url": "https://github.com/liammews/
|
|
16
|
+
"url": "https://github.com/liammews/goodnocodetoolsv2/issues"
|
|
17
17
|
},
|
|
18
18
|
"type": "module",
|
|
19
19
|
"files": [
|
|
20
20
|
"dist"
|
|
21
21
|
],
|
|
22
|
-
"scripts": {
|
|
23
|
-
"dev": "cross-env NODE_ENV=development node ./bin/build.js",
|
|
24
|
-
"build": "cross-env NODE_ENV=production node ./bin/build.js",
|
|
25
|
-
"lint": "eslint ./src && prettier --check ./src",
|
|
26
|
-
"lint:fix": "eslint ./src --fix",
|
|
27
|
-
"check": "tsc --noEmit",
|
|
28
|
-
"format": "prettier --write ./src",
|
|
29
|
-
"test": "playwright test",
|
|
30
|
-
"test:ui": "playwright test --ui",
|
|
31
|
-
"release": "changeset publish",
|
|
32
|
-
"update": "pnpm update -i -L -r"
|
|
33
|
-
},
|
|
34
22
|
"devDependencies": {
|
|
35
23
|
"@changesets/changelog-git": "^0.2.0",
|
|
36
24
|
"@changesets/cli": "^2.27.12",
|
|
@@ -53,5 +41,17 @@
|
|
|
53
41
|
},
|
|
54
42
|
"engines": {
|
|
55
43
|
"pnpm": ">=10"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"dev": "cross-env NODE_ENV=development node ./bin/build.js",
|
|
47
|
+
"build": "cross-env NODE_ENV=production node ./bin/build.js",
|
|
48
|
+
"lint": "eslint ./src && prettier --check ./src",
|
|
49
|
+
"lint:fix": "eslint ./src --fix",
|
|
50
|
+
"check": "tsc --noEmit",
|
|
51
|
+
"format": "prettier --write ./src",
|
|
52
|
+
"test": "playwright test",
|
|
53
|
+
"test:ui": "playwright test --ui",
|
|
54
|
+
"release": "changeset publish",
|
|
55
|
+
"update": "pnpm update -i -L -r"
|
|
56
56
|
}
|
|
57
|
-
}
|
|
57
|
+
}
|
package/dist/global/index.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../bin/live-reload.js", "../../src/utils/pricing-switch.ts", "../../src/global/index.ts"],
|
|
4
|
-
"sourcesContent": ["new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener('change', () => location.reload());\n", "/**\n * Pricing switch configuration options\n */\ninterface PricingSwitchOptions {\n defaultState?: 'monthly' | 'annual';\n sectionSelector?: string;\n}\n\n/**\n * Initializes pricing toggle switches across all pricing sections on the page.\n * Supports multiple independent sections with monthly/annual toggle animations.\n *\n * @param options - Configuration options for the pricing switch\n */\nexport function initPricingSwitch(options: PricingSwitchOptions = {}) {\n // Check for GSAP, retry if not loaded yet\n if (typeof gsap === 'undefined') {\n window.debugWarn('[pricing-switch] GSAP not loaded yet, retrying in 100ms');\n setTimeout(() => initPricingSwitch(options), 100);\n return;\n }\n\n const DEFAULT_STATE = (options.defaultState || 'annual').toLowerCase();\n const defaultIsMonthly = DEFAULT_STATE === 'monthly';\n const SECTION_SELECTOR = options.sectionSelector || '[data-pricing-section]';\n const CLIP_MONTHLY = 'inset(0% 50% 0% 0% round 100rem)';\n const CLIP_ANNUAL = 'inset(0% 0% 0% 50% round 100rem)';\n\n window.debug('[pricing-switch] Initializing with options:', options);\n\n function showEl(el: HTMLElement | null) {\n if (!el) return;\n el.style.display = '';\n }\n\n function hideEl(el: HTMLElement | null) {\n if (!el) return;\n el.style.display = 'none';\n }\n\n function blurIn(el: HTMLElement | null, delay = 0) {\n if (!el) return;\n gsap.killTweensOf(el);\n gsap.fromTo(\n el,\n { autoAlpha: 0, filter: 'blur(4px)' },\n { autoAlpha: 1, filter: 'blur(0px)', duration: 0.28, delay, ease: 'power1.out' }\n );\n }\n\n function swapCard(card: Element, isMonthly: boolean) {\n const monthlyWrap = card.querySelector<HTMLElement>('[data-price=\"monthly\"]');\n const annualWrap = card.querySelector<HTMLElement>('[data-price=\"annual\"]');\n const monthlyActions = card.querySelector<HTMLElement>(\n '[data-price-element=\"actions\"][data-price=\"monthly\"]'\n );\n const annualActions = card.querySelector<HTMLElement>(\n '[data-price-element=\"actions\"][data-price=\"annual\"]'\n );\n\n if (monthlyWrap && annualWrap) {\n const showWrap = isMonthly ? monthlyWrap : annualWrap;\n const hideWrap = isMonthly ? annualWrap : monthlyWrap;\n hideEl(hideWrap);\n showEl(showWrap);\n\n const price = showWrap.querySelector<HTMLElement>('[data-price-element=\"price\"]');\n const term = showWrap.querySelector<HTMLElement>('[data-price-element=\"term\"]');\n blurIn(price, 0);\n blurIn(term, 0.06);\n }\n\n if (monthlyActions && annualActions) {\n const showActions = isMonthly ? monthlyActions : annualActions;\n const hideActions = isMonthly ? annualActions : monthlyActions;\n hideEl(hideActions);\n showEl(showActions);\n }\n }\n\n function applyState(sectionEl: Element, isMonthly: boolean, animateMask: boolean) {\n const darkLabelContainer = sectionEl.querySelector<HTMLElement>(\n '.pricing-switch_label-container.is-dark'\n );\n if (darkLabelContainer) {\n gsap.to(darkLabelContainer, {\n clipPath: isMonthly ? CLIP_MONTHLY : CLIP_ANNUAL,\n duration: animateMask ? 0.4 : 0,\n ease: 'power2.inOut',\n });\n }\n\n sectionEl.querySelectorAll('[data-price-card]').forEach((card) => {\n swapCard(card, isMonthly);\n });\n }\n\n function initSection(sectionEl: Element) {\n const switchButton =\n sectionEl.querySelector<HTMLElement>('#payment-switch') ||\n sectionEl.querySelector<HTMLElement>('[data-payment-switch]');\n const darkLabelContainer = sectionEl.querySelector<HTMLElement>(\n '.pricing-switch_label-container.is-dark'\n );\n\n if (!switchButton || !darkLabelContainer) {\n window.debugWarn('[pricing-switch] Missing switch button or label container in section');\n return;\n }\n\n const initialIsMonthly = defaultIsMonthly;\n\n // Ensure this section's switch starts in the desired state\n switchButton.setAttribute('aria-checked', initialIsMonthly ? 'true' : 'false');\n\n // Initial mask for this section\n gsap.set(darkLabelContainer, {\n clipPath: initialIsMonthly ? CLIP_MONTHLY : CLIP_ANNUAL,\n });\n\n // Initial visibility (no animation on load) for this section only\n sectionEl.querySelectorAll('[data-price-card]').forEach((card) => {\n const monthlyWrap = card.querySelector<HTMLElement>('[data-price=\"monthly\"]');\n const annualWrap = card.querySelector<HTMLElement>('[data-price=\"annual\"]');\n const monthlyActions = card.querySelector<HTMLElement>(\n '[data-price-element=\"actions\"][data-price=\"monthly\"]'\n );\n const annualActions = card.querySelector<HTMLElement>(\n '[data-price-element=\"actions\"][data-price=\"annual\"]'\n );\n\n if (monthlyWrap && annualWrap) {\n if (initialIsMonthly) {\n showEl(monthlyWrap);\n hideEl(annualWrap);\n } else {\n showEl(annualWrap);\n hideEl(monthlyWrap);\n }\n }\n\n if (monthlyActions && annualActions) {\n if (initialIsMonthly) {\n showEl(monthlyActions);\n hideEl(annualActions);\n } else {\n showEl(annualActions);\n hideEl(monthlyActions);\n }\n }\n });\n\n // Prevent double-binding if initPricingSwitch runs more than once\n if (switchButton.dataset.pricingSwitchBound === 'true') {\n window.debug('[pricing-switch] Section already initialized, skipping');\n return;\n }\n switchButton.dataset.pricingSwitchBound = 'true';\n\n // Click handler scoped to this section\n switchButton.addEventListener('click', function (this: HTMLElement) {\n const wasMonthly = this.getAttribute('aria-checked') === 'true';\n this.setAttribute('aria-checked', wasMonthly ? 'false' : 'true');\n window.debug('[pricing-switch] Toggled to:', wasMonthly ? 'annual' : 'monthly');\n applyState(sectionEl, !wasMonthly, true);\n });\n\n window.debug('[pricing-switch] Section initialized');\n }\n\n // Init all independent sections\n const sections = document.querySelectorAll(SECTION_SELECTOR);\n window.debug('[pricing-switch] Found sections:', sections.length);\n sections.forEach(initSection);\n}\n", "// Global debug logging functions\n// Usage: Add ?debug=true to URL to enable debug logging\nwindow.debug = (...args: unknown[]) => {\n new URLSearchParams(location.search).get('debug') === 'true' && console.log(...args);\n};\nwindow.debugError = (...args: unknown[]) => {\n new URLSearchParams(location.search).get('debug') === 'true' && console.error(...args);\n};\nwindow.debugWarn = (...args: unknown[]) => {\n new URLSearchParams(location.search).get('debug') === 'true' && console.warn(...args);\n};\n\nimport { initPricingSwitch } from '$utils/pricing-switch';\n\nwindow.Webflow ||= [];\nwindow.Webflow.push(() => {\n window.debug('Webflow initialized - debug mode active');\n\n // Initialize pricing switches if any exist on the page\n if (document.querySelector('[data-pricing-section]')) {\n initPricingSwitch({\n defaultState: 'monthly',\n sectionSelector: '[data-pricing-section]',\n });\n }\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|