feat(frontend): add static shell + index page

This commit is contained in:
devilreef 2026-04-30 09:44:14 +06:00
parent 01c281ca80
commit 04835f31b6
Signed by: devilreef
SSH key fingerprint: SHA256:UZisRr4iuXx+IhkbZnR655L2RWAT6o2rgbGv5F/6m3Y
6 changed files with 118 additions and 0 deletions

View file

@ -0,0 +1,8 @@
---
---
<footer class="footer">
<div class="footer-bot">
<span>denpa.fm — a tiny independent radio · est. 2026</span>
<span><a href="https://denpa.femboy.page/status-json.xsl">icecast status</a></span>
</div>
</footer>

View file

@ -0,0 +1,28 @@
---
const ORIGIN = 'https://denpa.femboy.page';
interface Props { stationId: string; }
const { stationId } = Astro.props;
---
<div class="card listen-ways">
<div class="full-secthead">
<div class="full-secthead-jp">他の聴き方</div>
<div class="full-secthead-en">// other ways to listen</div>
</div>
<div class="listen-ways-list">
<div class="listen-way">
<div class="lw-label">DIRECT STREAM (MP3)</div>
<code class="lw-url">{ORIGIN}/{stationId}.mp3</code>
<div class="lw-hint">drop into VLC, mpv, foobar, etc.</div>
</div>
<div class="listen-way">
<div class="lw-label">DIRECT STREAM (OPUS)</div>
<code class="lw-url">{ORIGIN}/{stationId}.opus</code>
<div class="lw-hint">smaller, better quality. modern players only.</div>
</div>
<div class="listen-way">
<div class="lw-label">METADATA JSON</div>
<code class="lw-url">{ORIGIN}/now-playing/{stationId}.json</code>
<div class="lw-hint">build your own scrobbler.</div>
</div>
</div>
</div>

View file

@ -0,0 +1,9 @@
---
---
<nav class="topnav">
<span class="topnav-brand">電波 / denpa.fm</span>
<div class="topnav-links">
<a href="#listen">listen</a>
<a href="#about">about</a>
</div>
</nav>

View file

@ -0,0 +1,44 @@
---
import '@styles/tokens.css';
import '@styles/global.css';
import '@styles/components/hero.css';
import '@styles/components/deck.css';
import '@styles/components/spectrum.css';
import '@styles/components/tape.css';
import '@styles/components/history-card.css';
import '@styles/components/listen-ways-card.css';
import '@styles/components/footer.css';
import TopNav from '@components/TopNav.astro';
import HistoryCard from '@components/HistoryCard.astro';
import ListenWaysCard from '@components/ListenWaysCard.astro';
import FooterStrip from '@components/FooterStrip.astro';
import { HeroPlayer } from '@components/HeroPlayer';
import { listStations } from '@lib/stations';
export const prerender = false;
const root = process.env.LIBRARY_ROOT ?? '/library';
const initialStations = await listStations(root);
const firstStation = initialStations[0]?.id ?? '';
---
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>denpa.fm // 電波</title>
<meta name="description" content="denpa.fm — a tiny independent radio." />
</head>
<body>
<div class="page">
<TopNav />
<HeroPlayer initialStations={initialStations} client:load />
<div id="listen" class="row-grid two">
{firstStation ? <HistoryCard station={firstStation} /> : <div />}
{firstStation ? <ListenWaysCard stationId={firstStation} /> : <div />}
</div>
<FooterStrip />
</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
.footer {
margin-top: 12px; padding: 30px 0 24px;
border-top: 2px dashed #ff3ea566;
}
.footer-bot {
display: flex; justify-content: space-between; gap: 14px;
font-family: var(--f-mono); font-size: 12px; color: #fff4e8aa;
flex-wrap: wrap;
}

View file

@ -0,0 +1,20 @@
.listen-ways-list { display: flex; flex-direction: column; gap: 14px; }
.listen-way {
border: 1.5px dashed #5ef7ff44;
padding: 12px;
background: #0a04108c;
}
.lw-label { font-family: var(--f-pixel); font-size: 12px; color: var(--lemon); letter-spacing: 2px; margin-bottom: 4px; }
.lw-url {
display: block; font-family: var(--f-mono); font-size: 13px;
color: var(--cyan); background: var(--ink);
padding: 6px 8px; word-break: break-all;
}
.lw-hint { font-family: var(--f-mono); font-size: 11px; color: #fff4e866; margin-top: 6px; }
.row-grid { display: grid; gap: 24px; margin-bottom: 36px; }
.row-grid.two { grid-template-columns: 1.2fr 1fr; }
@media (max-width: 1000px) {
.row-grid.two { grid-template-columns: 1fr; }
}