Changed Styling. Added category id to responses

This commit is contained in:
Xnoe 2022-05-20 00:12:35 +01:00
parent a974a59121
commit d52c401206
Signed by: xnoe
GPG Key ID: 45AC398F44F0DAFE
2 changed files with 135 additions and 81 deletions

View File

@ -43,7 +43,8 @@ getPostListing c page = do
let sub = ("subtext", toJSString $ fromSql subtext) let sub = ("subtext", toJSString $ fromSql subtext)
let cat = ("category", toJSString category) let cat = ("category", toJSString category)
let id = ("id", toJSString $ show $ (fromSql pid::Int)) let id = ("id", toJSString $ show $ (fromSql pid::Int))
return $ showJSON $ toJSObject [id, title, sub, cat] let catid = ("catid", toJSString $ fromSql cid)
return $ showJSON $ toJSObject [id, title, sub, cat, catid]
) result ) result
return $ Just $ showJSON $ JSArray posts return $ Just $ showJSON $ JSArray posts
@ -75,7 +76,8 @@ getPostsInCategory c cat page = do
let sub = ("subtext", toJSString $ fromSql subtext) let sub = ("subtext", toJSString $ fromSql subtext)
let id = ("id", toJSString $ show $ (fromSql pid::Int)) let id = ("id", toJSString $ show $ (fromSql pid::Int))
let cat = ("category", toJSString category) let cat = ("category", toJSString category)
return $ showJSON $ toJSObject [id, cat, title, sub] let catid = ("catid", toJSString $ fromSql cid)
return $ showJSON $ toJSObject [id, cat, title, sub, catid]
) result ) result
return $ Just $ showJSON $ toJSObject [("category", showJSON $ toJSString category), ("posts", showJSON $ JSArray posts)] return $ Just $ showJSON $ toJSObject [("category", showJSON $ toJSString category), ("posts", showJSON $ JSArray posts)]
@ -92,7 +94,8 @@ getPostContent c pid = do
let title = ("title", toJSString $ fromSql t) let title = ("title", toJSString $ fromSql t)
let content = ("content", toJSString $ fromSql con) let content = ("content", toJSString $ fromSql con)
let cat = ("category", toJSString category) let cat = ("category", toJSString category)
return $ Just $ showJSON $ toJSObject [title, content, cat]; let catid = ("catid", toJSString $ fromSql cid)
return $ Just $ showJSON $ toJSObject [title, content, cat, catid];
_ -> fail "Post does not exist!" _ -> fail "Post does not exist!"
main :: IO () main :: IO ()

View File

