Added support for saving items
This commit is contained in:
parent
14176078ea
commit
9a25332ded
@ -57,6 +57,18 @@ func (fs *FeedStore) GetUnread() *[]ItemWithFeed {
|
|||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *FeedStore) GetSaved() *[]ItemWithFeed {
|
||||||
|
items := &[]ItemWithFeed{}
|
||||||
|
fs.getDB().Table("items").
|
||||||
|
Where("save = ?", true).
|
||||||
|
Select("items.*, feeds.title as feed_title, feeds.homepage_url as feed_homepage_url").
|
||||||
|
Order("items.created desc, items.title").
|
||||||
|
Joins("left join feeds on feeds.id = items.feed_id").
|
||||||
|
Find(items)
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *FeedStore) DeleteOldReadItems() {
|
func (fs *FeedStore) DeleteOldReadItems() {
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
threshold := t.Add(-time.Hour * 24 * 7)
|
threshold := t.Add(-time.Hour * 24 * 7)
|
||||||
@ -98,3 +110,12 @@ func (fs *FeedStore) MarkAsRead(itemID string) {
|
|||||||
|
|
||||||
fs.getDB().Save(*item)
|
fs.getDB().Save(*item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *FeedStore) ToggleSaved(itemID string) {
|
||||||
|
item := &Item{}
|
||||||
|
fs.getDB().Where("id = ?", itemID).First(item)
|
||||||
|
|
||||||
|
item.Save = !item.Save
|
||||||
|
|
||||||
|
fs.getDB().Save(*item)
|
||||||
|
}
|
||||||
|
@ -33,6 +33,10 @@ func (a *API) GetUnread(c *fiber.Ctx) error {
|
|||||||
return c.JSON(a.FeedStore.GetUnread())
|
return c.JSON(a.FeedStore.GetUnread())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *API) GetSaved(c *fiber.Ctx) error {
|
||||||
|
return c.JSON(a.FeedStore.GetSaved())
|
||||||
|
}
|
||||||
|
|
||||||
func (a *API) GetAll(c *fiber.Ctx) error {
|
func (a *API) GetAll(c *fiber.Ctx) error {
|
||||||
return c.JSON(a.FeedStore.GetAll())
|
return c.JSON(a.FeedStore.GetAll())
|
||||||
}
|
}
|
||||||
@ -60,3 +64,8 @@ func (a *API) RefreshAll(c *fiber.Ctx) error {
|
|||||||
|
|
||||||
return c.JSON(a.FeedStore.GetUnread())
|
return c.JSON(a.FeedStore.GetUnread())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *API) SaveItem(c *fiber.Ctx) error {
|
||||||
|
a.FeedStore.ToggleSaved(c.Params("id"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -51,7 +51,9 @@ func Start(port string) error {
|
|||||||
app.Post("/api/feeds", api.PostFeed)
|
app.Post("/api/feeds", api.PostFeed)
|
||||||
app.Get("/api/feed/:id", api.GetFeed)
|
app.Get("/api/feed/:id", api.GetFeed)
|
||||||
app.Get("/api/item/:id", api.GetItem)
|
app.Get("/api/item/:id", api.GetItem)
|
||||||
|
app.Post("/api/item/:id/save", api.SaveItem)
|
||||||
app.Get("/api/unread", api.GetUnread)
|
app.Get("/api/unread", api.GetUnread)
|
||||||
|
app.Get("/api/saved", api.GetSaved)
|
||||||
app.Get("/api/all", api.GetAll)
|
app.Get("/api/all", api.GetAll)
|
||||||
app.Post("/api/read/:id", api.PostRead)
|
app.Post("/api/read/:id", api.PostRead)
|
||||||
app.Post("/api/read", api.PostReadAll)
|
app.Post("/api/read", api.PostReadAll)
|
||||||
|
@ -60,6 +60,11 @@
|
|||||||
{{feed.Title}} ({{unreadCounts[feed.ID] || '0'}})
|
{{feed.Title}} ({{unreadCounts[feed.ID] || '0'}})
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div :class="{ strong: items.length, alert: true, 'alert-success': selectedFeed == 'SAVED'}" v-on:click="loadFeed('SAVED')">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" xmlns="http://www.w3.org/2000/svg"><path d="M12.8 5.6l-.8.8-.8-.8a5.4 5.4 0 00-7.6 7.6l7.9 7.9c.3.3.7.3 1 0l8-8a5.4 5.4 0 10-7.7-7.5z" style="fill: #ff2e88" fill-rule="nonzero"/></svg>
|
||||||
|
Saved ({{saved}})
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<button title="Add New Site" v-on:click="showAddModal = true" :disabled="isBusy">
|
<button title="Add New Site" v-on:click="showAddModal = true" :disabled="isBusy">
|
||||||
<svg width="30" height="30" viewbox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17.8 3C19.5 3 21 4.5 21 6.3V12a6.5 6.5 0 00-8.2 1H8.6a.8.8 0 000 1.5h3.1A6.5 6.5 0 0012 21H6.3A3.3 3.3 0 013 17.7V9.4A2.2 2.2 0 103.2 5C3.7 3.9 5 3 6.2 3h11.6zm-2.5 6.5H8.7a.8.8 0 000 1.5h6.6a.8.8 0 000-1.5z" fill="#212121"/><path d="M3.8 6a1.3 1.3 0 110 2.5 1.3 1.3 0 010-2.5z" fill="#212121"/><path d="M23 17.5a5.5 5.5 0 10-11 0 5.5 5.5 0 0011 0zm-5 .5v2.5a.5.5 0 11-1 0V18h-2.5a.5.5 0 010-1H17v-2.5a.5.5 0 111 0V17h2.5a.5.5 0 010 1H18z" fill="#212121"/></svg>
|
<svg width="30" height="30" viewbox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17.8 3C19.5 3 21 4.5 21 6.3V12a6.5 6.5 0 00-8.2 1H8.6a.8.8 0 000 1.5h3.1A6.5 6.5 0 0012 21H6.3A3.3 3.3 0 013 17.7V9.4A2.2 2.2 0 103.2 5C3.7 3.9 5 3 6.2 3h11.6zm-2.5 6.5H8.7a.8.8 0 000 1.5h6.6a.8.8 0 000-1.5z" fill="#212121"/><path d="M3.8 6a1.3 1.3 0 110 2.5 1.3 1.3 0 010-2.5z" fill="#212121"/><path d="M23 17.5a5.5 5.5 0 10-11 0 5.5 5.5 0 0011 0zm-5 .5v2.5a.5.5 0 11-1 0V18h-2.5a.5.5 0 010-1H17v-2.5a.5.5 0 111 0V17h2.5a.5.5 0 010 1H18z" fill="#212121"/></svg>
|
||||||
@ -100,6 +105,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card item-content" :data-id="item.ID" v-if="item.ID == selectedItem">
|
<div class="card item-content" :data-id="item.ID" v-if="item.ID == selectedItem">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
|
<div class="menu">
|
||||||
|
<button title="Save" v-on:click="saveItem(item)" :disabled="isBusy">
|
||||||
|
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg"><path d="M12.8 5.6l-.8.8-.8-.8a5.4 5.4 0 00-7.6 7.6l7.9 7.9c.3.3.7.3 1 0l8-8a5.4 5.4 0 10-7.7-7.5z" :style="{'fill': item.Save ? '#ff2e88' : '#eee' }" fill-rule="nonzero"/></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<feed-item :item-id="item.ID" :class="{ dark: isDark }"></feed-item>
|
<feed-item :item-id="item.ID" :class="{ dark: isDark }"></feed-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -120,6 +131,7 @@
|
|||||||
data: {
|
data: {
|
||||||
feeds: [],
|
feeds: [],
|
||||||
items: [],
|
items: [],
|
||||||
|
savedItems: [],
|
||||||
selectedFeed: '',
|
selectedFeed: '',
|
||||||
selectedItem: undefined,
|
selectedItem: undefined,
|
||||||
showAddModal: false,
|
showAddModal: false,
|
||||||
@ -133,6 +145,8 @@
|
|||||||
shownItems() {
|
shownItems() {
|
||||||
if (this.selectedFeed === '') {
|
if (this.selectedFeed === '') {
|
||||||
return this.items.filter(item => item.ID == this.selectedItem || !item.Read || item.Read === this.showRead);
|
return this.items.filter(item => item.ID == this.selectedItem || !item.Read || item.Read === this.showRead);
|
||||||
|
} else if (this.selectedFeed === 'SAVED') {
|
||||||
|
return this.savedItems;
|
||||||
} else {
|
} else {
|
||||||
return this.items.filter(item => item.ID == this.selectedItem || item.FeedID === this.selectedFeed && (!item.Read || item.Read === this.showRead));
|
return this.items.filter(item => item.ID == this.selectedItem || item.FeedID === this.selectedFeed && (!item.Read || item.Read === this.showRead));
|
||||||
}
|
}
|
||||||
@ -140,6 +154,9 @@
|
|||||||
unread() {
|
unread() {
|
||||||
return this.items.filter(item => !item.Read).length;
|
return this.items.filter(item => !item.Read).length;
|
||||||
},
|
},
|
||||||
|
saved() {
|
||||||
|
return this.savedItems.length;
|
||||||
|
},
|
||||||
unreadCounts() {
|
unreadCounts() {
|
||||||
return this.items.filter(item => !item.Read).reduce((acc, item) => {
|
return this.items.filter(item => !item.Read).reduce((acc, item) => {
|
||||||
if (!acc[item.FeedID]) acc[item.FeedID] = 0;
|
if (!acc[item.FeedID]) acc[item.FeedID] = 0;
|
||||||
@ -172,6 +189,20 @@
|
|||||||
fetch(`/api/read/${item.ID}`, {method: "POST"})
|
fetch(`/api/read/${item.ID}`, {method: "POST"})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
saveItem(item) {
|
||||||
|
this.setBusy(true);
|
||||||
|
fetch(`/api/item/${item.ID}/save`, {method: "POST"})
|
||||||
|
.then(() => {
|
||||||
|
item.Save = !item.Save;
|
||||||
|
|
||||||
|
if (item.Save) {
|
||||||
|
this.savedItems.push(item);
|
||||||
|
} else {
|
||||||
|
this.savedItems = this.savedItems.filter(i => item.ID != i.ID);
|
||||||
|
}
|
||||||
|
this.setBusy(false);
|
||||||
|
})
|
||||||
|
},
|
||||||
nextItem() {
|
nextItem() {
|
||||||
let currentItem = -1;
|
let currentItem = -1;
|
||||||
if (this.selectedItem != undefined) {
|
if (this.selectedItem != undefined) {
|
||||||
@ -294,7 +325,8 @@
|
|||||||
this.setBusy(true);
|
this.setBusy(true);
|
||||||
Promise.all([
|
Promise.all([
|
||||||
fetch(`/api/feeds`).then(res => res.json()).then(feeds => this.feeds = feeds),
|
fetch(`/api/feeds`).then(res => res.json()).then(feeds => this.feeds = feeds),
|
||||||
fetch(`/api/unread`).then(res => res.json()).then(items => this.items = items)
|
fetch(`/api/unread`).then(res => res.json()).then(items => this.items = items),
|
||||||
|
fetch(`/api/saved`).then(res => res.json()).then(items => this.savedItems = items)
|
||||||
])
|
])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setBusy(false);
|
this.setBusy(false);
|
||||||
|
Loading…
Reference in New Issue
Block a user