@justai/cuts 0.25.1 → 0.26.0
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 +3 -3
- package/src/Base.astro +2 -68
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justai/cuts",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A persona's named parts
|
|
3
|
+
"version": "0.26.0",
|
|
4
|
+
"description": "A persona's named parts \u2014 the page shell that holds them, and the cuts themselves.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -29,6 +29,6 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@justai/core": "^0.
|
|
32
|
+
"@justai/core": "^0.4.0"
|
|
33
33
|
}
|
|
34
34
|
}
|
package/src/Base.astro
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
import { dir as dirOf } from "@justai/ui/locale";
|
|
30
30
|
// The load-bearing behaviour is framework-free and lives in @justai/core, so `feed` (Next) injects the
|
|
31
31
|
// SAME strings instead of hand-copying them. This binding just decides where they go in an Astro head.
|
|
32
|
-
import { AUTH_CAPTURE_JS, JS_CLASS_JS, REVEAL_CSS, analyticsJs, consentCopy } from "@justai/core";
|
|
32
|
+
import { AUTH_CAPTURE_JS, CONSENT_JS, JS_CLASS_JS, REVEAL_CSS, analyticsJs, consentCopy } from "@justai/core";
|
|
33
33
|
// The consent ask IS a confirmation — a moment of trust — so it rides the fleet's ONE dialog
|
|
34
34
|
// rather than keeping a private dialect. One anatomy for "are you sure?" and "may I count you?".
|
|
35
35
|
import ConfirmSheet from "./ConfirmSheet.astro";
|
|
@@ -217,73 +217,7 @@ const localePath = (l: string) => (l === defaultLocale ? "/" : `/${l}/`);
|
|
|
217
217
|
<ConfirmSheet id="consent" ask body={consent.consentText}
|
|
218
218
|
actionLabel={consent.consentAllow} cancelLabel={consent.consentDecline} cancelValue="denied"
|
|
219
219
|
data-choice-label={consent.consentChoice} />
|
|
220
|
-
<script is:inline
|
|
221
|
-
(function () {
|
|
222
|
-
try {
|
|
223
|
-
// same non-production guard as the analytics block: no measurement → nothing to consent to
|
|
224
|
-
var h = location.hostname;
|
|
225
|
-
if (h === "localhost" || h === "127.0.0.1" || h === "::1" || h === "[::1]" || h.indexOf("dev-") === 0) return;
|
|
226
|
-
var el = document.getElementById("consent"); if (!el || !el.showModal) return;
|
|
227
|
-
// returnValue survives a close, so reset before every open or a stale answer replays.
|
|
228
|
-
var open = function () { if (!el.open) { el.returnValue = ""; el.showModal(); } };
|
|
229
|
-
el.addEventListener("close", function () {
|
|
230
|
-
var rv = el.returnValue;
|
|
231
|
-
// "confirm" = the ❤️. "denied" = a CHOSEN "Stay invisible" (the sheet's cancelValue).
|
|
232
|
-
// Anything else (Escape, a backdrop tap) is NOT an answer, and ONLY A CHOICE MAY BE
|
|
233
|
-
// REMEMBERED AS A CHOICE (founder's law, 2026-07-24 — an earlier draft recorded the
|
|
234
|
-
// slip-away as a "quiet no", i.e. an answer the visitor never gave). A slip-away
|
|
235
|
-
// stores nothing: analytics stays at the regional default and the ask RETURNS on the
|
|
236
|
-
// next visit; the session flag below just keeps THIS visit quiet — one dodge buys one
|
|
237
|
-
// visit of peace, not an answer.
|
|
238
|
-
var v = rv === "confirm" ? "granted" : rv === "denied" ? "denied" : null;
|
|
239
|
-
if (v) {
|
|
240
|
-
gtag("consent", "update", { analytics_storage: v });
|
|
241
|
-
try { localStorage.setItem("consent", v); } catch (_) {}
|
|
242
|
-
} else {
|
|
243
|
-
try { sessionStorage.setItem("consent-later", "1"); } catch (_) {}
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
// THE CHANGE-YOUR-MIND DOOR — and it is universal, not a consent-region courtesy. Trust is
|
|
247
|
-
// the choice staying reachable: the Posts cut's footer carries a hidden anchor
|
|
248
|
-
// ([data-consent-open]); this script labels it, reveals it, and wires it to reopen the
|
|
249
|
-
// sheet for ANY visitor in ANY region, stored choice or not. A non-EEA visitor gets a real
|
|
250
|
-
// opt-out they were never offered before; an EEA visitor can reverse either answer. The
|
|
251
|
-
// auto-ask below keeps its narrow gates — the DOOR has none.
|
|
252
|
-
var doors = document.querySelectorAll("[data-consent-open]");
|
|
253
|
-
for (var i = 0; i < doors.length; i++) {
|
|
254
|
-
var a = doors[i];
|
|
255
|
-
if (!a.textContent) a.textContent = el.getAttribute("data-choice-label") || "privacy choice";
|
|
256
|
-
a.hidden = false;
|
|
257
|
-
var w = a.closest("[data-consent-door]"); if (w) w.hidden = false;
|
|
258
|
-
a.addEventListener("click", function (ev) { ev.preventDefault(); open(); });
|
|
259
|
-
}
|
|
260
|
-
// auto-ask: no stored CHOICE, not already dodged THIS visit, only where consent is
|
|
261
|
-
// legally asked, only on a content page
|
|
262
|
-
if (localStorage.getItem("consent")) return;
|
|
263
|
-
try { if (sessionStorage.getItem("consent-later")) return; } catch (_) {}
|
|
264
|
-
if (!document.getElementById("kernel")) return; // no kernel = not a content page (e.g. 404) — don't ask for consent on a dead end
|
|
265
|
-
// WHERE CONSENT IS LEGALLY ASKED — and a timezone is a PROXY for that, never the thing
|
|
266
|
-
// itself. `Europe/` carries almost all of the region list in the head, but not all of it:
|
|
267
|
-
// an EEA country can sit in another continent's zone entirely, and those visitors were
|
|
268
|
-
// DENIED by the regional default while never being offered the dialog — no path to
|
|
269
|
-
// consent at all. Twelve zones, measured, listed here with the country that owns them.
|
|
270
|
-
// The two lists are siblings: if the region array up there ever changes, this changes too.
|
|
271
|
-
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone || "";
|
|
272
|
-
var asked = tz.indexOf("Europe/") === 0 || [
|
|
273
|
-
"Asia/Nicosia", "Asia/Famagusta", // Cyprus
|
|
274
|
-
"Atlantic/Canary", // Spain — Canary Islands
|
|
275
|
-
"Atlantic/Azores", "Atlantic/Madeira", // Portugal
|
|
276
|
-
"Atlantic/Reykjavik", // Iceland
|
|
277
|
-
"Arctic/Longyearbyen", // Norway — Svalbard
|
|
278
|
-
"America/Guadeloupe", "America/Martinique", "America/Cayenne", // France — outermost
|
|
279
|
-
"Indian/Reunion", "Indian/Mayotte" // regions; EU law applies
|
|
280
|
-
].indexOf(tz) >= 0;
|
|
281
|
-
if (!asked) return;
|
|
282
|
-
// the first second belongs to the kernel; the question arrives on the second beat
|
|
283
|
-
setTimeout(open, 700);
|
|
284
|
-
} catch (_) {}
|
|
285
|
-
})();
|
|
286
|
-
</script>
|
|
220
|
+
<script is:inline set:html={CONSENT_JS} />
|
|
287
221
|
)}
|
|
288
222
|
</body>
|
|
289
223
|
</html>
|