aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 12:27:31 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 12:27:31 -0800
commitb9c7497fc25d23492fe013a3541b8d4d66c6970c (patch)
tree3a909aeb8adb1231b37d1e5b80e613cc10fa416d
parenta1baa8f9655e6fc4343475d2a38b2d7f6c7d0955 (diff)
downloadneko-b9c7497fc25d23492fe013a3541b8d4d66c6970c.tar.gz
neko-b9c7497fc25d23492fe013a3541b8d4d66c6970c.tar.bz2
neko-b9c7497fc25d23492fe013a3541b8d4d66c6970c.zip
UI: replace text star button with icon next to title (NK-ymf1jb)
-rw-r--r--.thicket/tickets.jsonl2
-rw-r--r--frontend/src/components/FeedItem.css24
-rw-r--r--frontend/src/components/FeedItem.test.tsx3
-rw-r--r--frontend/src/components/FeedItem.tsx17
4 files changed, 37 insertions, 9 deletions
diff --git a/.thicket/tickets.jsonl b/.thicket/tickets.jsonl
index d3c70fc..9032d0c 100644
--- a/.thicket/tickets.jsonl
+++ b/.thicket/tickets.jsonl
@@ -32,7 +32,7 @@
{"id":"NK-uywybr","title":"https://computer.rip/rss.xml fails to importa","description":"running neko -a https://computer.rip/rss.xml gave an error. debug it and add test case to catch.","type":"bug","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-13T20:12:28.54350403Z","updated":"2026-02-13T20:12:28.54350403Z"}
{"id":"NK-wibjlg","title":"update README.md","description":"Ensure the build, configuration, etc are up too date.\nNote the git change when we started to vibe-code this in the history (with dates etc.)","type":"task","status":"open","priority":0,"labels":null,"assignee":"","created":"2026-02-13T20:18:08.790048498Z","updated":"2026-02-13T20:18:08.790048498Z"}
{"id":"NK-x924bu","title":"test coverage","description":"assume the code works properly (it mostly does)\nget to 90% test coverage on the go code","type":"task","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-13T01:52:01.042476226Z","updated":"2026-02-13T03:54:21.526519915Z"}
-{"id":"NK-ymf1jb","title":"add \"star\" back in","description":"rather than the word \"star\" it should just have a star that changes colors right next to the title","type":"task","status":"open","priority":0,"labels":null,"assignee":"","created":"2026-02-13T19:29:05.582140321Z","updated":"2026-02-13T19:29:05.582140321Z"}
+{"id":"NK-ymf1jb","title":"add \"star\" back in","description":"rather than the word \"star\" it should just have a star that changes colors right next to the title","type":"task","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-13T19:29:05.582140321Z","updated":"2026-02-13T20:27:31.598346438Z"}
{"id":"NK-zs9we8","title":"UI Styling: Sidebar (Fixed, Gray Background)","description":"","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T18:05:16.188317572Z","updated":"2026-02-13T18:11:46.213993245Z"}
{"id":"NK-zt4e32","title":"Implement Frontend Feed List","description":"Create feed list view in new frontend. Fetch feeds from API.","type":"task","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-13T05:44:01.58866298Z","updated":"2026-02-13T05:59:46.132148641Z"}
{"id":"NK-d0ghccy","from_ticket_id":"NK-ric1zs","to_ticket_id":"NK-1phdpf","type":"created_from","created":"2026-02-13T04:26:55.875394997Z"}
diff --git a/frontend/src/components/FeedItem.css b/frontend/src/components/FeedItem.css
index fef1f93..1e7b9bd 100644
--- a/frontend/src/components/FeedItem.css
+++ b/frontend/src/components/FeedItem.css
@@ -44,6 +44,30 @@
}
/* Legacy controls were simple text/links, but buttons are fine if minimal */
+.star-btn {
+ background: none;
+ border: none;
+ cursor: pointer;
+ font-size: 1.2rem;
+ padding: 0 0.5rem 0 0;
+ vertical-align: middle;
+ transition: color 0.2s;
+ line-height: 1;
+}
+
+.star-btn.is-starred {
+ color: #ffd700;
+ /* Gold */
+}
+
+.star-btn.is-unstarred {
+ color: #ccc;
+}
+
+.star-btn:hover {
+ color: #ffeb3b;
+}
+
.action-btn {
background: whitesmoke;
border: none;
diff --git a/frontend/src/components/FeedItem.test.tsx b/frontend/src/components/FeedItem.test.tsx
index 5e7522f..913e6ff 100644
--- a/frontend/src/components/FeedItem.test.tsx
+++ b/frontend/src/components/FeedItem.test.tsx
@@ -36,10 +36,11 @@ describe('FeedItem Component', () => {
render(<FeedItem item={mockItem} />);
const starBtn = screen.getByTitle('Star');
+ expect(starBtn).toHaveTextContent('☆');
fireEvent.click(starBtn);
// Optimistic update
- expect(await screen.findByTitle('Unstar')).toBeInTheDocument();
+ expect(await screen.findByTitle('Unstar')).toHaveTextContent('★');
expect(global.fetch).toHaveBeenCalledWith('/api/item/1', expect.objectContaining({
method: 'PUT',
diff --git a/frontend/src/components/FeedItem.tsx b/frontend/src/components/FeedItem.tsx
index 03910e4..23f2bae 100644
--- a/frontend/src/components/FeedItem.tsx
+++ b/frontend/src/components/FeedItem.tsx
@@ -54,6 +54,16 @@ export default function FeedItem({ item: initialItem }: FeedItemProps) {
return (
<li className={`feed-item ${item.read ? 'read' : 'unread'} ${loading ? 'loading' : ''}`}>
<div className="item-header">
+ <button
+ onClick={(e) => {
+ e.stopPropagation();
+ toggleStar();
+ }}
+ className={`star-btn ${item.starred ? 'is-starred' : 'is-unstarred'}`}
+ title={item.starred ? "Unstar" : "Star"}
+ >
+ {item.starred ? '★' : '☆'}
+ </button>
<a href={item.url} target="_blank" rel="noopener noreferrer" className="item-title">
{item.title || '(No Title)'}
</a>
@@ -64,13 +74,6 @@ export default function FeedItem({ item: initialItem }: FeedItemProps) {
{item.feed_title && ` - ${item.feed_title}`}
</a>
<div className="item-actions" style={{ display: 'inline-block', float: 'right' }}>
- <button
- onClick={toggleStar}
- className={`action-btn ${item.starred ? 'is-starred' : 'is-unstarred'}`}
- title={item.starred ? "Unstar" : "Star"}
- >
- {item.starred ? 'unstar' : 'star'}
- </button>
</div>
</div>
{item.description && (