Skip to content

Commit 95b5cf3

Browse files
committed
feat: podcast themes, hide RSS icon setting, CSS modular build
1 parent eaebcdd commit 95b5cf3

30 files changed

+18915
-7043
lines changed

.claude/settings.local.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
"Bash(npx tsc:*)",
55
"Bash(cd:*)",
66
"Bash(npx eslint:*)",
7-
"Bash(npm run build:*)"
7+
"Bash(npm run build:*)",
8+
"Bash(grep:*)",
9+
"Bash(sed:*)"
810
]
911
}
1012
}

docs/releases/2.1.9.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## 2.1.9
2+
3+
### Added
4+
5+
- 6 new podcast player themes: Nord, Dracula, Solarized Dark, Catppuccin Mocha, Gruvbox, Tokyo Night
6+
- Setting to hide the default RSS icon for regular feeds in the sidebar
7+
- CSS modular build system: styles split into 15 files under `src/styles/`, bundled via esbuild
8+
- Instant podcast theme switching from settings (no reload needed)
9+
10+
### Fixed
11+
12+
- Podcast playlist scroll position preserved when switching episodes
13+
- Replaced deprecated `lucide-` prefixed icon names with standard Obsidian icon names

esbuild.config.mjs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,18 @@ const context = await esbuild.context({
4444
}
4545
});
4646

47+
// CSS bundling: resolves @import in src/styles/index.css → styles.css
48+
const cssContext = await esbuild.context({
49+
entryPoints: ["src/styles/index.css"],
50+
bundle: true,
51+
outfile: "styles.css",
52+
logLevel: "info",
53+
minify: prod,
54+
});
55+
4756
if (prod) {
48-
await context.rebuild();
57+
await Promise.all([context.rebuild(), cssContext.rebuild()]);
4958
process.exit(0);
5059
} else {
51-
await context.watch();
60+
await Promise.all([context.watch(), cssContext.watch()]);
5261
}

main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export default class RssDashboardPlugin extends Plugin {
131131
void this.activateView();
132132
});
133133

