Add banner, Apple Podcasts link, feed proxy, and fetch retry
- Add roostbanner.png hero banner image - Add Apple Podcasts subscribe button - Add Cloudflare Pages Function to proxy RSS feed (avoids CORS) - Add fetch timeout and retry for episode loading - Add contact email to footer - Replace favicon with inline SVG rooster Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,18 @@ a:hover {
|
||||
color: var(--accent-hover);
|
||||
}
|
||||
|
||||
/* Banner */
|
||||
.banner {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.banner-img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hero */
|
||||
.hero {
|
||||
padding: 3rem 1.5rem 2rem;
|
||||
@@ -356,6 +368,18 @@ a:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.footer-contact {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.footer-contact a {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.footer-contact a:hover {
|
||||
color: var(--accent-hover);
|
||||
}
|
||||
|
||||
/* Desktop */
|
||||
@media (min-width: 768px) {
|
||||
.hero {
|
||||
|
||||
BIN
website/images/banner.png
Normal file
BIN
website/images/banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
@@ -18,12 +18,17 @@
|
||||
<meta name="twitter:image" content="https://podcast.macneilmediagroup.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=2">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="https://podcast.macneilmediagroup.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=2">
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cpath d='M32 4c-2 0-4 2-4 5 0 1 .3 2 .8 3C26 13 24 16 24 20c0 2 .5 4 1.5 5.5L22 28c-2 1-4 3-5 6l-3 10c-.5 2 .5 3 2 3h4l1-4 2 4h6l-1-6 3 6h6l-1-6 3 6h4c1.5 0 2.5-1 2-3l-3-10c-1-3-3-5-5-6l-3.5-2.5C35.5 24 36 22 36 20c0-4-2-7-4.8-8 .5-1 .8-2 .8-3 0-3-2-5-4-5z' fill='%23e8791d'/%3E%3Ccircle cx='30' cy='17' r='1.5' fill='%231a1209'/%3E%3Cpath d='M36 15c1-1 3-1 4 0s1 3 0 4' fill='none' stroke='%23cc2222' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='M28 22c2 1 4 1 6 0' fill='none' stroke='%23e8791d' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E">
|
||||
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Banner -->
|
||||
<div class="banner">
|
||||
<img src="images/banner.png" alt="Luke at the Roost — ON AIR" class="banner-img">
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<section class="hero">
|
||||
<div class="hero-inner">
|
||||
@@ -49,7 +54,7 @@
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>
|
||||
YouTube
|
||||
</a>
|
||||
<a href="#" class="subscribe-btn btn-apple" title="Coming soon to Apple Podcasts">
|
||||
<a href="https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848" target="_blank" rel="noopener" class="subscribe-btn btn-apple">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M5.34 0A5.328 5.328 0 0 0 0 5.34v13.32A5.328 5.328 0 0 0 5.34 24h13.32A5.328 5.328 0 0 0 24 18.66V5.34A5.328 5.328 0 0 0 18.66 0zm6.525 2.568c2.336 0 4.448.902 4.448 3.545 0 1.497-.89 2.67-1.916 3.545-.663.566-.795 .84-.795 1.347 0 .6.397 1.173.894 1.722 1.417 1.564 1.96 2.853 1.96 4.448 0 3.063-2.673 4.257-5.165 4.257-.315 0-.658-.02-.994-.063-1.523-.195-2.86-.9-3.632-.9-.82 0-1.98.623-3.377.87A5.715 5.715 0 0 1 3.15 21.4c-1.27 0-2.1-.96-2.1-2.663 0-1.2.6-2.7 1.845-4.29.63-.81 1.62-1.83 2.91-2.31-.06-.6-.09-1.14-.09-1.62 0-4.28 2.76-7.95 6.15-7.95z"/></svg>
|
||||
Apple
|
||||
</a>
|
||||
@@ -77,6 +82,7 @@
|
||||
<a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-" target="_blank" rel="noopener">YouTube</a>
|
||||
<a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank" rel="noopener">RSS</a>
|
||||
</div>
|
||||
<p class="footer-contact">Sales & Collaboration: <a href="mailto:luke@macneilmediagroup.com">luke@macneilmediagroup.com</a></p>
|
||||
<p>© 2026 Luke at the Roost</p>
|
||||
</footer>
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const FEED_URL = 'https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml';
|
||||
const CORS_PROXY = 'https://api.allorigins.win/raw?url=';
|
||||
const FEED_URL = '/feed';
|
||||
|
||||
const audio = document.getElementById('audio-element');
|
||||
const stickyPlayer = document.getElementById('sticky-player');
|
||||
@@ -57,23 +56,29 @@ function truncate(html, maxLen) {
|
||||
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>';
|
||||
|
||||
// Fetch with timeout
|
||||
function fetchWithTimeout(url, ms = 8000) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), ms);
|
||||
return fetch(url, { signal: controller.signal }).finally(() => clearTimeout(timeout));
|
||||
}
|
||||
|
||||
// Fetch and parse RSS feed
|
||||
async function fetchEpisodes() {
|
||||
let xml;
|
||||
try {
|
||||
// Try direct fetch first
|
||||
const res = await fetch(FEED_URL);
|
||||
if (!res.ok) throw new Error('Direct fetch failed');
|
||||
xml = await res.text();
|
||||
} catch {
|
||||
const maxRetries = 2;
|
||||
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
// Fallback to CORS proxy
|
||||
const res = await fetch(CORS_PROXY + encodeURIComponent(FEED_URL));
|
||||
if (!res.ok) throw new Error('Proxy fetch failed');
|
||||
const res = await fetchWithTimeout(FEED_URL);
|
||||
if (!res.ok) throw new Error('Fetch failed');
|
||||
xml = await res.text();
|
||||
} catch {
|
||||
episodesList.innerHTML = '<div class="episodes-error">Unable to load episodes. <a href="' + FEED_URL + '" target="_blank">View RSS feed</a></div>';
|
||||
return;
|
||||
if (xml.includes('<item>')) break;
|
||||
throw new Error('Invalid response');
|
||||
} catch (err) {
|
||||
if (attempt === maxRetries) {
|
||||
episodesList.innerHTML = '<div class="episodes-error">Unable to load episodes. <a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank">View RSS feed</a></div>';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user