mirror of
https://github.com/avinal/avinal.github.io.git
synced 2026-07-03 23:30: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",
|
||||
"dependencies": {
|
||||
"direct": {
|
||||
"MaybeJustJames/yaml": "2.1.2",
|
||||
"elm/browser": "1.0.2",
|
||||
"elm/core": "1.0.5",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/http": "2.0.0",
|
||||
"elm/url": "1.0.0",
|
||||
"hecrj/html-parser": "2.4.0"
|
||||
"elm/parser": "1.1.0",
|
||||
"elm/url": "1.0.0"
|
||||
},
|
||||
"indirect": {
|
||||
"elm/bytes": "1.0.8",
|
||||
"elm/file": "1.0.5",
|
||||
"elm/json": "1.1.3",
|
||||
"elm/parser": "1.1.0",
|
||||
"elm/regex": "1.0.0",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.3",
|
||||
"rtfeldman/elm-hex": "1.0.0"
|
||||
@@ -27,4 +28,4 @@
|
||||
"direct": {},
|
||||
"indirect": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-21
@@ -16,9 +16,9 @@
|
||||
<div id="app"></div>
|
||||
|
||||
<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/clipboard.js/2.0.7/clipboard.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"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.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>
|
||||
@@ -73,25 +73,25 @@
|
||||
}
|
||||
})
|
||||
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>
|
||||
|
||||
|
||||
|
||||
+26
-2
@@ -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 =
|
||||
"website"
|
||||
"website"
|
||||
|
||||
|
||||
contentUrlPrefix : String
|
||||
contentUrlPrefix =
|
||||
contentBase ++ "/" ++ user ++ "/" ++ urlPrefix ++ "/main/content/"
|
||||
|
||||
+117
-57
@@ -3,10 +3,9 @@ port module Blog exposing (..)
|
||||
import Base exposing (urlPrefix)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (class, href, id, style)
|
||||
import Html.Parser
|
||||
import Html.Parser.Util
|
||||
import Http exposing (Error(..))
|
||||
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 =
|
||||
{ blog : Blog
|
||||
, markDownUrl : String
|
||||
, markDown : String
|
||||
{ blog : Maybe Blog
|
||||
, markdownUrl : String
|
||||
, success : Bool
|
||||
, fragment : String
|
||||
}
|
||||
|
||||
|
||||
@@ -26,13 +25,17 @@ type alias Model =
|
||||
|
||||
|
||||
type alias Blog =
|
||||
{ title : String
|
||||
, url : String
|
||||
, description : String
|
||||
{ meta : YamlMeta
|
||||
, 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-console foo-terminal foo-active" ]
|
||||
[ div [ class "main-wrapper" ]
|
||||
[ viewToc model.success
|
||||
, main_ [ class "main-content", id "content" ]
|
||||
[ main_ [ class "main-content", id "content" ]
|
||||
[ viewArticle model.success ]
|
||||
]
|
||||
]
|
||||
@@ -61,17 +63,16 @@ viewToc show =
|
||||
if show then
|
||||
div
|
||||
[ class "toc"
|
||||
, style "display"
|
||||
(if show then
|
||||
"block"
|
||||
|
||||
else
|
||||
"none"
|
||||
)
|
||||
]
|
||||
[ aside [ class "document-toc-container" ]
|
||||
[ 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
|
||||
[ class "document-toc-list", id "toc-entries" ]
|
||||
[]
|
||||
@@ -125,17 +126,43 @@ viewMetadata show =
|
||||
type Msg
|
||||
= GetMarkdown
|
||||
| DataReceived (Result Http.Error String)
|
||||
| NoSuchPage
|
||||
|
||||
|
||||
init : Maybe String -> ( Model, Cmd Msg )
|
||||
init slug =
|
||||
( { blog = initBlog
|
||||
, markDownUrl = finalUrl slug
|
||||
, markDown = ""
|
||||
, success = False
|
||||
}
|
||||
, getMarkdown <| finalUrl slug
|
||||
)
|
||||
init : List String -> ( Model, Cmd Msg )
|
||||
init pathList =
|
||||
case pathList of
|
||||
[ category, slug, fragment ] ->
|
||||
( { initialModel
|
||||
| markdownUrl = Base.contentUrlPrefix ++ "posts/" ++ category ++ "/" ++ slug ++ ".md"
|
||||
, fragment = fragment
|
||||
}
|
||||
, 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
|
||||
@@ -164,29 +191,25 @@ finalUrl slug =
|
||||
++ ".md"
|
||||
|
||||
|
||||
initBlog : Blog
|
||||
initBlog =
|
||||
{ title = ""
|
||||
, url = ""
|
||||
, description = ""
|
||||
, content = ""
|
||||
, category = ""
|
||||
, tags = []
|
||||
, date = ""
|
||||
}
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
GetMarkdown ->
|
||||
( model, Http.get { url = model.markDownUrl, expect = Http.expectString DataReceived } )
|
||||
( model, Http.get { url = model.markdownUrl, expect = Http.expectString DataReceived } )
|
||||
|
||||
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) ->
|
||||
( { model | success = False, markDown = errorToString err }, Cmd.none )
|
||||
Err _ ->
|
||||
( { model | success = False }, Cmd.none )
|
||||
|
||||
DataReceived (Err _) ->
|
||||
( { model | success = False }, Cmd.none )
|
||||
|
||||
NoSuchPage ->
|
||||
( { model | success = False }, Cmd.none )
|
||||
|
||||
|
||||
errorToString : Http.Error -> String
|
||||
@@ -214,16 +237,6 @@ errorToString error =
|
||||
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 =
|
||||
@@ -237,7 +250,7 @@ textToHtml text =
|
||||
-- [ class "foo-term-story section-content" ]
|
||||
-- [ input
|
||||
-- [ placeholder "Enter URL to a markdown file"
|
||||
-- , value model.markDownUrl
|
||||
-- , value model.markdownUrl
|
||||
-- , onInput StoreInput
|
||||
-- ]
|
||||
-- []
|
||||
@@ -247,3 +260,50 @@ textToHtml text =
|
||||
-- else
|
||||
-- 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))
|
||||
|
||||
+24
-9
@@ -149,12 +149,21 @@ update msg model =
|
||||
|
||||
GotBlogMsg blogMsg ->
|
||||
case model.page of
|
||||
BlogPage blog ->
|
||||
BlogPage blogModel ->
|
||||
let
|
||||
title =
|
||||
case blogModel.blog of
|
||||
Just blog ->
|
||||
blog.meta.title
|
||||
|
||||
Nothing ->
|
||||
"Blog"
|
||||
in
|
||||
toBlog
|
||||
{ model
|
||||
| title = blog.blog.title ++ " | " ++ model.title
|
||||
| title = title ++ " | " ++ model.title
|
||||
}
|
||||
(Blog.update blogMsg blog)
|
||||
(Blog.update blogMsg blogModel)
|
||||
|
||||
_ ->
|
||||
( model, Cmd.none )
|
||||
@@ -219,9 +228,9 @@ init _ url key =
|
||||
type Route
|
||||
= Splash
|
||||
| Blog
|
||||
| BlogPost String String (Maybe String)
|
||||
| Terminal
|
||||
| Static
|
||||
| BlogPost String String
|
||||
|
||||
|
||||
|
||||
@@ -234,7 +243,7 @@ parser =
|
||||
[ Parser.map Splash Parser.top
|
||||
, Parser.map Splash (s urlPrefix)
|
||||
, 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 Terminal (s urlPrefix </> s "terminal")
|
||||
]
|
||||
@@ -248,12 +257,18 @@ updateUrl model =
|
||||
|> toSplash model
|
||||
|
||||
Just Blog ->
|
||||
Blog.init Nothing
|
||||
Blog.init []
|
||||
|> toBlog model
|
||||
|
||||
Just (BlogPost category slug) ->
|
||||
Blog.init (Just (category ++ "/" ++ slug))
|
||||
|> toBlog model
|
||||
Just (BlogPost category title fragment) ->
|
||||
case fragment of
|
||||
Just something ->
|
||||
Blog.init [ category, title, something ]
|
||||
|> toBlog model
|
||||
|
||||
Nothing ->
|
||||
Blog.init [ category, title ]
|
||||
|> toBlog model
|
||||
|
||||
Just Terminal ->
|
||||
Terminal.init ()
|
||||
|
||||
Reference in New Issue
Block a user