mirror of
https://github.com/nkanaev/yarr.git
synced 2025-05-24 21:19:19 +00:00
basic feed list view
This commit is contained in:
parent
9cea82005b
commit
9d5d8f4df2
@ -256,3 +256,14 @@ func FeedHandler(rw http.ResponseWriter, req *http.Request) {
|
|||||||
rw.WriteHeader(http.StatusMethodNotAllowed)
|
rw.WriteHeader(http.StatusMethodNotAllowed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FeedItemsHandler(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
id, err := strconv.ParseInt(Vars(req)["id"], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
rw.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
items := db(req).ListFeedItems(id)
|
||||||
|
writeJSON(rw, items)
|
||||||
|
}
|
||||||
|
@ -80,6 +80,7 @@ var routes []Route = []Route{
|
|||||||
p("/api/folders/:id", FolderHandler),
|
p("/api/folders/:id", FolderHandler),
|
||||||
p("/api/feeds", FeedListHandler),
|
p("/api/feeds", FeedListHandler),
|
||||||
p("/api/feeds/:id", FeedHandler),
|
p("/api/feeds/:id", FeedHandler),
|
||||||
|
p("/api/feeds/:id/items", FeedItemsHandler),
|
||||||
p("/api/feeds/find", FeedHandler),
|
p("/api/feeds/find", FeedHandler),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,17 +14,17 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Item struct {
|
type Item struct {
|
||||||
Id string
|
Id string `json:"id"`
|
||||||
FeedId int64
|
FeedId int64 `json:"feed_id"`
|
||||||
Title string
|
Title string `json:"title"`
|
||||||
Link string
|
Link string `json:"link"`
|
||||||
Description string
|
Description string `json:"description"`
|
||||||
Content string
|
Content string `json:"content"`
|
||||||
Author string
|
Author string `json:"author"`
|
||||||
Date *time.Time
|
Date *time.Time `json:"date"`
|
||||||
DateUpdated *time.Time
|
DateUpdated *time.Time `json:"date_updated"`
|
||||||
Status ItemStatus
|
Status ItemStatus `json:"status"`
|
||||||
Image string
|
Image string `json:"image"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) CreateItems(items []Item) bool {
|
func (s *Storage) CreateItems(items []Item) bool {
|
||||||
@ -70,7 +70,6 @@ func itemQuery(s *Storage, cond string, v ...interface{}) []Item {
|
|||||||
content, author, date, date_updated, status, image
|
content, author, date, date_updated, status, image
|
||||||
from items
|
from items
|
||||||
where %s`, cond)
|
where %s`, cond)
|
||||||
s.log.Print(query)
|
|
||||||
rows, err := s.db.Query(query, v...)
|
rows, err := s.db.Query(query, v...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Print(err)
|
s.log.Print(err)
|
||||||
|
@ -77,12 +77,12 @@
|
|||||||
<input type="radio" name="item" :value="item.id" v-model="itemSelected">
|
<input type="radio" name="item" :value="item.id" v-model="itemSelected">
|
||||||
<div class="menu-item p-2">
|
<div class="menu-item p-2">
|
||||||
<div class="d-flex flex-column ml-4">
|
<div class="d-flex flex-column ml-4">
|
||||||
<div style="line-height: 1" class="d-flex">
|
<div style="line-height: 1" class="d-flex text-muted">
|
||||||
<img src="./static/images/circle-full.svg" class="nav-icon ml-n4 mr-2" v-if="item.status === 'unread'">
|
<img src="./static/images/circle-full.svg" class="nav-icon ml-n4 mr-2" v-if="item.status === 'unread'">
|
||||||
<img src="./static/images/circle.svg" class="nav-icon ml-n4 mr-2" v-if="item.status === 'read'">
|
<img src="./static/images/circle.svg" class="nav-icon ml-n4 mr-2" v-if="item.status === 'read'">
|
||||||
<img src="./static/images/star.svg" class="nav-icon ml-n4 mr-2" v-if="item.status === 'starred'">
|
<img src="./static/images/star.svg" class="nav-icon ml-n4 mr-2" v-if="item.status === 'starred'">
|
||||||
<small class="flex-fill text-truncate">{{feedsById[item.feed_id].title}}</small>
|
<small class="flex-fill text-truncate mr-1">{{feedsById[item.feed_id].title}}</small>
|
||||||
<small class="">{{formatDate(item.date)}}</small>
|
<small class="flex-shrink-0">{{formatDate(item.date)}}</small>
|
||||||
</div>
|
</div>
|
||||||
<span>{{item.title}}</span>
|
<span>{{item.title}}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -97,7 +97,7 @@
|
|||||||
<img src="./static/images/settings.svg" alt="" style="width: 20px; height: 20px;">
|
<img src="./static/images/settings.svg" alt="" style="width: 20px; height: 20px;">
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="itemSelected" class="mx-3 my-2 overflow-auto">
|
<div v-if="itemSelected" class="px-3 mt-2 overflow-auto">
|
||||||
<h3>{{itemSelectedDetails.title}}</h3>
|
<h3>{{itemSelectedDetails.title}}</h3>
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<div>{{ feedsById[itemSelectedDetails.feed_id].title }}</div>
|
<div>{{ feedsById[itemSelectedDetails.feed_id].title }}</div>
|
||||||
@ -105,7 +105,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div>
|
<div>
|
||||||
content goes here
|
<div v-html="itemSelectedDetails.description" v-if="itemSelectedDetails.description"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,7 +26,10 @@
|
|||||||
},
|
},
|
||||||
delete: function(id) {
|
delete: function(id) {
|
||||||
return api('delete', '/api/feeds/' + id)
|
return api('delete', '/api/feeds/' + id)
|
||||||
}
|
},
|
||||||
|
list_items: function(id) {
|
||||||
|
return api('get', '/api/feeds/' + id + '/items').then(json)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
folders: {
|
folders: {
|
||||||
list: function() {
|
list: function() {
|
||||||
@ -41,6 +44,6 @@
|
|||||||
delete: function(id) {
|
delete: function(id) {
|
||||||
return api('delete', '/api/folders/' + id)
|
return api('delete', '/api/folders/' + id)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
@ -43,9 +43,15 @@ var vm = new Vue({
|
|||||||
watch: {
|
watch: {
|
||||||
'feedSelected': function(newVal, oldVal) {
|
'feedSelected': function(newVal, oldVal) {
|
||||||
if (newVal === null) return
|
if (newVal === null) return
|
||||||
|
var vm = this
|
||||||
var parts = newVal.split(':', 2)
|
var parts = newVal.split(':', 2)
|
||||||
var type = parts[0]
|
var type = parts[0]
|
||||||
var guid = parts[1]
|
var guid = parts[1]
|
||||||
|
if (type === 'feed') {
|
||||||
|
api.feeds.list_items(guid).then(function(items) {
|
||||||
|
vm.items = items
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'itemSelected': function(newVal, oldVal) {
|
'itemSelected': function(newVal, oldVal) {
|
||||||
this.itemSelectedDetails = this.itemsById[newVal]
|
this.itemSelectedDetails = this.itemsById[newVal]
|
||||||
@ -64,9 +70,8 @@ var vm = new Vue({
|
|||||||
toggleFolderExpanded: function(folder) {
|
toggleFolderExpanded: function(folder) {
|
||||||
folder.is_expanded = !folder.is_expanded
|
folder.is_expanded = !folder.is_expanded
|
||||||
},
|
},
|
||||||
formatDate: function(timestamp_s) {
|
formatDate: function(datestr) {
|
||||||
var d = new Date(timestamp_s * 1000)
|
return new Date(datestr).toLocaleDateString(undefined, {year: "numeric", month: "long", day: "numeric"})
|
||||||
return d.getDate() + '/' + d.getMonth() + '/' + d.getFullYear()
|
|
||||||
},
|
},
|
||||||
moveFeed: function(feed, folder) {
|
moveFeed: function(feed, folder) {
|
||||||
var folder_id = folder ? folder.id : null
|
var folder_id = folder ? folder.id : null
|
||||||
|
Loading…
x
Reference in New Issue
Block a user