@koehler8/cms-ext-crypto 1.0.0-beta.4

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +198 -0
  3. package/components/CommunityStrip.vue +655 -0
  4. package/components/CuriosityTeaser.vue +842 -0
  5. package/components/HeaderWalletAction.vue +398 -0
  6. package/components/HeroPresale.vue +778 -0
  7. package/components/PercentDoughnut.vue +249 -0
  8. package/components/Presale.vue +507 -0
  9. package/components/PresaleAdmin.vue +1259 -0
  10. package/components/PresaleFaq.vue +95 -0
  11. package/components/ProgressFomo.vue +766 -0
  12. package/components/SocialProofFeed.vue +585 -0
  13. package/components/Tokenomics.vue +617 -0
  14. package/components/Trust.vue +123 -0
  15. package/components/TrustBar.vue +619 -0
  16. package/components/presale/BonusIncentive.vue +476 -0
  17. package/components/presale/Buy.vue +5388 -0
  18. package/components/presale/CountdownTimer.vue +326 -0
  19. package/components/presale/FirstTimeOnboarding.vue +443 -0
  20. package/components/presale/FuseMeter.vue +276 -0
  21. package/components/presale/HoldersBenefits.vue +135 -0
  22. package/components/presale/MomentumCard.vue +163 -0
  23. package/components/presale/PresaleFaqContent.vue +393 -0
  24. package/components/presale/PriceTimeline.vue +143 -0
  25. package/components/presale/Stake.vue +1415 -0
  26. package/components/presale/Status.vue +1113 -0
  27. package/components/presale/StatusMetric.vue +336 -0
  28. package/components/presale/StatusProgressBar.vue +98 -0
  29. package/components/presale/TrustSignals.vue +595 -0
  30. package/components/presale/buyAnalytics.js +58 -0
  31. package/components/presale/buyAssets.js +75 -0
  32. package/components/presale/buyTextHelpers.js +582 -0
  33. package/components/presale/priceSnapshotCache.js +72 -0
  34. package/components/presale/useBuyContentConfig.js +643 -0
  35. package/components/presale/useBuyOnboarding.js +338 -0
  36. package/components/presale/useBuyTransaction.js +464 -0
  37. package/components/presale/useBuyWallet.js +509 -0
  38. package/components/presale/useFomoProgress.js +578 -0
  39. package/components/presale/walletBalanceHelper.js +47 -0
  40. package/composables/usePresaleContext.js +24 -0
  41. package/content.defaults.json +171 -0
  42. package/extension.config.json +116 -0
  43. package/index.js +8 -0
  44. package/package.json +47 -0
  45. package/plugins/appKit.js +261 -0
  46. package/setup.js +29 -0
  47. package/stores/presale.js +70 -0
  48. package/utils/presaleContracts.js +69 -0
  49. package/utils/scrollToPresale.js +21 -0
  50. package/utils/tokenFormat.js +21 -0
  51. package/utils/walletTracking.js +175 -0
