Compare commits
2 commits
4f52d12629
...
345c22e561
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
345c22e561 | ||
|
|
0562fd2bd3 |
3 changed files with 255 additions and 3 deletions
104
site/public/js/pw-crtc-collapse.css
Normal file
104
site/public/js/pw-crtc-collapse.css
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/* pw-crtc-collapse.css — styles for the CRTC page reading aid (TL;DR + accordions). */
|
||||
|
||||
.pw-tldr {
|
||||
border: 1px solid #cfe0f5;
|
||||
background: linear-gradient(135deg, #f0f6ff 0%, #eef9f3 100%);
|
||||
border-radius: 14px;
|
||||
padding: 1.1rem 1.25rem;
|
||||
margin: 0 0 1.75rem;
|
||||
}
|
||||
.pw-tldr-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1.05rem;
|
||||
color: #1a2744;
|
||||
}
|
||||
.pw-tldr-badge {
|
||||
background: #059669;
|
||||
color: #fff;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.02em;
|
||||
text-transform: uppercase;
|
||||
padding: 0.18rem 0.5rem;
|
||||
border-radius: 999px;
|
||||
}
|
||||
.pw-tldr-lead {
|
||||
margin: 0 0 0.85rem;
|
||||
color: #334155;
|
||||
font-size: 0.96rem;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.pw-tldr-jump {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.pw-tldr-jump > span {
|
||||
color: #64748b;
|
||||
font-weight: 600;
|
||||
margin-right: 0.15rem;
|
||||
}
|
||||
.pw-tldr-chip {
|
||||
display: inline-block;
|
||||
padding: 0.28rem 0.7rem;
|
||||
background: #fff;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 999px;
|
||||
color: #1d4ed8;
|
||||
text-decoration: none;
|
||||
font-size: 0.82rem;
|
||||
transition: background 0.12s, border-color 0.12s;
|
||||
}
|
||||
.pw-tldr-chip:hover {
|
||||
background: #1d4ed8;
|
||||
color: #fff;
|
||||
border-color: #1d4ed8;
|
||||
}
|
||||
|
||||
/* Collapsible section */
|
||||
.pw-collapse {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 12px;
|
||||
margin: 0.75rem 0;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
.pw-collapse[open] {
|
||||
box-shadow: 0 1px 4px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
.pw-collapse-summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.95rem 1.15rem;
|
||||
font-weight: 600;
|
||||
font-size: 1.05rem;
|
||||
color: #1a2744;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
user-select: none;
|
||||
}
|
||||
.pw-collapse-summary::-webkit-details-marker { display: none; }
|
||||
.pw-collapse-summary::before {
|
||||
content: "";
|
||||
flex: 0 0 auto;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
border-right: 2px solid #2d4e78;
|
||||
border-bottom: 2px solid #2d4e78;
|
||||
transform: rotate(-45deg);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
.pw-collapse[open] > .pw-collapse-summary::before {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.pw-collapse-summary:hover { background: #f8fafc; }
|
||||
.pw-collapse-body {
|
||||
padding: 0 1.15rem 1.1rem;
|
||||
}
|
||||
.pw-collapse-body > h2 { display: none; }
|
||||
148
site/public/js/pw-crtc-collapse.js
Normal file
148
site/public/js/pw-crtc-collapse.js
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* pw-crtc-collapse.js — progressive-enhancement reading aid for the long
|
||||
* Canada CRTC carrier page (public/services/telecom/canada-crtc/index.html).
|
||||
*
|
||||
* Why a runtime script instead of editing the HTML: that page is a single
|
||||
* 183 KB minified file with auto-generated markup whose section headings sit
|
||||
* at inconsistent DOM depths. Rewriting it by hand risks corrupting the markup
|
||||
* and is hard to maintain. This script enhances it non-destructively:
|
||||
*
|
||||
* 1. Injects a "5-minute read" TL;DR + jump menu at the top of the article.
|
||||
* 2. Collapses a curated set of deep-detail H2 sections into <details>-style
|
||||
* accordions (collapsed by default) so the page reads short, while every
|
||||
* word remains present for SEO and for anyone who expands it.
|
||||
*
|
||||
* It is idempotent (guards against double-run) and degrades gracefully: with
|
||||
* JS off, the full page renders exactly as before.
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
if (window.__pwCrtcCollapse) return;
|
||||
window.__pwCrtcCollapse = true;
|
||||
|
||||
// H2 headings (matched by normalized text prefix) to collapse by default.
|
||||
// Order here is also the order used in the TL;DR jump menu.
|
||||
var COLLAPSE = [
|
||||
{ key: "why canada", label: "Why Canada: FCC vs CRTC" },
|
||||
{ key: "corporate tax comparison", label: "Corporate tax comparison (BC vs US)" },
|
||||
{ key: "canada telecom m&a", label: "Canada telecom M&A climate" },
|
||||
{ key: "step 6: canadian business banking", label: "Canadian business banking" },
|
||||
{ key: "included: canadian wholesale", label: "Wholesale vendor directory" },
|
||||
{ key: "frequently asked questions", label: "FAQ", open: false },
|
||||
{ key: "us wholesale voice market", label: "US wholesale / DID restrictions" },
|
||||
{ key: "the growing burden", label: "The growing burden of a US carrier" },
|
||||
{ key: "what you'll need", label: "What you'll need to get started" }
|
||||
];
|
||||
|
||||
function norm(s) {
|
||||
return (s || "").replace(/\s+/g, " ").trim().toLowerCase();
|
||||
}
|
||||
|
||||
function ready(fn) {
|
||||
if (document.readyState !== "loading") fn();
|
||||
else document.addEventListener("DOMContentLoaded", fn);
|
||||
}
|
||||
|
||||
ready(function () {
|
||||
var h2s = Array.prototype.slice.call(document.querySelectorAll("h2"));
|
||||
if (!h2s.length) return;
|
||||
|
||||
var made = [];
|
||||
|
||||
COLLAPSE.forEach(function (cfg) {
|
||||
var h2 = h2s.find(function (h) {
|
||||
return norm(h.textContent).indexOf(cfg.key) === 0 ||
|
||||
norm(h.textContent).indexOf(cfg.key) !== -1;
|
||||
});
|
||||
if (!h2 || h2.dataset.pwCollapsed) return;
|
||||
|
||||
var parent = h2.parentNode;
|
||||
// Collect this H2 plus its following siblings up to the next H2 sibling.
|
||||
var nodes = [h2];
|
||||
var n = h2.nextSibling;
|
||||
while (n) {
|
||||
if (n.nodeType === 1 && n.tagName === "H2") break;
|
||||
var next = n.nextSibling;
|
||||
// Skip (don't absorb) a standalone block such as the "is this real?"
|
||||
// proof expander — it must stay visible outside any collapsed body.
|
||||
// We leave it in place; surrounding siblings still get collected, so it
|
||||
// ends up rendered right after this accordion.
|
||||
if (!(n.nodeType === 1 && n.classList &&
|
||||
n.classList.contains("pw-standalone"))) {
|
||||
nodes.push(n);
|
||||
}
|
||||
n = next;
|
||||
}
|
||||
if (nodes.length < 2) {
|
||||
// Heading has no sibling body at this level (body nested elsewhere);
|
||||
// skip rather than risk an empty/incorrect accordion.
|
||||
return;
|
||||
}
|
||||
|
||||
var details = document.createElement("details");
|
||||
details.className = "pw-collapse";
|
||||
if (cfg.open) details.open = true;
|
||||
|
||||
var summary = document.createElement("summary");
|
||||
summary.className = "pw-collapse-summary";
|
||||
summary.textContent = h2.textContent.replace(/\s+/g, " ").trim();
|
||||
details.appendChild(summary);
|
||||
|
||||
var body = document.createElement("div");
|
||||
body.className = "pw-collapse-body";
|
||||
|
||||
// Move the original H2 (hidden, keeps heading in DOM for SEO) + siblings in.
|
||||
h2.style.display = "none";
|
||||
h2.dataset.pwCollapsed = "1";
|
||||
parent.insertBefore(details, nodes[0]);
|
||||
nodes.forEach(function (node) { body.appendChild(node); });
|
||||
details.appendChild(body);
|
||||
|
||||
var id = "crtc-" + cfg.key.replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
||||
details.id = id;
|
||||
made.push({ id: id, label: cfg.label });
|
||||
});
|
||||
|
||||
if (!made.length) return;
|
||||
|
||||
// Build the TL;DR + jump menu and insert it right after the hero/pricing card.
|
||||
var anchor = document.querySelector("nav[aria-label], .max-w-4xl") || document.body;
|
||||
var tldr = document.createElement("div");
|
||||
tldr.className = "pw-tldr";
|
||||
tldr.innerHTML =
|
||||
'<div class="pw-tldr-head">' +
|
||||
'<span class="pw-tldr-badge">5-min read</span>' +
|
||||
'<strong>The short version</strong></div>' +
|
||||
'<p class="pw-tldr-lead">Become a single <strong>Canadian CRTC/BITS carrier</strong> ' +
|
||||
'and lawfully serve US & international customers \u2014 without taking on the US ' +
|
||||
'FCC 499/USF, RMD, STIR/SHAKEN and state-PUC stack a US carrier carries. ' +
|
||||
'A Canadian carrier serving US customers as one entity is a common, established ' +
|
||||
'structure (per public FCC records). Details below are optional \u2014 tap any to expand.</p>' +
|
||||
'<div class="pw-tldr-jump"><span>Jump to:</span></div>';
|
||||
|
||||
var jump = tldr.querySelector(".pw-tldr-jump");
|
||||
made.forEach(function (m) {
|
||||
var a = document.createElement("a");
|
||||
a.href = "#" + m.id;
|
||||
a.className = "pw-tldr-chip";
|
||||
a.textContent = m.label;
|
||||
a.addEventListener("click", function (e) {
|
||||
var d = document.getElementById(m.id);
|
||||
if (d) {
|
||||
d.open = true;
|
||||
e.preventDefault();
|
||||
d.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
}
|
||||
});
|
||||
jump.appendChild(a);
|
||||
});
|
||||
|
||||
// Insert TL;DR before the first collapsed section for a clean top-of-article placement.
|
||||
var firstDetails = document.querySelector("details.pw-collapse");
|
||||
if (firstDetails && firstDetails.parentNode) {
|
||||
firstDetails.parentNode.insertBefore(tldr, firstDetails);
|
||||
} else {
|
||||
anchor.insertBefore(tldr, anchor.firstChild);
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue