@ansidev-oss/vitepress-theme-ansidev 1.0.6 → 1.0.11
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/client/Sharing-ZrU7YF-x.js +190 -0
- package/dist/client/Swetrix-CM1mbD6X.js +450 -0
- package/dist/client/{VPAlgoliaSearchBox-DXE-LCVf.js → VPAlgoliaSearchBox-BAhNuo7n.js} +1 -1
- package/dist/client/{VPCarbonAds-Czmm53YE.js → VPCarbonAds-CSK7KnIu.js} +1 -1
- package/dist/client/{VPLocalSearchBox-ihwA4uH-.js → VPLocalSearchBox-TYbANUkJ.js} +1 -1
- package/dist/client/composables/index.d.ts +1 -1
- package/dist/client/{index-CZCdwVUW.js → index-C43AnX3f.js} +1623 -1573
- package/dist/client/index-DuYWs0vj.js +265 -0
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js +7 -2
- package/dist/client/plugins/medium-zoom/index.d.ts +14 -0
- package/dist/client/plugins/sharing/index.d.ts +59 -0
- package/dist/client/plugins/swetrix/index.d.ts +10 -0
- package/dist/client/styles.css +1 -1
- package/dist/client/types/index.d.ts +14 -1
- package/dist/node/composables/index.d.ts +3 -0
- package/dist/node/composables/markdown.d.ts +2 -0
- package/dist/node/composables/route.d.ts +15 -0
- package/dist/node/composables/slug.d.ts +7 -0
- package/dist/node/composables/types.d.ts +7 -0
- package/dist/node/composables.d.mts +4 -2
- package/dist/node/composables.mjs +4 -1
- package/dist/node/config.d.mts +90 -8
- package/dist/node/config.d.ts +45 -0
- package/dist/node/config.mjs +19 -10
- package/dist/shared/composables/index.d.ts +1 -0
- package/package.json +11 -3
- package/src/client/components/DonationWidget.vue +22 -0
- package/src/client/components/Footer.vue +12 -12
- package/src/client/components/SharingWidget.vue +19 -0
- package/src/client/composables/index.ts +1 -1
- package/src/client/index.ts +2 -8
- package/src/client/layouts/Layout.vue +48 -2
- package/src/client/plugins/medium-zoom/index.ts +30 -0
- package/src/client/plugins/sharing/components/Sharing.vue +81 -0
- package/src/client/plugins/sharing/components/SharingButton.vue +115 -0
- package/src/client/plugins/sharing/index.ts +76 -0
- package/src/client/plugins/swetrix/components/Swetrix.vue +43 -0
- package/src/client/plugins/swetrix/index.ts +11 -0
- package/src/client/types/index.ts +14 -1
- package/src/node/composables/slug.ts +3 -13
- package/src/node/config.ts +22 -13
- package/src/shared/composables/index.ts +1 -0
- /package/dist/{client/composables/slug.d.ts → shared/composables/useSlug.d.ts} +0 -0
- /package/src/{client/composables/slug.ts → shared/composables/useSlug.ts} +0 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { defineComponent as h, computed as a, openBlock as l, createElementBlock as u, createBlock as b, unref as z, createCommentVNode as m, Fragment as w, createTextVNode as B, toDisplayString as y, normalizeClass as p, createElementVNode as v, renderList as U } from "vue";
|
|
2
|
+
import { useData as L } from "vitepress";
|
|
3
|
+
import { Icon as R } from "@iconify/vue";
|
|
4
|
+
const _ = (s) => {
|
|
5
|
+
if (!s)
|
|
6
|
+
return "";
|
|
7
|
+
const t = encodeURIComponent, r = Object.keys(s);
|
|
8
|
+
return r.length < 1 ? "" : `?${r.filter((e) => s[e] !== void 0).map((e) => `${t(e)}=${t(s[e])}`).join("&")}`;
|
|
9
|
+
}, P = ["href", "aria-label"], M = /* @__PURE__ */ h({
|
|
10
|
+
__name: "SharingButton",
|
|
11
|
+
props: {
|
|
12
|
+
url: {},
|
|
13
|
+
text: {},
|
|
14
|
+
network: {},
|
|
15
|
+
buttonSize: {},
|
|
16
|
+
iconStyle: {},
|
|
17
|
+
iconSize: { default: 32 },
|
|
18
|
+
displayMode: { default: "icon" }
|
|
19
|
+
},
|
|
20
|
+
setup(s) {
|
|
21
|
+
const t = s, r = a(() => {
|
|
22
|
+
switch (t.network) {
|
|
23
|
+
case "email":
|
|
24
|
+
return {
|
|
25
|
+
name: "E-mail",
|
|
26
|
+
shareBaseURL: "mailto:",
|
|
27
|
+
icon: "bi:envelope-fill",
|
|
28
|
+
params: { subject: t.text, body: t.url },
|
|
29
|
+
allowedParams: ["subject", "body"]
|
|
30
|
+
};
|
|
31
|
+
case "facebook":
|
|
32
|
+
return {
|
|
33
|
+
name: "Facebook",
|
|
34
|
+
shareBaseURL: "https://facebook.com/sharer/sharer.php",
|
|
35
|
+
icon: "bi:facebook",
|
|
36
|
+
params: { u: t.url },
|
|
37
|
+
allowedParams: ["u", "display", "redirect_uri"]
|
|
38
|
+
};
|
|
39
|
+
case "linkedin":
|
|
40
|
+
return {
|
|
41
|
+
name: "LinkedIn",
|
|
42
|
+
shareBaseURL: "https://www.linkedin.com/sharing/share-offsite",
|
|
43
|
+
icon: "bi:linkedin",
|
|
44
|
+
params: { url: t.url },
|
|
45
|
+
allowedParams: ["url"]
|
|
46
|
+
};
|
|
47
|
+
case "pinterest":
|
|
48
|
+
return {
|
|
49
|
+
name: "Pinterest",
|
|
50
|
+
shareBaseURL: "https://pinterest.com/pin/create/button",
|
|
51
|
+
icon: "bi:pinterest",
|
|
52
|
+
params: { posttype: "link", title: t.text, url: t.url },
|
|
53
|
+
allowedParams: ["posttype", "tags", "title", "content", "caption", "show-via", "canonicalUrl"]
|
|
54
|
+
};
|
|
55
|
+
case "reddit":
|
|
56
|
+
return {
|
|
57
|
+
name: "Reddit",
|
|
58
|
+
shareBaseURL: "https://www.reddit.com/submit",
|
|
59
|
+
icon: "bi:reddit",
|
|
60
|
+
params: { title: t.text, url: t.url },
|
|
61
|
+
allowedParams: ["title", "url"]
|
|
62
|
+
};
|
|
63
|
+
case "telegram":
|
|
64
|
+
return {
|
|
65
|
+
name: "Telegram",
|
|
66
|
+
shareBaseURL: "https://telegram.me/share/url",
|
|
67
|
+
icon: "bi:telegram",
|
|
68
|
+
params: { text: t.text, url: t.url },
|
|
69
|
+
allowedParams: ["text", "url"]
|
|
70
|
+
};
|
|
71
|
+
// case 'tumblr':
|
|
72
|
+
// return {
|
|
73
|
+
// name: 'Tumblr',
|
|
74
|
+
// shareBaseURL: 'https://www.tumblr.com/widgets/share/tool',
|
|
75
|
+
// icon: 'bi:tumblr',
|
|
76
|
+
// params: { posttype: 'link', title: props.text, url: props.url },
|
|
77
|
+
// allowedParams: ['posttype', 'tags', 'title', 'content', 'caption', 'show-via', 'canonicalUrl'],
|
|
78
|
+
// }
|
|
79
|
+
case "twitter":
|
|
80
|
+
return {
|
|
81
|
+
name: "Twitter",
|
|
82
|
+
shareBaseURL: "https://twitter.com/intent/tweet",
|
|
83
|
+
icon: "bi:twitter",
|
|
84
|
+
params: { text: t.text, url: t.url },
|
|
85
|
+
allowedParams: ["text", "url", "hashtag", "via"]
|
|
86
|
+
};
|
|
87
|
+
// case 'vk':
|
|
88
|
+
// return {
|
|
89
|
+
// name: 'VK',
|
|
90
|
+
// shareBaseURL: 'https://vk.com/share.php',
|
|
91
|
+
// icon: 'vk-icon',
|
|
92
|
+
// params: { title: props.text, url: props.url },
|
|
93
|
+
// allowedParams: ['title', 'url'],
|
|
94
|
+
// }
|
|
95
|
+
case "whatsapp":
|
|
96
|
+
return {
|
|
97
|
+
name: "WhatsApp",
|
|
98
|
+
shareBaseURL: "whatsapp://send",
|
|
99
|
+
icon: "bi:whatsapp",
|
|
100
|
+
params: { text: t.url },
|
|
101
|
+
allowedParams: ["text"]
|
|
102
|
+
};
|
|
103
|
+
default:
|
|
104
|
+
return {};
|
|
105
|
+
}
|
|
106
|
+
}), n = a(() => r.value.name), e = a(() => r.value.icon), c = a(() => {
|
|
107
|
+
const o = r.value.shareBaseURL, i = _(r.value.params);
|
|
108
|
+
return `${o}${i}`;
|
|
109
|
+
});
|
|
110
|
+
return (o, i) => (l(), u("a", {
|
|
111
|
+
href: c.value,
|
|
112
|
+
target: "_blank",
|
|
113
|
+
rel: "noopener",
|
|
114
|
+
"aria-label": n.value,
|
|
115
|
+
style: { "padding-left": "0.25rem", "padding-right": "0.25rem" }
|
|
116
|
+
}, [
|
|
117
|
+
["icon", "both"].includes(t.displayMode) ? (l(), b(z(R), {
|
|
118
|
+
key: 0,
|
|
119
|
+
icon: e.value,
|
|
120
|
+
width: s.iconSize,
|
|
121
|
+
height: s.iconSize,
|
|
122
|
+
class: "fill-current text-gray-700 dark:text-gray-200 hover:text-blue-500 dark:hover:text-blue-400"
|
|
123
|
+
}, null, 8, ["icon", "width", "height"])) : m("", !0),
|
|
124
|
+
["text", "both"].includes(t.displayMode) ? (l(), u(w, { key: 1 }, [
|
|
125
|
+
B(" " + y(n.value), 1)
|
|
126
|
+
], 64)) : m("", !0)
|
|
127
|
+
], 8, P));
|
|
128
|
+
}
|
|
129
|
+
}), E = /* @__PURE__ */ h({
|
|
130
|
+
__name: "Sharing",
|
|
131
|
+
props: {
|
|
132
|
+
url: {},
|
|
133
|
+
text: {}
|
|
134
|
+
},
|
|
135
|
+
setup(s) {
|
|
136
|
+
const t = {
|
|
137
|
+
wrapperCssClass: "pl-4 py-4",
|
|
138
|
+
titleCssClass: "text-sm/[32px] font-semibold mb-2",
|
|
139
|
+
buttonCssClass: "flex flex-wrap space-x-1",
|
|
140
|
+
title: "Share",
|
|
141
|
+
networks: ["email", "facebook", "twitter", "telegram", "reddit", "linkedin", "whatsapp", "pinterest", "tumblr", "vk"],
|
|
142
|
+
buttonSize: 18,
|
|
143
|
+
iconSize: 20,
|
|
144
|
+
iconStyle: "solid",
|
|
145
|
+
displayMode: "both"
|
|
146
|
+
}, r = s, { theme: n } = L(), e = a(() => n.value.sharing || !1), c = a(
|
|
147
|
+
() => e.value && typeof e.value.wrapperCssClass == "string" ? e.value.wrapperCssClass : t.wrapperCssClass
|
|
148
|
+
), o = a(
|
|
149
|
+
() => e.value && typeof e.value.title == "string" ? e.value.title : t.title
|
|
150
|
+
), i = a(
|
|
151
|
+
() => e.value && typeof e.value.titleCssClass == "string" ? e.value.titleCssClass : t.titleCssClass
|
|
152
|
+
), f = a(
|
|
153
|
+
() => e.value && typeof e.value.buttonCssClass == "string" ? e.value.buttonCssClass : t.buttonCssClass
|
|
154
|
+
), C = a(
|
|
155
|
+
() => e.value && Array.isArray(e.value.networks) ? e.value.networks : t.networks
|
|
156
|
+
), g = a(
|
|
157
|
+
() => e.value && Number.isInteger(e.value.buttonSize) && e.value.buttonSize > 0 ? e.value.buttonSize : t.buttonSize
|
|
158
|
+
), k = a(
|
|
159
|
+
() => e.value && Number.isInteger(e.value.iconSize) && e.value.iconSize > 0 ? e.value.iconSize : t.iconSize
|
|
160
|
+
), x = a(
|
|
161
|
+
() => e.value && typeof e.value.iconStyle == "string" ? e.value.iconStyle : t.iconStyle
|
|
162
|
+
), S = a(
|
|
163
|
+
() => e.value && typeof e.value.displayMode == "string" ? e.value.displayMode : t.displayMode
|
|
164
|
+
);
|
|
165
|
+
return (I, N) => (l(), u("div", {
|
|
166
|
+
class: p(c.value)
|
|
167
|
+
}, [
|
|
168
|
+
v("p", {
|
|
169
|
+
class: p(i.value)
|
|
170
|
+
}, y(o.value), 3),
|
|
171
|
+
v("div", {
|
|
172
|
+
class: p(f.value)
|
|
173
|
+
}, [
|
|
174
|
+
(l(!0), u(w, null, U(C.value, (d) => (l(), b(M, {
|
|
175
|
+
key: d,
|
|
176
|
+
url: r.url,
|
|
177
|
+
text: r.text,
|
|
178
|
+
network: d,
|
|
179
|
+
"button-size": g.value,
|
|
180
|
+
"icon-size": k.value,
|
|
181
|
+
"icon-style": x.value,
|
|
182
|
+
"display-mode": S.value
|
|
183
|
+
}, null, 8, ["url", "text", "network", "button-size", "icon-size", "icon-style", "display-mode"]))), 128))
|
|
184
|
+
], 2)
|
|
185
|
+
], 2));
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
export {
|
|
189
|
+
E as default
|
|
190
|
+
};
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { defineComponent as y, onMounted as b } from "vue";
|
|
2
|
+
const h = (r) => {
|
|
3
|
+
const t = location.search.match(r);
|
|
4
|
+
return t && t[2] || void 0;
|
|
5
|
+
}, x = /[?&](ref|source|utm_source|gad_source)=([^?&]+)/, P = /[?&](utm_campaign|gad_campaignid)=([^?&]+)/, O = /[?&](utm_medium)=([^?&]+)/, k = /[?&](utm_term)=([^?&]+)/, T = /[?&](utm_content)=([^?&]+)/, C = /[?&](gclid)=([^?&]+)/, v = () => h(C) ? "<gclid>" : void 0, p = () => typeof window < "u", _ = () => location?.hostname === "localhost" || location?.hostname === "127.0.0.1" || location?.hostname === "", j = () => navigator?.webdriver, u = () => typeof navigator.languages < "u" ? navigator.languages[0] : navigator.language, f = () => {
|
|
6
|
+
try {
|
|
7
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
8
|
+
} catch {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
}, g = () => document.referrer || void 0, m = () => h(x), w = () => h(O) || v(), I = () => h(P), D = () => h(k), E = () => h(T), l = (r) => {
|
|
12
|
+
let t = location.pathname || "";
|
|
13
|
+
if (r.hash) {
|
|
14
|
+
const e = location.hash.indexOf("?"), s = e > -1 ? location.hash.substring(0, e) : location.hash;
|
|
15
|
+
t += s;
|
|
16
|
+
}
|
|
17
|
+
if (r.search) {
|
|
18
|
+
const e = location.hash.indexOf("?"), s = location.search || (e > -1 ? location.hash.substring(e) : "");
|
|
19
|
+
t += s;
|
|
20
|
+
}
|
|
21
|
+
return t;
|
|
22
|
+
}, d = {
|
|
23
|
+
stop() {
|
|
24
|
+
}
|
|
25
|
+
}, L = "https://api.swetrix.com/log", R = "https://api.swetrix.com", S = 300 * 1e3;
|
|
26
|
+
class A {
|
|
27
|
+
constructor(t, e) {
|
|
28
|
+
this.projectID = t, this.options = e, this.pageData = null, this.pageViewsOptions = null, this.errorsOptions = null, this.perfStatsCollected = !1, this.activePage = null, this.errorListenerExists = !1, this.cachedData = null, this.trackPathChange = this.trackPathChange.bind(this), this.heartbeat = this.heartbeat.bind(this), this.captureError = this.captureError.bind(this);
|
|
29
|
+
}
|
|
30
|
+
captureError(t) {
|
|
31
|
+
typeof this.errorsOptions?.sampleRate == "number" && this.errorsOptions.sampleRate >= Math.random() || this.submitError({
|
|
32
|
+
// The file in which error occured.
|
|
33
|
+
filename: t.filename,
|
|
34
|
+
// The line of code error occured on.
|
|
35
|
+
lineno: t.lineno,
|
|
36
|
+
// The column of code error occured on.
|
|
37
|
+
colno: t.colno,
|
|
38
|
+
// Name of the error, if not exists (i.e. it's a custom thrown error). The initial value of name is "Error", but just in case lets explicitly set it here too.
|
|
39
|
+
name: t.error?.name || "Error",
|
|
40
|
+
// Description of the error. By default, we use message from Error object, is it does not contain the error name
|
|
41
|
+
// (we want to split error name and message so we could group them together later in dashboard).
|
|
42
|
+
// If message in error object does not exist - lets use a message from the Error event itself.
|
|
43
|
+
message: t.error?.message || t.message,
|
|
44
|
+
// Stack trace of the error, if available.
|
|
45
|
+
stackTrace: t.error?.stack
|
|
46
|
+
}, !0);
|
|
47
|
+
}
|
|
48
|
+
trackErrors(t) {
|
|
49
|
+
return this.errorListenerExists || !this.canTrack() ? d : (this.errorsOptions = t, window.addEventListener("error", this.captureError), this.errorListenerExists = !0, {
|
|
50
|
+
stop: () => {
|
|
51
|
+
window.removeEventListener("error", this.captureError), this.errorListenerExists = !1;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
submitError(t, e) {
|
|
56
|
+
const s = {
|
|
57
|
+
pid: this.projectID
|
|
58
|
+
}, a = {
|
|
59
|
+
pg: this.activePage || l({
|
|
60
|
+
hash: this.pageViewsOptions?.hash,
|
|
61
|
+
search: this.pageViewsOptions?.search
|
|
62
|
+
}),
|
|
63
|
+
lc: u(),
|
|
64
|
+
tz: f(),
|
|
65
|
+
...t
|
|
66
|
+
};
|
|
67
|
+
if (e && this.errorsOptions?.callback) {
|
|
68
|
+
const i = this.errorsOptions.callback(a);
|
|
69
|
+
if (i === !1)
|
|
70
|
+
return;
|
|
71
|
+
i && typeof i == "object" && Object.assign(a, i);
|
|
72
|
+
}
|
|
73
|
+
Object.assign(a, s), this.sendRequest("error", a);
|
|
74
|
+
}
|
|
75
|
+
async track(t) {
|
|
76
|
+
if (!this.canTrack())
|
|
77
|
+
return;
|
|
78
|
+
const e = {
|
|
79
|
+
...t,
|
|
80
|
+
pid: this.projectID,
|
|
81
|
+
pg: this.activePage || l({
|
|
82
|
+
hash: this.pageViewsOptions?.hash,
|
|
83
|
+
search: this.pageViewsOptions?.search
|
|
84
|
+
}),
|
|
85
|
+
lc: u(),
|
|
86
|
+
tz: f(),
|
|
87
|
+
ref: g(),
|
|
88
|
+
so: m(),
|
|
89
|
+
me: w(),
|
|
90
|
+
ca: I(),
|
|
91
|
+
te: D(),
|
|
92
|
+
co: E(),
|
|
93
|
+
profileId: t.profileId ?? this.options?.profileId
|
|
94
|
+
};
|
|
95
|
+
await this.sendRequest("custom", e);
|
|
96
|
+
}
|
|
97
|
+
trackPageViews(t) {
|
|
98
|
+
if (!this.canTrack())
|
|
99
|
+
return d;
|
|
100
|
+
if (this.pageData)
|
|
101
|
+
return this.pageData.actions;
|
|
102
|
+
this.pageViewsOptions = t;
|
|
103
|
+
let e;
|
|
104
|
+
t?.unique || (e = setInterval(this.trackPathChange, 2e3)), setTimeout(this.heartbeat, 3e3);
|
|
105
|
+
const s = setInterval(this.heartbeat, 28e3), a = l({
|
|
106
|
+
hash: t?.hash,
|
|
107
|
+
search: t?.search
|
|
108
|
+
});
|
|
109
|
+
return this.pageData = {
|
|
110
|
+
path: a,
|
|
111
|
+
actions: {
|
|
112
|
+
stop: () => {
|
|
113
|
+
clearInterval(e), clearInterval(s);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}, this.trackPage(a, t?.unique), this.pageData.actions;
|
|
117
|
+
}
|
|
118
|
+
getPerformanceStats() {
|
|
119
|
+
if (!this.canTrack() || this.perfStatsCollected || !window.performance?.getEntriesByType)
|
|
120
|
+
return {};
|
|
121
|
+
const t = window.performance.getEntriesByType("navigation")[0];
|
|
122
|
+
return t ? (this.perfStatsCollected = !0, {
|
|
123
|
+
// Network
|
|
124
|
+
dns: t.domainLookupEnd - t.domainLookupStart,
|
|
125
|
+
// DNS Resolution
|
|
126
|
+
tls: t.secureConnectionStart ? t.requestStart - t.secureConnectionStart : 0,
|
|
127
|
+
// TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
|
|
128
|
+
conn: t.secureConnectionStart ? t.secureConnectionStart - t.connectStart : t.connectEnd - t.connectStart,
|
|
129
|
+
// Connection time
|
|
130
|
+
response: t.responseEnd - t.responseStart,
|
|
131
|
+
// Response Time (Download)
|
|
132
|
+
// Frontend
|
|
133
|
+
render: t.domComplete - t.domContentLoadedEventEnd,
|
|
134
|
+
// Browser rendering the HTML time
|
|
135
|
+
dom_load: t.domContentLoadedEventEnd - t.responseEnd,
|
|
136
|
+
// DOM loading timing
|
|
137
|
+
page_load: t.loadEventStart,
|
|
138
|
+
// Page load time
|
|
139
|
+
// Backend
|
|
140
|
+
ttfb: t.responseStart - t.requestStart
|
|
141
|
+
}) : {};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Fetches all feature flags and experiments for the project.
|
|
145
|
+
* Results are cached for 5 minutes by default.
|
|
146
|
+
*
|
|
147
|
+
* @param options - Options for evaluating feature flags.
|
|
148
|
+
* @param forceRefresh - If true, bypasses the cache and fetches fresh data.
|
|
149
|
+
* @returns A promise that resolves to a record of flag keys to boolean values.
|
|
150
|
+
*/
|
|
151
|
+
async getFeatureFlags(t, e) {
|
|
152
|
+
if (!p())
|
|
153
|
+
return {};
|
|
154
|
+
const s = t?.profileId ?? this.options?.profileId;
|
|
155
|
+
if (!e && this.cachedData) {
|
|
156
|
+
const a = Date.now();
|
|
157
|
+
if (this.cachedData.profileId === s && a - this.cachedData.timestamp < S)
|
|
158
|
+
return this.cachedData.flags;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
return await this.fetchFlagsAndExperiments(t), this.cachedData?.flags || {};
|
|
162
|
+
} catch (a) {
|
|
163
|
+
return console.warn("[Swetrix] Error fetching feature flags:", a), this.cachedData?.flags || {};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Internal method to fetch both feature flags and experiments from the API.
|
|
168
|
+
*/
|
|
169
|
+
async fetchFlagsAndExperiments(t) {
|
|
170
|
+
const e = this.getApiBase(), s = {
|
|
171
|
+
pid: this.projectID
|
|
172
|
+
}, a = t?.profileId ?? this.options?.profileId;
|
|
173
|
+
a && (s.profileId = a);
|
|
174
|
+
const i = await fetch(`${e}/feature-flag/evaluate`, {
|
|
175
|
+
method: "POST",
|
|
176
|
+
headers: {
|
|
177
|
+
"Content-Type": "application/json"
|
|
178
|
+
},
|
|
179
|
+
body: JSON.stringify(s)
|
|
180
|
+
});
|
|
181
|
+
if (!i.ok) {
|
|
182
|
+
console.warn("[Swetrix] Failed to fetch feature flags and experiments:", i.status);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const n = await i.json(), c = t?.profileId ?? this.options?.profileId;
|
|
186
|
+
this.cachedData = {
|
|
187
|
+
flags: n.flags || {},
|
|
188
|
+
experiments: n.experiments || {},
|
|
189
|
+
timestamp: Date.now(),
|
|
190
|
+
profileId: c
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Gets the value of a single feature flag.
|
|
195
|
+
*
|
|
196
|
+
* @param key - The feature flag key.
|
|
197
|
+
* @param options - Options for evaluating the feature flag.
|
|
198
|
+
* @param defaultValue - Default value to return if the flag is not found. Defaults to false.
|
|
199
|
+
* @returns A promise that resolves to the boolean value of the flag.
|
|
200
|
+
*/
|
|
201
|
+
async getFeatureFlag(t, e, s = !1) {
|
|
202
|
+
return (await this.getFeatureFlags(e))[t] ?? s;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Clears the cached feature flags and experiments, forcing a fresh fetch on the next call.
|
|
206
|
+
*/
|
|
207
|
+
clearFeatureFlagsCache() {
|
|
208
|
+
this.cachedData = null;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Fetches all A/B test experiments for the project.
|
|
212
|
+
* Results are cached for 5 minutes by default (shared cache with feature flags).
|
|
213
|
+
*
|
|
214
|
+
* @param options - Options for evaluating experiments.
|
|
215
|
+
* @param forceRefresh - If true, bypasses the cache and fetches fresh data.
|
|
216
|
+
* @returns A promise that resolves to a record of experiment IDs to variant keys.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* const experiments = await getExperiments()
|
|
221
|
+
* // experiments = { 'exp-123': 'variant-a', 'exp-456': 'control' }
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
async getExperiments(t, e) {
|
|
225
|
+
if (!p())
|
|
226
|
+
return {};
|
|
227
|
+
const s = t?.profileId ?? this.options?.profileId;
|
|
228
|
+
if (!e && this.cachedData) {
|
|
229
|
+
const a = Date.now();
|
|
230
|
+
if (this.cachedData.profileId === s && a - this.cachedData.timestamp < S)
|
|
231
|
+
return this.cachedData.experiments;
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
return await this.fetchFlagsAndExperiments(t), this.cachedData?.experiments || {};
|
|
235
|
+
} catch (a) {
|
|
236
|
+
return console.warn("[Swetrix] Error fetching experiments:", a), this.cachedData?.experiments || {};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Gets the variant key for a specific A/B test experiment.
|
|
241
|
+
*
|
|
242
|
+
* @param experimentId - The experiment ID.
|
|
243
|
+
* @param options - Options for evaluating the experiment.
|
|
244
|
+
* @param defaultVariant - Default variant key to return if the experiment is not found. Defaults to null.
|
|
245
|
+
* @returns A promise that resolves to the variant key assigned to this user, or defaultVariant if not found.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```typescript
|
|
249
|
+
* const variant = await getExperiment('checkout-redesign')
|
|
250
|
+
*
|
|
251
|
+
* if (variant === 'new-checkout') {
|
|
252
|
+
* // Show new checkout flow
|
|
253
|
+
* } else {
|
|
254
|
+
* // Show control (original) checkout
|
|
255
|
+
* }
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
async getExperiment(t, e, s = null) {
|
|
259
|
+
return (await this.getExperiments(e))[t] ?? s;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Clears the cached experiments (alias for clearFeatureFlagsCache since they share the same cache).
|
|
263
|
+
*/
|
|
264
|
+
clearExperimentsCache() {
|
|
265
|
+
this.cachedData = null;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Gets the anonymous profile ID for the current visitor.
|
|
269
|
+
* If profileId was set via init options, returns that.
|
|
270
|
+
* Otherwise, requests server to generate one from IP/UA hash.
|
|
271
|
+
*
|
|
272
|
+
* This ID can be used for revenue attribution with payment providers.
|
|
273
|
+
*
|
|
274
|
+
* @returns A promise that resolves to the profile ID string, or null on error.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* const profileId = await swetrix.getProfileId()
|
|
279
|
+
*
|
|
280
|
+
* // Pass to Paddle Checkout for revenue attribution
|
|
281
|
+
* Paddle.Checkout.open({
|
|
282
|
+
* items: [{ priceId: 'pri_01234567890', quantity: 1 }],
|
|
283
|
+
* customData: {
|
|
284
|
+
* swetrix_profile_id: profileId,
|
|
285
|
+
* swetrix_session_id: await swetrix.getSessionId()
|
|
286
|
+
* }
|
|
287
|
+
* })
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
async getProfileId() {
|
|
291
|
+
if (this.options?.profileId)
|
|
292
|
+
return this.options.profileId;
|
|
293
|
+
if (!p())
|
|
294
|
+
return null;
|
|
295
|
+
try {
|
|
296
|
+
const t = this.getApiBase(), e = await fetch(`${t}/log/profile-id`, {
|
|
297
|
+
method: "POST",
|
|
298
|
+
headers: {
|
|
299
|
+
"Content-Type": "application/json"
|
|
300
|
+
},
|
|
301
|
+
body: JSON.stringify({ pid: this.projectID })
|
|
302
|
+
});
|
|
303
|
+
return e.ok ? (await e.json()).profileId : null;
|
|
304
|
+
} catch {
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Gets the current session ID for the visitor.
|
|
310
|
+
* Session IDs are generated server-side based on IP and user agent.
|
|
311
|
+
*
|
|
312
|
+
* This ID can be used for revenue attribution with payment providers.
|
|
313
|
+
*
|
|
314
|
+
* @returns A promise that resolves to the session ID string, or null on error.
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* ```typescript
|
|
318
|
+
* const sessionId = await swetrix.getSessionId()
|
|
319
|
+
*
|
|
320
|
+
* // Pass to Paddle Checkout for revenue attribution
|
|
321
|
+
* Paddle.Checkout.open({
|
|
322
|
+
* items: [{ priceId: 'pri_01234567890', quantity: 1 }],
|
|
323
|
+
* customData: {
|
|
324
|
+
* swetrix_profile_id: await swetrix.getProfileId(),
|
|
325
|
+
* swetrix_session_id: sessionId
|
|
326
|
+
* }
|
|
327
|
+
* })
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
async getSessionId() {
|
|
331
|
+
if (!p())
|
|
332
|
+
return null;
|
|
333
|
+
try {
|
|
334
|
+
const t = this.getApiBase(), e = await fetch(`${t}/log/session-id`, {
|
|
335
|
+
method: "POST",
|
|
336
|
+
headers: {
|
|
337
|
+
"Content-Type": "application/json"
|
|
338
|
+
},
|
|
339
|
+
body: JSON.stringify({ pid: this.projectID })
|
|
340
|
+
});
|
|
341
|
+
return e.ok ? (await e.json()).sessionId : null;
|
|
342
|
+
} catch {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Gets the API base URL (without /log suffix).
|
|
348
|
+
*/
|
|
349
|
+
getApiBase() {
|
|
350
|
+
return this.options?.apiURL ? this.options.apiURL.replace(/\/log\/?$/, "") : R;
|
|
351
|
+
}
|
|
352
|
+
heartbeat() {
|
|
353
|
+
if (!this.pageViewsOptions?.heartbeatOnBackground && document.visibilityState === "hidden")
|
|
354
|
+
return;
|
|
355
|
+
const t = {
|
|
356
|
+
pid: this.projectID
|
|
357
|
+
};
|
|
358
|
+
this.options?.profileId && (t.profileId = this.options.profileId), this.sendRequest("hb", t);
|
|
359
|
+
}
|
|
360
|
+
// Tracking path changes. If path changes -> calling this.trackPage method
|
|
361
|
+
trackPathChange() {
|
|
362
|
+
if (!this.pageData)
|
|
363
|
+
return;
|
|
364
|
+
const t = l({
|
|
365
|
+
hash: this.pageViewsOptions?.hash,
|
|
366
|
+
search: this.pageViewsOptions?.search
|
|
367
|
+
}), { path: e } = this.pageData;
|
|
368
|
+
e !== t && this.trackPage(t, !1);
|
|
369
|
+
}
|
|
370
|
+
trackPage(t, e = !1) {
|
|
371
|
+
if (!this.pageData)
|
|
372
|
+
return;
|
|
373
|
+
this.pageData.path = t;
|
|
374
|
+
const s = this.getPerformanceStats();
|
|
375
|
+
this.activePage = t, this.submitPageView({ pg: t }, e, s, !0);
|
|
376
|
+
}
|
|
377
|
+
submitPageView(t, e, s, a) {
|
|
378
|
+
const i = {
|
|
379
|
+
pid: this.projectID,
|
|
380
|
+
perf: s,
|
|
381
|
+
unique: e
|
|
382
|
+
}, n = {
|
|
383
|
+
lc: u(),
|
|
384
|
+
tz: f(),
|
|
385
|
+
ref: g(),
|
|
386
|
+
so: m(),
|
|
387
|
+
me: w(),
|
|
388
|
+
ca: I(),
|
|
389
|
+
te: D(),
|
|
390
|
+
co: E(),
|
|
391
|
+
profileId: this.options?.profileId,
|
|
392
|
+
...t
|
|
393
|
+
};
|
|
394
|
+
if (a && this.pageViewsOptions?.callback) {
|
|
395
|
+
const c = this.pageViewsOptions.callback(n);
|
|
396
|
+
if (c === !1)
|
|
397
|
+
return;
|
|
398
|
+
c && typeof c == "object" && Object.assign(n, c);
|
|
399
|
+
}
|
|
400
|
+
Object.assign(n, i), this.sendRequest("", n);
|
|
401
|
+
}
|
|
402
|
+
canTrack() {
|
|
403
|
+
return !(this.options?.disabled || !p() || this.options?.respectDNT && window.navigator?.doNotTrack === "1" || !this.options?.devMode && _() || j());
|
|
404
|
+
}
|
|
405
|
+
async sendRequest(t, e) {
|
|
406
|
+
const s = this.options?.apiURL || L;
|
|
407
|
+
await fetch(`${s}/${t}`, {
|
|
408
|
+
method: "POST",
|
|
409
|
+
headers: {
|
|
410
|
+
"Content-Type": "application/json"
|
|
411
|
+
},
|
|
412
|
+
body: JSON.stringify(e)
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
let o = null;
|
|
417
|
+
function V(r, t) {
|
|
418
|
+
return o || (o = new A(r, t)), o;
|
|
419
|
+
}
|
|
420
|
+
function F(r) {
|
|
421
|
+
return new Promise((t) => {
|
|
422
|
+
if (!o) {
|
|
423
|
+
t(d);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
typeof document > "u" || document.readyState === "complete" ? t(o.trackPageViews(r)) : window.addEventListener("load", () => {
|
|
427
|
+
t(o.trackPageViews(r));
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
function B(r) {
|
|
432
|
+
return o ? o.trackErrors(r) : d;
|
|
433
|
+
}
|
|
434
|
+
const q = /* @__PURE__ */ y({
|
|
435
|
+
__name: "Swetrix",
|
|
436
|
+
props: {
|
|
437
|
+
swetrix: {}
|
|
438
|
+
},
|
|
439
|
+
setup(r) {
|
|
440
|
+
const e = r.swetrix;
|
|
441
|
+
let s = !1;
|
|
442
|
+
function a() {
|
|
443
|
+
typeof window > "u" || s || (s = !0, V(e.id, e.options), F(), B());
|
|
444
|
+
}
|
|
445
|
+
return e?.id && b(a), (i, n) => null;
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
export {
|
|
449
|
+
q as default
|
|
450
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineComponent as O, watch as I, onUnmounted as P, nextTick as B, openBlock as L, createElementBlock as z, Fragment as T, createElementVNode as g } from "vue";
|
|
2
2
|
import { useRouter as U, inBrowser as D } from "vitepress";
|
|
3
|
-
import { b as F, v as M, r as H } from "./index-
|
|
3
|
+
import { b as F, v as M, r as H } from "./index-C43AnX3f.js";
|
|
4
4
|
const j = /* @__PURE__ */ O({
|
|
5
5
|
__name: "VPAlgoliaSearchBox",
|
|
6
6
|
props: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent as d, ref as l, watch as t, onMounted as p, openBlock as f, createElementBlock as u } from "vue";
|
|
2
|
-
import { b as _, j as m, _ as b } from "./index-
|
|
2
|
+
import { b as _, j as m, _ as b } from "./index-C43AnX3f.js";
|
|
3
3
|
const v = /* @__PURE__ */ d({
|
|
4
4
|
__name: "VPCarbonAds",
|
|
5
5
|
props: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { shallowRef as Z, watch as Le, computed as Se, toValue as He, readonly as Et, defineComponent as Tt, ref as ue, watchEffect as It, onMounted as Ne, nextTick as de, onBeforeUnmount as kt, openBlock as B, createBlock as Nt, Teleport as Ft, createElementVNode as T, withModifiers as Rt, unref as C, withDirectives as At, isRef as Ot, vModelText as Ct, createElementBlock as H, normalizeClass as qe, createCommentVNode as me, Fragment as Ge, renderList as Qe, createTextVNode as fe, toDisplayString as he, markRaw as Ye, createApp as Mt } from "vue";
|
|
2
2
|
import Lt from "@localSearchIndex";
|
|
3
|
-
import { t as Dt, u as Pt, n as zt, a as Vt, i as jt, s as Ze, b as ct, c as Xe, d as $t, e as Bt, w as Wt, o as ge, f as Kt, g as Jt, h as Ut, _ as Ht } from "./index-
|
|
3
|
+
import { t as Dt, u as Pt, n as zt, a as Vt, i as jt, s as Ze, b as ct, c as Xe, d as $t, e as Bt, w as Wt, o as ge, f as Kt, g as Jt, h as Ut, _ as Ht } from "./index-C43AnX3f.js";
|
|
4
4
|
import { useRouter as qt, dataSymbol as Gt, inBrowser as Qt } from "vitepress";
|
|
5
5
|
import Yt from "@siteData";
|
|
6
6
|
var ut = ["input:not([inert]):not([inert] *)", "select:not([inert]):not([inert] *)", "textarea:not([inert]):not([inert] *)", "a[href]:not([inert]):not([inert] *)", "button:not([inert]):not([inert] *)", "[tabindex]:not(slot):not([inert]):not([inert] *)", "audio[controls]:not([inert]):not([inert] *)", "video[controls]:not([inert]):not([inert] *)", '[contenteditable]:not([contenteditable="false"]):not([inert]):not([inert] *)', "details>summary:first-of-type:not([inert]):not([inert] *)", "details:not([inert]):not([inert] *)"], _e = /* @__PURE__ */ ut.join(","), dt = typeof Element > "u", X = dt ? function() {
|