17 Commits

Author SHA1 Message Date
58773fc193 release: v3.0.0
Some checks failed
Code Analysis / SonarQube (push) Failing after 17s
Node.js CI / Lint and Test (push) Successful in 40s
2025-07-08 16:46:48 -07:00
5d0660c003 feat!: rename variables to avoid collision (#5)
Some checks failed
Code Analysis / SonarQube (push) Failing after 16s
Node.js CI / Lint and Test (push) Has been cancelled
### Explanation

_No response_

### Issue

_No response_

### Attestations

- [x] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/)
- [x] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/).
- [x] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/).

### Dependencies

- [x] I have pinned the dependencies to a specific patch version.

### Style

- [x] I have run the linter and resolved any errors.
- [x] My pull request uses an appropriate title, matching the conventional commit standards.
- [x] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request.

### Tests

- [ ] My contribution adds new code, and I have added tests to cover it.
- [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes.
- [ ] All new and existing tests pass locally with my changes.
- [ ] Code coverage remains at or above the configured threshold.

### Documentation

_No response_

### Versioning

Major - My pull request introduces a breaking change.

Reviewed-on: #5
Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
2025-07-08 16:46:34 -07:00
ab663e9f4b feat: add full social list to footer (#4)
Some checks failed
Code Analysis / SonarQube (push) Failing after 16s
Node.js CI / Lint and Test (push) Successful in 39s
### Explanation

_No response_

### Issue

_No response_

### Attestations

- [x] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/)
- [x] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/).
- [x] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/).

### Dependencies

- [x] I have pinned the dependencies to a specific patch version.

### Style

- [x] I have run the linter and resolved any errors.
- [x] My pull request uses an appropriate title, matching the conventional commit standards.
- [x] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request.

### Tests

- [ ] My contribution adds new code, and I have added tests to cover it.
- [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes.
- [ ] All new and existing tests pass locally with my changes.
- [ ] Code coverage remains at or above the configured threshold.

### Documentation

_No response_

### Versioning

_No response_

Reviewed-on: #4
Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
2025-07-08 16:32:40 -07:00
2bd410631b release: v2.1.0
Some checks failed
Code Analysis / SonarQube (push) Failing after 16s
Node.js CI / Lint and Test (push) Successful in 41s
2025-07-04 14:30:54 -07:00
25ec9f8e2a feat: add id to programmatically remove custom styling (#3)
Some checks failed
Code Analysis / SonarQube (push) Failing after 15s
Node.js CI / Lint and Test (push) Has been cancelled
### Explanation

_No response_

### Issue

_No response_

### Attestations

- [x] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/)
- [x] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/).
- [x] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/).

### Dependencies

- [ ] I have pinned the dependencies to a specific patch version.

### Style

- [x] I have run the linter and resolved any errors.
- [x] My pull request uses an appropriate title, matching the conventional commit standards.
- [x] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request.

### Tests

