mirror of
https://github.com/avinal/avinal.github.io.git
synced 2026-07-04 07:40:09 +05:30
add metadata parsing
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
This commit is contained in:
@@ -6,18 +6,19 @@
|
|||||||
"elm-version": "0.19.1",
|
"elm-version": "0.19.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"direct": {
|
"direct": {
|
||||||
|
"MaybeJustJames/yaml": "2.1.2",
|
||||||
"elm/browser": "1.0.2",
|
"elm/browser": "1.0.2",
|
||||||
"elm/core": "1.0.5",
|
"elm/core": "1.0.5",
|
||||||
"elm/html": "1.0.0",
|
"elm/html": "1.0.0",
|
||||||
"elm/http": "2.0.0",
|
"elm/http": "2.0.0",
|
||||||
"elm/url": "1.0.0",
|
"elm/parser": "1.1.0",
|
||||||
"hecrj/html-parser": "2.4.0"
|
"elm/url": "1.0.0"
|
||||||
},
|
},
|
||||||
"indirect": {
|
"indirect": {
|
||||||
"elm/bytes": "1.0.8",
|
"elm/bytes": "1.0.8",
|
||||||
"elm/file": "1.0.5",
|
"elm/file": "1.0.5",
|
||||||
"elm/json": "1.1.3",
|
"elm/json": "1.1.3",
|
||||||
"elm/parser": "1.1.0",
|
"elm/regex": "1.0.0",
|
||||||
"elm/time": "1.0.0",
|
"elm/time": "1.0.0",
|
||||||
"elm/virtual-dom": "1.0.3",
|
"elm/virtual-dom": "1.0.3",
|
||||||
"rtfeldman/elm-hex": "1.0.0"
|
"rtfeldman/elm-hex": "1.0.0"
|
||||||
|
|||||||
+21
-21
@@ -16,9 +16,9 @@
|
|||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|
||||||
<script src="/website/app.js"></script>
|
<script src="/website/app.js"></script>
|
||||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" crossorigin="anonymous"></script> -->
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" crossorigin="anonymous"></script>
|
||||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.7/clipboard.min.js"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.7/clipboard.min.js"
|
||||||
crossorigin="anonymous"></script> -->
|
crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||||
<script src="/website/prism.js"></script>
|
<script src="/website/prism.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
||||||
@@ -73,25 +73,25 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
document.getElementById("insert-here").innerHTML = marked.parse(markdowndata);
|
document.getElementById("insert-here").innerHTML = marked.parse(markdowndata);
|
||||||
document.getElementById("toc-entries").innerHTML = toc;
|
// document.getElementById("toc-entries").innerHTML = toc;
|
||||||
|
});
|
||||||
|
$(function () {
|
||||||
|
// copy-btn HTML
|
||||||
|
var btn = "<span class=\"btn-copy tooltipped tooltipped-sw\" aria-label=\"Copy to clipboard!\">";
|
||||||
|
btn += '<i class="far fa-clone"></i>';
|
||||||
|
btn += '</span>';
|
||||||
|
// mount it!
|
||||||
|
$(".highlight table").before(btn);
|
||||||
|
var clip = new ClipboardJS('.btn-copy', {
|
||||||
|
text: function (trigger) {
|
||||||
|
return Array.from(trigger.nextElementSibling.querySelectorAll('.code')).reduce((str, it) => str + it.innerText + '\n', '')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
clip.on('success', function (e) {
|
||||||
|
e.trigger.setAttribute('aria-label', "Copied!");
|
||||||
|
e.clearSelection();
|
||||||
|
})
|
||||||
});
|
});
|
||||||
// $(function () {
|
|
||||||
// // copy-btn HTML
|
|
||||||
// var btn = "<span class=\"btn-copy tooltipped tooltipped-sw\" aria-label=\"Copy to clipboard!\">";
|
|
||||||
// btn += '<i class="far fa-clone"></i>';
|
|
||||||
// btn += '</span>';
|
|
||||||
// // mount it!
|
|
||||||
// $(".highlight table").before(btn);
|
|
||||||
// var clip = new ClipboardJS('.btn-copy', {
|
|
||||||
// text: function (trigger) {
|
|
||||||
// return Array.from(trigger.nextElementSibling.querySelectorAll('.code')).reduce((str, it) => str + it.innerText + '\n', '')
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// clip.on('success', function (e) {
|
|
||||||
// e.trigger.setAttribute('aria-label', "Copied!");
|
|
||||||
// e.clearSelection();
|
|
||||||
// })
|
|
||||||
// });
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+25
-1
@@ -1,5 +1,29 @@
|
|||||||
module Base exposing (urlPrefix)
|
module Base exposing (urlPrefix, contentUrlPrefix)
|
||||||
|
|
||||||
|
{-| The base URL for accessing the content for the site
|
||||||
|
|
||||||
|
Using Github CDN for now, but this could be changed to a custom domain
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
contentBase : String
|
||||||
|
contentBase =
|
||||||
|
"https://raw.githubusercontent.com"
|
||||||
|
|
||||||
|
|
||||||
|
{-| The Github user name for the site
|
||||||
|
-}
|
||||||
|
user : String
|
||||||
|
user =
|
||||||
|
"avinal"
|
||||||
|
|
||||||
|
|
||||||
urlPrefix : String
|
urlPrefix : String
|
||||||
urlPrefix =
|
urlPrefix =
|
||||||
"website"
|
"website"
|
||||||
|
|
||||||
|
|
||||||
|
contentUrlPrefix : String
|
||||||
|
contentUrlPrefix =
|
||||||
|
contentBase ++ "/" ++ user ++ "/" ++ urlPrefix ++ "/main/content/"
|
||||||
|
|||||||
+115
-55
@@ -3,10 +3,9 @@ port module Blog exposing (..)
|
|||||||
import Base exposing (urlPrefix)
|
import Base exposing (urlPrefix)
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (class, href, id, style)
|
import Html.Attributes exposing (class, href, id, style)
|
||||||
import Html.Parser
|
|
||||||
import Html.Parser.Util
|
|
||||||
import Http exposing (Error(..))
|
import Http exposing (Error(..))
|
||||||
import Url exposing (Protocol(..))
|
import Url exposing (Protocol(..))
|
||||||
|
import Yaml.Decode as Yaml exposing (Decoder, field, list, string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -14,10 +13,10 @@ import Url exposing (Protocol(..))
|
|||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ blog : Blog
|
{ blog : Maybe Blog
|
||||||
, markDownUrl : String
|
, markdownUrl : String
|
||||||
, markDown : String
|
|
||||||
, success : Bool
|
, success : Bool
|
||||||
|
, fragment : String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -26,13 +25,17 @@ type alias Model =
|
|||||||
|
|
||||||
|
|
||||||
type alias Blog =
|
type alias Blog =
|
||||||
{ title : String
|
{ meta : YamlMeta
|
||||||
, url : String
|
|
||||||
, description : String
|
|
||||||
, content : String
|
, content : String
|
||||||
, category : String
|
}
|
||||||
, tags : List String
|
|
||||||
, date : String
|
|
||||||
|
initialModel : Model
|
||||||
|
initialModel =
|
||||||
|
{ blog = Nothing
|
||||||
|
, markdownUrl = ""
|
||||||
|
, success = False
|
||||||
|
, fragment = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -48,8 +51,7 @@ view model =
|
|||||||
div [ class "foo-interface" ]
|
div [ class "foo-interface" ]
|
||||||
[ div [ class "foo-console foo-terminal foo-active" ]
|
[ div [ class "foo-console foo-terminal foo-active" ]
|
||||||
[ div [ class "main-wrapper" ]
|
[ div [ class "main-wrapper" ]
|
||||||
[ viewToc model.success
|
[ main_ [ class "main-content", id "content" ]
|
||||||
, main_ [ class "main-content", id "content" ]
|
|
||||||
[ viewArticle model.success ]
|
[ viewArticle model.success ]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@@ -61,17 +63,16 @@ viewToc show =
|
|||||||
if show then
|
if show then
|
||||||
div
|
div
|
||||||
[ class "toc"
|
[ class "toc"
|
||||||
, style "display"
|
|
||||||
(if show then
|
|
||||||
"block"
|
|
||||||
|
|
||||||
else
|
|
||||||
"none"
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
[ aside [ class "document-toc-container" ]
|
[ aside [ class "document-toc-container" ]
|
||||||
[ section [ class "document-toc" ]
|
[ section [ class "document-toc" ]
|
||||||
[ h2 [ class "document-toc-heading" ] [ text "In this page" ]
|
[ h2 [ class "document-toc-heading" ]
|
||||||
|
[ if show then
|
||||||
|
text "In this page"
|
||||||
|
|
||||||
|
else
|
||||||
|
text ""
|
||||||
|
]
|
||||||
, ul
|
, ul
|
||||||
[ class "document-toc-list", id "toc-entries" ]
|
[ class "document-toc-list", id "toc-entries" ]
|
||||||
[]
|
[]
|
||||||
@@ -125,18 +126,44 @@ viewMetadata show =
|
|||||||
type Msg
|
type Msg
|
||||||
= GetMarkdown
|
= GetMarkdown
|
||||||
| DataReceived (Result Http.Error String)
|
| DataReceived (Result Http.Error String)
|
||||||
|
| NoSuchPage
|
||||||
|
|
||||||
|
|
||||||
init : Maybe String -> ( Model, Cmd Msg )
|
init : List String -> ( Model, Cmd Msg )
|
||||||
init slug =
|
init pathList =
|
||||||
( { blog = initBlog
|
case pathList of
|
||||||
, markDownUrl = finalUrl slug
|
[ category, slug, fragment ] ->
|
||||||
, markDown = ""
|
( { initialModel
|
||||||
, success = False
|
| markdownUrl = Base.contentUrlPrefix ++ "posts/" ++ category ++ "/" ++ slug ++ ".md"
|
||||||
|
, fragment = fragment
|
||||||
}
|
}
|
||||||
, getMarkdown <| finalUrl slug
|
, getMarkdown (Base.contentUrlPrefix ++ "posts/" ++ category ++ "/" ++ slug ++ ".md")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
[ category, slug ] ->
|
||||||
|
( { initialModel
|
||||||
|
| markdownUrl = Base.contentUrlPrefix ++ "posts/" ++ category ++ "/" ++ slug ++ ".md"
|
||||||
|
}
|
||||||
|
, getMarkdown (Base.contentUrlPrefix ++ "posts/" ++ category ++ "/" ++ slug ++ ".md")
|
||||||
|
)
|
||||||
|
|
||||||
|
-- [ "categories" ] ->
|
||||||
|
-- ( { blog = Nothing
|
||||||
|
-- , markdownUrl = urlPrefix ++ "/categories" ++ ".md"
|
||||||
|
-- , markDown = ""
|
||||||
|
-- , success = False
|
||||||
|
-- , fragment = ""
|
||||||
|
-- }
|
||||||
|
-- , getMarkdown (urlPrefix ++ "/categories" ++ ".md")
|
||||||
|
-- )
|
||||||
|
[] ->
|
||||||
|
( initialModel
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
( initialModel, Cmd.none )
|
||||||
|
|
||||||
|
|
||||||
getMarkdown : String -> Cmd Msg
|
getMarkdown : String -> Cmd Msg
|
||||||
getMarkdown url =
|
getMarkdown url =
|
||||||
@@ -164,29 +191,25 @@ finalUrl slug =
|
|||||||
++ ".md"
|
++ ".md"
|
||||||
|
|
||||||
|
|
||||||
initBlog : Blog
|
|
||||||
initBlog =
|
|
||||||
{ title = ""
|
|
||||||
, url = ""
|
|
||||||
, description = ""
|
|
||||||
, content = ""
|
|
||||||
, category = ""
|
|
||||||
, tags = []
|
|
||||||
, date = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
update msg model =
|
update msg model =
|
||||||
case msg of
|
case msg of
|
||||||
GetMarkdown ->
|
GetMarkdown ->
|
||||||
( model, Http.get { url = model.markDownUrl, expect = Http.expectString DataReceived } )
|
( model, Http.get { url = model.markdownUrl, expect = Http.expectString DataReceived } )
|
||||||
|
|
||||||
DataReceived (Ok data) ->
|
DataReceived (Ok data) ->
|
||||||
( { model | markDown = data, success = True }, sendString data )
|
case splitMetaContent data of
|
||||||
|
Ok blog ->
|
||||||
|
( { model | blog = Just blog, success = True }, sendString blog.content )
|
||||||
|
|
||||||
DataReceived (Err err) ->
|
Err _ ->
|
||||||
( { model | success = False, markDown = errorToString err }, Cmd.none )
|
( { model | success = False }, Cmd.none )
|
||||||
|
|
||||||
|
DataReceived (Err _) ->
|
||||||
|
( { model | success = False }, Cmd.none )
|
||||||
|
|
||||||
|
NoSuchPage ->
|
||||||
|
( { model | success = False }, Cmd.none )
|
||||||
|
|
||||||
|
|
||||||
errorToString : Http.Error -> String
|
errorToString : Http.Error -> String
|
||||||
@@ -214,16 +237,6 @@ errorToString error =
|
|||||||
errorMessage
|
errorMessage
|
||||||
|
|
||||||
|
|
||||||
textToHtml : String -> List (Html.Html msg)
|
|
||||||
textToHtml text =
|
|
||||||
case Html.Parser.run text of
|
|
||||||
Ok nodes ->
|
|
||||||
Html.Parser.Util.toVirtualDom nodes
|
|
||||||
|
|
||||||
Err _ ->
|
|
||||||
[]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- main : Program (String, String) Model Msg
|
-- main : Program (String, String) Model Msg
|
||||||
-- main =
|
-- main =
|
||||||
@@ -237,7 +250,7 @@ textToHtml text =
|
|||||||
-- [ class "foo-term-story section-content" ]
|
-- [ class "foo-term-story section-content" ]
|
||||||
-- [ input
|
-- [ input
|
||||||
-- [ placeholder "Enter URL to a markdown file"
|
-- [ placeholder "Enter URL to a markdown file"
|
||||||
-- , value model.markDownUrl
|
-- , value model.markdownUrl
|
||||||
-- , onInput StoreInput
|
-- , onInput StoreInput
|
||||||
-- ]
|
-- ]
|
||||||
-- []
|
-- []
|
||||||
@@ -247,3 +260,50 @@ textToHtml text =
|
|||||||
-- else
|
-- else
|
||||||
-- div [ class "foo-error" ] [ text model.markDown ]
|
-- div [ class "foo-error" ] [ text model.markDown ]
|
||||||
-- ]
|
-- ]
|
||||||
|
-- YAML Stuff
|
||||||
|
|
||||||
|
|
||||||
|
type alias YamlMeta =
|
||||||
|
{ title : String
|
||||||
|
, date : String
|
||||||
|
, description : Maybe String
|
||||||
|
, tags : List String
|
||||||
|
, category : String
|
||||||
|
, image : Maybe String
|
||||||
|
, modified : Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
splitMetaContent : String -> Result String Blog
|
||||||
|
splitMetaContent data =
|
||||||
|
let
|
||||||
|
headIndices : List Int
|
||||||
|
headIndices =
|
||||||
|
String.indices "---" data |> List.take 2
|
||||||
|
|
||||||
|
metadata =
|
||||||
|
String.slice ((Maybe.withDefault 0 <| List.head headIndices) + 3)
|
||||||
|
((Maybe.withDefault 0 <| List.head <| List.reverse headIndices) - 1)
|
||||||
|
data
|
||||||
|
|
||||||
|
content =
|
||||||
|
String.dropLeft ((Maybe.withDefault 0 <| List.head <| List.reverse headIndices) + 3) data
|
||||||
|
in
|
||||||
|
case Yaml.fromString metaDecoder metadata of
|
||||||
|
Ok meta ->
|
||||||
|
Ok { meta = meta, content = content }
|
||||||
|
|
||||||
|
Err _ ->
|
||||||
|
Err "YAML front matter parsing failed"
|
||||||
|
|
||||||
|
|
||||||
|
metaDecoder : Decoder YamlMeta
|
||||||
|
metaDecoder =
|
||||||
|
Yaml.map7 YamlMeta
|
||||||
|
(field "title" string)
|
||||||
|
(field "date" string)
|
||||||
|
(field "description" (Yaml.maybe string))
|
||||||
|
(field "tags" (list string))
|
||||||
|
(field "category" string)
|
||||||
|
(field "image" (Yaml.maybe string))
|
||||||
|
(field "modified" (Yaml.maybe string))
|
||||||
|
|||||||
+23
-8
@@ -149,12 +149,21 @@ update msg model =
|
|||||||
|
|
||||||
GotBlogMsg blogMsg ->
|
GotBlogMsg blogMsg ->
|
||||||
case model.page of
|
case model.page of
|
||||||
BlogPage blog ->
|
BlogPage blogModel ->
|
||||||
|
let
|
||||||
|
title =
|
||||||
|
case blogModel.blog of
|
||||||
|
Just blog ->
|
||||||
|
blog.meta.title
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
"Blog"
|
||||||
|
in
|
||||||
toBlog
|
toBlog
|
||||||
{ model
|
{ model
|
||||||
| title = blog.blog.title ++ " | " ++ model.title
|
| title = title ++ " | " ++ model.title
|
||||||
}
|
}
|
||||||
(Blog.update blogMsg blog)
|
(Blog.update blogMsg blogModel)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
( model, Cmd.none )
|
( model, Cmd.none )
|
||||||
@@ -219,9 +228,9 @@ init _ url key =
|
|||||||
type Route
|
type Route
|
||||||
= Splash
|
= Splash
|
||||||
| Blog
|
| Blog
|
||||||
|
| BlogPost String String (Maybe String)
|
||||||
| Terminal
|
| Terminal
|
||||||
| Static
|
| Static
|
||||||
| BlogPost String String
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -234,7 +243,7 @@ parser =
|
|||||||
[ Parser.map Splash Parser.top
|
[ Parser.map Splash Parser.top
|
||||||
, Parser.map Splash (s urlPrefix)
|
, Parser.map Splash (s urlPrefix)
|
||||||
, Parser.map Blog (s urlPrefix </> s "posts")
|
, Parser.map Blog (s urlPrefix </> s "posts")
|
||||||
, Parser.map BlogPost (s urlPrefix </> s "posts" </> Parser.string </> Parser.string)
|
, Parser.map BlogPost (s urlPrefix </> s "posts" </> Parser.string </> Parser.string </> Parser.fragment identity)
|
||||||
, Parser.map Static (s urlPrefix </> s "pages")
|
, Parser.map Static (s urlPrefix </> s "pages")
|
||||||
, Parser.map Terminal (s urlPrefix </> s "terminal")
|
, Parser.map Terminal (s urlPrefix </> s "terminal")
|
||||||
]
|
]
|
||||||
@@ -248,11 +257,17 @@ updateUrl model =
|
|||||||
|> toSplash model
|
|> toSplash model
|
||||||
|
|
||||||
Just Blog ->
|
Just Blog ->
|
||||||
Blog.init Nothing
|
Blog.init []
|
||||||
|> toBlog model
|
|> toBlog model
|
||||||
|
|
||||||
Just (BlogPost category slug) ->
|
Just (BlogPost category title fragment) ->
|
||||||
Blog.init (Just (category ++ "/" ++ slug))
|
case fragment of
|
||||||
|
Just something ->
|
||||||
|
Blog.init [ category, title, something ]
|
||||||
|
|> toBlog model
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
Blog.init [ category, title ]
|
||||||
|> toBlog model
|
|> toBlog model
|
||||||
|
|
||||||
Just Terminal ->
|
Just Terminal ->
|
||||||
|
|||||||
Reference in New Issue
Block a user