mirror of
https://github.com/avinal/avinal.github.io.git
synced 2026-07-03 23:30:09 +05:30
remove blogs from elm, switch to hugo
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com> rh-pre-commit.version: 2.2.0 rh-pre-commit.check-secrets: ENABLED
This commit is contained in:
@@ -1,86 +0,0 @@
|
|||||||
module Layouts.Blog exposing (Model, Msg, Props, layout)
|
|
||||||
|
|
||||||
import Components.Footer exposing (footerLinksToSide)
|
|
||||||
import Effect exposing (Effect)
|
|
||||||
import Html
|
|
||||||
import Html.Attributes exposing (class, id)
|
|
||||||
import Layout exposing (Layout)
|
|
||||||
import Route exposing (Route)
|
|
||||||
import Shared
|
|
||||||
import Utils.Constants exposing (..)
|
|
||||||
import View exposing (View)
|
|
||||||
|
|
||||||
|
|
||||||
type alias Props =
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
layout : Props -> Shared.Model -> Route () -> Layout () Model Msg contentMsg
|
|
||||||
layout props shared route =
|
|
||||||
Layout.new
|
|
||||||
{ init = init
|
|
||||||
, update = update
|
|
||||||
, view = view
|
|
||||||
, subscriptions = subscriptions
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- MODEL
|
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
init : () -> ( Model, Effect Msg )
|
|
||||||
init _ =
|
|
||||||
( {}
|
|
||||||
, Effect.none
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- UPDATE
|
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
|
||||||
= ReplaceMe
|
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Effect Msg )
|
|
||||||
update msg model =
|
|
||||||
case msg of
|
|
||||||
ReplaceMe ->
|
|
||||||
( model
|
|
||||||
, Effect.none
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
subscriptions : Model -> Sub Msg
|
|
||||||
subscriptions model =
|
|
||||||
Sub.none
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- VIEW
|
|
||||||
|
|
||||||
blogTheme : String
|
|
||||||
blogTheme =
|
|
||||||
"prose prose-invert mx-auto lg:prose-lg prose-a:decoration-cyan-500 hover:prose-a:decoration-pink-500"
|
|
||||||
|
|
||||||
|
|
||||||
view : { toContentMsg : Msg -> contentMsg, content : View contentMsg, model : Model } -> View contentMsg
|
|
||||||
view { toContentMsg, model, content } =
|
|
||||||
{ title = content.title
|
|
||||||
, body =
|
|
||||||
[ Html.div [ class "min-h-screen flex flex-col justify-center relative overflow-hidden" ]
|
|
||||||
[ Html.div [ class "relative w-full bg-neutral md:max-w-3xl md:mx-auto lg:max-w-4xl lg:pb-28" ]
|
|
||||||
[ Html.article [ class blogTheme ]
|
|
||||||
content.body
|
|
||||||
, Html.div [ id "remark42", class "md:px-4 mb-16" ] []
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, footerLinksToSide
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
module Pages.Posts exposing (Model, Msg, page)
|
|
||||||
|
|
||||||
import Components.Footer exposing (footerLinksToSide)
|
|
||||||
import Effect exposing (Effect)
|
|
||||||
import Html exposing (Html)
|
|
||||||
import Html.Attributes exposing (alt, class, datetime, href, src, target)
|
|
||||||
import Http
|
|
||||||
import Json.Decode as Json
|
|
||||||
import Page exposing (Page)
|
|
||||||
import Route exposing (Route)
|
|
||||||
import Shared
|
|
||||||
import Url exposing (Protocol(..))
|
|
||||||
import Utils.Constants exposing (..)
|
|
||||||
import Utils.Utils as UU
|
|
||||||
import View exposing (View)
|
|
||||||
|
|
||||||
|
|
||||||
page : Shared.Model -> Route () -> Page Model Msg
|
|
||||||
page _ _ =
|
|
||||||
Page.new
|
|
||||||
{ init = init
|
|
||||||
, update = update
|
|
||||||
, subscriptions = subscriptions
|
|
||||||
, view = view
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- INIT
|
|
||||||
|
|
||||||
|
|
||||||
type alias JsonMeta =
|
|
||||||
{ title : String
|
|
||||||
, date : String
|
|
||||||
, description : String
|
|
||||||
, category : String
|
|
||||||
, slug : String
|
|
||||||
, image : String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
|
||||||
{ error : Maybe String
|
|
||||||
, blogList : Maybe (List JsonMeta)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
init : () -> ( Model, Effect Msg )
|
|
||||||
init () =
|
|
||||||
let
|
|
||||||
cmd : Cmd Msg
|
|
||||||
cmd =
|
|
||||||
Http.get
|
|
||||||
{ url = "/content/posts/posts.json"
|
|
||||||
, expect = Http.expectJson BloglistReceived (Json.list jsonMetaDecoder)
|
|
||||||
}
|
|
||||||
in
|
|
||||||
( { error = Nothing
|
|
||||||
, blogList = Nothing
|
|
||||||
}
|
|
||||||
, Effect.sendCmd cmd
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- UPDATE
|
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
|
||||||
= BloglistReceived (Result Http.Error (List JsonMeta))
|
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Effect Msg )
|
|
||||||
update msg model =
|
|
||||||
case msg of
|
|
||||||
BloglistReceived (Ok data) ->
|
|
||||||
( { model | blogList = Just data }
|
|
||||||
, Effect.none
|
|
||||||
)
|
|
||||||
|
|
||||||
BloglistReceived (Err err) ->
|
|
||||||
( { model | error = Just (UU.errorToString err) }, Effect.none )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- SUBSCRIPTIONS
|
|
||||||
|
|
||||||
|
|
||||||
subscriptions : Model -> Sub Msg
|
|
||||||
subscriptions _ =
|
|
||||||
Sub.none
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- VIEW
|
|
||||||
|
|
||||||
|
|
||||||
view : Model -> View Msg
|
|
||||||
view model =
|
|
||||||
let
|
|
||||||
maincard : List JsonMeta -> Html msg
|
|
||||||
maincard bloglist =
|
|
||||||
case bloglist of
|
|
||||||
first :: rest ->
|
|
||||||
Html.div [ class "max-w-6xl p-6 mx-auto space-y-6 sm:space-y-12 mb-16" ]
|
|
||||||
[ Html.div [ class "block max-w-sm gap-3 mx-auto sm:max-w-full group hover:no-underline focus:no-underline lg:grid lg:grid-cols-12 bg-neutral-900" ]
|
|
||||||
[ Html.a [ class "lg:col-span-7", href <| "/posts/" ++ first.category ++ "/" ++ first.slug ] [ Html.img [ class "object-cover w-full h-64 rounded sm:h-96 lg:col-span-7", src first.image, alt first.title ] [] ]
|
|
||||||
, Html.div [ class "p-6 space-y-2 lg:col-span-5" ]
|
|
||||||
[ Html.a [ href <| "/posts/" ++ first.category ++ "/" ++ first.slug ]
|
|
||||||
[ Html.h3 [ class "text-2xl font-semibold sm:text-4xl group-hover:underline group-focus:underline" ]
|
|
||||||
[ Html.text first.title ]
|
|
||||||
, Html.time [ class "text-gray-400", datetime first.date ] [ Html.text <| UU.getFormattedDate first.date False ]
|
|
||||||
, Html.p [] [ Html.text <| String.left 200 first.description ]
|
|
||||||
]
|
|
||||||
, Html.a [ href <| "/posts/" ++ first.category, target "_blank" ] [ UU.categoryNtags first.category [] ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, Html.div [ class "grid justify-center grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3" ] <| List.map card rest
|
|
||||||
]
|
|
||||||
|
|
||||||
[] ->
|
|
||||||
Html.div [] []
|
|
||||||
|
|
||||||
card : JsonMeta -> Html msg
|
|
||||||
card blog =
|
|
||||||
Html.div [ class "max-w-sm mx-auto group hover:no-underline focus:no-underline bg-neutral-900", href ("/posts/" ++ blog.category ++ "/" ++ blog.slug) ]
|
|
||||||
[ Html.a [ href <| "/posts/" ++ blog.category ++ "/" ++ blog.slug ] [ Html.img [ class "object-cover w-full h-44 rounded", src blog.image, alt blog.title ] [] ]
|
|
||||||
, Html.div [ class "p-6 space-y-2" ]
|
|
||||||
[ Html.a [ href <| "/posts/" ++ blog.category ++ "/" ++ blog.slug ]
|
|
||||||
[ Html.h3 [ class "text-2xl font-semibold group-hover:underline group-focus:underline" ] [ Html.text blog.title ]
|
|
||||||
, Html.time [ class " text-gray-400", datetime blog.date ] [ Html.text <| UU.getFormattedDate blog.date False ]
|
|
||||||
, Html.p [] [ Html.text <| String.left 200 blog.description ]
|
|
||||||
]
|
|
||||||
, Html.a [ href <| "/posts/" ++ blog.category, target "_blank" ] [ UU.categoryNtags blog.category [] ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
in
|
|
||||||
case model.blogList of
|
|
||||||
Just blogList ->
|
|
||||||
{ title = "Blog"
|
|
||||||
, body =
|
|
||||||
[ Html.section [ class "text-gray-100" ]
|
|
||||||
[ Html.h1 [ class "text-5xl font-bold mb-6 mt-12 text-center text-white" ] [ Html.text <| "Welcome to my blog" ]
|
|
||||||
, maincard blogList
|
|
||||||
, footerLinksToSide
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
{ title = "Something went wrong"
|
|
||||||
, body = [ Html.text <| Maybe.withDefault "" model.error ]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- UTILS
|
|
||||||
|
|
||||||
|
|
||||||
jsonMetaDecoder : Json.Decoder JsonMeta
|
|
||||||
jsonMetaDecoder =
|
|
||||||
Json.map6 JsonMeta
|
|
||||||
(Json.field "title" Json.string)
|
|
||||||
(Json.field "date" Json.string)
|
|
||||||
(Json.field "description" Json.string)
|
|
||||||
(Json.field "category" Json.string)
|
|
||||||
(Json.field "slug" Json.string)
|
|
||||||
(Json.field "image" Json.string)
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
module Pages.Posts.Category_ exposing (Model, Msg, page)
|
|
||||||
|
|
||||||
import Components.Footer exposing (footerLinksToSide)
|
|
||||||
import Effect exposing (Effect)
|
|
||||||
import Html exposing (Html)
|
|
||||||
import Html.Attributes exposing (alt, class, datetime, href, src)
|
|
||||||
import Http
|
|
||||||
import Json.Decode as Json
|
|
||||||
import Page exposing (Page)
|
|
||||||
import Route exposing (Route)
|
|
||||||
import Shared
|
|
||||||
import Utils.Constants exposing (..)
|
|
||||||
import Utils.Utils as UU
|
|
||||||
import View exposing (View)
|
|
||||||
|
|
||||||
|
|
||||||
page : Shared.Model -> Route { category : String } -> Page Model Msg
|
|
||||||
page _ route =
|
|
||||||
Page.new
|
|
||||||
{ init = init route
|
|
||||||
, update = update
|
|
||||||
, subscriptions = subscriptions
|
|
||||||
, view = view
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- INIT
|
|
||||||
|
|
||||||
|
|
||||||
type alias JsonMeta =
|
|
||||||
{ title : String
|
|
||||||
, date : String
|
|
||||||
, description : String
|
|
||||||
, category : String
|
|
||||||
, slug : String
|
|
||||||
, image : String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
|
||||||
{ error : Maybe String
|
|
||||||
, blogList : Maybe (List JsonMeta)
|
|
||||||
, category : String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
init : Route { category : String } -> () -> ( Model, Effect Msg )
|
|
||||||
init route () =
|
|
||||||
let
|
|
||||||
cmd : Cmd Msg
|
|
||||||
cmd =
|
|
||||||
Http.get
|
|
||||||
{ url = "/content/posts/posts.json"
|
|
||||||
, expect = Http.expectJson BloglistReceived (Json.list jsonMetaDecoder)
|
|
||||||
}
|
|
||||||
in
|
|
||||||
( { error = Nothing
|
|
||||||
, blogList = Nothing
|
|
||||||
, category = route.params.category
|
|
||||||
}
|
|
||||||
, Effect.sendCmd cmd
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- UPDATE
|
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
|
||||||
= BloglistReceived (Result Http.Error (List JsonMeta))
|
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Effect Msg )
|
|
||||||
update msg model =
|
|
||||||
case msg of
|
|
||||||
BloglistReceived (Ok data) ->
|
|
||||||
( { model | blogList = Just data }
|
|
||||||
, Effect.none
|
|
||||||
)
|
|
||||||
|
|
||||||
BloglistReceived (Err err) ->
|
|
||||||
( { model | error = Just (UU.errorToString err) }, Effect.none )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- SUBSCRIPTIONS
|
|
||||||
|
|
||||||
|
|
||||||
subscriptions : Model -> Sub Msg
|
|
||||||
subscriptions _ =
|
|
||||||
Sub.none
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- VIEW
|
|
||||||
|
|
||||||
|
|
||||||
view : Model -> View Msg
|
|
||||||
view model =
|
|
||||||
let
|
|
||||||
card : JsonMeta -> Html msg
|
|
||||||
card blog =
|
|
||||||
Html.a [ class "flex flex-wrap mb-6 ", href <| "/posts/" ++ blog.category ++ "/" ++ blog.slug ]
|
|
||||||
[ Html.div [ class "grow-0 shrink-0 basis-auto w-full md:w-3/12 md:mb-0 ml-auto" ]
|
|
||||||
[ Html.div [ class "overflow-hidden relative bg-no-repeat bg-cover ripple" ]
|
|
||||||
[ Html.img [ src blog.image, class "w-full h-44 object-cover rounded", alt blog.title ] []
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, Html.div [ class "grow-0 shrink-0 basis-auto w-full md:w-9/12 xl:w-7/12 p-3 md:mb-0 mr-auto bg-neutral-900" ]
|
|
||||||
[ Html.h5 [ class "text-2xl font-bold mb-2" ] [ Html.text blog.title ]
|
|
||||||
, Html.time [ class "text-gray-400 text-sm", datetime blog.date ] [ Html.text <| UU.getFormattedDate blog.date True ]
|
|
||||||
, Html.p [ class "text-gray-500 mt-4 text-md" ] [ Html.text <| String.left 200 blog.description ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
in
|
|
||||||
case model.blogList of
|
|
||||||
Just blogList ->
|
|
||||||
let
|
|
||||||
filteredList =
|
|
||||||
filterBlogListByCategory blogList model.category
|
|
||||||
in
|
|
||||||
case filteredList of
|
|
||||||
[] ->
|
|
||||||
{ title = "No posts in this category"
|
|
||||||
, body = []
|
|
||||||
}
|
|
||||||
|
|
||||||
clist ->
|
|
||||||
{ title = "Posts in " ++ model.category ++ " category"
|
|
||||||
, body =
|
|
||||||
[ Html.div []
|
|
||||||
[ Html.section [ class "mb-32 text-gray-200 text-center md:text-left" ] <|
|
|
||||||
Html.h1 [ class "text-5xl font-bold mb-12 mt-12 text-center text-white" ] [ Html.text "Posts in ", Html.i [ class "text-pink-600" ] [ Html.text model.category ], Html.text " category" ]
|
|
||||||
:: List.map card clist
|
|
||||||
, footerLinksToSide
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
{ title = "There is no such category"
|
|
||||||
, body = []
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- UTILS
|
|
||||||
|
|
||||||
|
|
||||||
jsonMetaDecoder : Json.Decoder JsonMeta
|
|
||||||
jsonMetaDecoder =
|
|
||||||
Json.map6 JsonMeta
|
|
||||||
(Json.field "title" Json.string)
|
|
||||||
(Json.field "date" Json.string)
|
|
||||||
(Json.field "description" Json.string)
|
|
||||||
(Json.field "category" Json.string)
|
|
||||||
(Json.field "slug" Json.string)
|
|
||||||
(Json.field "image" Json.string)
|
|
||||||
|
|
||||||
|
|
||||||
filterBlogListByCategory : List JsonMeta -> String -> List JsonMeta
|
|
||||||
filterBlogListByCategory blogList category =
|
|
||||||
List.filter (\meta -> meta.category == category) blogList
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
module Pages.Posts.Category_.Post_ exposing (Model, Msg, page)
|
|
||||||
|
|
||||||
import Effect exposing (Effect)
|
|
||||||
import Html exposing (Html)
|
|
||||||
import Html.Attributes exposing (alt, class, datetime, href, src, title)
|
|
||||||
import Http
|
|
||||||
import Layouts
|
|
||||||
import Page exposing (Page)
|
|
||||||
import Route exposing (Route)
|
|
||||||
import Shared
|
|
||||||
import String exposing (words)
|
|
||||||
import Url exposing (Protocol(..))
|
|
||||||
import Utils.Utils as UU
|
|
||||||
import View exposing (View)
|
|
||||||
import Yaml.Decode as Yaml
|
|
||||||
|
|
||||||
|
|
||||||
page : Shared.Model -> Route { category : String, post : String } -> Page Model Msg
|
|
||||||
page _ route =
|
|
||||||
Page.new
|
|
||||||
{ init = init route
|
|
||||||
, update = update
|
|
||||||
, subscriptions = subscriptions
|
|
||||||
, view = view
|
|
||||||
}
|
|
||||||
|> Page.withLayout layout
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- LAYOUT
|
|
||||||
|
|
||||||
|
|
||||||
layout : Model -> Layouts.Layout Msg
|
|
||||||
layout _ =
|
|
||||||
Layouts.Blog
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- INIT
|
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
|
||||||
{ blog : Maybe Blog
|
|
||||||
, requestUrl : String
|
|
||||||
, success : Bool
|
|
||||||
, fragment : String
|
|
||||||
, error : Maybe String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type alias Blog =
|
|
||||||
{ meta : YamlMeta
|
|
||||||
, content : String
|
|
||||||
, words : Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
init : Route { category : String, post : String } -> () -> ( Model, Effect Msg )
|
|
||||||
init route () =
|
|
||||||
let
|
|
||||||
requestUrl =
|
|
||||||
UU.contentUrl
|
|
||||||
{ category = route.params.category
|
|
||||||
, post = route.params.post
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd : Cmd Msg
|
|
||||||
cmd =
|
|
||||||
Http.get
|
|
||||||
{ url = requestUrl
|
|
||||||
, expect = Http.expectString RawMarkdownReceived
|
|
||||||
}
|
|
||||||
in
|
|
||||||
( { blog = Nothing
|
|
||||||
, requestUrl = requestUrl
|
|
||||||
, success = False
|
|
||||||
, fragment = Maybe.withDefault "" route.hash
|
|
||||||
, error = Nothing
|
|
||||||
}
|
|
||||||
, Effect.sendCmd cmd
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- UPDATE
|
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
|
||||||
= RawMarkdownReceived (Result Http.Error String)
|
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Effect Msg )
|
|
||||||
update msg model =
|
|
||||||
case msg of
|
|
||||||
RawMarkdownReceived (Ok data) ->
|
|
||||||
case splitMetaContent data of
|
|
||||||
Ok blog ->
|
|
||||||
( { model | blog = Just blog, success = True }, Effect.none )
|
|
||||||
|
|
||||||
Err err ->
|
|
||||||
( { model | success = False, error = Just err }, Effect.none )
|
|
||||||
|
|
||||||
RawMarkdownReceived (Err err) ->
|
|
||||||
( { model | success = False, error = Just (UU.errorToString err) }, Effect.none )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- SUBSCRIPTIONS
|
|
||||||
|
|
||||||
|
|
||||||
subscriptions : Model -> Sub Msg
|
|
||||||
subscriptions _ =
|
|
||||||
Sub.none
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- VIEW
|
|
||||||
|
|
||||||
|
|
||||||
view : Model -> View Msg
|
|
||||||
view model =
|
|
||||||
case model.blog of
|
|
||||||
Just blog ->
|
|
||||||
{ title = blog.meta.title ++ " | Blog"
|
|
||||||
, body =
|
|
||||||
[ Html.div [ class "bg-neutral-900 md:-mx-8 lg:-mx-16 px-8 py-1" ]
|
|
||||||
[ Html.header [ class "relative" ]
|
|
||||||
[ Html.img
|
|
||||||
[ class "object-cover w-full h-60 sm:h-96 brightness-50 "
|
|
||||||
, src blog.meta.image
|
|
||||||
, alt blog.meta.title
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
, Html.h1 [ class "absolute top-3/4 left-1/2 -translate-x-1/2 -translate-y-1/2 text-center w-full" ]
|
|
||||||
[ Html.text blog.meta.title ]
|
|
||||||
]
|
|
||||||
, Html.span [ class "text-base font-light font-sans oldstyle-nums" ]
|
|
||||||
[ Html.a [ href "/pages/about-me", class "font-bold no-underline hover:text-pink-500" ]
|
|
||||||
[ Html.text "Avinal Kumar" ]
|
|
||||||
, Html.text " | "
|
|
||||||
, Html.time [ datetime blog.meta.date ] [ Html.text <| UU.getFormattedDate blog.meta.date False ]
|
|
||||||
, Html.text <|
|
|
||||||
" | "
|
|
||||||
++ String.fromInt blog.words
|
|
||||||
++ " words | ~"
|
|
||||||
++ String.fromInt (blog.words // 200)
|
|
||||||
++ " mins read"
|
|
||||||
]
|
|
||||||
, Html.span [ class "text-base font-light float-right" ]
|
|
||||||
[ Html.a
|
|
||||||
[ String.dropLeft 8 model.requestUrl
|
|
||||||
|> String.dropRight 3
|
|
||||||
|> String.append "https://null.avinal.space"
|
|
||||||
|> href
|
|
||||||
, class "hover:text-pink-500"
|
|
||||||
]
|
|
||||||
[ Html.abbr [ class "fa-solid fa-terminal no-underline", title "See a basic version of this page." ] [] ]
|
|
||||||
]
|
|
||||||
, articleNode blog.content model.fragment blog.meta.title blog.meta.description
|
|
||||||
]
|
|
||||||
, UU.categoryNtags blog.meta.category blog.meta.tags
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
{ title = "Avinal Kumar | Something went wrong"
|
|
||||||
, body =
|
|
||||||
[ case model.error of
|
|
||||||
Just err ->
|
|
||||||
UU.errorView err
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
Html.div [ class "flex items-center justify-center flex-col object-cover object-center " ]
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
articleNode : String -> String -> String -> String -> Html Msg
|
|
||||||
articleNode data fragment title description =
|
|
||||||
Html.node "rendered-md"
|
|
||||||
[ Html.Attributes.attribute "markdowndata" data
|
|
||||||
, Html.Attributes.attribute "fragment" fragment
|
|
||||||
, Html.Attributes.attribute "title" title
|
|
||||||
, Html.Attributes.attribute "description" description
|
|
||||||
, class "line-numbers"
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- UTILITIES
|
|
||||||
|
|
||||||
|
|
||||||
type alias YamlMeta =
|
|
||||||
{ title : String
|
|
||||||
, date : String
|
|
||||||
, description : String
|
|
||||||
, tags : List String
|
|
||||||
, category : String
|
|
||||||
, image : 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, words = List.length <| words content }
|
|
||||||
|
|
||||||
Err err ->
|
|
||||||
Err ("YAML front matter parsing failed: " ++ Yaml.errorToString err)
|
|
||||||
|
|
||||||
|
|
||||||
metaDecoder : Yaml.Decoder YamlMeta
|
|
||||||
metaDecoder =
|
|
||||||
Yaml.map7 YamlMeta
|
|
||||||
(Yaml.field "title" Yaml.string)
|
|
||||||
(Yaml.field "date" Yaml.string)
|
|
||||||
(Yaml.field "description" Yaml.string)
|
|
||||||
(Yaml.field "tags" (Yaml.list Yaml.string))
|
|
||||||
(Yaml.field "category" Yaml.string)
|
|
||||||
(Yaml.field "image" Yaml.string)
|
|
||||||
(Yaml.maybe (Yaml.field "modified" Yaml.string))
|
|
||||||
+1
-2
@@ -1,4 +1,3 @@
|
|||||||
import "./web-components/MarkedRender.js";
|
|
||||||
import "./web-components/Calcom.js";
|
import "./web-components/Calcom.js";
|
||||||
|
|
||||||
export const onReady = ({ app, env }) => {};
|
export const onReady = ({ app, env }) => { };
|
||||||
|
|||||||
@@ -1,144 +0,0 @@
|
|||||||
import { marked } from "marked";
|
|
||||||
import { markedHighlight } from "marked-highlight";
|
|
||||||
import Prism from "prismjs";
|
|
||||||
|
|
||||||
import "./Prism";
|
|
||||||
|
|
||||||
customElements.define(
|
|
||||||
"rendered-md",
|
|
||||||
class extends HTMLElement {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.lead = 0; // Moved lead here
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
this.runMarked();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateMeta(title, description) {
|
|
||||||
const metaInfo = {
|
|
||||||
'meta[name="title"]': `${title} | Avinal Kumar | Personal Website`,
|
|
||||||
'meta[name="description"]': description,
|
|
||||||
'meta[property="og:title"]': `${title} | Avinal Kumar | Personal Website`,
|
|
||||||
'meta[property="og:description"]': description,
|
|
||||||
'meta[property="og:url"]': window.location,
|
|
||||||
'meta[property="twitter:title"]': `${title} | Avinal Kumar | Personal Website`,
|
|
||||||
'meta[property="twitter:description"]': description,
|
|
||||||
'meta[property="twitter:url"]': window.location,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const [selector, content] of Object.entries(metaInfo)) {
|
|
||||||
const element = document.querySelector(selector);
|
|
||||||
if (element) {
|
|
||||||
element.setAttribute("content", content);
|
|
||||||
} else {
|
|
||||||
console.warn(`Element ${selector} not found`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addComments() {
|
|
||||||
window.remark_config = {
|
|
||||||
host: "https://remark42.avinal.space",
|
|
||||||
site_id: "remark",
|
|
||||||
theme: "dark",
|
|
||||||
show_rss_subscription: false,
|
|
||||||
no_footer: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
!(function (e, n) {
|
|
||||||
for (var o = 0; o < e.length; o++) {
|
|
||||||
var r = n.createElement("script"),
|
|
||||||
c = ".js",
|
|
||||||
d = n.head || n.body;
|
|
||||||
"noModule" in r
|
|
||||||
? ((r.type = "module"), (c = ".mjs"))
|
|
||||||
: (r.async = !0),
|
|
||||||
(r.defer = !0),
|
|
||||||
(r.src = remark_config.host + "/web/" + e[o] + c),
|
|
||||||
d.appendChild(r);
|
|
||||||
}
|
|
||||||
})(remark_config.components || ["embed"], document);
|
|
||||||
}
|
|
||||||
|
|
||||||
runMarked() {
|
|
||||||
const {
|
|
||||||
markdowndata: data,
|
|
||||||
fragment,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
} = this.attributes;
|
|
||||||
this.updateMeta(title.value, description.value);
|
|
||||||
|
|
||||||
const renderer = new marked.Renderer();
|
|
||||||
|
|
||||||
renderer.heading = (text, level) => {
|
|
||||||
const escapedText = text
|
|
||||||
.trim()
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/[^\w]+/g, "-");
|
|
||||||
|
|
||||||
return `<h${level} id="${escapedText}">
|
|
||||||
${text}
|
|
||||||
<a title="Permalink to ${text}" href="#${escapedText}">
|
|
||||||
#
|
|
||||||
</a>
|
|
||||||
</h${level}>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
renderer.paragraph = (text) => {
|
|
||||||
this.lead++;
|
|
||||||
return this.lead === 1
|
|
||||||
? `<p class="lead">${text}</p>`
|
|
||||||
: `<p>${text}</p>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
renderer.image = (href, title, text) => {
|
|
||||||
let pos = text.search(":");
|
|
||||||
let direction = text.substr(pos + 1);
|
|
||||||
text = text.substr(0, pos);
|
|
||||||
let put = "max-w-xs ";
|
|
||||||
switch (direction) {
|
|
||||||
case "right":
|
|
||||||
put += "float-right ";
|
|
||||||
break;
|
|
||||||
case "left":
|
|
||||||
put += "float-left ";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
put = "float-none ";
|
|
||||||
}
|
|
||||||
return `<img class="${put} grow-0 shrink-0 basis-auto w-full px-3" src=${href} alt="${text}">`;
|
|
||||||
};
|
|
||||||
|
|
||||||
marked.setOptions({
|
|
||||||
renderer: renderer,
|
|
||||||
});
|
|
||||||
|
|
||||||
marked.use(
|
|
||||||
markedHighlight({
|
|
||||||
highlight(code, lang) {
|
|
||||||
const grammer = Prism.languages[lang];
|
|
||||||
if (!grammer) {
|
|
||||||
console.warn(`Unable to find prism highlight for '${lang}'`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return Prism.highlight(code, grammer, lang);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
this.innerHTML = marked(data.value);
|
|
||||||
this.addComments();
|
|
||||||
|
|
||||||
if (fragment && fragment.value) {
|
|
||||||
window.location = `#${fragment.value}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static get observedAttributes() {
|
|
||||||
return ["markdowndata", "fragment", "title", "description"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
// Load Plugins
|
|
||||||
|
|
||||||
// import 'prismjs/plugins/toolbar/prism-toolbar';
|
|
||||||
// import "prismjs/plugins/line-numbers/prism-line-numbers";
|
|
||||||
// import "prismjs/plugins/line-numbers/prism-line-numbers.css";
|
|
||||||
// import "prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard";
|
|
||||||
|
|
||||||
// load languages
|
|
||||||
import "prismjs/components/prism-bash";
|
|
||||||
import "prismjs/components/prism-markup";
|
|
||||||
import "prismjs/components/prism-css";
|
|
||||||
import "prismjs/components/prism-clike";
|
|
||||||
import "prismjs/components/prism-javascript";
|
|
||||||
import "prismjs/components/prism-bash";
|
|
||||||
import "prismjs/components/prism-basic";
|
|
||||||
import "prismjs/components/prism-brainfuck";
|
|
||||||
import "prismjs/components/prism-c";
|
|
||||||
import "prismjs/components/prism-cpp";
|
|
||||||
import "prismjs/components/prism-cmake";
|
|
||||||
import "prismjs/components/prism-diff";
|
|
||||||
import "prismjs/components/prism-docker";
|
|
||||||
import "prismjs/components/prism-elm";
|
|
||||||
import "prismjs/components/prism-git";
|
|
||||||
import "prismjs/components/prism-go";
|
|
||||||
import "prismjs/components/prism-go-module";
|
|
||||||
import "prismjs/components/prism-graphql";
|
|
||||||
import "prismjs/components/prism-haskell";
|
|
||||||
import "prismjs/components/prism-http";
|
|
||||||
import "prismjs/components/prism-java";
|
|
||||||
import "prismjs/components/prism-json";
|
|
||||||
import "prismjs/components/prism-json5";
|
|
||||||
import "prismjs/components/prism-jsonp";
|
|
||||||
import "prismjs/components/prism-makefile";
|
|
||||||
import "prismjs/components/prism-markdown";
|
|
||||||
import "prismjs/components/prism-matlab";
|
|
||||||
import "prismjs/components/prism-mermaid";
|
|
||||||
import "prismjs/components/prism-powershell";
|
|
||||||
import "prismjs/components/prism-protobuf";
|
|
||||||
import "prismjs/components/prism-python";
|
|
||||||
import "prismjs/components/prism-rest";
|
|
||||||
import "prismjs/components/prism-rust";
|
|
||||||
import "prismjs/components/prism-shell-session";
|
|
||||||
import "prismjs/components/prism-sql";
|
|
||||||
import "prismjs/components/prism-toml";
|
|
||||||
import "prismjs/components/prism-typescript";
|
|
||||||
import "prismjs/components/prism-vim";
|
|
||||||
import "prismjs/components/prism-wasm";
|
|
||||||
import "prismjs/components/prism-yaml";
|
|
||||||
Reference in New Issue
Block a user