{{bookmarkTime(item)}}
{{item.title}}
-{{item.url}}
+{{getDomainURL(item.url)}}
{{item.excerpt}}
+diff --git a/cmd/add.go b/cmd/add.go index 7611340..1c98192 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -22,11 +22,13 @@ var ( offline, _ := cmd.Flags().GetBool("offline") // Save new bookmark - err := addBookmark(url, title, excerpt, tags, offline) + bookmark, err := addBookmark(url, title, excerpt, tags, offline) if err != nil { cError.Println(err) os.Exit(1) } + + printBookmark(bookmark) }, } ) @@ -39,7 +41,7 @@ func init() { rootCmd.AddCommand(addCmd) } -func addBookmark(url, title, excerpt string, tags []string, offline bool) (err error) { +func addBookmark(url, title, excerpt string, tags []string, offline bool) (book model.Bookmark, err error) { // Fetch data from internet article := readability.Article{} if !offline { @@ -83,10 +85,8 @@ func addBookmark(url, title, excerpt string, tags []string, offline bool) (err e // Save to database bookmark.ID, err = DB.SaveBookmark(bookmark) if err != nil { - return err + return book, err } - printBookmark(bookmark) - - return nil + return bookmark, nil } diff --git a/cmd/serve.go b/cmd/serve.go index a253bae..506c7f0 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -4,12 +4,12 @@ import ( "encoding/json" "fmt" db "github.com/RadhiFadlillah/shiori/database" + "github.com/RadhiFadlillah/shiori/model" "github.com/julienschmidt/httprouter" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "net/http" fp "path/filepath" - "strconv" "strings" ) @@ -27,6 +27,12 @@ var ( router.GET("/css/*filepath", serveFiles) router.GET("/webfonts/*filepath", serveFiles) router.GET("/api/bookmarks", apiGetBookmarks) + router.POST("/api/bookmarks", apiInsertBookmarks) + + // Route for panic + router.PanicHandler = func(w http.ResponseWriter, r *http.Request, arg interface{}) { + http.Error(w, fmt.Sprint(arg), 500) + } url := fmt.Sprintf(":%d", 8080) logrus.Infoln("Serve shiori in", url) @@ -48,26 +54,29 @@ func serveFiles(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { } func apiGetBookmarks(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - queries := r.URL.Query() - strLimit := queries.Get("limit") - strOffset := queries.Get("offset") - - limit, _ := strconv.Atoi(strLimit) - if limit <= 0 { - limit = 20 - } - - offset, _ := strconv.Atoi(strOffset) - if offset <= 0 { - offset = 0 - } - - bookmarks, err := DB.GetBookmarks(db.GetBookmarksOptions{ - Limit: limit, - Offset: offset, - OrderLatest: true}) + bookmarks, err := DB.GetBookmarks(db.GetBookmarksOptions{OrderLatest: true}) checkError(err) err = json.NewEncoder(w).Encode(&bookmarks) checkError(err) } + +func apiInsertBookmarks(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + // Decode request + request := model.Bookmark{} + err := json.NewDecoder(r.Body).Decode(&request) + checkError(err) + + // Save bookmark + tags := make([]string, len(request.Tags)) + for i, tag := range request.Tags { + tags[i] = tag.Name + } + + book, err := addBookmark(request.URL, request.Title, request.Excerpt, tags, false) + checkError(err) + + // Return new saved result + err = json.NewEncoder(w).Encode(&book) + checkError(err) +} diff --git a/database/database.go b/database/database.go index c1e3498..b5c5a5f 100644 --- a/database/database.go +++ b/database/database.go @@ -26,8 +26,6 @@ type Database interface { type GetBookmarksOptions struct { WithContents bool OrderLatest bool - Limit int - Offset int } func checkError(err error) { diff --git a/database/sqlite.go b/database/sqlite.go index 69a1005..ed529de 100644 --- a/database/sqlite.go +++ b/database/sqlite.go @@ -216,10 +216,6 @@ func (db *SQLiteDatabase) GetBookmarks(options GetBookmarksOptions, indices ...s query += ` ORDER BY modified DESC` } - if options.Limit > 0 { - query += fmt.Sprintf(` LIMIT %d OFFSET %d`, options.Limit, options.Offset) - } - bookmarks := []model.Bookmark{} err := db.Select(&bookmarks, query, args...) if err != nil && err != sql.ErrNoRows { diff --git a/view/css/stylesheet.css b/view/css/stylesheet.css index 045a419..39b0e53 100644 --- a/view/css/stylesheet.css +++ b/view/css/stylesheet.css @@ -1 +1 @@ -.header-link{border-right:1px solid #E5E5E5;color:#000;cursor:pointer;font-size:.9em;line-height:70px;overflow:hidden;padding:0 16px}.header-link:hover{color:#3F51B5}*{border-width:0;box-sizing:border-box;font-family:"Source Sans Pro",sans-serif;margin:0;padding:0;text-decoration:none}#app{background-color:#F5F5F5;display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap;height:auto;min-height:100vh}#app #header{background-color:#FFF;box-shadow:0 0 3px rgba(0,0,0,0.3);left:0;position:fixed;right:0;top:0;z-index:99;display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row nowrap}#app #header #logo{border-left:1px solid #E5E5E5;cursor:default;flex-shrink:0;border-right:1px solid #E5E5E5;color:#000;cursor:pointer;font-size:.9em;overflow:hidden;padding:0 16px;line-height:70px;display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row nowrap;font-size:1.5em;font-weight:100;color:#3F51B5}#app #header #logo:hover{color:#3F51B5}#app #header #logo span{margin-right:8px}#app #header #logo:hover{background-color:#F5F5F5}#app #header #search-box{-webkit-box-align:center;align-items:center;border-right:1px solid #E5E5E5;display:-webkit-box;display:flex;-webkit-box-flex:1;flex:1 0;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row nowrap;padding:16px;width:100%}#app #header #search-box button,#app #header #search-box input{background-color:#FFF;border:1px solid #E5E5E5;color:#000;font-size:.9em;padding:8px}#app #header #search-box button{cursor:pointer;color:#535A60}#app #header #search-box button:hover{color:#F44336}#app #header #search-box input{border-right:0;-webkit-box-flex:1;flex:1 0;padding:8px 16px}#app #main{margin-top:70px;display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap}#app #main #new-bookmark{align-self:center;max-width:600px;width:100%;display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row nowrap;margin:32px 8px 20px}#app #main #new-bookmark button,#app #main #new-bookmark input{background-color:#FFF;border:1px solid #E5E5E5;color:#000;font-size:.9em;padding:8px}#app #main #new-bookmark button{cursor:pointer;color:#535A60}#app #main #new-bookmark button:hover{color:#F44336}#app #main #new-bookmark input[type=text]{border-right:0;-webkit-box-flex:1;flex:1 0;padding:8px 16px}#app #main #grid{display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row;padding:4px}#app #main #grid>.column{-webkit-box-flex:1;flex:1 0;padding:12px}#app #main #grid>.column>*:not(:last-child){margin-bottom:24px}#app #main #progress-bar{display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column;-webkit-box-align:center;align-items:center;padding:32px}#app #main #progress-bar i{color:#6F757A;font-size:3em}#app #main #progress-bar a{color:#3F51B5 !important;font-size:.9em}#app #main #progress-bar a:hover{color:#F44336 !important}.bookmark{background-color:#FFF;border:1px solid #E5E5E5;position:relative}.bookmark .checkbox{z-index:9;right:0;opacity:0;position:absolute;outline:1px solid #E5E5E5;color:#6F757A;background-color:#FFF}.bookmark .checkbox::before{width:32px;line-height:32px;text-align:center;display:block;font-family:"Font Awesome 5 Free";font-weight:900;font-size:.9em;content:"\f00c"}.bookmark .checkbox:hover{color:#F44336 !important}.bookmark .bookmark-image{position:relative;display:block;height:250px;background-position:center;background-repeat:no-repeat;background-size:cover}.bookmark .bookmark-image .bookmark-metadata{position:absolute;top:0;left:0;width:100%;height:100%;padding:16px;-webkit-box-pack:end;justify-content:flex-end;background-color:rgba(0,0,0,0.5);border-bottom:0}.bookmark .bookmark-image .bookmark-metadata .bookmark-time,.bookmark .bookmark-image .bookmark-metadata .bookmark-url{color:white;text-shadow:1px 1px 1px rgba(0,0,0,0.5)}.bookmark .bookmark-image .bookmark-metadata .bookmark-title{color:white;text-shadow:1px 1px 1px rgba(0,0,0,0.5)}.bookmark .bookmark-image .bookmark-metadata:hover .bookmark-title{text-decoration:underline}.bookmark .bookmark-metadata{padding:16px;display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap}.bookmark .bookmark-metadata .bookmark-time{color:#6F757A;font-size:.9em;margin-bottom:8px}.bookmark .bookmark-metadata .bookmark-title{color:#000;font-size:1.3em;font-weight:600}.bookmark .bookmark-metadata .bookmark-url{color:#6F757A;font-size:.9em;margin-bottom:8px;margin-bottom:0;margin-top:8px}.bookmark .bookmark-metadata:hover .bookmark-title{text-decoration:underline}.bookmark .bookmark-excerpt{padding:16px;color:#000;border-top:1px solid #E5E5E5}.bookmark .bookmark-tags{display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row wrap;padding:0 12px 12px;margin-top:-4px}.bookmark .bookmark-tags a{font-size:.9em;padding:4px;color:#3F51B5 !important}.bookmark .bookmark-tags a::before{content:"#"}.bookmark .bookmark-tags a:hover{text-decoration:underline}.bookmark:hover .checkbox{opacity:1}.bookmark.checked{border:0;outline:6px solid #9E9E9E}.bookmark.checked .checkbox{opacity:1;outline:0;background-color:#9E9E9E;color:white} \ No newline at end of file +.header-link{border-right:1px solid #E5E5E5;color:#000;cursor:pointer;font-size:.9em;line-height:70px;overflow:hidden;padding:0 16px}.header-link:hover{color:#3F51B5}*{border-width:0;box-sizing:border-box;font-family:"Source Sans Pro",sans-serif;margin:0;padding:0;text-decoration:none}.spacer{-webkit-box-flex:1;flex:1 0}#app{background-color:#F5F5F5;display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap;height:auto;min-height:100vh}#app #header{background-color:#FFF;box-shadow:0 0 3px rgba(0,0,0,0.3);left:0;position:fixed;right:0;top:0;z-index:99;display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row nowrap}#app #header #logo{border-left:1px solid #E5E5E5;cursor:default;flex-shrink:0;border-right:1px solid #E5E5E5;color:#000;cursor:pointer;font-size:.9em;overflow:hidden;padding:0 16px;line-height:70px;display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row nowrap;font-size:1.5em;font-weight:100;color:#3F51B5}#app #header #logo:hover{color:#3F51B5}#app #header #logo span{margin-right:8px}#app #header #logo:hover{background-color:#F5F5F5}#app #header #search-box{-webkit-box-align:center;align-items:center;border-right:1px solid #E5E5E5;display:-webkit-box;display:flex;-webkit-box-flex:1;flex:1 0;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row nowrap;padding:16px;width:100%}#app #header #search-box .button,#app #header #search-box input{background-color:#FFF;border:1px solid #E5E5E5;color:#000;font-size:.9em;padding:8px}#app #header #search-box .button{cursor:pointer;color:#535A60}#app #header #search-box .button:hover{color:#F44336}#app #header #search-box input{border-right:0;-webkit-box-flex:1;flex:1 0;padding:8px 16px}#app #main{margin-top:70px;display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap}#app #main #new-bookmark{align-self:center;max-width:600px;width:100%;display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap;margin:32px 8px 20px;background-color:#FFF;outline:1px solid #E5E5E5}#app #main #new-bookmark input[type=text],#app #main #new-bookmark textarea{outline:1px solid #E5E5E5;color:#000;font-size:.9em;padding:12px 16px}#app #main #new-bookmark textarea{resize:vertical;min-height:4em;max-height:10em}#app #main #new-bookmark .button-area{display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row nowrap;padding:8px}#app #main #new-bookmark .button-area a{color:#535A60;text-transform:uppercase;padding:8px;background-color:#FFF}#app #main #new-bookmark .button-area a.button{font-size:.9em;cursor:pointer}#app #main #new-bookmark .button-area a.button:hover{color:#F44336}#app #main #grid{display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row;padding:4px}#app #main #grid>.column{-webkit-box-flex:1;flex:1 0;padding:12px}#app #main #grid>.column>*:not(:last-child){margin-bottom:24px}#app #main #progress-bar{display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column;-webkit-box-align:center;align-items:center;padding:32px}#app #main #progress-bar i{color:#6F757A;font-size:3em}#app #main #progress-bar a{color:#3F51B5 !important;font-size:.9em}#app #main #progress-bar a:hover{color:#F44336 !important}.bookmark{background-color:#FFF;border:1px solid #E5E5E5;position:relative}.bookmark .checkbox{z-index:9;right:0;opacity:0;position:absolute;outline:1px solid #E5E5E5;color:#535A60;background-color:#FFF;width:32px;line-height:32px;text-align:center;display:block;font-size:.9em}.bookmark .checkbox:hover{color:#F44336 !important}.bookmark .bookmark-metadata{padding:16px;display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap}.bookmark .bookmark-metadata .bookmark-time{color:#6F757A;font-size:.9em;margin-bottom:8px}.bookmark .bookmark-metadata .bookmark-title{color:#000;font-size:1.3em;font-weight:600}.bookmark .bookmark-metadata .bookmark-url{color:#6F757A;font-size:.9em;margin-bottom:8px;margin-bottom:0;margin-top:8px;max-height:2.6em;line-height:1.3em;text-overflow:ellipsis;overflow:hidden}.bookmark .bookmark-metadata.has-image{min-height:250px;background-position:center;background-repeat:no-repeat;background-size:cover;-webkit-box-pack:end;justify-content:flex-end;position:relative}.bookmark .bookmark-metadata.has-image::before{content:"";background-color:rgba(0,0,0,0.5);position:absolute;top:0;left:0;right:0;bottom:0;z-index:0}.bookmark .bookmark-metadata.has-image .bookmark-time,.bookmark .bookmark-metadata.has-image .bookmark-url{z-index:2;color:white;text-shadow:1px 1px 1px rgba(0,0,0,0.5)}.bookmark .bookmark-metadata.has-image .bookmark-title{z-index:2;color:white;text-shadow:1px 1px 1px rgba(0,0,0,0.5)}.bookmark .bookmark-metadata:hover .bookmark-title{text-decoration:underline}.bookmark .bookmark-excerpt{padding:16px;color:#000;border-top:1px solid #E5E5E5}.bookmark .bookmark-tags{display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row wrap;padding:0 12px 12px;margin-top:-4px}.bookmark .bookmark-tags a{font-size:.9em;padding:4px;color:#3F51B5 !important}.bookmark .bookmark-tags a::before{content:"#"}.bookmark .bookmark-tags a:hover{text-decoration:underline}.bookmark .bookmark-menu{display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row nowrap;border-top:1px solid #E5E5E5;visibility:hidden}.bookmark .bookmark-menu a{display:block;-webkit-box-flex:1;flex:1 0;color:#535A60 !important;padding:8px;font-size:.9em;text-align:center}.bookmark .bookmark-menu a:not(:last-child){border-right:1px solid #E5E5E5}.bookmark .bookmark-menu a:hover{color:#F44336 !important}.bookmark:hover .checkbox{opacity:1}.bookmark:hover .bookmark-menu{visibility:visible}.bookmark.checked{border:0;outline:6px solid #9E9E9E}.bookmark.checked .checkbox{opacity:1;outline:0;background-color:#9E9E9E;color:white} \ No newline at end of file diff --git a/view/index.html b/view/index.html index b4ce4d8..5a4eece 100644 --- a/view/index.html +++ b/view/index.html @@ -20,58 +20,61 @@ 栞shiori
{{bookmarkTime(item)}}
{{item.title}}
-{{item.url}}
+{{getDomainURL(item.url)}}
{{item.excerpt}}
+