- [ ] My contribution adds new code, and I have added tests to cover it.
- [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes.
- [ ] All new and existing tests pass locally with my changes.
- [ ] Code coverage remains at or above the configured threshold.

### Documentation

_No response_

### Versioning

_No response_

Reviewed-on: #3
Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
2025-07-04 14:30:25 -07:00
1f450156c8 2.0.0
Some checks failed
Code Analysis / SonarQube (push) Failing after 18s
Node.js CI / Lint and Test (push) Successful in 43s
2025-06-27 14:22:09 -07:00
5e9d0dd11e feat: copyright should link to homepage 2025-06-27 14:21:56 -07:00
4f05dbafbb feat: remove border radius from CTA avatar
Some checks failed
Code Analysis / SonarQube (push) Failing after 16s
Node.js CI / Lint and Test (push) Successful in 43s
2025-06-12 15:23:04 -07:00
934de19c1e release: v1.8.0
Some checks failed
Node.js CI / Lint and Test (push) Successful in 1m8s
Code Analysis / SonarQube (push) Failing after 1m21s
2025-05-31 17:39:55 -07:00
4a76b22119 feat: replace audio button with donate badge
Some checks failed
Code Analysis / SonarQube (push) Has been cancelled
Node.js CI / Lint and Test (push) Has been cancelled
2025-05-31 17:39:34 -07:00
542aef157a release: v1.7.0
Some checks failed
Node.js CI / Lint and Test (push) Successful in 1m18s
Code Analysis / SonarQube (push) Failing after 1m26s
2025-05-30 21:05:18 -07:00
2e72c34c2d feat: include google ads snippet 2025-05-30 21:04:38 -07:00
c9ae8804eb feat: remove video overlay
Some checks failed
Node.js CI / Lint and Test (push) Successful in 1m13s
Code Analysis / SonarQube (push) Failing after 1m24s
2025-05-08 16:55:33 -07:00
a5f17bb2eb feat: use logo in modalx
Some checks failed
Node.js CI / Lint and Test (push) Successful in 1m18s
Code Analysis / SonarQube (push) Failing after 1m28s
2025-05-08 16:54:00 -07:00
06e58752b9 release: v1.6.0
Some checks failed
Node.js CI / Lint and Test (push) Successful in 1m13s
Code Analysis / SonarQube (push) Failing after 1m22s
2025-04-04 15:06:21 -07:00
db4dcc3090 feat: track urls and page titles 2025-04-04 15:06:04 -07:00
53aa95c9c2 fix: tweak the colours a bit
Some checks failed
Node.js CI / Lint and Test (push) Successful in 1m12s
Code Analysis / SonarQube (push) Failing after 1m22s
2025-03-31 15:42:25 -07:00
3 changed files with 373 additions and 253 deletions

View File

@ -8,5 +8,10 @@
"sonarlint.connectedMode.project": { "sonarlint.connectedMode.project": {
"connectionId": "nhcarrigan", "connectionId": "nhcarrigan",
"projectKey": "nhcarrigan_website-headers" "projectKey": "nhcarrigan_website-headers"
} },
"cSpell.words": [
"Adsense",
"nhcarrigan",
"noreferrer"
]
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "website-headers", "name": "website-headers",
"version": "1.5.0", "version": "3.0.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"type": "module", "type": "module",

View File

@ -5,10 +5,10 @@
*/ */
// #region Version // #region Version
const version = "{{ version }}"; const nhcarriganHeadersVersion = "{{ version }}";
console.log(` console.log(`
======================================== ========================================
Loading NHCarrigan library v${version}. Loading NHCarrigan library v${nhcarriganHeadersVersion}.
Copyright (c) ${new Date().getFullYear(). Copyright (c) ${new Date().getFullYear().
toString()} NHCarrigan toString()} NHCarrigan
Changelog: https://codeberg.org/nhcarrigan/website-headers/releases Changelog: https://codeberg.org/nhcarrigan/website-headers/releases
@ -19,12 +19,18 @@ Questions? Contact us at https://docs.nhcarrigan.com/about/contact
// #endregion // #endregion
// #region Query Selectors // #region Query Selectors
const head = document.querySelector("head"); const nhcarriganHeadersHead = document.querySelector("head");
const body = document.querySelector("body"); const nhcarriganHeadersBody = document.querySelector("body");
const title = document.querySelector("title"); const nhcarriganHeadersTitle = document.querySelector("title");
const description = document.querySelector(`meta[name="description"]`); const nhcarriganHeadersDescription = document.querySelector(
`meta[name="description"]`,
);
const { href: url, hostname } = window.location; const {
href: nhcarriganHeadersUrl,
hostname: nhcarriganHeadersHostname,
pathname: nhcarriganHeadersPathname,
} = window.location;
// #endregion // #endregion
@ -34,86 +40,104 @@ const { href: url, hostname } = window.location;
* The title and description are set by each website. This should * The title and description are set by each website. This should
* only load things like open graph data and favicons. * only load things like open graph data and favicons.
*/ */
const openGraphTitle = document.createElement("meta"); const nhcarriganHeadersOpenGraphTitle = document.createElement("meta");
openGraphTitle.setAttribute("property", "og:title"); nhcarriganHeadersOpenGraphTitle.setAttribute("property", "og:title");
openGraphTitle.setAttribute("content", title?.innerText ?? "NHCarrigan"); nhcarriganHeadersOpenGraphTitle.setAttribute(
const openGraphDescription = document.createElement("meta");
openGraphDescription.setAttribute("property", "og:description");
openGraphDescription.setAttribute(
"content", "content",
description?.getAttribute("content") nhcarriganHeadersTitle?.innerText ?? "NHCarrigan",
// eslint-disable-next-line stylistic/max-len
?? "We are a software engineering and community management consulting firm.",
); );
const openGraphImage = document.createElement("meta"); const nhcarriganHeadersOpenGraphDescription = document.createElement("meta");
openGraphImage.setAttribute("property", "og:image"); nhcarriganHeadersOpenGraphDescription.setAttribute(
openGraphImage.setAttribute( "property",
"og:description",
);
nhcarriganHeadersOpenGraphDescription.setAttribute(
"content",
nhcarriganHeadersDescription?.getAttribute("content")
?? "We are a software engineering and community management consulting firm.",
);
const nhcarriganHeadersOpenGraphImage = document.createElement("meta");
nhcarriganHeadersOpenGraphImage.setAttribute("property", "og:image");
nhcarriganHeadersOpenGraphImage.setAttribute(
"content", "content",
"https://cdn.nhcarrigan.com/og-image.png", "https://cdn.nhcarrigan.com/og-image.png",
); );
const openGraphUrl = document.createElement("meta"); const nhcarriganHeadersOpenGraphUrl = document.createElement("meta");
openGraphUrl.setAttribute("property", "og:url"); nhcarriganHeadersOpenGraphUrl.setAttribute("property", "og:url");
openGraphUrl.setAttribute("content", url); nhcarriganHeadersOpenGraphUrl.setAttribute("content", nhcarriganHeadersUrl);
const openGraphType = document.createElement("meta"); const nhcarriganHeadersOpenGraphType = document.createElement("meta");
openGraphType.setAttribute("property", "og:type"); nhcarriganHeadersOpenGraphType.setAttribute("property", "og:type");
openGraphType.setAttribute("content", "website"); nhcarriganHeadersOpenGraphType.setAttribute("content", "website");
const twitterCard = document.createElement("meta"); const nhcarriganHeadersTwitterCard = document.createElement("meta");
twitterCard.setAttribute("name", "twitter:card"); nhcarriganHeadersTwitterCard.setAttribute("name", "twitter:card");
twitterCard.setAttribute("content", "summary_large_image"); nhcarriganHeadersTwitterCard.setAttribute("content", "summary_large_image");
const twitterDomain = document.createElement("meta"); const nhcarriganHeadersTwitterDomain = document.createElement("meta");
twitterDomain.setAttribute("name", "twitter:domain"); nhcarriganHeadersTwitterDomain.setAttribute("name", "twitter:domain");
twitterDomain.setAttribute("content", hostname); nhcarriganHeadersTwitterDomain.setAttribute(
const twitterUrl = document.createElement("meta");
twitterUrl.setAttribute("name", "twitter:url");
twitterUrl.setAttribute("content", url);
const twitterTitle = document.createElement("meta");
twitterTitle.setAttribute("name", "twitter:title");
twitterTitle.setAttribute("content", title?.innerText ?? "NHCarrigan");
const twitterDescription = document.createElement("meta");
twitterDescription.setAttribute("name", "twitter:description");
twitterDescription.setAttribute(
"content", "content",
description?.getAttribute("content") nhcarriganHeadersHostname,
// eslint-disable-next-line stylistic/max-len );
?? "We are a software engineering and community management consulting firm.", const nhcarriganHeadersTwitterUrl = document.createElement("meta");
nhcarriganHeadersTwitterUrl.setAttribute("name", "twitter:url");
nhcarriganHeadersTwitterUrl.setAttribute("content", nhcarriganHeadersUrl);
const nhcarriganHeadersTwitterTitle = document.createElement("meta");
nhcarriganHeadersTwitterTitle.setAttribute("name", "twitter:title");
nhcarriganHeadersTwitterTitle.setAttribute(
"content",
nhcarriganHeadersTitle?.innerText ?? "NHCarrigan",
);
const nhcarriganHeadersTwitterDescription = document.createElement("meta");
nhcarriganHeadersTwitterDescription.setAttribute("name", "twitter:description");
nhcarriganHeadersTwitterDescription.setAttribute(
"content",
nhcarriganHeadersDescription?.getAttribute("content")
?? "We are a software engineering and community management consulting firm.",
);
const nhcarriganHeadersTwitterImage = document.createElement("meta");
nhcarriganHeadersTwitterImage.setAttribute("name", "twitter:image");
nhcarriganHeadersTwitterImage.setAttribute(
"content",
"https://cdn.nhcarrigan.com/og-image.png",
); );
const twitterImage = document.createElement("meta");
twitterImage.setAttribute("name", "twitter:image");
twitterImage.setAttribute("content", "https://cdn.nhcarrigan.com/og-image.png");
// #endregion // #endregion
// #region Favicon // #region Favicon
const favicon = document.createElement("link"); const nhcarriganHeadersFavicon = document.createElement("link");
favicon.rel = "icon"; nhcarriganHeadersFavicon.rel = "icon";
favicon.type = "image/x-icon"; nhcarriganHeadersFavicon.type = "image/x-icon";
favicon.href = "https://cdn.nhcarrigan.com/favicon/favicon.ico"; nhcarriganHeadersFavicon.href
const appleTouchIcon = document.createElement("link"); = "https://cdn.nhcarrigan.com/favicon/favicon.ico";
appleTouchIcon.rel = "apple-touch-icon"; const nhcarriganHeadersAppleTouchIcon = document.createElement("link");
appleTouchIcon.href = "https://cdn.nhcarrigan.com/favicon/apple-touch-icon.png"; nhcarriganHeadersAppleTouchIcon.rel = "apple-touch-icon";
const smallIcon = document.createElement("link"); nhcarriganHeadersAppleTouchIcon.href
smallIcon.rel = "icon"; = "https://cdn.nhcarrigan.com/favicon/apple-touch-icon.png";
smallIcon.href = "https://cdn.nhcarrigan.com/favicon/favicon-16x16.png"; const nhcarriganHeadersSmallIcon = document.createElement("link");
const largeIcon = document.createElement("link"); nhcarriganHeadersSmallIcon.rel = "icon";
largeIcon.rel = "icon"; nhcarriganHeadersSmallIcon.href
largeIcon.href = "https://cdn.nhcarrigan.com/favicon/favicon-32x32.png"; = "https://cdn.nhcarrigan.com/favicon/favicon-16x16.png";
const nhcarriganHeadersLargeIcon = document.createElement("link");
nhcarriganHeadersLargeIcon.rel = "icon";
nhcarriganHeadersLargeIcon.href
= "https://cdn.nhcarrigan.com/favicon/favicon-32x32.png";
// #endregion // #endregion
// #region Styles // #region Styles
const styles = document.createElement("style"); const nhcarriganHeadersStyles = document.createElement("style");
styles.innerHTML = ` nhcarriganHeadersStyles.id = "nhcarrigan-global-styles";
nhcarriganHeadersStyles.innerHTML = `
@font-face { @font-face {
font-family: 'OpenDyslexic'; font-family: 'OpenDyslexic';
src: url('https://cdn.nhcarrigan.com/fonts/OpenDyslexicMono-Regular.otf') format('opentype'); src: url('https://cdn.nhcarrigan.com/fonts/OpenDyslexicMono-Regular.otf') format('opentype');
} }
:root { :root {
--foreground: #db7093; --foreground: #2a0a18;
--background: #ffefefbb; --background: #ffb6c1bb;
} }
* { * {
@ -152,7 +176,7 @@ main {
width: 95%; width: 95%;
max-width: 1080px; max-width: 1080px;
margin: auto; margin: auto;
margin-bottom: 105px; margin-bottom: 85px;
padding: 10px; padding: 10px;
} }
footer { footer {
@ -161,7 +185,7 @@ footer {
background-color: var(--background); background-color: var(--background);
position: fixed; position: fixed;
bottom: 0; bottom: 0;
height: 95px; height: 75px;
padding: 0 10px; padding: 0 10px;
} }
#footer-inner-container { #footer-inner-container {
@ -176,11 +200,16 @@ footer {
align-items: center; align-items: center;
justify-content: space-around; justify-content: space-around;
} }
#audio-theme-button, #theme-select-button { #show-socials-button, #theme-select-button {
background: none; background: none;
border: none; border: none;
cursor: url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer; cursor: url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
color: var(--foreground); color: var(--foreground);
font-size: 1rem;
font-family: 'OpenDyslexic', monospace;
}
#show-socials-button > i, #theme-select-button > i {
font-size: 1.5rem;
} }
a { a {
color: unset; color: unset;
@ -190,40 +219,45 @@ a {
display: flex; display: flex;
align-items: center; align-items: center;
} }
#social-list {
position: absolute;
bottom: 75px;
left: 0;
right: 0;
width: 100vw;
max-width: 400px;
padding: 10px;
background-color: var(--background);
color: var(--foreground);
border-radius: 10px;
border: 1px solid var(--foreground);
display: none;
z-index: 1000;
}
.social-list-item {
padding: 10px;
}
.social-list-item > a {
display: flex;
align-items: center;
justify-content: space-between;
text-decoration: none;
}
.social-list-divider {
border: 0.5px solid var(--foreground);
}
.social-list-item:hover {
background-color: var(--foreground);
color: var(--background);
}
.is-dark { .is-dark {
--foreground: #ffefef; --foreground: #ffb6c1;
--background: #db7093bb; --background: #2a0a18bb;
}
@media screen and (prefers-reduced-motion) {
#footer-badge-container {
display: none;
}
footer, #footer-inner-container {
height: 75px;
justify-content: space-around;
}
main {
margin-bottom: 85px;
}
}
@media screen and (max-width: 1225px) {
#footer-badge-container {
grid-template-columns: repeat(4, 1fr);
}
footer {
height: 120px;
}
main {
margin-bottom: 130px;
}
} }
@media screen and (max-width: 625px) { @media screen and (max-width: 625px) {
#tree-nation-offset-website { #tree-nation-offset-website {
display: none; display: none;
} }
#footer-badge-container {
display: none;
}
footer, #footer-inner-container { footer, #footer-inner-container {
height: 50px; height: 50px;
justify-content: space-around; justify-content: space-around;
@ -238,60 +272,86 @@ a {
// #region Components // #region Components
const footer = document.createElement("footer"); const nhcarriganHeadersFooter = document.createElement("footer");
footer.innerHTML = ` nhcarriganHeadersFooter.innerHTML = `
<div id="footer-badge-container">
<img src="https://cdn.nhcarrigan.com/blinkies/bigots.gif" alt="no bigots allowed"/>
<img src="https://cdn.nhcarrigan.com/blinkies/blm.gif" alt="black lives matter"/>
<img src="https://cdn.nhcarrigan.com/blinkies/miku.gif" alt="miku fan!!!"/>
<img src="https://cdn.nhcarrigan.com/blinkies/neuro.gif" alt="neurodivergent pride"/>
<img src="https://cdn.nhcarrigan.com/blinkies/palestine.gif" alt="free palestine"/>
<img src="https://cdn.nhcarrigan.com/blinkies/technomancer.gif" alt="technomancer"/>
<img src="https://cdn.nhcarrigan.com/blinkies/trans.gif" alt="trans rights!!!"/>
<img src="https://cdn.nhcarrigan.com/blinkies/ukraine.gif" alt="glory to ukraine"/>
</div>
<div id="footer-inner-container"> <div id="footer-inner-container">
<p>&copy; Naomi Carrigan</p> <p>&copy; <a href="https://nhcarrigan.com" target="_blank">Naomi Carrigan</a></p>
<a href="https://chat.nhcarrigan.com" target="_blank" rel="noreferrer"> <button id="show-socials-button" type="button">
<i class="fa-solid fa-comments"></i> <i class="fa-solid fa-share-nodes"></i> Connect with Us
</a> </button>
<button id="theme-select-button" type="button"> <button id="theme-select-button" type="button">
<i id="theme-select-icon" class="fa-solid fa-moon"></i> <i id="theme-select-icon" class="fa-solid fa-moon"></i> Toggle Theme
</button>
<button id="audio-theme-button" type="button">
<i class="fa-solid fa-play"></i>
</button> </button>
<a href="https://buy.stripe.com/cN24iTfqu1j6b3afZ2" target="_blank" rel="noreferrer">
<img src="https://cdn.nhcarrigan.com/donate.png" alt="Donate" style="width: 70px; height: 70px;">
</a>
<div id="tree-nation-offset-website"></div> <div id="tree-nation-offset-website"></div>
</div> </div>
<div id="social-list">
<div class="social-list-item">
<a href="https://chat.nhcarrigan.com" target="_blank" rel="noreferrer">
<i class="fa-brands fa-discord"></i><span>Join our Discord~!</span>
</a>
</div>
<hr class="social-list-divider" />
<div class="social-list-item">
<a href="https://forum.nhcarrigan.com" target="_blank" rel="noreferrer">
<i class="fa-brands fa-discourse"></i><span>Sign up for our forum~!</span>
</a>
</div>
<hr class="social-list-divider" />
<div class="social-list-item">
<a href="https://git.nhcarrigan.com" target="_blank" rel="noreferrer">
<i class="fa-brands fa-git-alt"></i><span>Check out our source code~!</span>
</a>
</div>
<hr class="social-list-divider" />
<div class="social-list-item">
<a href="https://bsky.app/profile/nhcarrigan.com" target="_blank" rel="noreferrer">
<i class="fa-brands fa-bluesky"></i><span>Follow us on Bluesky~!</span>
</a>
</div>
<hr class="social-list-divider" />
<div class="social-list-item">
<a href="https://www.linkedin.com/company/nhcarrigan" target="_blank" rel="noreferrer">
<i class="fa-brands fa-linkedin"></i><span>Connect with us on LinkedIn~!</span>
</a>
</div>
<hr class="social-list-divider" />
<div class="social-list-item">
<a href="https://www.reddit.com/r/nhcarrigan/" target="_blank" rel="noreferrer">
<i class="fa-brands fa-reddit"></i><span>Join our subreddit~!</span>
</a>
</div>
<hr class="social-list-divider" />
<div class="social-list-item">
<a href="https://www.youtube.com/@naomilgbt" target="_blank" rel="noreferrer">
<i class="fa-brands fa-youtube"></i><span>Subscribe to our YouTube~!</span>
</a>
</div>
<hr class="social-list-divider" />
<div class="social-list-item">
<a href="https://twitch.tv/naomilgbt" target="_blank" rel="noreferrer">
<i class="fa-brands fa-twitch"></i><span>Subscribe to our Twitch~!</span>
</a>
</div>
<hr class="social-list-divider" />
<div class="social-list-item">
<a href="https://x.com/nhcarrigan1" target="_blank" rel="noreferrer">
<i class="fa-brands fa-twitter"></i><span>We are even on Twitter~!</span>
</a>
</div>
</div>
`; `;
const videoOverlay = document.createElement("video");
videoOverlay.autoplay = true;
videoOverlay.loop = true;
videoOverlay.muted = true;
videoOverlay.playsInline = true;
videoOverlay.src = "https://cdn.nhcarrigan.com/overlay.webm";
videoOverlay.style.pointerEvents = "none";
videoOverlay.style.position = "fixed";
videoOverlay.style.top = "0";
videoOverlay.style.left = "0";
videoOverlay.style.opacity = "0.25";
videoOverlay.style.width = "100vw";
videoOverlay.style.height = "100vh";
videoOverlay.style.objectFit = "cover";
videoOverlay.style.zIndex = "10000";
// #endregion
// #region Scripts // #region Scripts
const treeNation = document.createElement("script"); const nhcarriganHeadersTreeNation = document.createElement("script");
treeNation.src nhcarriganHeadersTreeNation.src
= "https://widgets.tree-nation.com/js/widgets/v1/widgets.min.js?v=1.0"; = "https://widgets.tree-nation.com/js/widgets/v1/widgets.min.js?v=1.0";
const treeNationBottom = document.createElement("script"); const nhcarriganHeadersTreeNationBottom = document.createElement("script");
treeNationBottom.defer = true; nhcarriganHeadersTreeNationBottom.defer = true;
treeNationBottom.async = true; nhcarriganHeadersTreeNationBottom.async = true;
treeNationBottom.innerHTML = ` nhcarriganHeadersTreeNationBottom.innerHTML = `
const interval = setInterval(() => { const interval = setInterval(() => {
const tree = document.querySelector("#tree-nation-offset-website"); const tree = document.querySelector("#tree-nation-offset-website");
if (!tree) { if (!tree) {
@ -306,127 +366,167 @@ const interval = setInterval(() => {
clearInterval(interval); clearInterval(interval);
}, 1000); }, 1000);
`; `;
const fontAwesome = document.createElement("script"); const nhcarriganHeadersFontAwesome = document.createElement("script");
fontAwesome.src = "https://kit.fontawesome.com/f949111719.js"; nhcarriganHeadersFontAwesome.src = "https://kit.fontawesome.com/f949111719.js";
const analytics = document.createElement("script"); const nhcarriganHeadersAnalytics = document.createElement("script");
analytics.defer = true; nhcarriganHeadersAnalytics.defer = true;
analytics.setAttribute("domain", "nhcarrigan.com"); nhcarriganHeadersAnalytics.setAttribute("domain", "nhcarrigan.com");
analytics.src nhcarriganHeadersAnalytics.src
// eslint-disable-next-line stylistic/max-len // eslint-disable-next-line stylistic/max-len
= "https://analytics.nhcarrigan.com/js/script.file-downloads.hash.outbound-links.pageview-props.revenue.tagged-events.js"; = "https://analytics.nhcarrigan.com/js/script.file-downloads.hash.outbound-links.pageview-props.revenue.tagged-events.js";
const analytics2 = document.createElement("script"); nhcarriganHeadersAnalytics.setAttribute(
analytics2.innerHTML = ` "event-domain",
nhcarriganHeadersHostname,
);
nhcarriganHeadersAnalytics.setAttribute("data-domain", "nhcarrigan.com");
nhcarriganHeadersAnalytics.setAttribute(
"event-page",
nhcarriganHeadersTitle?.innerText ?? "Unknown Page",
);
nhcarriganHeadersAnalytics.setAttribute(
"event-path",
nhcarriganHeadersPathname,
);
const nhcarriganHeadersAnalytics2 = document.createElement("script");
nhcarriganHeadersAnalytics2.innerHTML = `
window.plausible = window.plausible ?? window.plausible = window.plausible ??
function() { function() {
(window.plausible.q = window.plausible.q ?? []).push(arguments) (window.plausible.q = window.plausible.q ?? []).push(arguments)
} }
`; `;
const nhcarriganHeadersGoogleAdsense = document.createElement("script");
nhcarriganHeadersGoogleAdsense.async = true;
nhcarriganHeadersGoogleAdsense.src
// eslint-disable-next-line stylistic/max-len -- big boi string
= "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3569924701890974";
nhcarriganHeadersGoogleAdsense.setAttribute("crossorigin", "anonymous");
// #endregion // #endregion
// #region Inject Elements // #region Inject Elements
head?.appendChild(openGraphTitle); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersOpenGraphTitle);
head?.appendChild(openGraphDescription); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersOpenGraphDescription);
head?.appendChild(openGraphImage); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersOpenGraphImage);
head?.appendChild(openGraphUrl); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersOpenGraphUrl);
head?.appendChild(openGraphType); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersOpenGraphType);
head?.appendChild(twitterCard); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersTwitterCard);
head?.appendChild(twitterDomain); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersTwitterDomain);
head?.appendChild(twitterUrl); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersTwitterUrl);
head?.appendChild(twitterTitle); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersTwitterTitle);
head?.appendChild(twitterDescription); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersTwitterDescription);
head?.appendChild(twitterImage); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersTwitterImage);
head?.appendChild(favicon); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersFavicon);
head?.appendChild(appleTouchIcon); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersAppleTouchIcon);
head?.appendChild(smallIcon); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersSmallIcon);
head?.appendChild(largeIcon); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersLargeIcon);
head?.appendChild(styles); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersStyles);
head?.appendChild(treeNation); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersTreeNation);
head?.appendChild(fontAwesome); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersFontAwesome);
head?.appendChild(analytics); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersAnalytics);
head?.appendChild(analytics2); nhcarriganHeadersHead?.appendChild(nhcarriganHeadersAnalytics2);
nhcarriganHeadersHead?.appendChild(nhcarriganHeadersGoogleAdsense);
body?.appendChild(footer);
body?.appendChild(videoOverlay);
body?.appendChild(treeNationBottom);
// #endregion
// #region Audio
const playButton = document.querySelector("#audio-theme-button");
const audio = new Audio("https://cdn.nhcarrigan.com/theme.mp3");
let playing = false;
playButton?.addEventListener("click", () => {
if (playing) {
audio.pause();
playing = false;
playButton.innerHTML = "<i class=\"fa-solid fa-play\"></i>";
} else {
void audio.play();
playing = true;
playButton.innerHTML = "<i class=\"fa-solid fa-pause\"></i>";
}
});
nhcarriganHeadersBody?.appendChild(nhcarriganHeadersFooter);
nhcarriganHeadersBody?.appendChild(nhcarriganHeadersTreeNationBottom);
// #endregion // #endregion
// #region Theme // #region Theme
const themeButton = document.querySelector("#theme-select-button"); const nhcarriganHeadersThemeButton = document.querySelector(
const themeIcon = document.querySelector("#theme-select-icon"); "#theme-select-button",
);
const nhcarriganHeadersThemeIcon = document.querySelector("#theme-select-icon");
if (localStorage.getItem("theme") === "dark") { if (localStorage.getItem("theme") === "dark") {
themeIcon?.classList.remove("fa-moon"); nhcarriganHeadersThemeIcon?.classList.remove("fa-moon");
themeIcon?.classList.add("fa-sun"); nhcarriganHeadersThemeIcon?.classList.add("fa-sun");
document.querySelector("html")?.classList.add("is-dark"); document.querySelector("html")?.classList.add("is-dark");
} }
const toggleTheme = (): void => { const nhcarriganHeadersToggleTheme = (): void => {
const currentTheme = localStorage.getItem("theme"); const nhcarriganHeadersCurrentTheme = localStorage.getItem("theme");
if (currentTheme === "dark") { if (nhcarriganHeadersCurrentTheme === "dark") {
localStorage.setItem("theme", "light"); localStorage.setItem("theme", "light");
themeIcon?.classList.remove("fa-sun"); nhcarriganHeadersThemeIcon?.classList.remove("fa-sun");
themeIcon?.classList.add("fa-moon"); nhcarriganHeadersThemeIcon?.classList.add("fa-moon");
document.querySelector("html")?.classList.remove("is-dark"); document.querySelector("html")?.classList.remove("is-dark");
return; return;
} }
localStorage.setItem("theme", "dark"); localStorage.setItem("theme", "dark");
themeIcon?.classList.remove("fa-moon"); nhcarriganHeadersThemeIcon?.classList.remove("fa-moon");
themeIcon?.classList.add("fa-sun"); nhcarriganHeadersThemeIcon?.classList.add("fa-sun");
document.querySelector("html")?.classList.add("is-dark"); document.querySelector("html")?.classList.add("is-dark");
}; };
themeButton?.addEventListener("click", toggleTheme); nhcarriganHeadersThemeButton?.addEventListener(
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); "click",
if (prefersDark.matches && localStorage.getItem("theme") !== null) { nhcarriganHeadersToggleTheme,
);
const nhcarriganHeadersPrefersDark = window.matchMedia(
"(prefers-color-scheme: dark)",
);
if (
nhcarriganHeadersPrefersDark.matches
&& localStorage.getItem("theme") !== null
) {
localStorage.setItem("theme", "dark"); localStorage.setItem("theme", "dark");
themeIcon?.classList.remove("fa-moon"); nhcarriganHeadersThemeIcon?.classList.remove("fa-moon");
themeIcon?.classList.add("fa-sun"); nhcarriganHeadersThemeIcon?.classList.add("fa-sun");
document.querySelector("html")?.classList.add("is-dark"); document.querySelector("html")?.classList.add("is-dark");
} }
// #endregion // #endregion
// #region Social Toggle
const nhcarriganHeadersShowSocialsButton
= document.querySelector<HTMLButtonElement>("#show-socials-button");
const nhcarriganHeadersSocialList
= document.querySelector<HTMLDivElement>("#social-list");
const nhcarriganHeadersToggleSocials = (): void => {
if (!nhcarriganHeadersSocialList) {
throw new Error("Social list element not found.");
}
if (nhcarriganHeadersSocialList.style.display === "block") {
nhcarriganHeadersSocialList.style.display = "none";
nhcarriganHeadersShowSocialsButton?.setAttribute("aria-expanded", "false");
nhcarriganHeadersShowSocialsButton?.setAttribute(
"aria-label",
"Show Socials",
);
return;
}
nhcarriganHeadersSocialList.style.display = "block";
nhcarriganHeadersShowSocialsButton?.setAttribute("aria-expanded", "true");
nhcarriganHeadersShowSocialsButton?.setAttribute(
"aria-label",
"Hide Socials",
);
};
nhcarriganHeadersShowSocialsButton?.addEventListener(
"click",
nhcarriganHeadersToggleSocials,
);
// #region CTA // #region CTA
const cta = document.createElement("dialog"); const nhcarriganHeadersCta = document.createElement("dialog");
cta.style.position = "fixed"; nhcarriganHeadersCta.style.position = "fixed";
cta.style.top = "50%"; nhcarriganHeadersCta.style.top = "50%";
cta.style.left = "50%"; nhcarriganHeadersCta.style.left = "50%";
cta.style.transform = "translate(-50%, -50%)"; nhcarriganHeadersCta.style.transform = "translate(-50%, -50%)";
cta.style.padding = "10px"; nhcarriganHeadersCta.style.padding = "10px";
cta.style.borderRadius = "10px"; nhcarriganHeadersCta.style.borderRadius = "10px";
cta.style.backgroundColor = "var(--background)"; nhcarriganHeadersCta.style.backgroundColor = "var(--background)";
cta.style.color = "var(--foreground)"; nhcarriganHeadersCta.style.color = "var(--foreground)";
cta.style.textAlign = "center"; nhcarriganHeadersCta.style.textAlign = "center";
cta.style.width = "95%"; nhcarriganHeadersCta.style.width = "95%";
cta.style.maxWidth = "400px"; nhcarriganHeadersCta.style.maxWidth = "400px";
cta.id = "community-cta"; nhcarriganHeadersCta.id = "community-cta";
cta.innerHTML = ` nhcarriganHeadersCta.innerHTML = `
<h1 autofocus>Hello~!</h1> <h1 autofocus>Hello~!</h1>
<div style="display: flex; justify-content: space-around; margin-bottom: 10px;"> <div style="display: flex; justify-content: space-around; margin-bottom: 10px;">
<img src="https://cdn.nhcarrigan.com/profile.png" alt="Naomi Carrigan" style="width: 100px; height: 100px; border-radius: 50%;"> <img src="https://cdn.nhcarrigan.com/logo.png" alt="NHCarrigan Logo" style="width: 100px; height: 100px;">
<p> <p>
Consider joining our community so you can keep up to date on all of our latest activities! Consider joining our community so you can keep up to date on all of our latest activities!
</p> </p>
@ -434,47 +534,62 @@ cta.innerHTML = `
<a href="https://chat.nhcarrigan.com" target="_blank" rel="noreferrer" style="padding: 10px; background: var(--foreground); color: var(--background); outline: none">Okay, take me there~!</a> <a href="https://chat.nhcarrigan.com" target="_blank" rel="noreferrer" style="padding: 10px; background: var(--foreground); color: var(--background); outline: none">Okay, take me there~!</a>
`; `;
const modalBg = document.createElement("div"); const nhcarriganHeadersModalBg = document.createElement("div");
modalBg.style.zIndex = "4999"; nhcarriganHeadersModalBg.style.zIndex = "4999";
modalBg.style.position = "fixed"; nhcarriganHeadersModalBg.style.position = "fixed";
modalBg.style.top = "0"; nhcarriganHeadersModalBg.style.top = "0";
modalBg.style.left = "0"; nhcarriganHeadersModalBg.style.left = "0";
modalBg.style.width = "100vw"; nhcarriganHeadersModalBg.style.width = "100vw";
modalBg.style.height = "100vh"; nhcarriganHeadersModalBg.style.height = "100vh";
modalBg.style.backgroundColor = "rgba(0, 0, 0, 0.5)"; nhcarriganHeadersModalBg.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
modalBg.style.display = "none"; nhcarriganHeadersModalBg.style.display = "none";
modalBg.id = "modal-bg"; nhcarriganHeadersModalBg.id = "modal-bg";
const closeModal = (): void => { const nhcarriganHeadersCloseModal = (): void => {
cta.close(); nhcarriganHeadersCta.close();
modalBg.style.display = "none"; nhcarriganHeadersModalBg.style.display = "none";
}; };
const handleModalClick = (event: MouseEvent): void => { const nhcarriganHeadersHandleModalClick = (event: MouseEvent): void => {
event.stopPropagation(); event.stopPropagation();
if (event.target === cta) { if (event.target === nhcarriganHeadersCta) {
closeModal(); nhcarriganHeadersCloseModal();
} }
}; };
const showModal = (): void => { const nhcarriganHeadersShowModal = (): void => {
const lastShown = Number.parseInt( const nhcarriganHeadersLastShown = Number.parseInt(
localStorage.getItem("naomi-community-cta") ?? "0", localStorage.getItem("naomi-community-cta") ?? "0",
10, 10,
); );
const lastShownDate = new Date(lastShown); const nhcarriganHeadersLastShownDate = new Date(nhcarriganHeadersLastShown);
const diff = Date.now() - lastShownDate.getTime(); const nhcarriganHeadersDiff
console.table({ diff, lastShown, lastShownDate }); = Date.now() - nhcarriganHeadersLastShownDate.getTime();
console.table({
diff: nhcarriganHeadersDiff,
lastShown: nhcarriganHeadersLastShown,
lastShownDate: nhcarriganHeadersLastShownDate,
});
// We only want to show this once a week. // We only want to show this once a week.
if (diff < 1000 * 60 * 60 * 24 * 7) { if (nhcarriganHeadersDiff < 1000 * 60 * 60 * 24 * 7) {
return; return;
} }
cta.showModal(); nhcarriganHeadersCta.showModal();
modalBg.style.display = "block"; nhcarriganHeadersModalBg.style.display = "block";
modalBg.addEventListener("click", closeModal); nhcarriganHeadersModalBg.addEventListener(
const closeButton = cta.querySelector("button"); "click",
closeButton?.addEventListener("click", closeModal); nhcarriganHeadersCloseModal,
cta.addEventListener("click", handleModalClick); );
const nhcarriganHeadersCloseButton
= nhcarriganHeadersCta.querySelector("button");
nhcarriganHeadersCloseButton?.addEventListener(
"click",
nhcarriganHeadersCloseModal,
);
nhcarriganHeadersCta.addEventListener(
"click",
nhcarriganHeadersHandleModalClick,
);
localStorage.setItem("naomi-community-cta", Date.now().toString()); localStorage.setItem("naomi-community-cta", Date.now().toString());
}; };
body?.appendChild(cta); nhcarriganHeadersBody?.appendChild(nhcarriganHeadersCta);
body?.appendChild(modalBg); nhcarriganHeadersBody?.appendChild(nhcarriganHeadersModalBg);
showModal(); nhcarriganHeadersShowModal();