@ -1,15 +1,18 @@
module Main exposing (..) module Main exposing (..)
import Http import Http
import Json.Decode exposing (Decoder, field, string, map2, map3, map4) import Json.Decode exposing (Decoder, field, string, map2, map3, map4, map5)
import Browser import Browser
import Browser.Navigation exposing (..) import Browser.Navigation exposing (..)
import Url import Url
import Html exposing (..) import Html exposing (..)
import Html.Attributes exposing (..) import Html.Attributes exposing (..)
import Html.Events exposing (onInput, onClick)
import Url.Parser as P exposing ((</>)) import Url.Parser as P exposing ((</>))
import Http exposing (multipartBody)
import Http exposing (stringPart)
main : Program () Model Msg main : Program () Model Msg
main = main =
@ -22,27 +25,16 @@ main =
onUrlChange = UrlChanged onUrlChange = UrlChanged
} }
type alias Post = {
id: String,
category: String,
title: String,
subtext: String
}
type alias Category = { type alias Category = {
id: String, id: String,
name: String name: String
} }
type alias Model = { type alias Post = {
header: String, id: String,
content: String, category: Category,
footer: String, title: String,
pinnedPosts: List Post, subtext: String
posts: List Post,
route: Maybe Route,
key: Browser.Navigation.Key,
errMessage: Maybe (String)
} }
type Route type Route
@ -50,9 +42,9 @@ type Route
| CategoriesView | CategoriesView
| CategoryView String | CategoryView String
| PostView String | PostView String
| Login | LoginView
| Logout | LogoutView
| CreatePost | CreatePostView
routeParser : P.Parser (Route -> a) a routeParser : P.Parser (Route -> a) a
routeParser = routeParser =
@ -61,46 +53,15 @@ routeParser =
, P.map CategoriesView (P.s "categories") , P.map CategoriesView (P.s "categories")
, P.map CategoryView (P.s "category" </> P.string) , P.map CategoryView (P.s "category" </> P.string)
, P.map PostView (P.s "post" </> P.string) , P.map PostView (P.s "post" </> P.string)
, P.map Login (P.s "login") , P.map LoginView (P.s "login")
, P.map Logout (P.s "logout") , P.map LogoutView (P.s "logout")
, P.map CreatePost (P.s "create") , P.map CreatePostView (P.s "create")
] ]
messageOfRoute : Maybe Route -> Cmd Msg
messageOfRoute r =
case r of
Just route ->
case route of
Home -> Http.get {url = "/v1/posts", expect = Http.expectJson GotPosts processPostListing}
CategoriesView -> Http.get {url = "/v1/categories", expect = Http.expectJson GotCategories processCategoryListing}
PostView p -> Http.get {url = "/v1/post/" ++ p, expect = Http.expectJson GotPost processPost}
CategoryView c -> Http.get {url = "/v1/category/" ++ c, expect = Http.expectJson GotCategory processCategory}
_ -> Cmd.none
Nothing -> Cmd.none
init : () -> Url.Url -> Browser.Navigation.Key -> (Model, Cmd Msg)
init _ url key =
let r = P.parse routeParser url in
({
header = "", content = "", footer = "", pinnedPosts = [],
posts = [], route = r, key = key, errMessage = Just "Loading Posts..."
},
messageOfRoute r
)
type Msg
= LinkClinked Browser.UrlRequest
| UrlChanged Url.Url
| GotPosts (Result Http.Error (List Post))
| GotCategories (Result Http.Error (List Category))
| GotPost (Result Http.Error (String, String, String))
| GotCategory (Result Http.Error (String, List Post))
processPostListing : Decoder (List Post) processPostListing : Decoder (List Post)
processPostListing = processPostListing =
Json.Decode.list ( Json.Decode.list (
map4 Post (field "id" string) (field "category" string) (field "title" string) (field "subtext" string) map5(\a->\b->\c->\d->\e-> Post a (Category b c) d e) (field "id" string) (field "catid" string) (field "category" string) (field "title" string) (field "subtext" string)
) )
processCategoryListing : Decoder (List Category) processCategoryListing : Decoder (List Category)
@ -115,6 +76,61 @@ processCategory : Decoder (String, List Post)
processCategory = processCategory =
map2 (\a -> \b -> (a,b)) (field "category" string) (field "posts" processPostListing) map2 (\a -> \b -> (a,b)) (field "category" string) (field "posts" processPostListing)
processLogin : Decoder (String)
processLogin =
(field "username" string)
messageOfRoute : Maybe Route -> Cmd Msg
messageOfRoute r =
case r of
Just route ->
case route of
Home -> Http.get {url = "/v1/posts", expect = Http.expectJson GotPosts processPostListing}
CategoriesView -> Http.get {url = "/v1/categories", expect = Http.expectJson GotCategories processCategoryListing}
PostView p -> Http.get {url = "/v1/post/" ++ p, expect = Http.expectJson GotPost processPost}
CategoryView c -> Http.get {url = "/v1/category/" ++ c, expect = Http.expectJson GotCategory processCategory}
_ -> Cmd.none
Nothing -> Cmd.none
type alias User = {
username: String
}
type alias Model = {
header: String,
content: String,
footer: String,
pinnedPosts: List Post,
posts: List Post,
route: Maybe Route,
key: Browser.Navigation.Key,
errMessage: Maybe (String),
username: String,
password: String,
user: Maybe User
}
type Msg
= LinkClinked Browser.UrlRequest
| UrlChanged Url.Url
| GotPosts (Result Http.Error (List Post))
| GotCategories (Result Http.Error (List Category))
| GotPost (Result Http.Error (String, String, String))
| GotCategory (Result Http.Error (String, List Post))
| LoginResult (Result Http.Error String)
| Username String
| Password String
| Login
init : () -> Url.Url -> Browser.Navigation.Key -> (Model, Cmd Msg)
init _ url key =
let r = P.parse routeParser url in
({
header = "", content = "", footer = "", pinnedPosts = [],
posts = [], route = r, key = key, errMessage = Nothing,
username = "", password = "", user = Nothing
},
messageOfRoute r
)
update : Msg -> Model -> (Model, Cmd Msg) update : Msg -> Model -> (Model, Cmd Msg)
update msg model = update msg model =
case msg of case msg of
@ -130,8 +146,16 @@ update msg model =
GotPosts (Ok l) -> ({model | errMessage = Nothing, posts = l}, Cmd.none) GotPosts (Ok l) -> ({model | errMessage = Nothing, posts = l}, Cmd.none)
GotPosts (Err _) -> ({model | errMessage = Just "Failed to load posts"}, Cmd.none) GotPosts (Err _) -> ({model | errMessage = Just "Failed to load posts"}, Cmd.none)
GotPost (Ok (title, content, category)) -> ({model | errMessage = Nothing, header = title, content = content, footer = category}, Cmd.none) GotPost (Ok (title, content, category)) -> ({model | errMessage = Nothing, header = title, content = content, footer = category}, Cmd.none)
GotCategory (Ok (title, posts)) -> ({model | errMessage = Nothing, header = title, posts = posts}, Cmd.none)
Username u -> ({model | username = u}, Cmd.none)
Password p -> ({model | password = p}, Cmd.none)
Login -> (model, handleLogin model)
_ -> ({model | errMessage = Just "Something has gone horribly wrong."}, Cmd.none) _ -> ({model | errMessage = Just "Something has gone horribly wrong."}, Cmd.none)
handleLogin : Model -> Cmd Msg
handleLogin model =
Http.post {url = "/v1/login", body = multipartBody [stringPart "username" model.username, stringPart "password" model.password], expect = Http.expectJson LoginResult processLogin}
type alias Document msg = { type alias Document msg = {
title: String, title: String,
body: List (Html msg) body: List (Html msg)
@ -139,12 +163,29 @@ type alias Document msg = {
view : Model -> Document Msg view : Model -> Document Msg
view model = view model =
{title = "Xnopyt.com", body = [htmlView model]} {title = "XNOEBLOG", body = [htmlView model]}
htmlView : Model -> Html Msg htmlView : Model -> Html Msg
htmlView model = htmlView model =
renderModel model div [
style "flex-direction" "column",
style "margin" "0",
style "padding" "0"
] [
div [
style "border-bottom" "2px solid black",
style "height" "1.5em",
style "padding" "5px"
] ([
a [href "/"] [text "Home"],
text " - "
] ++
case model.user of
Nothing -> [a [href "/login"] [text "Login"]]
Just u -> [a [href "/logout"] [text "Logout"], text " - ", a [href "/create"] [text "Create Post"]]
),
renderModel model
]
renderModel : Model -> Html Msg renderModel : Model -> Html Msg
renderModel model = renderModel model =
case (model.errMessage) of case (model.errMessage) of
@ -152,15 +193,23 @@ renderModel model =
Nothing -> Nothing ->
case model.route of case model.route of
Just route -> case route of Just route -> case route of
Home -> cardListing model Home -> div [] [h1 [] [text "Welcome to my blog."],cardListing model]
PostView _ -> div [] [h1 [] [text (model.header)], p [] [text(model.content)], h3 [] [text(model.footer), a [href "/"] [text "Go Home"]]] PostView _ -> div [] [h1 [] [text (model.header)], p [] [text(model.content)], h3 [] [text(model.footer ++ " ")]]
CategoryView _ -> div [] [h1 [] [text (model.header)], cardListing model]
LoginView -> loginForm model
_ -> h1 [] [ text ("Not found."), a [ href "/"] [text("Return home")] ] _ -> h1 [] [ text ("Not found."), a [ href "/"] [text("Return home")] ]
_ -> h1 [] [ text ("Not found."), a [ href "/"] [text("Return home")] ] _ -> h1 [] [ text ("Not found."), a [ href "/"] [text("Return home")] ]
cardListing : Model -> Html Msg
cardListing model =
div [
style "display" "grid",
style "grid-template-columns" "repeat(auto-fill, minmax(16rem, 1fr))"
] (List.map renderPost model.posts)
renderPost : Post -> Html Msg renderPost : Post -> Html Msg
renderPost post = renderPost post =
div [ div [
style "width" "25%", style "max-width" "32rem",
style "height" "auto", style "height" "auto",
style "box-sizing" "border-box", style "box-sizing" "border-box",
style "padding" "15px" style "padding" "15px"
@ -169,12 +218,12 @@ renderPost post =
style "flex-direction" "column", style "flex-direction" "column",
style "border-radius" "5px", style "border-radius" "5px",
style "display" "flex", style "display" "flex",
style "height" "100%" style "height" "100%",
style "border" "2px solid black",
style "padding" "5px"
] [ ] [
header [ header [
style "background-color" "#404040", style "min-height" "75px",
style "color" "white",
style "height" "75px",
style "display" "flex", style "display" "flex",
style "flex-direction" "column", style "flex-direction" "column",
style "align-items" "center", style "align-items" "center",
@ -184,36 +233,38 @@ renderPost post =
style "font-weight" "bold", style "font-weight" "bold",
style "border-radius" "10px 10px 0 0" style "border-radius" "10px 10px 0 0"
] [ ] [
a [href ("/post/" ++ post.id)] [text (post.title)] a [style "text-align" "center", href ("/post/" ++ post.id)] [text (post.title)]
], ],
div [ div [
style "color" "white",
style "flex-grow" "1", style "flex-grow" "1",
style "background-color" "#505050",
style "padding" "10px" style "padding" "10px"
] [ ] [
text (post.subtext) text (post.subtext)
], ],
footer [ footer [
style "background-color" "#404040", style "min-height" "50px",
style "color" "white",
style "height" "50px",
style "display" "flex", style "display" "flex",
style "flex-direction" "row", style "flex-direction" "row",
style "justify-content" "space-around", style "justify-content" "space-around",
style "align-items" "center",
style "box-shadow" "none", style "box-shadow" "none",
style "box-sizing" "border-box", style "box-sizing" "border-box",
style "padding" "10px", style "padding" "10px",
style "border-radius" "0 0 10px 10px" style "border-radius" "0 0 10px 10px"
] [ ] [
text (post.category) text ("Category: "), a [href ("/category/" ++ post.category.id)] [text (post.category.name)]
] ]
] ]
] ]
cardListing : Model -> Html Msg loginForm : Model -> Html Msg
cardListing model = loginForm model =
div [ div [] [
style "display" "flex", viewInput "text" "username" "Username" model.username Username,
style "flex-flow" "row wrap" viewInput "password" "password" "Password" model.password Password,
] (List.map renderPost model.posts) button [onClick Login] [text "Login"]
]
viewInput : String -> String -> String -> String -> (String -> msg) -> Html msg
viewInput t n p v toMsg =
input [ name n, type_ t, placeholder p, value v, onInput toMsg ] []