diff --git a/CHANGELOG.md b/CHANGELOG.md index 9404b32..ca069d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,31 @@ Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) — versi --- +## [0.2.0] — 2026-05-26 + +### Changed — UI rebuilt to WordPress admin standards +v0.1.0 worked but looked like a third-party React widget sitting on top of WordPress rather than part of it. v0.2.0 rebuilds the player UI to use WP-native patterns end-to-end. + +- **Main page** now uses the standard **`.postbox` container** (gray header bar + `.inside` body) instead of a custom rounded-shadow card. +- **Play button** is now a standard **`.button .button-primary`** with both icon AND text label (Play / Pause), matching every other admin button. Replaces the giant blue circular icon-only button. +- **Now Playing** uses left-aligned default body text with `.description` muted-gray for the station tagline. Replaces the centered large-typography card. +- **Genre badge** moved to a small `.radio-player__station-genre` text label aligned right of the station name. Replaces the custom pill. +- **Volume slider** now uses `accent-color: var(--wp-admin-theme-color)` — adapts to whichever admin colour scheme the user has chosen (Default / Light / Modern / Blue / Coffee / Ectoplasm / Midnight / Ocean / Sunrise). +- **All link colours** likewise adapt to the user's admin theme via `var(--wp-admin-theme-color, #2271b1)`. +- **Dashboard widget** content sits bare inside its `.inside` — WordPress already wraps it in a postbox. v0.1.0 was rendering a card inside a card. +- **About page** cards now use postbox-style gray header bars + WP-standard 1px border + subtle shadow. Replaces the custom rounded grid. +- **Credit footer** uses `.description` class, smaller and more native. + +### Net effect +The plugin feels like part of WordPress now, not bolted onto it. Picks up your admin colour scheme automatically. Closer to WP.org submission criteria — they look for native-styled plugins during plugin review. + +### Not changed +- Functionality identical to v0.1.0 — same 44 stations, same audio path, same user_meta persistence, same updater, same AJAX endpoint. +- No behaviour change for end users; this is purely visual. +- About page version-history card promotes v0.2.0 to "latest", demotes v0.1.0. + +--- + ## [0.1.0] — 2026-05-26 **Radio is born.** First release of a new standalone WordPress plugin extracted-and-rebuilt from the radio feature that lives inside RangerPlex. Radio stands on its own as a focused, friendly companion plugin for the WordPress dashboard — a tab of background music while you work. diff --git a/assets/css/radio.css b/assets/css/radio.css index a1fcbd0..f790725 100644 --- a/assets/css/radio.css +++ b/assets/css/radio.css @@ -1,118 +1,109 @@ -/* Radio — admin styles */ +/* Radio — admin styles, WordPress-native */ + +/* ────────────────────────────────────────────────────────────────── + * Player layout (works inside .postbox .inside on main page, + * and bare on the dashboard widget where .inside is the parent) + * ─────────────────────────────────────────────────────────────── */ .radio-player { display: flex; flex-direction: column; - gap: 12px; - padding: 8px 0; + gap: 14px; } +/* Now Playing — left-aligned, body text size, no custom typography */ .radio-player__now { - text-align: center; - padding-bottom: 6px; - border-bottom: 1px solid #e5e5e5; -} - -.radio-player__now--large { - padding: 18px 0; + display: flex; + align-items: baseline; + flex-wrap: wrap; + gap: 8px; + padding-bottom: 10px; + border-bottom: 1px solid #dcdcde; } .radio-player__label { font-size: 11px; text-transform: uppercase; - letter-spacing: 0.08em; + letter-spacing: 0.06em; color: #646970; - margin-bottom: 4px; + font-weight: 600; + margin-right: 4px; } .radio-player__station-name { - font-size: 16px; + font-size: 14px; font-weight: 600; color: #1d2327; } -.radio-player__now--large .radio-player__station-name { - font-size: 24px; -} - .radio-player__station-desc { font-size: 13px; color: #50575e; - margin-top: 2px; + flex: 1 1 100%; + margin: 0; } .radio-player__station-genre { - display: inline-block; - margin-top: 6px; - padding: 2px 10px; - background: #f0f0f1; - border-radius: 12px; font-size: 11px; - color: #2c3338; + color: #646970; text-transform: uppercase; letter-spacing: 0.04em; + margin-left: auto; } +/* Controls — single row, native button + slider */ .radio-player__controls { display: flex; align-items: center; gap: 12px; -} - -.radio-player__controls--large { - justify-content: center; - gap: 20px; - padding: 8px 0; + flex-wrap: wrap; } .radio-player__play { - display: inline-flex; + /* native .button .button-primary styling; just ensure icon aligns */ + display: inline-flex !important; align-items: center; - justify-content: center; - width: 40px; - height: 40px; - border-radius: 50% !important; - padding: 0 !important; - line-height: 1 !important; + gap: 6px; } .radio-player__play .dashicons { - font-size: 20px; - width: 20px; - height: 20px; + font-size: 18px; + width: 18px; + height: 18px; line-height: 1; } -.radio-player__controls--large .radio-player__play { - width: 56px; - height: 56px; -} - -.radio-player__controls--large .radio-player__play .dashicons { - font-size: 28px; - width: 28px; - height: 28px; -} - .radio-player__volume { display: flex; align-items: center; - gap: 6px; + gap: 8px; flex: 1; + min-width: 200px; +} + +.radio-player__volume .dashicons { + color: #646970; + font-size: 16px; + width: 16px; + height: 16px; } .radio-player__volume input[type="range"] { flex: 1; - accent-color: #2271b1; + margin: 0; + /* Use WP's admin theme colour for the slider thumb/track */ + accent-color: var(--wp-admin-theme-color, #2271b1); } .radio-player__volume-pct { min-width: 36px; font-size: 12px; - color: #50575e; + color: #646970; text-align: right; + font-variant-numeric: tabular-nums; } +/* Station selector — label-on-top, full-width select */ .radio-player__station-select { display: flex; flex-direction: column; @@ -124,35 +115,38 @@ text-transform: uppercase; letter-spacing: 0.06em; color: #646970; + font-weight: 600; } .radio-player__station-select select { width: 100%; - max-width: 480px; + max-width: 100%; } +/* Error notice — uses WP notice styling */ .radio-player__error { color: #b32d2e; - font-size: 12px; + font-size: 13px; padding: 6px 10px; background: #fcf0f1; - border-left: 3px solid #b32d2e; - border-radius: 2px; -} - -.radio-player__credit { - font-size: 12px; - color: #646970; - text-align: center; + border-left: 4px solid #b32d2e; + border-radius: 0; margin: 0; } +/* Credit footer */ +.radio-player__credit { + margin: 0; + color: #646970; + font-size: 12px; +} + .radio-player__credit--main { - margin-top: 18px; + margin-top: 12px; } .radio-player__credit a { - color: #2271b1; + color: var(--wp-admin-theme-color, #2271b1); text-decoration: none; } @@ -160,54 +154,101 @@ text-decoration: underline; } -/* Main page wraps the player at a comfortable max width. */ -.radio-wrap .radio-player--main { - max-width: 640px; - padding: 20px 24px; - background: #fff; - border: 1px solid #ccd0d4; - border-radius: 6px; - margin-top: 18px; +/* ────────────────────────────────────────────────────────────────── + * Main admin page — wrap player in a postbox-like card + * ─────────────────────────────────────────────────────────────── */ + +.radio-wrap .radio-player { + margin-top: 4px; } .radio-intro { - max-width: 640px; + margin: 0 0 16px; color: #50575e; + font-size: 13px; + max-width: 720px; } -/* About page layout */ +/* ────────────────────────────────────────────────────────────────── + * Dashboard widget — no nested card; bare content inside .inside + * (WP renders the widget as a postbox already; don't double up) + * ─────────────────────────────────────────────────────────────── */ + +#radio_dashboard_widget .radio-player { + gap: 10px; +} + +#radio_dashboard_widget .radio-player__now { + padding-bottom: 8px; +} + +#radio_dashboard_widget .radio-player__station-name { + font-size: 14px; +} + +#radio_dashboard_widget .radio-player__credit { + border-top: 1px solid #dcdcde; + padding-top: 8px; + margin-top: 4px; + text-align: center; +} + +/* ────────────────────────────────────────────────────────────────── + * About page — postbox-style cards in a metabox column layout + * ─────────────────────────────────────────────────────────────── */ + .radio-about-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 18px; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 16px; max-width: 1100px; + margin-top: 16px; } .radio-about-card { background: #fff; - border: 1px solid #ccd0d4; - border-radius: 6px; - padding: 18px 20px; + border: 1px solid #c3c4c7; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); } .radio-about-card h2 { - margin-top: 0; - font-size: 16px; + margin: 0; + padding: 8px 12px; + font-size: 14px; + font-weight: 600; + background: #f6f7f7; + border-bottom: 1px solid #c3c4c7; +} + +.radio-about-card > p, +.radio-about-card > ul, +.radio-about-card > a { + padding: 12px; + margin: 0; +} + +.radio-about-card > p + p { + padding-top: 0; } .radio-about-card--versions ul { list-style: none; - margin-left: 0; - padding-left: 0; + padding: 12px; + margin: 0; } .radio-about-card--versions li { - margin-bottom: 12px; + margin-bottom: 10px; + font-size: 13px; +} + +.radio-about-card--versions li:last-child { + margin-bottom: 0; } .radio-about-card--versions .ver { font-weight: 600; - color: #2271b1; + color: var(--wp-admin-theme-color, #2271b1); } .radio-about-card--versions .latest { @@ -219,10 +260,17 @@ border-radius: 9px; font-size: 11px; font-weight: 600; + vertical-align: middle; } .radio-about-changelog-link { display: inline-block; - margin-top: 8px; + margin: 0 12px 12px; font-size: 13px; + color: var(--wp-admin-theme-color, #2271b1); + text-decoration: none; +} + +.radio-about-changelog-link:hover { + text-decoration: underline; } diff --git a/assets/js/radio.js b/assets/js/radio.js index ce95bea..891bf47 100644 --- a/assets/js/radio.js +++ b/assets/js/radio.js @@ -42,11 +42,16 @@ }).catch(function () { /* swallow — local UI already updated */ }); } - /** Update play/pause button icon to reflect current audio state. */ + /** Update play/pause button icon + label to reflect current audio state. */ function setPlayIcon(btn, playing) { var icon = btn.querySelector('.dashicons'); - if (!icon) { return; } - icon.className = 'dashicons ' + (playing ? 'dashicons-controls-pause' : 'dashicons-controls-play'); + var label = btn.querySelector('[data-radio-play-label]'); + if (icon) { + icon.className = 'dashicons ' + (playing ? 'dashicons-controls-pause' : 'dashicons-controls-play'); + } + if (label) { + label.textContent = playing ? (cfg.strings.pause || 'Pause') : (cfg.strings.play || 'Play'); + } btn.setAttribute('title', playing ? (cfg.strings.pause || 'Pause') : (cfg.strings.play || 'Play')); } @@ -122,6 +127,8 @@ audio.load(); if (nameEl) { nameEl.textContent = s.name; } if (descEl) { descEl.textContent = s.description || ''; } + var genreEl = player.querySelector('[data-radio-genre]'); + if (genreEl) { genreEl.textContent = s.genre || ''; } // Mirror selection to any OTHER .radio-player surfaces on the page. mirrorSelection(player, newId); saveState({ station_id: newId }); @@ -157,8 +164,10 @@ if (s) { var nm = other.querySelector('[data-radio-name]'); var dc = other.querySelector('[data-radio-desc]'); + var gn = other.querySelector('[data-radio-genre]'); if (nm) { nm.textContent = s.name; } if (dc) { dc.textContent = s.description || ''; } + if (gn) { gn.textContent = s.genre || ''; } } } }); diff --git a/inc/about.php b/inc/about.php index 6784990..7c9ca0c 100644 --- a/inc/about.php +++ b/inc/about.php @@ -48,7 +48,11 @@ function radio_render_about_page() {

diff --git a/inc/admin-page.php b/inc/admin-page.php index 752d32b..c213240 100644 --- a/inc/admin-page.php +++ b/inc/admin-page.php @@ -2,9 +2,10 @@ /** * Radio — main admin page (WP Admin → Radio → My Radio). * - * Larger player with the same controls as the dashboard widget. Both - * surfaces share the same JS (assets/js/radio.js binds to every - * .radio-player on the page). + * Uses WP-native postbox structure so the player feels like part of + * WordPress, not a third-party widget. The dashboard widget shares + * the same internal markup via assets/js/radio.js binding to every + * .radio-player on the page. */ if ( ! defined( 'ABSPATH' ) ) { exit; } @@ -26,55 +27,64 @@ function radio_render_main_page() {

-
-
-
-
-
-
+
+
+

+
+
-
- +
+ + + +

+
-
- - - % +
+ + +
+ + + % +
+
+ +
+ + +
+ + + +
- -
- - -
- - - -
-

+

-

+
+
-
-
-
+ + + +

-
- + + %
@@ -57,7 +61,7 @@ function radio_render_dashboard_widget() { ?> - @@ -72,7 +76,6 @@ function radio_render_dashboard_widget() {