diff --git a/src/Layouts/Blog.elm b/src/Layouts/Blog.elm deleted file mode 100644 index 5297ea7..0000000 --- a/src/Layouts/Blog.elm +++ /dev/null @@ -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 - ] - } diff --git a/src/Pages/Posts.elm b/src/Pages/Posts.elm deleted file mode 100644 index e5821ae..0000000 --- a/src/Pages/Posts.elm +++ /dev/null @@ -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) diff --git a/src/Pages/Posts/Category_.elm b/src/Pages/Posts/Category_.elm deleted file mode 100644 index 05b9a23..0000000 --- a/src/Pages/Posts/Category_.elm +++ /dev/null @@ -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 diff --git a/src/Pages/Posts/Category_/Post_.elm b/src/Pages/Posts/Category_/Post_.elm deleted file mode 100644 index 45b61db..0000000 --- a/src/Pages/Posts/Category_/Post_.elm +++ /dev/null @@ -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)) diff --git a/src/interop.js b/src/interop.js index 9bb115a..5fa6ec2 100644 --- a/src/interop.js +++ b/src/interop.js @@ -1,4 +1,3 @@ -import "./web-components/MarkedRender.js"; import "./web-components/Calcom.js"; -export const onReady = ({ app, env }) => {}; +export const onReady = ({ app, env }) => { }; diff --git a/src/web-components/MarkedRender.js b/src/web-components/MarkedRender.js deleted file mode 100644 index 7e029ed..0000000 --- a/src/web-components/MarkedRender.js +++ /dev/null @@ -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 ` - ${text} - - # - - `; - }; - - renderer.paragraph = (text) => { - this.lead++; - return this.lead === 1 - ? `

${text}

` - : `

${text}

`; - }; - - 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 `${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"]; - } - } -); diff --git a/src/web-components/Prism.js b/src/web-components/Prism.js deleted file mode 100644 index 7baa732..0000000 --- a/src/web-components/Prism.js +++ /dev/null @@ -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";