diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-14 09:58:11 -0800 |
|---|---|---|
| committer | Adam Mathes <adam@adammathes.com> | 2026-02-14 09:58:11 -0800 |
| commit | c9c3469ce90f5e1cf624a9a97d66fd6db3aba8cb (patch) | |
| tree | dfc78feec1eff6cc5411b511123e6eefbdaf625b /frontend/src/components | |
| parent | ae2b06f7a702ea432b801985f534ade405d0299a (diff) | |
| download | neko-c9c3469ce90f5e1cf624a9a97d66fd6db3aba8cb.tar.gz neko-c9c3469ce90f5e1cf624a9a97d66fd6db3aba8cb.tar.bz2 neko-c9c3469ce90f5e1cf624a9a97d66fd6db3aba8cb.zip | |
feature: add scrape full text button to feed items (fixing NK-8hu7z1)
Diffstat (limited to 'frontend/src/components')
| -rw-r--r-- | frontend/src/components/FeedItem.css | 16 | ||||
| -rw-r--r-- | frontend/src/components/FeedItem.test.tsx | 18 | ||||
| -rw-r--r-- | frontend/src/components/FeedItem.tsx | 33 |
3 files changed, 64 insertions, 3 deletions
diff --git a/frontend/src/components/FeedItem.css b/frontend/src/components/FeedItem.css index fc2c850..3becb20 100644 --- a/frontend/src/components/FeedItem.css +++ b/frontend/src/components/FeedItem.css @@ -107,4 +107,20 @@ color: var(--text-color); opacity: 0.8; margin-left: 0; +} + +.scrape-btn { + background: var(--bg-color); + border: 1px solid var(--border-color, #ccc); + color: blue; + cursor: pointer; + font-family: 'Helvetica Neue'; + font-weight: bold; + font-size: 0.8rem; + padding: 2px 6px; + margin-left: 0.5rem; +} + +.scrape-btn:hover { + background: var(--sidebar-bg); }
\ No newline at end of file diff --git a/frontend/src/components/FeedItem.test.tsx b/frontend/src/components/FeedItem.test.tsx index cb9aafa..4c7d887 100644 --- a/frontend/src/components/FeedItem.test.tsx +++ b/frontend/src/components/FeedItem.test.tsx @@ -71,4 +71,22 @@ describe('FeedItem Component', () => { expect(listItem).toHaveClass('read'); expect(listItem).not.toHaveClass('unread'); }); + + it('loads full content', async () => { + (global.fetch as any).mockResolvedValueOnce({ + ok: true, + json: async () => ({ ...mockItem, full_content: '<p>Full Content Loaded</p>' }), + }); + + render(<FeedItem item={mockItem} />); + + const scrapeBtn = screen.getByTitle('Load Full Content'); + fireEvent.click(scrapeBtn); + + await waitFor(() => { + expect(screen.getByText('Full Content Loaded')).toBeInTheDocument(); + }); + + expect(global.fetch).toHaveBeenCalledWith('/api/item/1', expect.anything()); + }); }); diff --git a/frontend/src/components/FeedItem.tsx b/frontend/src/components/FeedItem.tsx index ae4462a..ac142dc 100644 --- a/frontend/src/components/FeedItem.tsx +++ b/frontend/src/components/FeedItem.tsx @@ -56,6 +56,24 @@ export default function FeedItem({ item: initialItem }: FeedItemProps) { }); }; + const loadFullContent = (e: React.MouseEvent) => { + e.stopPropagation(); + setLoading(true); + apiFetch(`/api/item/${item._id}`) + .then((res) => { + if (!res.ok) throw new Error('Failed to fetch full content'); + return res.json(); + }) + .then((data) => { + setItem({ ...item, ...data }); + setLoading(false); + }) + .catch((err) => { + console.error('Error fetching full content:', err); + setLoading(false); + }); + }; + return ( <li className={`feed-item ${item.read ? 'read' : 'unread'} ${loading ? 'loading' : ''}`}> <div className="item-header"> @@ -78,10 +96,19 @@ export default function FeedItem({ item: initialItem }: FeedItemProps) { {new Date(item.publish_date).toLocaleDateString()} {item.feed_title && ` - ${item.feed_title}`} </a> - <div className="item-actions" style={{ display: 'inline-block', float: 'right' }}></div> + <div className="item-actions" style={{ display: 'inline-block', float: 'right' }}> + {!item.full_content && ( + <button onClick={loadFullContent} className="scrape-btn" title="Load Full Content"> + text + </button> + )} + </div> </div> - {item.description && ( - <div className="item-description" dangerouslySetInnerHTML={{ __html: item.description }} /> + {(item.full_content || item.description) && ( + <div + className="item-description" + dangerouslySetInnerHTML={{ __html: item.full_content || item.description }} + /> )} </li> ); |
