diff --git a/CHANGELOG.md b/CHANGELOG.md index 6561c97..a4370e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ The long form, with what was wrong before and how it was found, is in ### Added +- A Classic theme after the 2004 Mac app, beside Dark and Light: brushed-metal toolbar, Aqua + blue selection, red unread badges, a striped table and Lucida Grande. The theme button steps + through all three and remembers the choice. - A toolbar across the top, after the original iPodderX: add and unsubscribe, play, mark read and keep for the selected item, scan, a search box for what is showing, and Settings and Log. - Directory, Popular and All Subscriptions at the top of the feed list, opening in the main pane. @@ -28,8 +31,10 @@ The long form, with what was wrong before and how it was found, is in items show without pressing Scan. - A file deleted to save space, or by hand, looks as if it was never downloaded: no "reaped" label, just the Download button. The retention summary says "deleted", not "reaped". -- The Files pane and an item's own buttons are icons, with the words in their tooltips: save, - delete, view, download, mark read, keep, and open the original. +- Buttons are icons, with the words in their tooltips: the Files pane (save, delete, view, + download), an item's own buttons (mark read, keep, open the original), the feed header (scan, + download latest, mark all read, settings, unsubscribe), and the Settings, feed settings and + Download latest dialogs (save, download, cancel). ### Security diff --git a/tests/ui/app.spec.js b/tests/ui/app.spec.js index f23e1d7..19de1a0 100644 --- a/tests/ui/app.spec.js +++ b/tests/ui/app.spec.js @@ -29,6 +29,18 @@ test('the theme toggle actually changes the theme', async ({ page }) => { .not.toBe(before); }); +test('the theme button steps through dark, light and classic, and remembers', async ({ page }) => { + const theme = () => page.evaluate(() => document.documentElement.dataset.theme); + for (let i = 0; i < 3 && (await theme()) !== 'classic'; i++) await page.locator('#theme').click(); + expect(await theme()).toBe('classic'); + await expect(page.locator('#theme')).toHaveAttribute('title', /Classic.*Click for Dark/); + + await page.reload(); + await expect.poll(theme).toBe('classic'); + // The 2004 Mac app set its type in Lucida Grande. + expect(await page.evaluate(() => getComputedStyle(document.body).fontFamily)).toContain('Lucida Grande'); +}); + test('settings opens and saves the global schedule', async ({ page }) => { await page.locator('#prefs').click(); await expect(page.locator('#modal.on')).toBeVisible(); @@ -136,7 +148,7 @@ test('the filter tabs change what is listed', async ({ page }) => { test('a feed URL is editable and has a copy button', async ({ page }) => { await page.getByText('Test Show').click(); - await page.locator('.btn', { hasText: 'Settings' }).first().click(); + await page.locator('#content .acts [data-a="settings"]').click(); await expect(page.locator('#surl')).toHaveValue(/show\.xml/); await expect(page.locator('#scopy')).toBeVisible(); @@ -239,7 +251,7 @@ test('marking an OPML subscription read covers the feeds inside it', async ({ pa await expect(folder.locator('.badge')).not.toHaveText('0'); await folder.click(); - await page.locator('#content .acts button', { hasText: 'Mark all read' }).click(); + await page.locator('#content .acts [data-a="read"]').click(); await expect(folder.locator('.badge')).toHaveText('0'); }); diff --git a/web/index.html b/web/index.html index 5b94539..9d6f933 100644 --- a/web/index.html +++ b/web/index.html @@ -44,6 +44,26 @@ --bad:#b3402f; --shadow:0 8px 28px rgba(45,83,145,.14); } +/* Classic: the 2004 Mac app. Colours here; the chrome it needs is at the end of the sheet. */ +:root[data-theme="classic"] { + color-scheme:light; + --bg:#ffffff; + --panel:#e7ebf1; /* the source list's pale blue-grey */ + --panel2:#f2f2f2; + --raise:#d5dce7; + --line:#a9a9a9; + --fg:#000000; + --dim:#444444; + --faint:#666666; + --accent:#3875d7; /* Aqua selection blue */ + --accent2:#2a5db0; + --ink:#ffffff; + --good:#237a23; + --warn:#a15f00; + --bad:#c42b1c; + --shadow:0 4px 16px rgba(0,0,0,.28); + --r:5px; +} *{box-sizing:border-box} /* A rule that sets display beats the UA's [hidden], and several below do. */ [hidden]{display:none!important} @@ -427,6 +447,54 @@ input[type=range]::-moz-range-thumb{width:12px;height:12px;border:0;border-radiu #logbox .lv{width:auto} #logbox .tg{display:none} } + +/* ---------- Classic: the 2004 Mac app ---------- */ +/* After the iPodderX screenshots: brushed-metal chrome, a pale blue-grey source list, Aqua blue + for whatever is selected, red unread badges, a striped table and Lucida Grande. */ +:root[data-theme="classic"] body{ + font-family:"Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif;font-size:13px; +} +:root[data-theme="classic"] #topbar, +:root[data-theme="classic"] #status, +:root[data-theme="classic"] #player{background:linear-gradient(#ececec,#c9c9c9);border-color:#8e8e8e;color:#1a1a1a} +:root[data-theme="classic"] #status{text-align:center} +:root[data-theme="classic"] #sidebar{background:#e7ebf1;border-right-color:#a3a3a3} +:root[data-theme="classic"] #files{background:#f4f4f4} +:root[data-theme="classic"] .tgroup{background:none;border-color:#8e8e8e;border-radius:6px} +:root[data-theme="classic"] .tgroup button+button{border-left-color:#8e8e8e} +:root[data-theme="classic"] .tgroup button, +:root[data-theme="classic"] .btn, +:root[data-theme="classic"] .tabs{background:linear-gradient(#ffffff,#d9d9d9);border-color:#8e8e8e;color:#1a1a1a} +:root[data-theme="classic"] .tabs{border:1px solid #8e8e8e;border-radius:6px} +:root[data-theme="classic"] .tgroup button:hover:not(:disabled), +:root[data-theme="classic"] .btn:hover{background:linear-gradient(#f5f9ff,#cbdbf4)} +:root[data-theme="classic"] .btn.primary, +:root[data-theme="classic"] .tabs button.on, +:root[data-theme="classic"] .feed.sel, +:root[data-theme="classic"] .place.sel{background:linear-gradient(#86b0ec,#3a73cf);border-color:#2d5eae;color:#fff} +:root[data-theme="classic"] .feed.sel .txt small, +:root[data-theme="classic"] .place.sel .ico{color:#e6eeff} +:root[data-theme="classic"] #epSearch{border-radius:14px} +:root[data-theme="classic"] .badge{background:#c9302c;color:#fff} +:root[data-theme="classic"] .badge.zero{background:#b4bdc9;color:#fff} +:root[data-theme="classic"] .ephead, +:root[data-theme="classic"] .fhd{ + background:linear-gradient(#fbfbfb,#dcdcdc);color:#1a1a1a;text-transform:none;letter-spacing:0;font-size:11px; +} +:root[data-theme="classic"] .fhd{padding:3px 6px;border:1px solid #c2c2c2} +:root[data-theme="classic"] .ephead{border-bottom-color:#a3a3a3} +:root[data-theme="classic"] .ep{border-radius:0;margin:0} +:root[data-theme="classic"] #eps .ep:nth-child(even){background:#edf3fe} +:root[data-theme="classic"] .ep .t{color:#1c4fa8} +:root[data-theme="classic"] .ep.read .t{color:#333} +:root[data-theme="classic"] #eps .ep.sel{background:#3875d7;border-color:#3875d7} +:root[data-theme="classic"] .ep.sel .t, +:root[data-theme="classic"] .ep.sel .fd, +:root[data-theme="classic"] .ep.sel .date, +:root[data-theme="classic"] .ep.sel .line, +:root[data-theme="classic"] .ep.sel .st, +:root[data-theme="classic"] .ep.sel .fl{color:#fff} +:root[data-theme="classic"] .dt{background:linear-gradient(#80aae6,#3f78cf);color:#fff;padding:6px 12px;border-radius:4px}
@@ -692,11 +760,11 @@ function renderFeed(){ ${f.group?`