Site code for clinicontact.com. Everything builds into one JS file that Webflow loads once per page. Webflow embeds become tiny mount points, so the 10,000-character embed limit stops being a constraint.
src/ ──build──> dist/cc.min.js ──CDN──> Webflow page
<script> tag in Webflow Page Settings → Custom Code → Before </body><div data-cc="nav"></div>npm install && npm run build
python3 -m http.server 8899
Then open:
| Page | URL |
|---|---|
| Redesigned homepage | http://localhost:8899/test/redesign.html |
| Solutions (by audience) | http://localhost:8899/test/solutions.html |
| How We Partner | http://localhost:8899/test/partner.html |
| Our Work | http://localhost:8899/test/work.html |
Nothing live, safe to click through. local.html and chat.html are component harnesses.
Note the chat will show “service temporarily unavailable” on localhost — the backend only allows clinicontact.com origins. That is CORS, not a bug, and it resolves on the real domain.
npm install
npm run dev # watch mode, rebuilds on save
npm run build # minified production build
Then serve the repo and open the harness, which simulates a Webflow page:
python3 -m http.server 8899
# http://localhost:8899/test/local.html
Commit dist/cc.min.js (it is intentionally not gitignored), then load it via jsDelivr:
<script src="https://cdn.jsdelivr.net/gh/CliniContact/CliniContact-Website@main/dist/cc.min.js"></script>
@main always serves latest but is cached ~12h. For instant cache-busting, tag a release
and pin the version — @v0.1.0 — which is served immutably and is the safer habit:
git tag v0.1.0 && git push --tags
src/modules/<name>/index.jsinjectCSS('<name>', css)define('<name>', mountFn)src/main.js<div data-cc="<name>"></div> into a Webflow embed| Thing | Where |
|---|---|
| Backend URL, lead endpoint, thank-you URL | src/core/api.js |
| Brand tokens (colors, fonts, radius) | src/core/tokens.css |
| Nav links & product structure | src/modules/nav/nav.data.js |
| Contact modal | src/modules/contact/ |
Page-level singleton. Any element on any page opens it — no extra embed, no extra JS:
<button data-cc-contact>Request a proposal</button>
Also available as window.CC.openContact(), and deep-linkable via ?contact=true.
The homepage and Solutions page each shipped their own copy of the nav, and the two drifted. Both now run the same module; where they disagreed, this is what won and why.
| Behaviour | Canonical | Why |
|---|---|---|
| Persona value for sites | Research Site or Investigator Network |
Matches the homepage and the B2B modal. The Solutions copy sent Research Site or Investigator, splitting one segment across two values in Monday. |
| On successful submit | Redirect to /thank-you |
Almost certainly the conversion trigger in GA/Ads. The Solutions copy stayed on the page, so its leads never fired a conversion. |
?contact=true |
Always opens the modal | The Solutions copy omitted the check entirely, so campaign deep-links silently no-opped. |
| Persona option count | 6 | Recovered from the orphaned B2B modal; the live nav offered 4 and had no academic option. |
If the redirect is ever swapped for stay-on-page, set up a replacement conversion trigger first — otherwise lead measurement goes dark.
The old embeds used <div id="cc-nav">. That id still mounts the new nav, so pages can be
migrated one at a time instead of in a single sweep. See LEGACY_IDS in src/core/mount.js.
| Module | Embed | State |
|---|---|---|
| Nav | data-cc="nav" |
product-shaped now (NAV_LINKS = PRODUCT_NAV). “Platform” is a mega-menu that teaches the products; “Pricing” is a top-level link. Add data-cc-dark on dark-hero pages (homepage). Old capability nav kept as CURRENT_NAV for rollback. |
| Quote modal | (none — global) | opens forms.clinicontact.com/pricing in an iframe; triggered by any data-cc-contact (value → ?source=). Replaces the old /api/lead form. |
| Stats / Our Results | data-cc="stats" |
ported |
| Footer | data-cc="footer" |
ported (homepage + Solutions were identical) |
| Alternating sections | data-cc="sections" data-cc-page="solutions" |
ported, data-driven — product pages are new data, not new code |
| Our Work / case studies | data-cc="work" |
ported; Navidea removed, consent now recorded |
| Hero (redesigned) | data-cc="hero" |
new — journey spine, no enrollment promise |
| Partner logos | data-cc="logos" |
new — 12 institutions |
| Product sections | data-cc="sections" data-cc-page="products" |
new — Horizon / Bridge / Screener / Vision |
| Protocol-complexity proof | data-cc="proof" |
new — replaces volume stats |
| How We Partner | data-cc="partner" |
new — engagement model |
| Pricing | data-cc="pricing" |
new — Pricing page only, not the homepage |
| Participant off-ramp | data-cc="participant" |
new — routes to Beacon |
| Newsletter | data-cc="newsletter" |
links to the “Protocol to Patients” LinkedIn newsletter (no backend) |
| B2B chat assistant | data-cc="chat" |
ported, but cut from the redesign (stale copy, largest block on the page) |