2025-04-17 14:11:11 +00:00

200 lines
9.9 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Good Morning Bitcoin</title>
<link rel="stylesheet" href="https://unpkg.com/@tailwindcss/ui@latest/dist/tailwind-ui.min.css" />
<!-- MailerLite styles -->
<style type="text/css">@import url("https://assets.mlcdn.com/fonts.css?version=1744733");</style>
<style>
.ml-form-embedSubmitLoad { display:inline-block;width:20px;height:20px; }
.ml-form-embedSubmitLoad:after { content:" ";display:block;width:11px;height:11px;margin:1px;border-radius:50%;border:4px solid #fff;border-color:#fff #fff #fff transparent;animation:ml-form-embedSubmitLoad 1.2s linear infinite; }
@keyframes ml-form-embedSubmitLoad {0%{transform:rotate(0deg);}100%{transform:rotate(360deg);}}
body { font-family:sans-serif; background-color:#fefdfc; }
.orange { color:#e86228; }
.bg-orange { background-color:#e86228; }
.text-xl-bold { font-size:1.5rem; font-weight:bold; }
</style>
</head>
<body class="text-gray-900">
<!-- Header -->
<header class="bg-orange text-white p-4">
<div class="max-w-5xl mx-auto flex justify-between items-center">
<h1 class="text-2xl font-bold">GOOD MORNING BITCOIN.COM</h1>
<nav class="space-x-4">
<a href="https://goodmorningbitcoin.com/about.html" class="hover:underline">About</a>
<a href="https://rustysats.com" class="hover:underline">RustySats</a>
<a href="https://www.orangem.art/" class="hover:underline">Orange</a>
<a href="https://ditto.pub/npub1n35s0hnjukw675njzqargeym7l9qzpg2dr6q9924yr798kafwvxsgp63m0" class="hover:underline">Nostr</a>
<a href="https://goodmorningbitcoin.com/shows.html" class="hover:underline">Shows</a>
</nav>
</div>
</header>
<!-- Now Playing -->
<section class="bg-black text-white py-6">
<div class="max-w-5xl mx-auto text-center">
<h2 class="text-3xl font-bold mb-2">The Voice of Bitcoin, Every Morning.</h2>
<iframe src="https://radio.goodmorningbitcoin.com/public/goodmorningbitcoin/embed?theme=dark" frameborder="0" allowtransparency="true" style="width:100%;min-height:150px;border:0;"></iframe>
</div>
</section>
<!-- Main Content -->
<main class="max-w-5xl mx-auto py-10 grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Featured Show -->
<section id="featured-show-container" class="md:col-span-1 p-4 border rounded">
<h3 class="text-xl-bold mb-2">Featured Show</h3>
<div id="featured-show">Loading show...</div>
</section>
<!-- Bitcoin News Brief -->
<section class="md:col-span-1 p-4 border rounded">
<h3 class="text-xl-bold mb-2">Bitcoin News Brief</h3>
<ul id="news-briefs" class="space-y-2 overflow-hidden" style="max-height:0;"></ul>
</section>
<!-- Bitcoin 101 + Email Signup -->
<div class="md:col-span-1 space-y-6">
<!-- Bitcoin 101 -->
<section class="p-4 border rounded">
<h3 class="text-xl-bold mb-2">Bitcoin 101</h3>
<p>Learn about Bitcoin basics.</p>
<a href="https://bitcoin101.goodmorningbitcoin.com" class="inline-block mt-2 bg-orange text-white px-4 py-2 rounded">Get Started</a>
</section>
<!-- Email Signup -->
<section class="p-4 border rounded">
<h3 class="text-xl-bold mb-2">Email Signup</h3>
<div id="mlb2-24950357" class="ml-form-embedContainer ml-subscribe-form ml-subscribe-form-24950357">
<!-- MailerLite embed -->
<div class="ml-form-align-center">
<div class="ml-form-embedWrapper embedForm">
<div class="ml-form-embedBody ml-form-embedBodyDefault row-form">
<div class="ml-form-embedContent mb-2" style="padding-bottom:1rem;"><p>Signup for the latest Bitcoin news!</p></div>
<form class="ml-block-form mt-2" action="https://assets.mailerlite.com/jsonp/1459975/forms/151930403370829428/subscribe" method="post" target="_blank">
<div class="ml-form-formContent">
<div class="ml-form-fieldRow ml-last-item">
<div class="ml-field-group ml-field-email ml-validate-email ml-validate-required">
<input type="email" name="fields[email]" placeholder="Email" required class="w-full p-3 border border-gray-300 rounded mb-2" />
</div>
</div>
</div>
<input type="hidden" name="ml-submit" value="1">
<div class="ml-form-embedSubmit">
<button type="submit" class="bg-black text-white px-4 py-2 rounded w-full">Subscribe</button>
<button disabled style="display:none;" class="loading"><div class="ml-form-embedSubmitLoad"></div><span class="sr-only">Loading...</span></button>
</div>
<input type="hidden" name="anticsrf" value="true">
</form>
</div>
</div>
</div>
<script src="https://groot.mailerlite.com/js/w/webforms.min.js?v176e10baa5e7ed80d35ae235be3d5024" async></script>
</div>
</section>
</div>
<!-- Network Stats -->
<section class="md:col-span-3 p-4 bg-black text-white rounded">
<div id="network-stats" class="text-lg font-mono text-center">Loading stats...</div>
</section>
<!-- Latest Episodes -->
<section class="md:col-span-3 p-4 border rounded">
<h3 class="text-xl-bold mb-2">Latest Episodes</h3>
<iframe src="https://radio.goodmorningbitcoin.com/public/goodmorningbitcoin/history?theme=light" frameborder="0" allowtransparency="true" style="width:100%;min-height:300px;border:0;"></iframe>
</section>
</main>
<!-- Scripts -->
<script>
// Helpers
let newsPosts = [], newsReady = false, showReady = false;
function renderNews() {
if (!newsReady || !showReady) return;
const ul = document.getElementById('news-briefs');
ul.innerHTML = '';
// Conservative height: reduce featured height by 16px
const fsHeight = document.getElementById('featured-show-container').offsetHeight;
const marginBufferPx = 40; // conservative buffer
const maxH = fsHeight - marginBufferPx;
ul.style.maxHeight = maxH + 'px';
for (const post of newsPosts) {
const li = document.createElement('li'); li.className = 'flex items-center space-x-2';
const media = post._embedded['wp:featuredmedia'];
if (media && media[0]) {
const img = document.createElement('img');
img.src = media[0].source_url;
img.className = 'w-10 h-10 object-cover rounded';
li.appendChild(img);
}
const a = document.createElement('a');
a.href = post.link; a.innerHTML = post.title.rendered;
a.target = '_blank'; a.className = 'text-blue-600 underline flex-1';
li.appendChild(a);
ul.appendChild(li);
if (ul.scrollHeight > maxH) { ul.removeChild(li); break; }
}
}
// Load news posts
fetch('https://bitcoinnews.com/wp-json/wp/v2/posts?_embed')
.then(r => r.json())
.then(posts => { newsPosts = posts; newsReady = true; renderNews(); })
.catch(() => { document.getElementById('news-briefs').innerHTML = '<li>Failed to load news.</li>'; });
// Load featured show
fetch('https://raw.githubusercontent.com/goodmorningbitcoin/goodmorningbitcoin-website/main/shows.json')
.then(r => r.json())
.then(data => {
const s = data[Math.floor(Math.random() * data.length)];
const div = document.getElementById('featured-show');
div.innerHTML = `<img src="https://raw.githubusercontent.com/goodmorningbitcoin/goodmorningbitcoin-website/main/${s.imgsrc}" class="w-full mb-2 rounded"/>` +
`<strong>${s.title}</strong><br/><a href="${s.fountainlink}" class="text-blue-600 underline" target="_blank">Listen now</a>`;
const img = div.querySelector('img');
if (img.complete) { showReady = true; renderNews(); }
else { img.onload = () => { showReady = true; renderNews(); }; }
})
.catch(console.error);
// Load stats
Promise.all([
fetch('https://mempool.space/api/v1/fees/recommended').then(r => r.json()),
fetch('https://mempool.space/api/v1/blocks/tip/height').then(r => r.json()),
fetch('https://mempool.space/api/v1/mining/hashrate/3d').then(r => r.json()),
fetch('https://mempool.space/api/v1/difficulty-adjustment').then(r => r.json()),
fetch('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd').then(r => r.json())
]).then(([fees, height, hrData, diffAdj, priceData]) => {
const price = priceData.bitcoin?.usd ? `$${priceData.bitcoin.usd.toLocaleString()}` : 'N/A';
const fee = fees.fastestFee ? `${fees.fastestFee} sat/vB` : 'N/A';
let difficulty = 'N/A';
if (hrData.currentDifficulty) {
const exp = Math.floor(Math.log10(hrData.currentDifficulty));
const power = Math.floor(exp / 3) * 3;
const base = hrData.currentDifficulty / Math.pow(10, power);
difficulty = `${base.toFixed(1)}×10<sup>${power}</sup>`;
}
let nextDate = 'N/A';
if (diffAdj.estimatedRetargetDate) {
const ts = diffAdj.estimatedRetargetDate;
const ms = ts < 1e12 ? ts * 1000 : ts;
nextDate = new Date(ms).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
}
let hashRate = 'N/A';
if (hrData.currentHashrate) {
const units = ['H/s', 'kH/s', 'MH/s', 'GH/s', 'TH/s', 'PH/s', 'EH/s', 'ZH/s'];
let v = hrData.currentHashrate, i = 0;
while (v >= 1000 && i < units.length - 1) { v /= 1000; i++; }
hashRate = v.toFixed(2) + ' ' + units[i];
}
document.getElementById('network-stats').innerHTML = `${price} | ${fee} | ${height} | ${difficulty} | Next Difficulty: ${nextDate} | ${hashRate}`;
}).catch(err => { console.error(err); document.getElementById('network-stats').innerText = 'Failed to load stats.'; });
</script>
</body>
</html>