Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b3060e1
fix(ui): remove the previous bundle's style sheets when PodNotes loads
chhoumann Oct 14, 2026
ab1f3a0
refactor(ui): share one button reset, one focus ring and one playing …
chhoumann Oct 14, 2026
6741da5
fix(ui): polish fallback covers, the address banner, disabled control…
chhoumann Oct 14, 2026
ff270f7
fix(ui): name settings fields, widen Edit, and stop all motion on req…
chhoumann Oct 14, 2026
da900f2
Merge remote-tracking branch 'origin/master' into feat/ui-polish-impl
chhoumann Oct 14, 2026
f24fbac
fix(ui): give the phone player room, and fix hover and menu Escape on…
chhoumann Oct 14, 2026
92d665a
refactor(ui): draw the full player's artwork with Cover, as rows and …
chhoumann Oct 14, 2026
cb594df
refactor(ui): keep master's wrapping feed banner detail
chhoumann Oct 14, 2026
a4e15ec
fix(ui): leave video fullscreen on the first Escape, and open a saved…
chhoumann Oct 14, 2026
9fccd8d
test(e2e): place the transcript journeys' view instead of assuming th…
chhoumann Oct 14, 2026
edf4875
test(e2e): a private feed with its address here lists its cached epis…
chhoumann Oct 14, 2026
4098137
refactor(ui): anchor each component's styles on its root
chhoumann Oct 14, 2026
5bf43ba
refactor(ui): keep the row equalizer's keyframes global
chhoumann Oct 14, 2026
1f835b3
refactor(ui): style a chapter's name with Panel's rows
chhoumann Oct 14, 2026
28b1789
fix(ui): open a saved transcript note when the feed transcript is mis…
chhoumann Oct 14, 2026
e69c606
fix(ui): name each settings toggle where it takes focus
chhoumann Oct 14, 2026
0b1c059
fix(ui): light up hovered controls only on a device that can hover
chhoumann Oct 14, 2026
7c72260
fix(ui): clip a text cover's name after its third line
chhoumann Oct 14, 2026
a824008
test(e2e): on a phone, the Escape that closes a row menu keeps focus …
chhoumann Oct 14, 2026
1e12314
test(e2e): restore the plugin's links after an update test that faile…
chhoumann Oct 15, 2026
62a2119
refactor(ui): drop declarations that restate Obsidian's defaults
chhoumann Oct 15, 2026
c4650f9
refactor(ui): draw a transcript that failed or is missing as one empt…
chhoumann Oct 15, 2026
ee864af
refactor(ui): count items with a class of the view's own, not Obsidia…
chhoumann Oct 15, 2026
7b55986
test(e2e): offline, a private feed shows no failure from before it we…
chhoumann Oct 15, 2026
6ee5a08
fix(ui): name the Local files page as it is spelled in its menu item
chhoumann Oct 15, 2026
5bd6ad4
fix(ui): say that a second download to a shared path fails
chhoumann Oct 15, 2026
71bd0e6
fix(ui): fold the transcript's Save into its icon wherever the head i…
chhoumann Oct 15, 2026
0b1da27
fix(ui): follow a transcript line with the line before it in full view
chhoumann Oct 15, 2026
b41ff7d
test(e2e): start each suite online, whatever the instance was left in
chhoumann Oct 15, 2026
7f6d1cb
Merge remote-tracking branch 'origin/master' into feat/ui-polish
chhoumann Oct 15, 2026
6b522ff
fix(ui): follow a line or chapter between the panel's faded edges
chhoumann Oct 15, 2026
f9128db
test(e2e): share the phone layout and the right drawer placement
chhoumann Oct 15, 2026
a45fb56
test(e2e): check the name Chromium gives each settings field Tab reaches
chhoumann Oct 15, 2026
cd1a917
fix(ui): name the transcript's note button by its label, with no tooltip
chhoumann Oct 15, 2026
4b6055f
fix(ui): keep the rail's add button padding on a tablet
chhoumann Oct 15, 2026
0e35861
fix(ui): keep the stage's artwork look off a panel's row covers
chhoumann Oct 15, 2026
254d81c
fix(ui): dim every disabled control to 0.4, the look of Obsidian's di…
chhoumann Oct 15, 2026
ed9f537
fix(ui): end a phone's search text where its clear button starts
chhoumann Oct 15, 2026
882200e
docs(ui): say what fits the transcript head's 340 px
chhoumann Oct 15, 2026
d5decf4
fix(ui): keep a pressed icon button dimmed when it is disabled
chhoumann Oct 15, 2026
6f73df0
test(e2e): turn diarization on only when it is off, and name what the…
chhoumann Oct 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ function fakeWorkspace(notes: ReturnType<typeof fakeVault>["notes"]) {
return {};
}),
getLeavesOfType: (type: string) => (type === "markdown" ? [...open] : []),
iterateAllLeaves: vi.fn(),
getActiveViewOfType: () => null,
getRightLeaf: () => null,
revealLeaf: vi.fn(),
Expand Down
34 changes: 33 additions & 1 deletion src/main.activateView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,10 @@ describe("PodNotes onload wiring (#55)", () => {
vi.restoreAllMocks();
});