134-
this.addRibbonIcon("lucide-compass", "RSS discover", () => {
134+
this.addRibbonIcon("compass", "RSS discover", () => {
135135
void this.activateDiscoverView();
136136
});
137137

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "rss-dashboard",
33
"name": "RSS Dashboard",
4-
"version": "2.1.8",
4+
"version": "2.1.9",
55
"minAppVersion": "1.1.0",
66
"description": "A dashboard for organizing and consuming RSS feeds, YouTube channels, and podcasts with smart tagging, media playback, and seamless content flow.",
77
"author": "Aditya Amatya",

src/components/article-list.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ export class ArticleList {
414414
: "Save article summary to notes"
415415
}
416416
});
417-
setIcon(saveButton, "lucide-save");
417+
setIcon(saveButton, "save");
418418
if (!saveButton.querySelector('svg')) {
419419
saveButton.textContent = '💾';
420420
}
@@ -437,7 +437,7 @@ export class ArticleList {
437437

438438
this.callbacks.onArticleSave(article);
439439
saveButton.classList.add("saved");
440-
setIcon(saveButton, "lucide-save");
440+
setIcon(saveButton, "save");
441441
if (!saveButton.querySelector('svg')) {
442442
saveButton.textContent = '💾';
443443
}
@@ -468,7 +468,7 @@ export class ArticleList {
468468
cls: 'rss-dashboard-star-icon'
469469
});
470470
starToggle.appendChild(starIcon);
471-
setIcon(starIcon, article.starred ? "lucide-star" : "lucide-star-off");
471+
setIcon(starIcon, article.starred ? "star" : "star-off");
472472
if (!starIcon.querySelector('svg')) {
473473
starIcon.textContent = article.starred ? '★' : '☆';
474474
}
@@ -479,7 +479,7 @@ export class ArticleList {
479479
starToggle.classList.toggle("unstarred", !starToggle.classList.contains("unstarred"));
480480
const iconEl = starToggle.querySelector('.rss-dashboard-star-icon');
481481
if (iconEl) {
482-
setIcon(iconEl as HTMLElement, article.starred ? "lucide-star" : "lucide-star-off");
482+
setIcon(iconEl as HTMLElement, article.starred ? "star" : "star-off");
483483
if (!iconEl.querySelector('svg')) {
484484
iconEl.textContent = article.starred ? '★' : '☆';
485485
}
@@ -744,7 +744,7 @@ export class ArticleList {
744744
: "Save article summary to notes"
745745
}
746746
});
747-
setIcon(saveButton, "lucide-save");
747+
setIcon(saveButton, "save");
748748
if (!saveButton.querySelector('svg')) {
749749
saveButton.textContent = '💾';
750750
}
@@ -767,7 +767,7 @@ export class ArticleList {
767767

768768
this.callbacks.onArticleSave(article);
769769
saveButton.classList.add("saved");
770-
setIcon(saveButton, "lucide-save");
770+
setIcon(saveButton, "save");
771771
if (!saveButton.querySelector('svg')) {
772772
saveButton.textContent = '💾';
773773
}
@@ -796,7 +796,7 @@ export class ArticleList {
796796
cls: 'rss-dashboard-star-icon'
797797
});
798798
starToggle.appendChild(starIcon);
799-
setIcon(starIcon, article.starred ? "lucide-star" : "lucide-star-off");
799+
setIcon(starIcon, article.starred ? "star" : "star-off");
800800
if (!starIcon.querySelector('svg')) {
801801
starIcon.textContent = article.starred ? '★' : '☆';
802802
}
@@ -807,7 +807,7 @@ export class ArticleList {
807807
starToggle.classList.toggle("unstarred", !starToggle.classList.contains("unstarred"));
808808
const iconEl = starToggle.querySelector('.rss-dashboard-star-icon');
809809
if (iconEl) {
810-
setIcon(iconEl as HTMLElement, article.starred ? "lucide-star" : "lucide-star-off");
810+
setIcon(iconEl as HTMLElement, article.starred ? "star" : "star-off");
811811
if (!iconEl.querySelector('svg')) {
812812
iconEl.textContent = article.starred ? '★' : '☆';
813813
}
@@ -1038,15 +1038,15 @@ export class ArticleList {
10381038

10391039
menu.addItem((item: MenuItem) => {
10401040
item.setTitle("Open in browser")
1041-
.setIcon("lucide-globe-2")
1041+
.setIcon("globe-2")
10421042
.onClick(() => {
10431043
window.open(article.link, "_blank");
10441044
});
10451045
});
10461046

10471047
menu.addItem((item: MenuItem) => {
10481048
item.setTitle("Open in split view")
1049-
.setIcon("lucide-sidebar")
1049+
.setIcon("panel-left")
10501050
.onClick(() => {
10511051
this.callbacks.onArticleClick(article);
10521052
});

src/components/sidebar.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ export class Sidebar {
247247
});
248248
menu.addItem((item: MenuItem) => {
249249
item.setTitle("Sort feeds")
250-
.setIcon("lucide-sort-asc")
250+
.setIcon("sort-asc")
251251
.onClick((evt) => {
252252
this.showFeedSortMenu(e, "");
253253
});
@@ -434,7 +434,7 @@ export class Sidebar {
434434
});
435435
menu.addItem((item: MenuItem) => {
436436
item.setTitle("Sort feeds")
437-
.setIcon("lucide-sort-asc")
437+
.setIcon("sort-asc")
438438
.onClick(() => {
439439
this.showFeedSortMenu(contextEvent, fullPath);
440440
});
@@ -562,15 +562,23 @@ export class Sidebar {
562562
// Fallback to RSS icon if favicon fails to load
563563
imgEl.onerror = () => {
564564
feedIcon.empty();
565-
setIcon(feedIcon, "rss");
565+
if (this.settings.display.hideDefaultRssIcon) {
566+
feedIcon.addClass("rss-icon-hidden");
567+
} else {
568+
setIcon(feedIcon, "rss");
569+
}
566570
};
567-
} else {
571+
} else if (!this.settings.display.hideDefaultRssIcon) {
568572
// No domain available, use generic RSS icon
569573
setIcon(feedIcon, "rss");
574+
} else {
575+
feedIcon.addClass("rss-icon-hidden");
570576
}
571-
} else {
577+
} else if (!this.settings.display.hideDefaultRssIcon) {
572578
// Show generic RSS icon when favicon setting is disabled
573579
setIcon(feedIcon, "rss");
580+
} else {
581+
feedIcon.addClass("rss-icon-hidden");
574582
}
575583

576584
feedNameContainer.createDiv({
@@ -1698,7 +1706,7 @@ export class Sidebar {
16981706
title: "Sort folders"
16991707
}
17001708
});
1701-
setIcon(sortButton, "lucide-sort-asc");
1709+
setIcon(sortButton, "sort-asc");
17021710
sortButton.addEventListener("click", (e) => {
17031711
const menu = new Menu();
17041712

@@ -1753,7 +1761,7 @@ export class Sidebar {
17531761
}
17541762

17551763
const allCollapsed = cachedFolderPaths.length > 0 && cachedFolderPaths.every(path => this.options.collapsedFolders.includes(path));
1756-
setIcon(collapseAllButton, allCollapsed ? "lucide-chevrons-down-up" : "lucide-chevrons-up-down");
1764+
setIcon(collapseAllButton, allCollapsed ? "chevrons-down-up" : "chevrons-up-down");
17571765
};
17581766

17591767
updateCollapseIcon();
@@ -1877,7 +1885,7 @@ export class Sidebar {
18771885

18781886
menu.addItem((item: MenuItem) => {
18791887
item.setTitle("Change media type")
1880-
.setIcon("lucide-circle-gauge")
1888+
.setIcon("circle-gauge")
18811889
.onClick((evt) => {
18821890
const typeMenu = new Menu();
18831891
typeMenu.addItem((subItem: MenuItem) => {

src/settings/settings-tab.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { App, PluginSettingTab, Setting, Notice, normalizePath, Modal, TextComponent } from "obsidian";
22
import RssDashboardPlugin from "./../../main";
3-
import { ViewLocation, RssDashboardSettings, SavedTemplate, DEFAULT_SETTINGS } from "../types/types";
3+
import { ViewLocation, RssDashboardSettings, SavedTemplate, DEFAULT_SETTINGS, PodcastTheme } from "../types/types";
44
import { FolderSuggest, VaultFolderSuggest } from "../components/folder-suggest";
55

66
class TemplateNameModal extends Modal {
@@ -107,6 +107,7 @@ export class RssDashboardSettingTab extends PluginSettingTab {
107107
this.display();
108108
};
109109
});
110+
110111

111112

112113
const tabContent = containerEl.createDiv("rss-dashboard-settings-tab-content");
@@ -350,6 +351,23 @@ export class RssDashboardSettingTab extends PluginSettingTab {
350351
})
351352
);
352353

354+
new Setting(containerEl)
355+
.setName("Hide default RSS icon")
356+
.setDesc("Hide the default RSS icon for regular feeds in the sidebar")
357+
.addToggle((toggle) =>
358+
toggle
359+
.setValue(!!this.plugin.settings.display.hideDefaultRssIcon)
360+
.onChange(async (value) => {
361+
this.plugin.settings.display.hideDefaultRssIcon = value;
362+
await this.plugin.saveSettings();
363+
const view = await this.plugin.getActiveDashboardView();
364+
if (view?.sidebar) {
365+
await this.app.workspace.revealLeaf(view.leaf);
366+
view.sidebar.render();
367+
}
368+
})
369+
);
370+
353371
new Setting(containerEl)
354372
.setName("Filter display style")
355373
.setDesc("Choose how to display the filter buttons in the sidebar")
@@ -545,6 +563,34 @@ export class RssDashboardSettingTab extends PluginSettingTab {
545563
await this.plugin.saveSettings();
546564
})
547565
);
566+
567+
new Setting(containerEl).setName("Podcast player").setHeading();
568+
569+
new Setting(containerEl)
570+
.setName("Player theme")
571+
.setDesc("Choose a visual theme for the podcast player")
572+
.addDropdown((dropdown) =>
573+
dropdown
574+
.addOption("obsidian", "Default")
575+
.addOption("minimal", "Minimal")
576+
.addOption("gradient", "Gradient")
577+
.addOption("spotify", "Spotify")
578+
.addOption("nord", "Nord")
579+
.addOption("dracula", "Dracula")
580+
.addOption("solarized", "Solarized dark")
581+
.addOption("catppuccin", "Catppuccin mocha")
582+
.addOption("gruvbox", "Gruvbox")
583+
.addOption("tokyonight", "Tokyo night")
584+
.setValue(this.plugin.settings.media.podcastTheme)
585+
.onChange(async (value) => {
586+
this.plugin.settings.media.podcastTheme = value as PodcastTheme;
587+
await this.plugin.saveSettings();
588+
const readerView = await this.plugin.getActiveReaderView();
589+
if (readerView) {
590+
readerView.updatePodcastTheme(value);
591+
}
592+
})
593+
);
548594
}
549595

550596
private createArticleSavingSettings(containerEl: HTMLElement): void {

0 commit comments

Comments
 (0)