@@ -0,0 +1,171 @@
1
+ {
2
+ "presale": {
3
+ "presaleStatus": "Presale is live",
4
+ "ethSpend": "ETH to spend",
5
+ "balance": "Your ETH Balance",
6
+ "youReceive": "You receive",
7
+ "defaultStakeAfterPurchase": true,
8
+ "connectHeadline": "Connect your wallet to get started",
9
+ "connectButtonLabel": "Buy With Crypto",
10
+ "needEthButtonLabel": "Need ETH?",
11
+ "chooseAmountTitle": "Choose your amount",
12
+ "confirmPurchaseTitle": "Confirm your purchase",
13
+ "confirmPurchaseSubtitle": "Choose your path. We'll show progress and a success receipt with links to Etherscan.",
14
+ "amountRaisedLabel": "Amount raised",
15
+ "timeRemainingLabel": "Time remaining",
16
+ "timeEndingLabel": "Ending now",
17
+ "timeEndedLabel": "Presale ended",
18
+ "countdownLabel": "Next price increase in",
19
+ "countdownPendingLabel": "Updating schedule…",
20
+ "countdownUnits": {
21
+ "day": "DAY",
22
+ "hour": "HRS",
23
+ "minute": "MINS",
24
+ "second": "SECS"
25
+ },
26
+ "metricWalletsLabel": "Wallets connected",
27
+ "sectionLabels": {
28
+ "summary": "Summary",
29
+ "status": "Status"
30
+ },
31
+ "panelTitles": {
32
+ "stake": "Stake & Rewards"
33
+ },
34
+ "pausedMessage": "The presale is paused right now. Check back soon for the next round.",
35
+ "walletStatus": {
36
+ "connected": "Wallet connected",
37
+ "wrongNetwork": "Wrong network",
38
+ "switching": "Switching…",
39
+ "switchButton": "Switch to Ethereum Mainnet"
40
+ },
41
+ "networkAlert": {
42
+ "title": "Network mismatch",
43
+ "ctaLabel": "Switch network"
44
+ },
45
+ "formCopy": {
46
+ "amountLabel": "Amount",
47
+ "fillMaxLabel": "Fill with maximum available ETH",
48
+ "maxButtonLabel": "MAX",
49
+ "conversionHint": "≈ {amount} {token} at the current presale rate.",
50
+ "estimateNotice": "You'll receive approximately {amount} {token}*"
51
+ },
52
+ "helperSurfaces": {
53
+ "howItWorks": { "enabled": false },
54
+ "needEth": { "enabled": false }
55
+ },
56
+ "howItWorks": {
57
+ "buttonLabel": "How it works",
58
+ "title": "How it works",
59
+ "stepTitles": [
60
+ "Connect wallet",
61
+ "Enter amount",
62
+ "Confirm purchase"
63
+ ],
64
+ "steps": [
65
+ "Connect your wallet to get started.",
66
+ "Enter the ETH you want to spend to see live token and USD estimates.",
67
+ "Review the totals, confirm in your wallet, and lock today's presale price."
68
+ ],
69
+ "switchNetworkPrompt": "Switch to Ethereum Mainnet, then enter how much ETH you want to spend.",
70
+ "pendingPrompt": "Approve the transaction in your wallet and watch for the confirmation banner.",
71
+ "successPrompt": "Purchase confirmed — your receipt is on Etherscan and staking is available."
72
+ },
73
+ "transactionStatus": {
74
+ "pendingTitle": "Transaction pending…",
75
+ "pendingMessages": {
76
+ "short": "Awaiting confirmation on Ethereum (~15 seconds).",
77
+ "medium": "Still pending… Ethereum is a bit busy. Hang tight.",
78
+ "long": "Still pending… the network is busy, but your transaction is queued."
79
+ },
80
+ "pendingOverlayTitle": "Transaction pending…",
81
+ "pendingLinkLabel": "View on Etherscan",
82
+ "pendingBuyLabel": "Purchasing…",
83
+ "pendingBuyAndStakeLabel": "Buying & Staking…",
84
+ "successTitle": "Presale purchase confirmed",
85
+ "successDescription": "You secured {tokens} {tokenSymbol} ({eth} ETH).",
86
+ "successLinkLabel": "View transaction on Etherscan",
87
+ "errorTitle": "We couldn't complete that",
88
+ "errorButtonLabel": "Try again"
89
+ },
90
+ "successCelebration": {
91
+ "dismissLabel": "Dismiss success message",
92
+ "eyebrow": "Presale success",
93
+ "transactionLabel": "Transaction",
94
+ "ethSpentLabel": "ETH Spent"
95
+ },
96
+ "accessibility": {
97
+ "dismissAlert": "Dismiss message",
98
+ "hideInstructions": "Hide instructions",
99
+ "closeNeedEth": "Close"
100
+ },
101
+ "statusCopy": {
102
+ "presaleComplete": "Presale is complete",
103
+ "claimLive": "Unstaked claim is live",
104
+ "stakedClaimLive": "Token claim is live",
105
+ "countdownLoading": "Countdown is loading",
106
+ "priceContext": "Live token price",
107
+ "priceLoading": "Token price is loading",
108
+ "emptyMetrics": "Presale metrics will appear once activity starts."
109
+ },
110
+ "onboarding": {
111
+ "enabled": false
112
+ },
113
+ "needEth": {
114
+ "title": "Need ETH for the presale?",
115
+ "description": "Grab ETH from a trusted on-ramp, then send it to the wallet you connect here.",
116
+ "links": [
117
+ {
118
+ "label": "Buy ETH on Coinbase",
119
+ "href": "https://www.coinbase.com/buy/ethereum"
120
+ },
121
+ {
122
+ "label": "MoonPay",
123
+ "href": "https://www.moonpay.com/buy/eth"
124
+ }
125
+ ],
126
+ "note": "Once your transfer lands, reconnect your wallet and finish the checkout."
127
+ },
128
+ "secondaryCtas": {
129
+ "emailSignup": {
130
+ "enabled": false,
131
+ "placeholder": "your@email.com",
132
+ "button": "Get presale updates",
133
+ "submittingLabel": "Submitting…",
134
+ "successMessage": "Thanks! Check your inbox to confirm.",
135
+ "errorMessage": "Please enter a valid email address.",
136
+ "label": "Email address"
137
+ }
138
+ },
139
+ "faq": {
140
+ "badge": "FAQ",
141
+ "defaultOpenIndex": -1,
142
+ "description": "Quick answers for the curious and the cautious.",
143
+ "items": [
144
+ {
145
+ "question": "Which wallets can I use?",
146
+ "answer": "We support MetaMask, WalletConnect, and Coinbase Wallet today. If your wallet isn't listed, connect through WalletConnect or import the account into one of these wallets."
147
+ },
148
+ {
149
+ "question": "What does staking do?",
150
+ "answer": "Staking locks purchased tokens for yield. Flip the Stake after purchase toggle for an automatic deposit or leave it off and stake later from the presale dashboard. Rewards accrue in the same wallet you used to buy."
151
+ },
152
+ {
153
+ "question": "When can I claim my tokens?",
154
+ "answer": "Claiming opens after the presale unlock. We'll notify holders through the dashboard and Telegram. Until then, your purchase receipt and staking rewards remain visible in the widget."
155
+ }
156
+ ]
157
+ }
158
+ },
159
+ "trustBar": {
160
+ "eyebrow": "Security checkpoint",
161
+ "etherscanLabel": "View on Etherscan",
162
+ "copyLabel": "Copy",
163
+ "copiedLabel": "Copied!",
164
+ "copyErrorLabel": "Copy failed. Try again.",
165
+ "badgesHeading": "Status summary",
166
+ "badges": [
167
+ { "text": "Verified on Etherscan", "variant": "verified" },
168
+ { "text": "Multi-sig custody enforced", "variant": "info" }
169
+ ]
170
+ }
171
+ }
@@ -0,0 +1,116 @@
1
+ {
2
+ "$schema": "../../manifest.schema.json",
3
+ "slug": "presale",
4
+ "version": "1.0.0",
5
+ "provider": {
6
+ "name": "Crypto Presale Extension Suite",
7
+ "url": "https://github.com/koehler8",
8
+ "contact": "tucsonconsulting@gmail.com"
9
+ },
10
+ "license": "MIT",
11
+ "components": [
12
+ {
13
+ "name": "HeaderActions",
14
+ "label": "Wallet Connect Button",
15
+ "description": "Wallet connection button injected into the site header via the HeaderActions extension slot.",
16
+ "module": "./components/HeaderWalletAction.vue",
17
+ "configKey": "headerWallet"
18
+ },
19
+ {
20
+ "name": "Presale",
21
+ "label": "Presale Deck",
22
+ "description": "Composes the status column and buy/stake tabs for the on-chain presale flow.",
23
+ "module": "./components/Presale.vue",
24
+ "configKey": "presale",
25
+ "allowedPages": ["home"]
26
+ },
27
+ {
28
+ "name": "PresaleFaq",
29
+ "label": "Presale FAQ",
30
+ "description": "Accordion wrapper for the presale FAQ entries defined under the presale block.",
31
+ "module": "./components/PresaleFaq.vue",
32
+ "configKey": "presale",
33
+ "allowedPages": ["home"],
34
+ "requiredContent": ["faq"]
35
+ },
36
+ {
37
+ "name": "MomentumCard",
38
+ "label": "Presale Momentum Card",
39
+ "description": "Standalone momentum card that mirrors the presale pulse stats and schedule copy.",
40
+ "module": "./components/presale/MomentumCard.vue",
41
+ "configKey": "presale",
42
+ "allowedPages": ["home"],
43
+ "requiredContent": ["progressFomo"]
44
+ },
45
+ {
46
+ "name": "HeroPresale",
47
+ "label": "Presale Hero",
48
+ "description": "Hero block that highlights the presale CTA, badge, and secondary actions.",
49
+ "module": "./components/HeroPresale.vue",
50
+ "configKey": "heroPresale"
51
+ },
52
+ {
53
+ "name": "ProgressFomo",
54
+ "label": "Progress & FOMO Card",
55
+ "description": "Standalone progress card featuring allocation sold, remaining supply, and next price schedule.",
56
+ "module": "./components/ProgressFomo.vue",
57
+ "configKey": "progressFomo",
58
+ "requiredContent": [
59
+ "totalAllocation",
60
+ "soldAmount",
61
+ "nextPhaseTimestamp"
62
+ ]
63
+ },
64
+ {
65
+ "name": "CuriosityTeaser",
66
+ "label": "Curiosity Teaser",
67
+ "description": "Secret-drop teaser with optional modal CTA and community links.",
68
+ "module": "./components/CuriosityTeaser.vue",
69
+ "configKey": "curiosityTeaser",
70
+ "allowedPages": ["home"]
71
+ },
72
+ {
73
+ "name": "SocialProofFeed",
74
+ "label": "Social Proof Feed",
75
+ "description": "Curated social feed with share CTA and optional live community counter.",
76
+ "module": "./components/SocialProofFeed.vue",
77
+ "configKey": "socialProof"
78
+ },
79
+ {
80
+ "name": "Tokenomics",
81
+ "label": "Tokenomics Chart",
82
+ "description": "Token allocation table paired with the radial chart.",
83
+ "module": "./components/Tokenomics.vue",
84
+ "configKey": "tokenomics"
85
+ },
86
+ {
87
+ "name": "Trust",
88
+ "label": "Trust Section",
89
+ "description": "Credentials and trust badges block rendered from the `trust` content node.",
90
+ "module": "./components/Trust.vue",
91
+ "configKey": "trust"
92
+ },
93
+ {
94
+ "name": "TrustBar",
95
+ "label": "Trust Contract Bar",
96
+ "description": "Sticky trust bar that surfaces audit/contract metadata and copying helpers.",
97
+ "module": "./components/TrustBar.vue",
98
+ "configKey": "trustBar"
99
+ },
100
+ {
101
+ "name": "CommunityStrip",
102
+ "label": "Community Strip",
103
+ "description": "Social proof rail with community links and optional email capture.",
104
+ "module": "./components/CommunityStrip.vue",
105
+ "configKey": "communityStrip"
106
+ },
107
+ {
108
+ "name": "PresaleAdmin",
109
+ "label": "Presale Admin Console",
110
+ "description": "Operations panel for presale managers (pricing controls, flags, treasury actions).",
111
+ "module": "./components/PresaleAdmin.vue",
112
+ "configKey": "presaleAdmin",
113
+ "allowedPages": ["admin"]
114
+ }
115
+ ]
116
+ }
package/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import manifest from './extension.config.json' with { type: 'json' };
2
+ import contentDefaults from './content.defaults.json' with { type: 'json' };
3
+ import { setup } from './setup.js';
4
+
5
+ const components = import.meta.glob('./components/**/*.{vue,js}');
6
+
7
+ export default { manifest, components, contentDefaults, setup };
8
+ export { manifest, contentDefaults, setup };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@koehler8/cms-ext-crypto",
3
+ "version": "1.0.0-beta.4",
4
+ "description": "Crypto extension for Vertex CMS — token presale, staking, tokenomics, wallet connection, and analytics",
5
+ "license": "MIT",
6
+ "keywords": ["cms", "extension", "koehler8", "crypto", "presale", "staking", "web3", "wallet"],
7
+ "bugs": {
8
+ "url": "https://github.com/koehler8/cms-ext-crypto/issues"
9
+ },
10
+ "type": "module",
11
+ "author": "Chris Koehler",
12
+ "homepage": "https://github.com/koehler8/cms-ext-crypto",
13
+ "exports": {
14
+ ".": "./index.js",
15
+ "./config": "./extension.config.json"
16
+ },
17
+ "files": [
18
+ "index.js",
19
+ "setup.js",
20
+ "extension.config.json",
21
+ "content.defaults.json",
22
+ "components",
23
+ "stores",
24
+ "utils",
25
+ "plugins",
26
+ "composables",
27
+ "README.md",
28
+ "LICENSE"
29
+ ],
30
+ "dependencies": {
31
+ "@reown/appkit": "^1.8.12",
32
+ "@reown/appkit-adapter-ethers": "^1.8.12",
33
+ "chart.js": "^4.5.1",
34
+ "chartjs-plugin-datalabels": "^2.2.0",
35
+ "ethers": "^6.13.5",
36
+ "vue-chartjs": "^5.3.2"
37
+ },
38
+ "peerDependencies": {
39
+ "@koehler8/cms": "^1.0.0-beta.1",
40
+ "pinia": "^3.0.0",
41
+ "vue": "^3.5.0"
42
+ },
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/koehler8/cms-ext-crypto.git"
46
+ }
47
+ }
@@ -0,0 +1,261 @@
1
+ import { createAppKit } from '@reown/appkit/vue';
2
+ import { EthersAdapter } from '@reown/appkit-adapter-ethers';
3
+ import { mainnet } from '@reown/appkit/networks';
4
+
5
+ let appKitInstance;
6
+ const FEATURED_WALLET_IDS = Object.freeze([
7
+ 'c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96', // MetaMask
8
+ 'fd20dc426fb37566d803205b19bbc1d4096b248ac04548e3cfb6b3a38bd033aa', // Base (Coinbase Wallet)
9
+ '4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0', // Trust Wallet
10
+ ]);
11
+
12
+ function buildMetadata(siteData) {
13
+ const hasWindow = typeof window !== 'undefined';
14
+ const fallbackUrl = hasWindow ? window.location.origin : '';
15
+ const site = siteData?.site ?? {};
16
+
17
+ let configuredUrl = typeof site.url === 'string' ? site.url.trim() : '';
18
+ if (!configuredUrl) {
19
+ configuredUrl = fallbackUrl;
20
+ }
21
+
22
+ if (hasWindow && configuredUrl) {
23
+ try {
24
+ const configuredOrigin = new URL(configuredUrl).origin;
25
+ const currentOrigin = new URL(fallbackUrl || configuredUrl).origin;
26
+ if (configuredOrigin !== currentOrigin) {
27
+ configuredUrl = currentOrigin;
28
+ }
29
+ } catch {
30
+ configuredUrl = fallbackUrl || configuredUrl;
31
+ }
32
+ }
33
+
34
+ return {
35
+ name: site.title ?? 'Product Site',
36
+ description: site.description ?? '',
37
+ url: configuredUrl,
38
+ icons: Array.isArray(site.icons) ? site.icons : [],
39
+ };
40
+ }
41
+
42
+ export function ensureAppKit({ siteData, projectId: overrideProjectId } = {}) {
43
+ if (appKitInstance) return appKitInstance;
44
+
45
+ const projectId = overrideProjectId || import.meta.env.VITE_REOWN_PROJECT_ID;
46
+ if (!projectId) {
47
+ console.warn('ensureAppKit: VITE_REOWN_PROJECT_ID is missing; wallet UI not initialised.');
48
+ return undefined;
49
+ }
50
+
51
+ if (typeof globalThis !== 'undefined') {
52
+ const issuedWarnings =
53
+ globalThis.litIssuedWarnings instanceof Set
54
+ ? globalThis.litIssuedWarnings
55
+ : (globalThis.litIssuedWarnings = new Set());
56
+ issuedWarnings.add('dev-mode');
57
+ issuedWarnings.add('change-in-update');
58
+
59
+ if (!globalThis.__appkitPatchedSvgAttributes) {
60
+ const svgProto = typeof SVGElement !== 'undefined' ? SVGElement.prototype : null;
61
+ if (svgProto) {
62
+ const originalSetAttribute = svgProto.setAttribute;
63
+ const originalSetAttributeNS = svgProto.setAttributeNS;
64
+ const originalRemoveAttribute = svgProto.removeAttribute;
65
+ const originalRemoveAttributeNS = svgProto.removeAttributeNS;
66
+
67
+ const shouldNullify = (name, value) =>
68
+ (name === 'height' || name === 'width') &&
69
+ (value === '' || value === null || value === undefined);
70
+
71
+ svgProto.setAttribute = function patchedSetAttribute(name, value) {
72
+ if (shouldNullify(name, value)) {
73
+ if (originalRemoveAttribute) {
74
+ originalRemoveAttribute.call(this, name);
75
+ return;
76
+ }
77
+ return;
78
+ }
79
+ return originalSetAttribute.call(this, name, value);
80
+ };
81
+
82
+ svgProto.setAttributeNS = function patchedSetAttributeNS(ns, name, value) {
83
+ if (shouldNullify(name, value)) {
84
+ if (originalRemoveAttributeNS) {
85
+ originalRemoveAttributeNS.call(this, ns, name);
86
+ return;
87
+ }
88
+ return;
89
+ }
90
+ return originalSetAttributeNS.call(this, ns, name, value);
91
+ };
92
+
93
+ globalThis.__appkitPatchedSvgAttributes = true;
94
+ }
95
+ }
96
+ }
97
+
98
+ const metadata = buildMetadata(siteData);
99
+
100
+ const neutralizeFontPreload = () => {
101
+ if (typeof document === 'undefined') return;
102
+
103
+ const BLOCKED_PREFIX = 'https://fonts.reown.com/';
104
+
105
+ const isBlockedLink = (node) => {
106
+ if (!node || node.nodeType !== Node.ELEMENT_NODE) return false;
107
+ const tag = node.tagName?.toLowerCase();
108
+ if (tag !== 'link') return false;
109
+ const rel = (node.rel || node.getAttribute('rel') || '').toLowerCase();
110
+ if (rel !== 'preload') return false;
111
+ const href = node.href || node.getAttribute('href') || '';
112
+ return href.startsWith(BLOCKED_PREFIX);
113
+ };
114
+
115
+ const pruneNode = (node) => {
116
+ if (!node) return false;
117
+ if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
118
+ let removed = false;
119
+ Array.from(node.childNodes).forEach((child) => {
120
+ if (isBlockedLink(child)) {
121
+ node.removeChild(child);
122
+ removed = true;
123
+ }
124
+ });
125
+ return removed;
126
+ }
127
+
128
+ if (isBlockedLink(node)) {
129
+ node.remove();
130
+ return true;
131
+ }
132
+ return false;
133
+ };
134
+
135
+ const patchHeadInsertion = () => {
136
+ const head = document.head;
137
+ if (!head || head.__reownPreloadBlocked) return;
138
+ Object.defineProperty(head, '__reownPreloadBlocked', {
139
+ value: true,
140
+ configurable: false,
141
+ enumerable: false,
142
+ writable: false,
143
+ });
144
+
145
+ const wrapMethod = (proto, method) => {
146
+ const original = proto?.[method];
147
+ if (!original) return;
148
+ proto[method] = function wrappedMethod(...args) {
149
+ if (this !== head) {
150
+ return original.apply(this, args);
151
+ }
152
+
153
+ if (!args.length) {
154
+ return original.apply(this, args);
155
+ }
156
+
157
+ if (method === 'append' || method === 'prepend') {
158
+ const filteredArgs = [];
159
+ let mutated = false;
160
+ for (const arg of args) {
161
+ if (arg instanceof Node) {
162
+ const wasPruned = pruneNode(arg);
163
+ if (arg.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !arg.childNodes.length) {
164
+ mutated = true;
165
+ continue;
166
+ }
167
+ if (isBlockedLink(arg)) {
168
+ mutated = true;
169
+ continue;
170
+ }
171
+ mutated = mutated || wasPruned;
172
+ }
173
+ filteredArgs.push(arg);
174
+ }
175
+
176
+ if (!filteredArgs.length && mutated) {
177
+ return undefined;
178
+ }
179
+ return original.apply(this, filteredArgs);
180
+ }
181
+
182
+ const targetNode = args[0];
183
+ if (targetNode instanceof Node && pruneNode(targetNode)) {
184
+ if (method === 'replaceChild') {
185
+ return args[1];
186
+ }
187
+ return targetNode;
188
+ }
189
+
190
+ return original.apply(this, args);
191
+ };
192
+ };
193
+
194
+ wrapMethod(Element.prototype, 'append');
195
+ wrapMethod(Element.prototype, 'prepend');
196
+ wrapMethod(Node.prototype, 'appendChild');
197
+ wrapMethod(Node.prototype, 'insertBefore');
198
+ wrapMethod(Node.prototype, 'replaceChild');
199
+ };
200
+
201
+ const transformLinks = () => {
202
+ let removed = false;
203
+ document
204
+ .querySelectorAll('link[rel="preload"][href^="https://fonts.reown.com/"]')
205
+ .forEach((link) => {
206
+ if (pruneNode(link)) {
207
+ removed = true;
208
+ }
209
+ });
210
+ return removed;
211
+ };
212
+
213
+ patchHeadInsertion();
214
+ transformLinks();
215
+
216
+ if (typeof MutationObserver === 'undefined') {
217
+ return;
218
+ }
219
+
220
+ const observer = new MutationObserver(() => {
221
+ transformLinks();
222
+ });
223
+
224
+ observer.observe(document.head || document.documentElement, {
225
+ childList: true,
226
+ subtree: true,
227
+ });
228
+ };
229
+
230
+ appKitInstance = createAppKit({
231
+ adapters: [new EthersAdapter()],
232
+ networks: [mainnet],
233
+ metadata,
234
+ projectId,
235
+ featuredWalletIds: FEATURED_WALLET_IDS,
236
+ features: {
237
+ analytics: true,
238
+ connectMethodsOrder: ['wallet'],
239
+ connectorTypeOrder: [
240
+ 'injected',
241
+ 'walletConnect',
242
+ 'recent',
243
+ 'featured',
244
+ 'custom',
245
+ 'external',
246
+ 'recommended',
247
+ ],
248
+ onramp: {
249
+ providers: ['meld'],
250
+ requireEmail: false,
251
+ },
252
+ swap: {
253
+ providers: ['1inch'],
254
+ },
255
+ },
256
+ });
257
+
258
+ neutralizeFontPreload();
259
+
260
+ return appKitInstance;
261
+ }
package/setup.js ADDED
@@ -0,0 +1,29 @@
1
+ import { h, toRef } from 'vue';
2
+ import { usePresaleStore } from './stores/presale.js';
3
+ import { ensureAppKit } from './plugins/appKit.js';
4
+
5
+ /**
6
+ * Extension setup hook — called by the CMS during app initialisation.
7
+ *
8
+ * Initializes AppKit wallet connection, registers the appkit-button web
9
+ * component proxy, and provides presale state to the component tree.
10
+ */
11
+ export async function setup({ app, pinia, siteData, isClient }) {
12
+ if (!isClient) return;
13
+
14
+ // Initialize AppKit so wallet modals work
15
+ ensureAppKit({ siteData });
16
+
17
+ // Register the appkit-button web component proxy so Vue doesn't warn
18
+ app.component('appkit-button', {
19
+ name: 'AppKitButtonProxy',
20
+ render() {
21
+ return h('appkit-button');
22
+ },
23
+ });
24
+
25
+ // Provide presale state to the component tree via provide/inject
26
+ const store = usePresaleStore(pinia);
27
+ app.provide('presalePulse', toRef(store, 'presalePulse'));
28
+ app.provide('personalPresaleSummary', toRef(store, 'personalPresaleSummary'));
29
+ }