Growth features: share buttons, NEW badge, sticky CTA, newsletter cross-promote
- Share buttons on episode and clip cards (Web Share API + clipboard fallback) - NEW badge on latest episode card - Sticky call-in CTA bar (appears after hero scrolls out) - Daily AI Briefing newsletter cross-promote in footer - Bump cache versions to v=5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/style.css?v=4">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
<link rel="stylesheet" href="css/style.css?v=4">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -460,6 +460,113 @@ a:hover {
|
|||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Share Buttons */
|
||||||
|
.episode-share-btn,
|
||||||
|
.clip-share-btn {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-dim);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.35rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: color 0.2s, background 0.2s;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.episode-share-btn svg,
|
||||||
|
.clip-share-btn svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.episode-share-btn:hover,
|
||||||
|
.clip-share-btn:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
background: rgba(212, 164, 74, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.episode-share-btn.share-copied,
|
||||||
|
.clip-share-btn.share-copied {
|
||||||
|
color: var(--accent);
|
||||||
|
animation: share-pulse 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes share-pulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.3); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.clip-share-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.5rem;
|
||||||
|
right: 0.5rem;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NEW Badge */
|
||||||
|
.episode-new-badge {
|
||||||
|
display: inline-block;
|
||||||
|
background: var(--accent);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 0.6rem;
|
||||||
|
font-weight: 800;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
padding: 0.15em 0.5em;
|
||||||
|
border-radius: 50px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sticky CTA Bar */
|
||||||
|
.sticky-cta {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: rgba(21, 15, 6, 0.92);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
border-top: 1px solid #2a2015;
|
||||||
|
padding: 0.6rem 1.5rem;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 90;
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: transform 0.3s, bottom 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-cta.visible {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-cta.player-active {
|
||||||
|
bottom: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-cta-link {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-cta-link:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-cta-link strong {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-cta-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Testimonials */
|
/* Testimonials */
|
||||||
.testimonials-section {
|
.testimonials-section {
|
||||||
max-width: 900px;
|
max-width: 900px;
|
||||||
@@ -778,6 +885,80 @@ a:hover {
|
|||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer-newsletter {
|
||||||
|
margin: 1.25rem 0;
|
||||||
|
padding: 1rem 0;
|
||||||
|
border-top: 1px solid #2a2015;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-text {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--text-dim);
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-name {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-form {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
max-width: 420px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-input {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
background: #1a1209;
|
||||||
|
border: 1px solid #3a2f20;
|
||||||
|
border-radius: 50px;
|
||||||
|
color: var(--text-light);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-input:focus {
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-input::placeholder {
|
||||||
|
color: var(--text-dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-btn {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--accent);
|
||||||
|
border: 2px solid var(--accent);
|
||||||
|
padding: 0.5rem 1.25rem;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 700;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: background 0.2s, color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-btn:hover {
|
||||||
|
background: var(--accent);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-success {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--accent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
.footer-contact {
|
.footer-contact {
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
@@ -1796,4 +1977,12 @@ p.about-teaser {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-form {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-newsletter-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
<link rel="stylesheet" href="css/style.css?v=4">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
|
||||||
<!-- Structured Data (dynamically updated by JS) -->
|
<!-- Structured Data (dynamically updated by JS) -->
|
||||||
<script type="application/ld+json" id="episode-jsonld">
|
<script type="application/ld+json" id="episode-jsonld">
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
<link rel="stylesheet" href="css/style.css?v=4">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
|
||||||
<!-- Structured Data -->
|
<!-- Structured Data -->
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
|
|||||||
+10
-2
@@ -31,7 +31,7 @@
|
|||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
<link rel="stylesheet" href="css/style.css?v=4">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
|
||||||
<!-- Structured Data -->
|
<!-- Structured Data -->
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
@@ -276,6 +276,14 @@
|
|||||||
|
|
||||||
<footer class="footer"></footer>
|
<footer class="footer"></footer>
|
||||||
|
|
||||||
|
<!-- Sticky CTA Bar — appears after scrolling past hero -->
|
||||||
|
<div class="sticky-cta" id="sticky-cta" aria-hidden="true">
|
||||||
|
<a href="tel:+12084395853" class="sticky-cta-link">
|
||||||
|
<svg class="sticky-cta-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></svg>
|
||||||
|
Call in live: <strong>208-439-LUKE</strong>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Sticky Audio Player -->
|
<!-- Sticky Audio Player -->
|
||||||
<div class="sticky-player" id="sticky-player">
|
<div class="sticky-player" id="sticky-player">
|
||||||
<div class="player-inner">
|
<div class="player-inner">
|
||||||
@@ -301,6 +309,6 @@
|
|||||||
<script src="js/clips.js"></script>
|
<script src="js/clips.js"></script>
|
||||||
<script>renderFeaturedClipsInline('home-clips');</script>
|
<script>renderFeaturedClipsInline('home-clips');</script>
|
||||||
<script src="js/player.js"></script>
|
<script src="js/player.js"></script>
|
||||||
<script src="js/app.js?v=4"></script>
|
<script src="js/app.js?v=5"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+47
-2
@@ -51,6 +51,7 @@ function truncate(html, maxLen) {
|
|||||||
// SVG icons
|
// SVG icons
|
||||||
const playSVG = '<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
|
const playSVG = '<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
|
||||||
const pauseSVG = '<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
|
const pauseSVG = '<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
|
||||||
|
const shareSVG = '<svg viewBox="0 0 24 24"><path d="M16 5l-1.42 1.42-1.59-1.59V16h-2V4.83L9.42 6.42 8 5l4-4 4 4zm4 5v11a2 2 0 01-2 2H6a2 2 0 01-2-2V10a2 2 0 012-2h3v2H6v11h12V10h-3V8h3a2 2 0 012 2z"/></svg>';
|
||||||
|
|
||||||
// Fetch with timeout
|
// Fetch with timeout
|
||||||
function fetchWithTimeout(url, ms = 8000) {
|
function fetchWithTimeout(url, ms = 8000) {
|
||||||
@@ -59,6 +60,26 @@ function fetchWithTimeout(url, ms = 8000) {
|
|||||||
return fetch(url, { signal: controller.signal }).finally(() => clearTimeout(timeout));
|
return fetch(url, { signal: controller.signal }).finally(() => clearTimeout(timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function shareContent(title, url, btn) {
|
||||||
|
if (navigator.share) {
|
||||||
|
try {
|
||||||
|
await navigator.share({ title, url });
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === 'AbortError') return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(url);
|
||||||
|
const orig = btn.innerHTML;
|
||||||
|
btn.innerHTML = 'Copied!';
|
||||||
|
btn.classList.add('share-copied');
|
||||||
|
setTimeout(() => { btn.innerHTML = orig; btn.classList.remove('share-copied'); }, 2000);
|
||||||
|
} catch (e) {
|
||||||
|
prompt('Copy this link:', url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch and parse RSS feed
|
// Fetch and parse RSS feed
|
||||||
async function fetchEpisodes() {
|
async function fetchEpisodes() {
|
||||||
let xml;
|
let xml;
|
||||||
@@ -130,19 +151,30 @@ function createEpisodeCard(ep) {
|
|||||||
<div class="episode-title">${escapeAttr(ep.title)}</div>
|
<div class="episode-title">${escapeAttr(ep.title)}</div>
|
||||||
<div class="episode-desc">${truncate(ep.description, 150)}</div>
|
<div class="episode-desc">${truncate(ep.description, 150)}</div>
|
||||||
${epSlug ? `<a href="/episode.html?slug=${encodeURIComponent(epSlug)}" class="episode-transcript-link">Read Transcript</a>` : ''}
|
${epSlug ? `<a href="/episode.html?slug=${encodeURIComponent(epSlug)}" class="episode-transcript-link">Read Transcript</a>` : ''}
|
||||||
|
<button class="episode-share-btn" aria-label="Share episode">${shareSVG}</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const btn = card.querySelector('.episode-play-btn');
|
const btn = card.querySelector('.episode-play-btn');
|
||||||
btn.addEventListener('click', () => playEpisode(ep.audioUrl, ep.title, card, btn));
|
btn.addEventListener('click', () => playEpisode(ep.audioUrl, ep.title, card, btn));
|
||||||
|
|
||||||
|
const shareBtn = card.querySelector('.episode-share-btn');
|
||||||
|
const shareUrl = epSlug
|
||||||
|
? `${window.location.origin}/episode.html?slug=${encodeURIComponent(epSlug)}`
|
||||||
|
: window.location.origin;
|
||||||
|
shareBtn.addEventListener('click', () => shareContent(ep.title, shareUrl, shareBtn));
|
||||||
|
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMoreEpisodes() {
|
function showMoreEpisodes() {
|
||||||
const batch = allEpisodes.slice(displayedCount, displayedCount + EPISODES_PER_PAGE);
|
const batch = allEpisodes.slice(displayedCount, displayedCount + EPISODES_PER_PAGE);
|
||||||
batch.forEach((ep) => {
|
batch.forEach((ep, i) => {
|
||||||
episodesList.appendChild(createEpisodeCard(ep));
|
const card = createEpisodeCard(ep);
|
||||||
|
if (displayedCount === 0 && i === 0) {
|
||||||
|
card.querySelector('.episode-meta').insertAdjacentHTML('afterbegin', '<span class="episode-new-badge">NEW</span> ');
|
||||||
|
}
|
||||||
|
episodesList.appendChild(card);
|
||||||
});
|
});
|
||||||
displayedCount += batch.length;
|
displayedCount += batch.length;
|
||||||
|
|
||||||
@@ -185,6 +217,7 @@ function playEpisode(url, title, card, btn) {
|
|||||||
|
|
||||||
playerTitle.textContent = title;
|
playerTitle.textContent = title;
|
||||||
stickyPlayer.classList.add('active');
|
stickyPlayer.classList.add('active');
|
||||||
|
if (stickyCta) stickyCta.classList.add('player-active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Episode card icon sync (sticky player icons handled by player.js)
|
// Episode card icon sync (sticky player icons handled by player.js)
|
||||||
@@ -295,6 +328,18 @@ function checkOnAir() {
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sticky CTA — show after scrolling past hero
|
||||||
|
const stickyCta = document.getElementById('sticky-cta');
|
||||||
|
const heroSection = document.querySelector('.hero');
|
||||||
|
if (stickyCta && heroSection) {
|
||||||
|
const ctaObserver = new IntersectionObserver(([entry]) => {
|
||||||
|
const show = !entry.isIntersecting;
|
||||||
|
stickyCta.classList.toggle('visible', show);
|
||||||
|
stickyCta.setAttribute('aria-hidden', String(!show));
|
||||||
|
}, { threshold: 0 });
|
||||||
|
ctaObserver.observe(heroSection);
|
||||||
|
}
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
fetchEpisodes();
|
fetchEpisodes();
|
||||||
initTestimonials();
|
initTestimonials();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const CLIPS_JSON_URL = '/data/clips.json';
|
const CLIPS_JSON_URL = '/data/clips.json';
|
||||||
|
|
||||||
const clipPlaySVG = '<svg viewBox="0 0 24 24" fill="#fff"><path d="M8 5v14l11-7z"/></svg>';
|
const clipPlaySVG = '<svg viewBox="0 0 24 24" fill="#fff"><path d="M8 5v14l11-7z"/></svg>';
|
||||||
|
const clipShareSVG = '<svg viewBox="0 0 24 24" fill="#fff"><path d="M16 5l-1.42 1.42-1.59-1.59V16h-2V4.83L9.42 6.42 8 5l4-4 4 4zm4 5v11a2 2 0 01-2 2H6a2 2 0 01-2-2V10a2 2 0 012-2h3v2H6v11h12V10h-3V8h3a2 2 0 012 2z"/></svg>';
|
||||||
|
|
||||||
function escapeHTML(str) {
|
function escapeHTML(str) {
|
||||||
const el = document.createElement('span');
|
const el = document.createElement('span');
|
||||||
@@ -8,6 +9,26 @@ function escapeHTML(str) {
|
|||||||
return el.innerHTML;
|
return el.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function shareClipContent(title, url, btn) {
|
||||||
|
if (navigator.share) {
|
||||||
|
try {
|
||||||
|
await navigator.share({ title, url });
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === 'AbortError') return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(url);
|
||||||
|
const orig = btn.innerHTML;
|
||||||
|
btn.innerHTML = 'Copied!';
|
||||||
|
btn.classList.add('share-copied');
|
||||||
|
setTimeout(() => { btn.innerHTML = orig; btn.classList.remove('share-copied'); }, 2000);
|
||||||
|
} catch (e) {
|
||||||
|
prompt('Copy this link:', url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function renderClipCard(clip, featured) {
|
function renderClipCard(clip, featured) {
|
||||||
const card = document.createElement('div');
|
const card = document.createElement('div');
|
||||||
card.className = 'clip-card' + (featured ? ' clip-card-featured' : '');
|
card.className = 'clip-card' + (featured ? ' clip-card-featured' : '');
|
||||||
@@ -31,6 +52,7 @@ function renderClipCard(clip, featured) {
|
|||||||
<h3 class="clip-card-title">${title}</h3>
|
<h3 class="clip-card-title">${title}</h3>
|
||||||
<p class="clip-card-desc">${desc}</p>
|
<p class="clip-card-desc">${desc}</p>
|
||||||
${hasVideo ? `<button class="clip-play-btn" aria-label="Play clip">${clipPlaySVG}</button>` : ''}
|
${hasVideo ? `<button class="clip-play-btn" aria-label="Play clip">${clipPlaySVG}</button>` : ''}
|
||||||
|
${hasVideo ? `<button class="clip-share-btn" aria-label="Share clip">${clipShareSVG}</button>` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -41,6 +63,13 @@ function renderClipCard(clip, featured) {
|
|||||||
const inner = card.querySelector('.clip-card-inner');
|
const inner = card.querySelector('.clip-card-inner');
|
||||||
inner.innerHTML = `<iframe src="https://www.youtube-nocookie.com/embed/${youtubeId}?autoplay=1&rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>`;
|
inner.innerHTML = `<iframe src="https://www.youtube-nocookie.com/embed/${youtubeId}?autoplay=1&rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>`;
|
||||||
});
|
});
|
||||||
|
const shareBtn = card.querySelector('.clip-share-btn');
|
||||||
|
if (shareBtn) {
|
||||||
|
shareBtn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
shareClipContent(clip.title || '', `https://youtube.com/watch?v=${youtubeId}`, shareBtn);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return card;
|
return card;
|
||||||
|
|||||||
@@ -41,10 +41,42 @@ function initFooter() {
|
|||||||
<a href="https://youtube.com/lukemacneil" target="_blank" rel="noopener">YouTube</a>
|
<a href="https://youtube.com/lukemacneil" target="_blank" rel="noopener">YouTube</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="footer-newsletter">
|
||||||
|
<p class="footer-newsletter-text">Also from Luke: <strong class="footer-newsletter-name">The Daily AI Briefing</strong> — curated insights on AI infrastructure, automation, and engineering.</p>
|
||||||
|
<form class="footer-newsletter-form" id="footer-newsletter-form">
|
||||||
|
<input type="email" class="footer-newsletter-input" placeholder="your@email.com" required aria-label="Email address">
|
||||||
|
<button type="submit" class="footer-newsletter-btn">Subscribe</button>
|
||||||
|
</form>
|
||||||
|
<p class="footer-newsletter-success" id="footer-newsletter-success" hidden>You're subscribed to the Daily AI Briefing.</p>
|
||||||
|
</div>
|
||||||
<p class="footer-contact"><a href="https://ko-fi.com/lukemacneil" target="_blank" rel="noopener">Support the Show</a></p>
|
<p class="footer-contact"><a href="https://ko-fi.com/lukemacneil" target="_blank" rel="noopener">Support the Show</a></p>
|
||||||
<p class="footer-contact">Sales & Collaboration: <a href="mailto:luke@lukeattheroost.com">luke@lukeattheroost.com</a></p>
|
<p class="footer-contact">Sales & Collaboration: <a href="mailto:luke@lukeattheroost.com">luke@lukeattheroost.com</a></p>
|
||||||
<p>© 2026 Luke at the Roost · <a href="/privacy">Privacy Policy</a> · <a href="/terms">Terms of Service</a> · <a href="https://monitoring.macneilmediagroup.com/status/lukeattheroost" target="_blank" rel="noopener">System Status</a></p>
|
<p>© 2026 Luke at the Roost · <a href="/privacy">Privacy Policy</a> · <a href="/terms">Terms of Service</a> · <a href="https://monitoring.macneilmediagroup.com/status/lukeattheroost" target="_blank" rel="noopener">System Status</a></p>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const form = document.getElementById('footer-newsletter-form');
|
||||||
|
const success = document.getElementById('footer-newsletter-success');
|
||||||
|
if (form) {
|
||||||
|
form.addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const btn = form.querySelector('.footer-newsletter-btn');
|
||||||
|
const email = form.querySelector('.footer-newsletter-input').value;
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.textContent = 'Subscribing...';
|
||||||
|
try {
|
||||||
|
await fetch('https://mmg-form-handler.luke-3b5.workers.dev/api/lead-magnet', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ email, source: 'lukeattheroost-footer' })
|
||||||
|
});
|
||||||
|
form.hidden = true;
|
||||||
|
success.hidden = false;
|
||||||
|
} catch {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = 'Subscribe';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initFooter();
|
initFooter();
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/style.css?v=4">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
<link rel="stylesheet" href="css/style.css?v=4">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@
|
|||||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/style.css?v=4">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
Reference in New Issue
Block a user