aboutsummaryrefslogtreecommitdiffstats
path: root/frontend-vanilla
diff options
context:
space:
mode:
Diffstat (limited to 'frontend-vanilla')
-rw-r--r--frontend-vanilla/src/main.test.ts21
-rw-r--r--frontend-vanilla/src/main.ts19
-rw-r--r--frontend-vanilla/src/style.css9
3 files changed, 33 insertions, 16 deletions
diff --git a/frontend-vanilla/src/main.test.ts b/frontend-vanilla/src/main.test.ts
index 2715b5c..2d74ea5 100644
--- a/frontend-vanilla/src/main.test.ts
+++ b/frontend-vanilla/src/main.test.ts
@@ -188,6 +188,27 @@ describe('main application logic', () => {
}));
});
+ it('should handle star toggle when _id is a string (API returns string)', async () => {
+ renderLayout();
+ // The Go API returns _id as a string due to json:",string" tag.
+ // fetchItems normalizes this, but verify the flow works end-to-end.
+ const mockItem = { _id: "5" as any, title: 'String ID Item', starred: true, publish_date: '2023-01-01' } as any;
+ store.setItems([mockItem]);
+ renderItems();
+
+ vi.mocked(apiFetch).mockResolvedValue({ ok: true } as Response);
+
+ const starBtn = document.querySelector('[data-action="toggle-star"]') as HTMLElement;
+ starBtn.click();
+
+ // parseInt in the click handler produces number 5, but store has string "5".
+ // This should still work because toggleStar finds the item.
+ expect(apiFetch).toHaveBeenCalledWith(expect.stringContaining('/api/item/5'), expect.objectContaining({
+ method: 'PUT',
+ body: expect.stringContaining('"starred":false')
+ }));
+ });
+
it('should handle theme change in settings', () => {
renderLayout();
renderSettings();
diff --git a/frontend-vanilla/src/main.ts b/frontend-vanilla/src/main.ts
index b59d185..5d67515 100644
--- a/frontend-vanilla/src/main.ts
+++ b/frontend-vanilla/src/main.ts
@@ -258,7 +258,7 @@ export function attachLayoutListeners() {
const id = parseInt(itemRow.getAttribute('data-id')!);
activeItemId = id;
- const item = store.items.find(i => i._id === id);
+ const item = store.items.find(i => Number(i._id) === Number(id));
if (item && !item.read) {
updateItem(id, { read: true });
}
@@ -361,7 +361,7 @@ function checkReadItems(scrollRoot?: HTMLElement) {
const id = parseInt(idAttr);
// Safety check: skip if store already says it's read (though unread class implies not)
- const item = store.items.find(i => i._id === id);
+ const item = store.items.find(i => Number(i._id) === Number(id));
if (item?.read) continue;
const rect = el.getBoundingClientRect();
@@ -674,14 +674,14 @@ export async function updateFeed(id: number, updates: Partial<Feed>): Promise<bo
// --- Data Actions ---
export async function toggleStar(id: number) {
- const item = store.items.find(i => i._id === id);
+ const item = store.items.find(i => Number(i._id) === Number(id));
if (item) {
updateItem(id, { starred: !item.starred });
}
}
export async function scrapeItem(id: number) {
- const item = store.items.find(i => i._id === id);
+ const item = store.items.find(i => Number(i._id) === Number(id));
if (!item) return;
try {
@@ -775,6 +775,11 @@ export async function fetchItems(feedId?: string, tagName?: string, append: bool
const res = await apiFetch(`/api/stream?${params.toString()}`);
if (res.ok) {
const items = await res.json();
+ // The Go API returns _id as a string (json:",string" tag). Coerce to
+ // number so DOM parseInt comparisons using === work everywhere.
+ for (const item of items) {
+ item._id = Number(item._id);
+ }
store.setHasMore(items.length > 0);
store.setItems(items, append);
}
@@ -840,13 +845,13 @@ window.addEventListener('keydown', (e) => {
break;
case 'r':
if (activeItemId) {
- const item = store.items.find(i => i._id === activeItemId);
+ const item = store.items.find(i => Number(i._id) === Number(activeItemId));
if (item) updateItem(item._id, { read: !item.read });
}
break;
case 's':
if (activeItemId) {
- const item = store.items.find(i => i._id === activeItemId);
+ const item = store.items.find(i => Number(i._id) === Number(activeItemId));
if (item) updateItem(item._id, { starred: !item.starred });
}
break;
@@ -859,7 +864,7 @@ window.addEventListener('keydown', (e) => {
function navigateItems(direction: number) {
if (store.items.length === 0) return;
- const currentIndex = store.items.findIndex(i => i._id === activeItemId);
+ const currentIndex = store.items.findIndex(i => Number(i._id) === Number(activeItemId));
let nextIndex;
if (currentIndex === -1) {
diff --git a/frontend-vanilla/src/style.css b/frontend-vanilla/src/style.css
index 757d213..47b2de2 100644
--- a/frontend-vanilla/src/style.css
+++ b/frontend-vanilla/src/style.css
@@ -490,15 +490,6 @@ select:focus {
vertical-align: middle;
transition: color 0.2s;
line-height: 1;
- flex-shrink: 0;
- min-width: 44px;
- min-height: 44px;
- display: flex;
- align-items: center;
- justify-content: center;
- height: auto;
- text-transform: none;
- font-weight: normal;
}
.star-btn.is-starred {