fixes some issue
This commit is contained in:
parent
a5b8968993
commit
c43a9ca800
7 changed files with 74 additions and 23 deletions
|
|
@ -1,3 +1,7 @@
|
|||
# Rufeed
|
||||
|
||||
Rufeed is a lightweight desktop feed reader built with Tauri and React.
|
||||
|
||||
## Screenshot
|
||||
|
||||

|
||||
|
|
|
|||
BIN
public/screenshot.png
Normal file
BIN
public/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 169 KiB |
|
|
@ -1,7 +1,6 @@
|
|||
use cached::proc_macro::cached;
|
||||
use feed_rs::parser;
|
||||
use reqwest::header::{ACCEPT, ACCEPT_ENCODING};
|
||||
use tauri::utils::config::parse;
|
||||
|
||||
use crate::client::CLIENT;
|
||||
use crate::config::feed_config::Feed;
|
||||
|
|
@ -65,11 +64,15 @@ pub async fn add_feed_direct(feed_url: &str) -> Result<Feed, Error> {
|
|||
let feed = parser::parse(xml.as_bytes())?;
|
||||
|
||||
let title = feed.title.map(|t| t.content).unwrap_or("no title".into());
|
||||
let icon = feed.icon.map(|i| i.uri).unwrap_or("defult.png".into());
|
||||
let url = url::Url::parse(feed_url)
|
||||
.unwrap()
|
||||
.origin()
|
||||
.ascii_serialization();
|
||||
|
||||
let icon = feed
|
||||
.icon
|
||||
.map(|i| i.uri)
|
||||
.unwrap_or(format!("{url}/favicon.ico"));
|
||||
Feed::add(&title, &url, feed_url, &icon)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,19 +21,19 @@ impl FeedItem {
|
|||
title: entry
|
||||
.title
|
||||
.map(|t| t.content)
|
||||
.ok_or(Error::MissingField("title".into()))?,
|
||||
.unwrap_or("no_title".to_string()),
|
||||
published: entry
|
||||
.published
|
||||
.or(entry.updated)
|
||||
.map(|d| d.to_rfc3339())
|
||||
.ok_or(Error::MissingField("published".into()))?,
|
||||
.unwrap_or("no_published".to_string()),
|
||||
url: entry
|
||||
.links
|
||||
.iter()
|
||||
.find(|l| l.rel.as_deref() == Some("alternate"))
|
||||
.or_else(|| entry.links.first())
|
||||
.map(|l| l.href.clone())
|
||||
.ok_or(Error::MissingField("url".into()))?,
|
||||
.unwrap_or("no_url".to_string()),
|
||||
};
|
||||
items.push(item);
|
||||
}
|
||||
|
|
@ -79,18 +79,18 @@ impl FeedEntry {
|
|||
title: entry
|
||||
.title
|
||||
.map(|t| t.content)
|
||||
.ok_or(Error::MissingField("title".into()))?,
|
||||
.unwrap_or("no_title".to_string()),
|
||||
url,
|
||||
published: entry
|
||||
.published
|
||||
.or(entry.updated)
|
||||
.map(|d| d.to_rfc3339())
|
||||
.ok_or(Error::MissingField("published".into()))?,
|
||||
.unwrap_or("no_published".to_string()),
|
||||
updated: entry
|
||||
.updated
|
||||
.or(entry.published)
|
||||
.map(|d| d.to_rfc3339())
|
||||
.ok_or(Error::MissingField("updated".into()))?,
|
||||
.unwrap_or("no_updated".to_string()),
|
||||
summary,
|
||||
content,
|
||||
authors: entry
|
||||
|
|
|
|||
|
|
@ -59,8 +59,7 @@ export default function App() {
|
|||
);
|
||||
|
||||
const handleRemoveFeed = useCallback(
|
||||
async (feed: Feed, e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
async (feed: Feed) => {
|
||||
try {
|
||||
await removeFeed(feed);
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { memo } from "react";
|
||||
import { Rss, Trash2 } from "lucide-react";
|
||||
import { memo, useCallback, useState, type MouseEvent } from "react";
|
||||
import { Check, Rss, Trash2, X } from "lucide-react";
|
||||
import { Feed } from "../../bindings";
|
||||
|
||||
interface FeedListItemProps {
|
||||
feed: Feed;
|
||||
isSelected: boolean;
|
||||
onSelect: (feed: Feed) => void;
|
||||
onRemove: (feed: Feed, e: React.MouseEvent) => void;
|
||||
onRemove: (feed: Feed) => void;
|
||||
}
|
||||
|
||||
export const FeedListItem = memo(function FeedListItem({
|
||||
|
|
@ -15,6 +15,27 @@ export const FeedListItem = memo(function FeedListItem({
|
|||
onSelect,
|
||||
onRemove,
|
||||
}: FeedListItemProps) {
|
||||
const [isConfirmingDelete, setIsConfirmingDelete] = useState(false);
|
||||
|
||||
const handleToggleDeleteConfirm = useCallback((e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
setIsConfirmingDelete((value) => !value);
|
||||
}, []);
|
||||
|
||||
const handleCancelDelete = useCallback((e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
setIsConfirmingDelete(false);
|
||||
}, []);
|
||||
|
||||
const handleConfirmDelete = useCallback(
|
||||
(e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
onRemove(feed);
|
||||
setIsConfirmingDelete(false);
|
||||
},
|
||||
[feed, onRemove]
|
||||
);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => onSelect(feed)}
|
||||
|
|
@ -36,8 +57,31 @@ export const FeedListItem = memo(function FeedListItem({
|
|||
<span dir="auto" className="min-w-0 flex-1 truncate font-medium">
|
||||
{feed.title || feed.url}
|
||||
</span>
|
||||
{isConfirmingDelete ? (
|
||||
<span className="inline-flex items-center gap-1">
|
||||
<span
|
||||
onClick={(e) => onRemove(feed, e)}
|
||||
onClick={handleConfirmDelete}
|
||||
role="button"
|
||||
aria-label="Confirm removing feed"
|
||||
title="Confirm remove"
|
||||
className="inline-flex items-center gap-1 rounded-md border border-destructive/50 bg-destructive/10 px-2 py-1 text-[11px] font-medium text-destructive transition-all hover:bg-destructive/20"
|
||||
>
|
||||
<Check className="h-3 w-3" />
|
||||
Confirm
|
||||
</span>
|
||||
<span
|
||||
onClick={handleCancelDelete}
|
||||
role="button"
|
||||
aria-label="Cancel removing feed"
|
||||
title="Cancel remove"
|
||||
className="inline-flex items-center justify-center rounded-md p-1 text-muted-foreground transition-all hover:bg-muted hover:text-foreground"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</span>
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
onClick={handleToggleDeleteConfirm}
|
||||
role="button"
|
||||
aria-label="Remove feed"
|
||||
title="Remove feed"
|
||||
|
|
@ -45,6 +89,7 @@ export const FeedListItem = memo(function FeedListItem({
|
|||
>
|
||||
<Trash2 className="h-3 w-3" />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ interface SidebarContentProps {
|
|||
loading: boolean;
|
||||
selectedFeedId?: string;
|
||||
onSelectFeed: (feed: Feed) => void;
|
||||
onRemoveFeed: (feed: Feed, e: React.MouseEvent) => void;
|
||||
onRemoveFeed: (feed: Feed) => void;
|
||||
onAddFeed: (url: string) => Promise<void>;
|
||||
onRefresh: () => void;
|
||||
onHideSidebar?: () => void;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue