summaryrefslogtreecommitdiff
path: root/apps/web/app/reader
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-08 00:06:53 -0800
committerFuwn <[email protected]>2026-02-08 00:06:53 -0800
commit2f3acb221af8cac85d3653ce8e7c7c30eb73ea77 (patch)
tree92ceab132fb4b6583cfaff46f5ac1adaed0a7d9e /apps/web/app/reader
parentfix: enforce same-origin on all service worker cache routes (diff)
downloadasa.news-2f3acb221af8cac85d3653ce8e7c7c30eb73ea77.tar.xz
asa.news-2f3acb221af8cac85d3653ce8e7c7c30eb73ea77.zip
feat: display folders above ungrouped feeds in sidebar, add delete-all-custom-feeds to danger zone
Diffstat (limited to 'apps/web/app/reader')
-rw-r--r--apps/web/app/reader/_components/sidebar-content.tsx78
-rw-r--r--apps/web/app/reader/settings/_components/danger-zone-settings.tsx38
2 files changed, 77 insertions, 39 deletions
diff --git a/apps/web/app/reader/_components/sidebar-content.tsx b/apps/web/app/reader/_components/sidebar-content.tsx
index 4b58934..844f8b3 100644
--- a/apps/web/app/reader/_components/sidebar-content.tsx
+++ b/apps/web/app/reader/_components/sidebar-content.tsx
@@ -214,45 +214,6 @@ export function SidebarContent() {
</div>
)}
- {ungroupedSubscriptions.length > 0 && (
- <div className="mt-3 space-y-0.5">
- {ungroupedSubscriptions.map((subscription) => (
- <Link
- key={subscription.subscriptionIdentifier}
- href={`/reader?feed=${subscription.feedIdentifier}`}
- data-sidebar-nav-item
- {...((unreadCounts?.[subscription.feedIdentifier] ?? 0) > 0 ? { "data-has-unreads": "" } : {})}
- onClick={closeSidebarOnMobile}
- className={classNames(
- NAVIGATION_LINK_CLASS,
- "flex items-center truncate pl-4 text-[0.85em]",
- activeFeedIdentifier === subscription.feedIdentifier &&
- ACTIVE_LINK_CLASS,
- sidebarFocusClass(focusedPanel, focusedSidebarIndex, navIndex++)
- )}
- >
- {showFeedFavicons && (
- <FeedFavicon feedUrl={subscription.feedUrl} />
- )}
- <span className={classNames("truncate", showFeedFavicons && "ml-2")}>
- {displayNameForSubscription(subscription)}
- </span>
- {subscription.feedType === "podcast" && (
- <span className="ml-1 shrink-0 text-text-dim" title="podcast">&#9835;</span>
- )}
- {subscription.consecutiveFailures > 0 && (
- <span className="ml-1 shrink-0 text-status-warning" title={subscription.lastFetchError ?? "feed error"}>
- [!]
- </span>
- )}
- <UnreadBadge
- count={unreadCounts?.[subscription.feedIdentifier] ?? 0}
- />
- </Link>
- ))}
- </div>
- )}
-
{folders.map((folder) => {
const isExpanded = expandedFolderIdentifiers.includes(
folder.folderIdentifier
@@ -347,6 +308,45 @@ export function SidebarContent() {
)
})}
+ {ungroupedSubscriptions.length > 0 && (
+ <div className="mt-3 space-y-0.5">
+ {ungroupedSubscriptions.map((subscription) => (
+ <Link
+ key={subscription.subscriptionIdentifier}
+ href={`/reader?feed=${subscription.feedIdentifier}`}
+ data-sidebar-nav-item
+ {...((unreadCounts?.[subscription.feedIdentifier] ?? 0) > 0 ? { "data-has-unreads": "" } : {})}
+ onClick={closeSidebarOnMobile}
+ className={classNames(
+ NAVIGATION_LINK_CLASS,
+ "flex items-center truncate pl-4 text-[0.85em]",
+ activeFeedIdentifier === subscription.feedIdentifier &&
+ ACTIVE_LINK_CLASS,
+ sidebarFocusClass(focusedPanel, focusedSidebarIndex, navIndex++)
+ )}
+ >
+ {showFeedFavicons && (
+ <FeedFavicon feedUrl={subscription.feedUrl} />
+ )}
+ <span className={classNames("truncate", showFeedFavicons && "ml-2")}>
+ {displayNameForSubscription(subscription)}
+ </span>
+ {subscription.feedType === "podcast" && (
+ <span className="ml-1 shrink-0 text-text-dim" title="podcast">&#9835;</span>
+ )}
+ {subscription.consecutiveFailures > 0 && (
+ <span className="ml-1 shrink-0 text-status-warning" title={subscription.lastFetchError ?? "feed error"}>
+ [!]
+ </span>
+ )}
+ <UnreadBadge
+ count={unreadCounts?.[subscription.feedIdentifier] ?? 0}
+ />
+ </Link>
+ ))}
+ </div>
+ )}
+
<div className="mt-3 space-y-0.5">
<button
type="button"
diff --git a/apps/web/app/reader/settings/_components/danger-zone-settings.tsx b/apps/web/app/reader/settings/_components/danger-zone-settings.tsx
index 3525426..eb6c008 100644
--- a/apps/web/app/reader/settings/_components/danger-zone-settings.tsx
+++ b/apps/web/app/reader/settings/_components/danger-zone-settings.tsx
@@ -5,14 +5,17 @@ import { useRouter } from "next/navigation"
import { useMutation } from "@tanstack/react-query"
import { useUnsubscribeAll } from "@/lib/queries/use-subscription-mutations"
import { useDeleteAllFolders } from "@/lib/queries/use-folder-mutations"
+import { useDeleteAllCustomFeeds } from "@/lib/queries/use-custom-feed-mutations"
import { notify } from "@/lib/notify"
export function DangerZoneSettings() {
const router = useRouter()
const unsubscribeAll = useUnsubscribeAll()
const deleteAllFolders = useDeleteAllFolders()
+ const deleteAllCustomFeeds = useDeleteAllCustomFeeds()
const [showDeleteSubsConfirm, setShowDeleteSubsConfirm] = useState(false)
const [showDeleteFoldersConfirm, setShowDeleteFoldersConfirm] = useState(false)
+ const [showDeleteCustomFeedsConfirm, setShowDeleteCustomFeedsConfirm] = useState(false)
const [showDeleteAccountConfirm, setShowDeleteAccountConfirm] = useState(false)
const [deleteConfirmText, setDeleteConfirmText] = useState("")
@@ -105,6 +108,41 @@ export function DangerZoneSettings() {
)}
</div>
+ <div className="mb-6">
+ <h3 className="mb-2 text-text-primary">delete all custom feeds</h3>
+ <p className="mb-2 text-text-dim">
+ remove all custom feeds (saved searches).
+ </p>
+ {showDeleteCustomFeedsConfirm ? (
+ <div className="flex items-center gap-2">
+ <span className="text-status-error">are you sure?</span>
+ <button
+ onClick={() => {
+ deleteAllCustomFeeds.mutate()
+ setShowDeleteCustomFeedsConfirm(false)
+ }}
+ disabled={deleteAllCustomFeeds.isPending}
+ className="border border-status-error px-3 py-1 text-status-error transition-colors hover:bg-status-error hover:text-background-primary disabled:opacity-50"
+ >
+ yes, delete all
+ </button>
+ <button
+ onClick={() => setShowDeleteCustomFeedsConfirm(false)}
+ className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
+ >
+ cancel
+ </button>
+ </div>
+ ) : (
+ <button
+ onClick={() => setShowDeleteCustomFeedsConfirm(true)}
+ className="border border-border px-3 py-1 text-text-secondary transition-colors hover:border-status-error hover:text-status-error"
+ >
+ delete all custom feeds
+ </button>
+ )}
+ </div>
+
<div>
<h3 className="mb-2 text-text-primary">delete account</h3>
<p className="mb-2 text-text-dim">