@escape-game-over/atlas 0.1.58 → 0.1.59
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/package.json +1 -1
- package/src/analytics/drip.ts +16 -0
- package/src/analytics/index.ts +7 -0
- package/src/astro/ConsentBanner.astro +3 -1
- package/src/astro/Drip.astro +18 -0
- package/src/astro/client.ts +1 -0
- package/src/astro/drip-event.ts +24 -0
- package/src/astro/drip.ts +37 -0
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { warn } from "../warn.ts";
|
|
2
|
+
|
|
3
|
+
/** Drip's site tracking. Marketing: it loads only once a visitor grants that. */
|
|
4
|
+
export interface DripSettings {
|
|
5
|
+
/** From Drip's Site Setup: digits, the `_dcs.account` of its snippet. */
|
|
6
|
+
readonly accountId: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Warns about an id that is not an account id: it would report nowhere. */
|
|
10
|
+
export function checkDrip(drip: DripSettings | undefined, at: string): void {
|
|
11
|
+
if (drip === undefined || /^\d+$/.test(drip.accountId)) return;
|
|
12
|
+
warn(
|
|
13
|
+
at,
|
|
14
|
+
`Drip account id "${drip.accountId}" is not all digits, so it reports nowhere. Copy it from Drip's Site Setup.`
|
|
15
|
+
);
|
|
16
|
+
}
|
package/src/analytics/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { MetaTag } from "../meta/tag.ts";
|
|
2
2
|
import type { HttpsUrl } from "../url.ts";
|
|
3
3
|
import { type AxonPixelSettings, checkAxonPixel } from "./axon-pixel.ts";
|
|
4
|
+
import { checkDrip, type DripSettings } from "./drip.ts";
|
|
4
5
|
import { type GoogleSettings, googleEmits, googleScripts } from "./google.ts";
|
|
5
6
|
import { checkMetaPixel, type MetaPixelSettings } from "./meta-pixel.ts";
|
|
6
7
|
import { checkSnapPixel, type SnapPixelSettings } from "./snap-pixel.ts";
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
*/
|
|
29
30
|
|
|
30
31
|
export type { AxonPixelSettings } from "./axon-pixel.ts";
|
|
32
|
+
export type { DripSettings } from "./drip.ts";
|
|
31
33
|
export {
|
|
32
34
|
CONSENT_UPDATE_GLOBAL,
|
|
33
35
|
type ConsentDefaults,
|
|
@@ -56,6 +58,8 @@ export interface AnalyticsSettings {
|
|
|
56
58
|
readonly snapchat?: SnapPixelSettings;
|
|
57
59
|
/** Loaded by `ConsentBanner`, after marketing is granted. */
|
|
58
60
|
readonly axon?: AxonPixelSettings;
|
|
61
|
+
/** Loaded by `ConsentBanner`, after marketing is granted. */
|
|
62
|
+
readonly drip?: DripSettings;
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
/**
|
|
@@ -80,6 +84,7 @@ export function analyticsScripts(
|
|
|
80
84
|
checkTikTokPixel(analytics.tiktok, origin);
|
|
81
85
|
checkSnapPixel(analytics.snapchat, origin);
|
|
82
86
|
checkAxonPixel(analytics.axon, origin);
|
|
87
|
+
checkDrip(analytics.drip, origin);
|
|
83
88
|
const google = googleScripts(analytics.google, origin);
|
|
84
89
|
return {
|
|
85
90
|
head: [...google.head, ...umamiScripts(analytics.umami)],
|
|
@@ -126,6 +131,8 @@ export function consentVendors(
|
|
|
126
131
|
snapchat: analytics.snapchat !== undefined,
|
|
127
132
|
// No consent mode at all.
|
|
128
133
|
axon: analytics.axon !== undefined,
|
|
134
|
+
// No consent mode at all.
|
|
135
|
+
drip: analytics.drip !== undefined,
|
|
129
136
|
};
|
|
130
137
|
|
|
131
138
|
return (Object.keys(VENDORS) as (keyof AnalyticsSettings)[]).filter(
|
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
* buttons.
|
|
6
6
|
*
|
|
7
7
|
* Renders nothing — and ships no script — when this site's analytics need no
|
|
8
|
-
* permission. Also loads the vendors that wait for consent, such as the Meta, TikTok, Snap and Axon pixels. Otherwise the banner starts hidden and shows only to a visitor
|
|
8
|
+
* permission. Also loads the vendors that wait for consent, such as the Meta, TikTok, Snap and Axon pixels and Drip. Otherwise the banner starts hidden and shows only to a visitor
|
|
9
9
|
* with no answer on record, or when a `data-consent-reopen` control is pressed.
|
|
10
10
|
*/
|
|
11
11
|
import type { HTMLAttributes } from "astro/types";
|
|
12
12
|
import { type AnalyticsSettings, consentRequired } from "../analytics/index.ts";
|
|
13
13
|
import AxonPixel from "./AxonPixel.astro";
|
|
14
14
|
import ConsentElement from "./ConsentElement.astro";
|
|
15
|
+
import Drip from "./Drip.astro";
|
|
15
16
|
import MetaPixel from "./MetaPixel.astro";
|
|
16
17
|
import SnapPixel from "./SnapPixel.astro";
|
|
17
18
|
import TikTokPixel from "./TikTokPixel.astro";
|
|
@@ -32,5 +33,6 @@ const { analytics, ...attrs } = Astro.props;
|
|
|
32
33
|
{analytics?.tiktok && <TikTokPixel settings={analytics.tiktok} />}
|
|
33
34
|
{analytics?.snapchat && <SnapPixel settings={analytics.snapchat} />}
|
|
34
35
|
{analytics?.axon && <AxonPixel settings={analytics.axon} />}
|
|
36
|
+
{analytics?.drip && <Drip settings={analytics.drip} />}
|
|
35
37
|
</>
|
|
36
38
|
)}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
/** Internal to `ConsentBanner.astro`, so Drip's script ships only where it is configured. */
|
|
3
|
+
import type { DripSettings } from "../analytics/drip.ts";
|
|
4
|
+
import AtlasElement from "./AtlasElement.astro";
|
|
5
|
+
import { dripElement } from "./drip.ts";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
readonly settings: DripSettings;
|
|
9
|
+
}
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<script src="./drip.ts" />
|
|
13
|
+
|
|
14
|
+
<AtlasElement
|
|
15
|
+
of={dripElement}
|
|
16
|
+
data-account-id={Astro.props.settings.accountId}
|
|
17
|
+
hidden
|
|
18
|
+
/>
|
package/src/astro/client.ts
CHANGED
|
@@ -16,6 +16,7 @@ export * from "./carousel.ts";
|
|
|
16
16
|
// Reading only: a form that reports what the visitor agreed to. Recording an
|
|
17
17
|
// answer stays with the banner.
|
|
18
18
|
export { type ConsentRecord, readConsent } from "./consent.ts";
|
|
19
|
+
export * from "./drip-event.ts";
|
|
19
20
|
export {
|
|
20
21
|
type Connect,
|
|
21
22
|
type ElementContext,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { readConsent } from "./consent.ts";
|
|
2
|
+
|
|
3
|
+
/** What `drip.ts` defines once marketing is granted. */
|
|
4
|
+
interface DripWindow {
|
|
5
|
+
_dcq?: unknown[][];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Records an event with Drip, to start a workflow — a lead sent, a voucher
|
|
10
|
+
* bought. Drip's events are named by the site, so any name goes.
|
|
11
|
+
*
|
|
12
|
+
* Dropped unless Drip loaded and marketing is still granted: Drip has no
|
|
13
|
+
* consent call of its own, so the check is here. An analytics call must never
|
|
14
|
+
* be the reason a page misbehaves, so a dropped event is silent.
|
|
15
|
+
*/
|
|
16
|
+
export function dripEvent(
|
|
17
|
+
action: string,
|
|
18
|
+
properties?: Readonly<Record<string, string | number | boolean>>
|
|
19
|
+
): void {
|
|
20
|
+
if (readConsent()?.marketing !== "granted") return;
|
|
21
|
+
const queue = (window as unknown as DripWindow)._dcq;
|
|
22
|
+
if (properties === undefined) queue?.push(["track", action]);
|
|
23
|
+
else queue?.push(["track", action, properties]);
|
|
24
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { appendScript } from "./append-script.ts";
|
|
2
|
+
import type { ConsentGated } from "./consent-gate.ts";
|
|
3
|
+
import { whenGranted } from "./consent-gate.ts";
|
|
4
|
+
import { element } from "./element.ts";
|
|
5
|
+
import { data } from "./ref.ts";
|
|
6
|
+
|
|
7
|
+
/** Drip's globals: a queue of calls, and the account its script reports to. */
|
|
8
|
+
interface DripWindow {
|
|
9
|
+
_dcq?: unknown[][];
|
|
10
|
+
_dcs?: { account?: string };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Drip, loaded on the first grant. Its script records visits by itself, so
|
|
15
|
+
* nothing is queued here. Drip has no consent call, so a withdrawal cannot
|
|
16
|
+
* pause what already loaded: `dripEvent` stops sending, and the next page does
|
|
17
|
+
* not load it.
|
|
18
|
+
*/
|
|
19
|
+
export function drip(accountId: string): ConsentGated {
|
|
20
|
+
let loaded = false;
|
|
21
|
+
return {
|
|
22
|
+
grant: () => {
|
|
23
|
+
if (loaded) return;
|
|
24
|
+
loaded = true;
|
|
25
|
+
const global = window as unknown as DripWindow;
|
|
26
|
+
global._dcq ??= [];
|
|
27
|
+
global._dcs ??= {};
|
|
28
|
+
global._dcs.account = accountId;
|
|
29
|
+
appendScript(`https://tag.getdrip.com/${accountId}.js`);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Internal to `Drip.astro`. */
|
|
35
|
+
export const dripElement = element("atlas-drip", ({ root, signal }) => {
|
|
36
|
+
whenGranted("marketing", drip(data(root, "account-id")), signal);
|
|
37
|
+
});
|