async function loadPlugin(loadedData: Record<string, unknown> = {}) {
async function loadPlugin(
loadedData: Record<string, unknown> = {},
own: Partial<Record<"loadData" | "registerView", unknown>> = {},
) {
const activateSpy = vi
.spyOn(PodNotes.prototype, "activateView")
.mockResolvedValue(undefined);
Expand Down Expand Up @@ -350,12 +353,14 @@ describe("PodNotes onload wiring (#55)", () => {
on: vi.fn(() => ({})),
offref: vi.fn(),
getLeavesOfType: vi.fn(() => []),
iterateAllLeaves: vi.fn(),
getRightLeaf: vi.fn(() => null),
getActiveViewOfType: vi.fn(() => null),
revealLeaf: vi.fn(),
detachLeavesOfType: vi.fn(),
},
},
...own,
});

await plugin.onload();
Expand All @@ -364,6 +369,33 @@ describe("PodNotes onload wiring (#55)", () => {
return { commands, ribbonCalls, activateSpy, plugin };
}

it("removes an earlier build's sheets before it loads anything, and keeps those its views append", async () => {
const sheet = (id: string) =>
document.head.appendChild(Object.assign(document.createElement("style"), { id }));
const shown = () => [...document.head.querySelectorAll("style")].map((style) => style.id);
sheet("pn-earlier");
const seen: Record<string, string[]> = {};
onTestFinished(() => document.head.replaceChildren());

await loadPlugin(
{ schemaVersion: 2 },
{
loadData: vi.fn(async () => {
seen.loadData = shown();
return { schemaVersion: 2 };
}),
// Obsidian mounts the restored views here, and each appends its sheet.
registerView: vi.fn(() => {
seen.registerView = shown();
sheet("pn-mounted");
}),
},
);

expect(seen).toEqual({ loadData: [], registerView: [] });
expect(shown()).toEqual(["pn-mounted"]);
});

it("starts no save once the window fires pagehide", async () => {
const { plugin } = await loadPlugin({ schemaVersion: 2 });
const domEvents = vi.mocked(plugin.registerDomEvent).mock.calls as unknown as Array<
Expand Down
1 change: 1 addition & 0 deletions src/main.fileRenames.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ async function loadPlugin(data: Record<string, unknown>): Promise<PodNotes> {
onLayoutReady: vi.fn(),
on: vi.fn(() => ({})),
getLeavesOfType: vi.fn(() => []),
iterateAllLeaves: vi.fn(),
getRightLeaf: vi.fn(() => null),
getActiveViewOfType: vi.fn(() => null),
revealLeaf: vi.fn(),
Expand Down
3 changes: 3 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { PodNotesSettingsTab } from "src/ui/settings/PodNotesSettingsTab";
import { MainView } from "src/ui/PodcastView";
import { Navigation } from "src/ui/PodcastView/Navigation";
import { dismissUndoNotices } from "src/ui/undoNotice";
import { removePreviousStyles } from "src/ui/removePreviousStyles";
import type { IPodNotesSettings } from "./types/IPodNotesSettings";
import type { IPodNotes } from "./types/IPodNotes";
import type PartialAppExtension from "./global";
Expand Down Expand Up @@ -127,6 +128,8 @@ export default class PodNotes extends Plugin implements IPodNotes {
private persistenceUnknownFields: Record<string, unknown> = {};

override async onload() {
// Before registerView, where the views Obsidian restores mount and append their sheets.
removePreviousStyles(this.app.workspace);
this.isUnloaded = false;
this.podcastViewMountEnabled = !this.isMobileRuntime();
this.registerDomEvent(window, "pagehide", () => {
Expand Down
1 change: 1 addition & 0 deletions src/main.undo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ async function loadPlugin(secrets: obsidian.SecretStorage): Promise<PodNotes> {
on: vi.fn(() => ({})),
offref: vi.fn(),
getLeavesOfType: vi.fn(() => []),
iterateAllLeaves: vi.fn(),
getActiveViewOfType: vi.fn(() => null),
},
},
Expand Down
55 changes: 21 additions & 34 deletions src/ui/PodcastView/AddPodcastPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@

{#snippet alternatives()}
<div class="pn-alts">
<button type="button" class="pn-alt" onclick={() => pickVaultMedia(app)}>
<button type="button" class="pn-bare pn-alt" onclick={() => pickVaultMedia(app)}>
<span {@attach icon("folder")}></span>Play a vault file
</button>
<button
type="button"
class="pn-alt"
class="pn-bare pn-alt"
onclick={() =>
pickFile(".opml", importOPML, {
tooLargeMessage: "That file is too large to be an OPML file.",
Expand Down Expand Up @@ -93,7 +93,7 @@
{@const added = actions.savedKey($savedFeeds, result.feed.url) !== undefined}
<button
type="button"
class="pn-result"
class="pn-bare pn-result"
aria-label="{added ? 'Open' : 'Add'} {result.feed.title}"
onclick={() => add(result)}
>
Expand All @@ -113,7 +113,7 @@
{/if}

<style>
.pn-empty {
.pn-empty :global {
flex: 1;
min-height: 0;
overflow-y: auto;
Expand All @@ -122,9 +122,7 @@
align-items: center;
padding: var(--size-4-6) var(--pn-pad) 72px;
text-align: center;
}

.pn-empty :global {
/* Centered, yet scrollable from its top when the view is short. */
> :first-child {
margin-top: auto;
Expand Down Expand Up @@ -161,33 +159,26 @@
}
}

.pn-alts {
.pn-alts :global {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: var(--size-2-2);
margin-top: var(--size-4-2);
}

.pn-alts :global {
.pn-alt {
display: inline-flex;
align-items: center;
gap: var(--size-4-2);
height: var(--pn-btn);
padding: 0 var(--size-4-2);
border: 0;
border-radius: var(--radius-s);
background: none;
box-shadow: none;
color: var(--text-muted);
font-size: var(--font-ui-small);
cursor: var(--cursor);
}

.pn-alt:hover {
background: var(--background-modifier-hover);
color: var(--text-normal);
@media (hover: hover) {
.pn-alt:hover {
background: var(--background-modifier-hover);
color: var(--text-normal);
}
}

.pn-alt > span {
Expand All @@ -201,24 +192,24 @@
/* Obsidian's buttons keep their text on one line; this one wraps its title. */
.pn-result {
display: flex;
align-items: center;
gap: var(--size-4-3);
width: 100%;
height: auto;
padding: var(--size-4-2);
border: 0;
border-radius: var(--radius-s);
background: none;
box-shadow: none;
color: var(--text-normal);
font-size: var(--font-ui-small);
text-align: left;
white-space: normal;
cursor: var(--cursor);
}

.pn-result:hover {
background: var(--background-modifier-hover);
@media (hover: hover) {
.pn-result:hover {
background: var(--background-modifier-hover);
}

.pn-result:hover .end:not(.added) {
color: var(--text-accent);
}
}

.pn-result .pn-cover {
Expand Down Expand Up @@ -268,20 +259,16 @@
color: var(--text-success);
}

.pn-result:hover .end:not(.added) {
color: var(--text-accent);
}

.pn-linkchip {
display: inline-flex;
align-items: center;
gap: 4px;
vertical-align: bottom;
--icon-size: 12px;
}
}

:global(.is-phone) .pn-results :global(.pn-result .pn-cover) {
width: 52px;
.is-phone & .pn-result .pn-cover {
width: 52px;
}
}
</style>
16 changes: 3 additions & 13 deletions src/ui/PodcastView/ChaptersPanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { Chapter } from "src/types/Chapter";
import { formatDuration } from "src/utility/formatDuration";
import { chapterAt } from "./chapters";
import Panel from "./Panel.svelte";
import Panel, { reveal } from "./Panel.svelte";

let {
chapters,
Expand All @@ -17,12 +17,8 @@
let list: HTMLElement | undefined = $state();
const current = $derived(chapterAt(chapters, position));

// Scrolls only the panel: scrollIntoView would also scroll the view and an editor around it.
$effect(() => {
const row = list?.children[current];
if (!list || !row) return;
const top = row.getBoundingClientRect().top - list.getBoundingClientRect().top;
list.scrollTop += top - list.clientHeight / 3;
if (list) reveal(list, current);
});
</script>

Expand All @@ -31,7 +27,7 @@
<li>
<button
type="button"
class="pn-row pn-chap"
class="pn-bare pn-row"
class:is-now={index === current}
aria-current={index === current || undefined}
onclick={() => onseek(chapter.startTime)}
Expand All @@ -42,9 +38,3 @@
</li>
{/each}
</Panel>

<style>
.pn-chap :global(.nm) {
font-weight: var(--font-medium);
}
</style>
43 changes: 25 additions & 18 deletions src/ui/PodcastView/Cover.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,38 @@
{/if}

<style>
.pn-cover {
.pn-cover :global {
display: block;
flex: none;
width: 100%;
aspect-ratio: 1;
border-radius: 6px;
object-fit: cover;
}

.pn-cover.is-text {
display: flex;
align-items: flex-end;
overflow: hidden;
background: var(--background-modifier-border);
color: var(--text-muted);
font-weight: var(--font-bold);
line-height: 1;
text-align: left;
overflow-wrap: anywhere;
container-type: inline-size;
}
&.is-text {
display: flex;
align-items: flex-end;
overflow: hidden;
background: var(--background-modifier-border);
color: var(--text-muted);
font-weight: var(--font-bold);
line-height: 1;
text-align: left;
overflow-wrap: anywhere;
container-type: inline-size;

/* cqw is the cover's width. A percentage padding on the cover is its row's. */
.pn-cover.is-text > :global(span) {
padding: 10cqw;
font-size: 12cqw;
/* cqw is the cover's width. Three lines keep a long title's beginning, at a size a
row's small cover can show. A padding would show the fourth line in it, above the
clip edge; a margin keeps that edge under the third. */
> span {
display: -webkit-box;
-webkit-line-clamp: 3;
line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
margin: 10cqw;
font-size: max(10px, 12cqw);
}
}
}
</style>
Loading
Loading