1
0
mirror of https://github.com/avinal/avinal.github.io.git synced 2026-07-04 15:50:08 +05:30

feat: use new theme for the website

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
This commit is contained in:
2025-01-01 23:39:45 +05:30
parent 1bb34a512a
commit 62efd95607
140 changed files with 78 additions and 10518 deletions
-59
View File
@@ -1,59 +0,0 @@
module Components.Footer exposing (..)
import Html exposing (Html)
import Html.Attributes exposing (class, href, src, target)
import Utils.Constants exposing (IconLink, Link, footerLinks)
import Html.Attributes exposing (rel)
singleLink : Link -> Html msg
singleLink link =
Html.a
[ href link.url
, class "underline decoration-cyan-500 hover:decoration-pink-500 text-xl"
, target "_blank"
, rel "noopener noreferrer"
]
[ Html.text link.text ]
iconedLink : IconLink -> Html msg
iconedLink iconLink =
Html.a [ href iconLink.url, class "hover:text-pink-500 inline-flex text-2xl p-3 no-underline" ]
[ Html.i [ class iconLink.icon ] []
]
footerLinksToSide : Html msg
footerLinksToSide =
Html.div [ class "fixed bottom-0 left-0 bg-neutral-900 p-4 w-full border-t border-cyan-500" ]
[ Html.div [ class "mx-auto flex justify-center space-x-6 text-gray-400" ]
(List.map singleLink <|
{ text = "Home", url = "/" }
:: footerLinks
)
]
iconLinkToCenter : Html msg
iconLinkToCenter =
Html.div [ class "flex justify-center flex-wrap" ] (List.map iconedLink Utils.Constants.iconLinks)
avatarAndLinks : Html msg
avatarAndLinks =
Html.div []
[ Html.div [ class "flex flex-col md:space-y-0 md:space-x-6 md:flex-row border-t border-neutral-700" ]
[ Html.img
[ class "self-center flex-shrink-0 w-24 h-24 border rounded-full md:justify-self-start"
, src "https://github.com/avinal.png"
]
[]
, Html.div [ class "flex flex-col self-center" ]
[ Html.h4 [ class "text-xl font-semibold sm:justify-self-start" ] [ Html.text "Avinal Kumar" ]
, Html.p [ class "text-gray-400" ]
[ Html.text "I am a Associate Software Engineer at Red Hat and I work for Hybrid Cloud Engineering. I contribute to Open Source projects and write blogs in tech and literature."
]
]
]
, Html.div [ class "flex justify-center align-center text-neutral-700 text-xl" ] (List.map iconedLink Utils.Constants.iconLinks)
]
-93
View File
@@ -1,93 +0,0 @@
module Layouts.Home exposing (Model, Msg, Props, layout)
import Components.Footer exposing (iconLinkToCenter)
import Effect exposing (Effect)
import Html exposing (Html)
import Html.Attributes exposing (class, href, target, rel)
import Layout exposing (Layout)
import Route exposing (Route)
import Shared
import Utils.Constants exposing (..)
import View exposing (View)
import Html.Attributes exposing (target)
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
view : { toContentMsg : Msg -> contentMsg, content : View contentMsg, model : Model } -> View contentMsg
view { toContentMsg, model, content } =
let
footerLinkToCenter : Link -> Html msg
footerLinkToCenter link =
Html.a
[ href link.url
, class "underline decoration-cyan-500 hover:decoration-pink-500 inline-flex text-xl p-3"
, target "_blank"
, rel "noopener noreferrer"
]
[ Html.text link.text ]
in
{ title = content.title
, body =
[ Html.section [ class "flex items-center justify-center flex-col h-screen text-gray-400" ]
[ Html.header [ class "object-cover object-center p-8" ] content.body
, iconLinkToCenter
, Html.div [ class "text-center text-xl p-2" ] [ Html.text "Avinal Kumar, Software Engineer II at Red Hat, Open Sourcerer" ]
, Html.footer [ class "flex justify-center flex-wrap" ]
(List.map footerLinkToCenter Utils.Constants.footerLinks)
]
]
}
-317
View File
@@ -1,317 +0,0 @@
module Pages.Home_ exposing (Model, Msg, page)
import Array exposing (Array)
import Effect exposing (Effect)
import Html exposing (Html)
import Html.Events exposing (onClick, onMouseLeave)
import Layouts
import Page exposing (Page)
import Route exposing (Route)
import Shared
import Svg exposing (..)
import Svg.Attributes as SA
import Svg.Events as SE
import Time
import Utils.Constants exposing (nameMatrix)
import View exposing (View)
page : Shared.Model -> Route () -> Page Model Msg
page _ _ =
Page.new
{ init = init
, update = update
, subscriptions = subscriptions
, view = view
}
|> Page.withLayout layout
-- LAYOUT
layout : Model -> Layouts.Layout Msg
layout _ =
Layouts.Home
{}
-- INIT
type Cell
= Alive
| Dead
type alias Universe a =
{ space : Array a
, width : Int
, height : Int
}
type alias Model =
{ universe : Universe Cell
, generations : Int
, generating : Bool
}
cellSize : Int
cellSize =
10
init : () -> ( Model, Effect Msg )
init () =
( { universe = bigBang 30 30 Dead
, generating = False
, generations = 0
}
, Effect.none
)
-- UPDATE
type Msg
= Ressurect Int Int
| NextGeneration
| LiveLife
| Apocalypse
update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
case msg of
Ressurect x y ->
( { model
| universe =
buildRelationship model.universe
x
y
invertLife
}
, Effect.none
)
NextGeneration ->
let
universe =
nextGeneration model.universe
generations =
model.generations + 1
generating =
model.generating && universe /= model.universe
in
( { model
| universe = universe
, generations = generations
, generating = generating
}
, Effect.none
)
LiveLife ->
( { model | generating = not model.generating }
, Effect.none
)
Apocalypse ->
( { model | generating = False }
, Effect.none
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
if model.generating then
Time.every 500 (always NextGeneration)
else
Sub.none
-- VIEW
view : Model -> View Msg
view model =
{ title = "Welcome to my website"
, body = [ Html.div [ onClick LiveLife, onMouseLeave LiveLife ] [ universeSvg model ] ]
}
cellToSvg : Int -> Int -> Cell -> Svg Msg
cellToSvg x y cell =
let
isName =
if Array.get ((y - 12) * 24 + x - 3) nameMatrix == Just 1 && x >= 3 && x < 27 then
True
else
False
color =
case cell of
Alive ->
if isName then
"fill-cyan-500"
else
"fill-pink-500"
Dead ->
"fill-neutral-800"
in
rect
[ SA.x (String.fromInt (x * cellSize))
, SA.y (String.fromInt (y * cellSize))
, SA.width (String.fromInt cellSize)
, SA.height (String.fromInt cellSize)
, SA.class color
, SE.onMouseOver (Ressurect x y)
]
[]
universeSvg : Model -> Html Msg
universeSvg model =
let
svgWidth =
String.fromInt (model.universe.width * cellSize)
svgHeight =
String.fromInt (model.universe.height * cellSize)
in
svg
[ SA.width "150"
, SA.height "150"
, SA.viewBox ("0 0 " ++ svgWidth ++ " " ++ svgHeight)
, SA.class "stroke-0"
]
(stretchUniverseThin cellToSvg model.universe)
-- UTIL
bigBang : Int -> Int -> a -> Universe a
bigBang width height value =
{ space = Array.repeat (width * height) value
, width = width
, height = height
}
stretchUniverseThin : (Int -> Int -> a -> b) -> Universe a -> List b
stretchUniverseThin f universe =
Array.toIndexedList universe.space
|> List.map (\( i, cell ) -> f (modBy universe.width i) (i // universe.width) cell)
nextGeneration : Universe Cell -> Universe Cell
nextGeneration universe =
{ universe
| space =
Array.indexedMap
(decideFateOf universe)
universe.space
}
decideFateOf : Universe Cell -> Int -> Cell -> Cell
decideFateOf u i today =
let
aliveAtoms =
countLiveAtoms i u
in
case today of
Alive ->
if aliveAtoms < 2 || aliveAtoms > 3 then
Dead
else
Alive
Dead ->
if aliveAtoms == 3 then
Alive
else
Dead
buildRelationship : Universe a -> Int -> Int -> (a -> a) -> Universe a
buildRelationship universe x y fn =
case getUniverseAt x y universe of
Just cell ->
setUniverseAt x y (fn cell) universe
Nothing ->
universe
getUniverseAt : Int -> Int -> Universe a -> Maybe a
getUniverseAt x y u =
Array.get (y * u.width + x) u.space
setUniverseAt : Int -> Int -> a -> Universe a -> Universe a
setUniverseAt x y value u =
{ u | space = Array.set (y * u.width + x) value u.space }
countLiveAtoms : Int -> Universe Cell -> Int
countLiveAtoms i universe =
let
above =
i - universe.width
below =
i + universe.width
coordinate =
[ above - 1
, above
, above + 1
, i - 1
, i + 1
, below - 1
, below
, below + 1
]
in
coordinate
|> List.filter
(\n ->
abs
(modBy universe.width n - modBy universe.width i)
<= 1
)
|> List.map (\c -> universe.space |> Array.get c)
|> List.filter (\c -> c == Just Alive)
|> List.length
invertLife : Cell -> Cell
invertLife cell =
case cell of
Alive ->
Dead
Dead ->
Alive
-19
View File
@@ -1,19 +0,0 @@
module Pages.Meet exposing (page)
import Components.Footer exposing (footerLinksToSide)
import Html
import Html.Attributes exposing (class, id)
import View exposing (View)
page : View msg
page =
{ title = "Schedule a meet with me"
, body =
[ Html.div [ class "flex items-center justify-center flex-col h-screen m-2" ]
[ Html.node "cal-com" [ id "calcom-widget", class "w-full p-2" ] []
]
, Html.div [ class "py-16" ] []
, footerLinksToSide
]
}
-20
View File
@@ -1,20 +0,0 @@
module Pages.NotFound_ exposing (page)
import Html exposing (Html)
import Html.Attributes exposing (class, href)
import Utils.Utils exposing (errorView)
import View exposing (View)
page : View msg
page =
{ title = "Not Found"
, 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 space-2" ]
[ errorView "Couldn't find what you are looking for. Please check back later"
, Html.a [ class "float-right bg-transparent mr-auto hover:bg-pink-600 text-cyan-500 hover:text-white rounded border py-2 px-4 border-cyan-500 mt-2", href "/" ] [ Html.text "Return to Home!" ]
]
]
]
}
-172
View File
@@ -1,172 +0,0 @@
module Pages.Pages.AboutMe exposing (Model, Msg, page)
import Components.Footer exposing (footerLinksToSide)
import Effect exposing (Effect)
import Html exposing (Html)
import Html.Attributes exposing (class, datetime, href, src)
import Http
import Page exposing (Page)
import Route exposing (Route)
import Shared
import Utils.JsonResume exposing (Education, Resume, Work, resumeDecoder)
import Utils.Utils exposing (getFormattedDate)
import View exposing (View)
import Components.Footer exposing (iconLinkToCenter)
page : Shared.Model -> Route () -> Page Model Msg
page _ _ =
Page.new
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
-- INIT
type alias Model =
{ resume : Maybe Resume
, error : Maybe String
}
init : () -> ( Model, Effect Msg )
init () =
let
cmd : Cmd Msg
cmd =
Http.get
{ url = "/resume/resume.json"
, expect = Http.expectJson GotResume resumeDecoder
}
in
( { resume = Nothing, error = Nothing }, Effect.sendCmd cmd )
-- UPDATE
type Msg
= GotResume (Result Http.Error Resume)
update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
case msg of
GotResume (Ok resume) ->
( { model | resume = Just resume }, Effect.none )
GotResume (Err err) ->
( { model | error = Just (Utils.Utils.errorToString err) }, Effect.none )
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> View msg
view model =
{ title = "About Me"
, body =
let
experience : List Work -> Html msg
experience workList =
Html.ol [ class "relative border-l border-cyan-700" ]
(List.map
(\work ->
Html.li [ class "mb-10 ml-6 " ]
[ Html.span [ class "absolute flex items-center justify-center w-6 h-6 bg-pink-600 ring-pink-900 rounded-full -left-3 ring-8" ]
[ Html.text <| String.left 1 work.name ]
, Html.h3 [ class "flex items-center mb-1 text-xl font-semibold" ] [ Html.text <| work.position ++ " at " ++ work.name ]
, Html.time [ class "block mb-2 text font-normal leading-none text-gray-500", datetime work.startDate ]
[ Html.text <| getFormattedDate work.startDate False ++ " - " ++ getFormattedDate work.endDate False ]
, Html.p [ class "mb-4 text-base font-normal text-gray-400" ] [ Html.text work.summary ]
, Html.p [ class "mb-4 text-lg font-normal text-gray-300" ] [ Html.text work.description ]
, Html.p [ class "mb-4 text-lg font-normal text-gray-300 ml-8" ] [ listThings work.highlights ]
]
)
workList
)
education : List Education -> Html msg
education eduList =
Html.ol [ class "relative border-l border-cyan-700" ]
(List.map
(\edu ->
Html.li [ class "mb-10 ml-6" ]
[ Html.span [ class "absolute flex items-center justify-center w-6 h-6 bg-pink-600 ring-pink-900 rounded-full -left-3 ring-8" ]
[ Html.text <| String.left 1 edu.institution ]
, Html.h3 [ class "flex items-center mb-1 text-xl font-semibold" ] [ Html.text <| edu.studyType ++ " at " ++ edu.institution ]
, Html.time [ class "block mb-2 text font-normal leading-none text-gray-500", datetime edu.startDate ]
[ Html.text <| getFormattedDate edu.startDate False ++ " - " ++ getFormattedDate edu.endDate False ]
, Html.p [ class "mb-4 text-base font-normal text-gray-400" ] [ Html.text edu.area ]
]
)
eduList
)
in
case model.resume of
Just resume ->
[ Html.section []
[ Html.div [ class "text-white" ]
[ Html.div [ class "container mx-auto flex flex-col items-start xl:flex-row my-12 xl:my-24" ]
[ Html.div [ class "flex flex-col w-full sticky xl:top-36 xl:w-2/3 mt-2 xl:mt-12 px-8" ]
[ Html.img [ class "w-full h-80 object-cover mx-auto mb-4", src resume.basics.image ] []
, Html.p [ class "text-5xl lg:text-6xl 2xl:text-7xl leading-normal md:leading-relaxed" ] [ Html.text resume.basics.name ]
, Html.p [ class "lg:text-xl md:text-md text-base text-cyan-500 uppercase tracking-lppse mb-2" ] [ Html.text resume.basics.label ]
, Html.p [ class "md:text-base text-gray-50 mb-4 lg:text-xl" ] [ Html.text resume.basics.summary ]
, iconLinkToCenter
]
, Html.div [ class "flex-row" ]
[ Html.div [ class "ml-0 md:ml-12 lg:w-3/3 sticky" ]
[ Html.div [ class "container mx-auto w-full h-full" ]
[ Html.div [ class "relative wrap overflow-hidden p-10 h-full" ]
[ experience resume.work ]
]
]
, Html.div [ class "ml-0 md:ml-12 lg:w-3/3 sticky" ]
[ Html.div [ class "container mx-auto w-full h-full" ]
[ Html.h2 [ class "text-xl ml-2 text-cyan-500" ] [ Html.text "Education" ]
, Html.div [ class "relative wrap overflow-hidden p-10 h-full" ]
[ education resume.education ]
]
]
]
]
]
]
, footerLinksToSide
]
Nothing ->
[]
}
-- simply list things
listThings : List String -> Html msg
listThings things =
Html.ul []
(List.map
(\thing ->
Html.li [ class "list-disc" ] [ Html.text thing ]
)
things
)
-95
View File
@@ -1,95 +0,0 @@
module Pages.Pages.Projects exposing (Model, Msg, page)
import Dict exposing (Dict)
import Effect exposing (Effect)
import Html exposing (div, img, section)
import Html.Attributes exposing (class, src)
import Page exposing (Page)
import Route exposing (Route)
import Route.Path
import Shared
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 Model =
{}
init : () -> ( Model, Effect Msg )
init () =
( {}
, Effect.replaceRoute { path = Route.Path.NotFound_, query = Dict.empty, hash = Nothing }
)
-- UPDATE
type Msg
= ExampleMsgReplaceMe
update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
case msg of
ExampleMsgReplaceMe ->
( model
, Effect.none
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
-- VIEW
view : Model -> View Msg
view _ =
{ title = "My Projects"
, body =
[ section [ class "overflow-hidden" ]
[ div
[ class "px-5 py-2 mx-auto lg:pt-24 lg:px-32" ]
[ div [ class "flex flex-wrap -m-1 md:-m-2" ]
(List.repeat 8
(div [ class "flex flex-wrap w-1/2" ]
(List.repeat 2
(div
[ class "w-full p-1 md:p-2" ]
[ img
[ src "https://opengraph.githubassets.com/string/avinal/blowfish"
, class "block object-cover object-center w-full h-full rounded-lg"
]
[]
]
)
)
)
)
]
]
]
}
-212
View File
@@ -1,212 +0,0 @@
module Utils.Constants exposing (..)
import Array exposing (Array)
import Html exposing (Html)
type alias Link =
{ url : String
, text : String
}
type alias IconLink =
{ url : String
, icon : String
}
type alias Job msg =
{ title : String
, company : String
, from : String
, to : String
, body : Html msg
}
footerLinks : List Link
footerLinks =
[ { text = "About", url = "/pages/about-me" }
, { text = "Blog", url = "https://avinal.space/posts" }
, { text = "Projects", url = "/pages/projects" }
, { text = "GSoC", url = "https://avinal.space/posts/category/gsoc" }
]
iconLinks : List IconLink
iconLinks =
[ { url = "https://github.com/avinal", icon = "fa-brands fa-github" }
, { url = "https://www.linkedin.com/in/avinal", icon = "fa-brands fa-linkedin" }
, { url = "https://twitter.com/Avinal_", icon = "fa-brands fa-twitter" }
, { url = "mailto:ripple@avinal.space", icon = "fa-solid fa-envelope" }
, { url = "/meet", icon = "fa-solid fa-video" }
]
months : Array String
months =
Array.fromList
[ "January"
, "February"
, "March"
, "April"
, "May"
, "June"
, "July"
, "August"
, "September"
, "October"
, "November"
, "December"
]
nameMatrix : Array Int
nameMatrix =
Array.fromList
[ 0
, 1
, 1
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 1
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 1
, 1
, 0
, 0
, 1
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 1
, 1
, 1
, 1
, 1
, 0
, 1
, 0
, 0
, 0
, 1
, 0
, 1
, 0
, 1
, 1
, 1
, 0
, 0
, 1
, 1
, 1
, 0
, 0
, 1
, 1
, 0
, 0
, 1
, 0
, 1
, 0
, 0
, 0
, 1
, 0
, 1
, 0
, 1
, 0
, 0
, 1
, 0
, 1
, 0
, 1
, 0
, 0
, 1
, 1
, 0
, 0
, 1
, 0
, 0
, 1
, 0
, 1
, 0
, 0
, 1
, 0
, 1
, 0
, 0
, 1
, 0
, 1
, 0
, 1
, 0
, 0
, 1
, 1
, 0
, 0
, 1
, 0
, 0
, 0
, 1
, 0
, 0
, 0
, 1
, 0
, 1
, 0
, 0
, 1
, 0
, 1
, 1
, 1
, 1
, 0
, 1
]
-435
View File
@@ -1,435 +0,0 @@
module Utils.JsonResume exposing (..)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
-- Main Resume type
type alias Resume =
{ basics : Basics
, work : List Work
, volunteer : List Volunteer
, education : List Education
, awards : List Award
, certificates : List Certificate
, publications : List Publication
, skills : List Skill
, languages : List Language
, interests : List Interest
, references : List Reference
, projects : List Project
, meta : Meta
}
-- Basics
type alias Basics =
{ name : String
, label : String
, image : String
, email : String
, phone : String
, url : String
, summary : String
, location : Location
, profiles : List Profile
}
type alias Location =
{ address : String
, postalCode : String
, city : String
, countryCode : String
, region : String
}
type alias Profile =
{ network : String
, username : String
, url : String
}
-- Work
type alias Work =
{ name : String
, location : String
, description : String
, position : String
, url : String
, startDate : String
, endDate : String
, summary : String
, highlights : List String
}
-- Volunteer
type alias Volunteer =
{ organization : String
, position : String
, url : String
, startDate : String
, endDate : String
, summary : String
, highlights : List String
}
-- Education
type alias Education =
{ institution : String
, url : String
, area : String
, studyType : String
, startDate : String
, endDate : String
, score : String
, courses : List String
}
-- Awards
type alias Award =
{ title : String
, date : String
, awarder : String
, summary : String
}
-- Certificates
type alias Certificate =
{ name : String
, date : String
, url : String
, issuer : String
}
-- Publications
type alias Publication =
{ name : String
, publisher : String
, releaseDate : String
, url : String
, summary : String
}
-- Skills
type alias Skill =
{ name : String
, level : String
, keywords : List String
}
-- Languages
type alias Language =
{ language : String
, fluency : String
}
-- Interests
type alias Interest =
{ name : String
, keywords : List String
}
-- References
type alias Reference =
{ name : String
, reference : String
}
-- Projects
type alias Project =
{ name : String
, description : String
, highlights : List String
, keywords : List String
, startDate : String
, endDate : String
, url : String
, roles : List String
, entity : String
, type_ : String
}
-- Meta
type alias Meta =
{ canonical : String
, version : String
, lastModified : String
}
-- JSON Decoders
-- Resume Decoder
resumeDecoder : Decoder Resume
resumeDecoder =
Decode.succeed Resume
|> required "basics" basicsDecoder
|> required "work" (Decode.list workDecoder)
|> optional "volunteer" (Decode.list volunteerDecoder) []
|> required "education" (Decode.list educationDecoder)
|> optional "awards" (Decode.list awardDecoder) []
|> optional "certificates" (Decode.list certificateDecoder) []
|> optional "publications" (Decode.list publicationDecoder) []
|> optional "skills" (Decode.list skillDecoder) []
|> optional "languages" (Decode.list languageDecoder) []
|> optional "interests" (Decode.list interestDecoder) []
|> optional "references" (Decode.list referenceDecoder) []
|> optional "projects" (Decode.list projectDecoder) []
|> optional "meta" metaDecoder (Meta "" "" "")
-- Basics Decoder
basicsDecoder : Decoder Basics
basicsDecoder =
Decode.succeed Basics
|> required "name" Decode.string
|> required "label" Decode.string
|> optional "image" Decode.string ""
|> required "email" Decode.string
|> optional "phone" Decode.string ""
|> required "url" Decode.string
|> required "summary" Decode.string
|> optional "location" locationDecoder (Location "" "" "" "" "")
|> optional "profiles" (Decode.list profileDecoder) []
locationDecoder : Decoder Location
locationDecoder =
Decode.succeed Location
|> optional "address" Decode.string ""
|> optional "postalCode" Decode.string ""
|> required "city" Decode.string
|> required "countryCode" Decode.string
|> optional "region" Decode.string ""
profileDecoder : Decoder Profile
profileDecoder =
Decode.succeed Profile
|> required "network" Decode.string
|> required "username" Decode.string
|> required "url" Decode.string
workDecoder : Decoder Work
workDecoder =
Decode.succeed Work
|> required "name" Decode.string
|> optional "location" Decode.string ""
|> optional "description" Decode.string ""
|> required "position" Decode.string
|> optional "url" Decode.string ""
|> required "startDate" Decode.string
|> required "endDate" Decode.string
|> required "summary" Decode.string
|> optional "highlights" (Decode.list Decode.string) []
-- Volunteer Decoder
volunteerDecoder : Decoder Volunteer
volunteerDecoder =
Decode.succeed Volunteer
|> required "organization" Decode.string
|> required "position" Decode.string
|> required "url" Decode.string
|> required "startDate" Decode.string
|> required "endDate" Decode.string
|> required "summary" Decode.string
|> optional "highlights" (Decode.list Decode.string) []
-- Education Decoder
educationDecoder : Decoder Education
educationDecoder =
Decode.succeed Education
|> required "institution" Decode.string
|> optional "url" Decode.string ""
|> required "area" Decode.string
|> required "studyType" Decode.string
|> required "startDate" Decode.string
|> required "endDate" Decode.string
|> optional "score" Decode.string ""
|> optional "courses" (Decode.list Decode.string) []
-- Award Decoder
awardDecoder : Decoder Award
awardDecoder =
Decode.succeed Award
|> required "title" Decode.string
|> required "date" Decode.string
|> required "awarder" Decode.string
|> required "summary" Decode.string
-- Certificate Decoder
certificateDecoder : Decoder Certificate
certificateDecoder =
Decode.succeed Certificate
|> required "name" Decode.string
|> required "date" Decode.string
|> required "url" Decode.string
|> required "issuer" Decode.string
-- Publication Decoder
publicationDecoder : Decoder Publication
publicationDecoder =
Decode.succeed Publication
|> required "name" Decode.string
|> required "publisher" Decode.string
|> required "releaseDate" Decode.string
|> required "url" Decode.string
|> required "summary" Decode.string
-- Skill Decoder
skillDecoder : Decoder Skill
skillDecoder =
Decode.succeed Skill
|> required "name" Decode.string
|> optional "level" Decode.string ""
|> optional "keywords" (Decode.list Decode.string) []
-- Language Decoder
languageDecoder : Decoder Language
languageDecoder =
Decode.succeed Language
|> required "language" Decode.string
|> required "fluency" Decode.string
-- Interest Decoder
interestDecoder : Decoder Interest
interestDecoder =
Decode.succeed Interest
|> required "name" Decode.string
|> required "keywords" (Decode.list Decode.string)
-- Reference Decoder
referenceDecoder : Decoder Reference
referenceDecoder =
Decode.succeed Reference
|> required "name" Decode.string
|> required "reference" Decode.string
-- Project Decoder
projectDecoder : Decoder Project
projectDecoder =
Decode.succeed Project
|> required "name" Decode.string
|> required "description" Decode.string
|> optional "highlights" (Decode.list Decode.string) []
|> optional "keywords" (Decode.list Decode.string) []
|> required "startDate" Decode.string
|> optional "endDate" Decode.string ""
|> required "url" Decode.string
|> optional "roles" (Decode.list Decode.string) []
|> optional "entity" Decode.string ""
|> optional "type_" Decode.string ""
-- Meta Decoder
metaDecoder : Decoder Meta
metaDecoder =
Decode.succeed Meta
|> required "canonical" Decode.string
|> required "version" Decode.string
|> required "lastModified" Decode.string
-154
View File
@@ -1,154 +0,0 @@
module Utils.Utils exposing (..)
import Array
import Html exposing (Html)
import Html.Attributes exposing (class, href, target)
import Http exposing (Error(..))
import Parser exposing (..)
import Utils.Constants exposing (..)
type alias DateTime =
{ year : Int
, month : Int
, day : Int
, hour : Int
, minute : Int
}
getFormattedDate : String -> Bool -> String
getFormattedDate dateString time =
case Parser.run dateParser dateString of
Ok date ->
(Maybe.withDefault "Month" <| Array.get (date.month - 1) months)
++ " "
++ String.fromInt date.day
++ ", "
++ String.fromInt date.year
++ (if time then
", "
++ String.fromInt date.hour
++ ":"
++ String.fromInt date.minute
++ " IST"
else
""
)
Err _ ->
if time then
"Invalid date!!"
else
"Today"
dateParser : Parser DateTime
dateParser =
oneOf
[ succeed Tuple.pair
|= datePart
|= optional timePart
]
|> map toDateTime
datePart : Parser ( Int, Int, Int )
datePart =
succeed (\y m d -> ( y, m, d ))
|= int
|. token "-"
|. chompWhile (\c -> c == '0')
|= int
|. token "-"
|. chompWhile (\c -> c == '0')
|= int
timePart : Parser ( Int, Int )
timePart =
succeed (\h m -> ( h, m ))
|. token "T"
|. chompWhile (\c -> c == '0')
|= int
|. token ":"
|. chompWhile (\c -> c == '0')
|= int
|. chompUntilEndOr "\n"
|. end
toDateTime : ( ( Int, Int, Int ), Maybe ( Int, Int ) ) -> DateTime
toDateTime ( ( y, m, d ), maybeTime ) =
case maybeTime of
Just ( h, min ) ->
DateTime y m d h min
Nothing ->
DateTime y m d 0 0
optional : Parser a -> Parser (Maybe a)
optional parser =
oneOf
[ succeed Just |= parser
, succeed Nothing
]
categoryNtags : String -> List String -> Html msg
categoryNtags category tags =
Html.span [ class "flex flex-wrap py-6 space-x-2" ]
(Html.a [ class "px-3 py-1 m-1 rounded-sm hover:underline bg-pink-400 text-gray-900 font-bold", href <| "/posts/" ++ category, target "_blank" ]
[ Html.text category
]
:: List.map
(\tag ->
Html.i [ class "px-3 py-1 m-1 rounded-sm hover:underline bg-cyan-500 text-gray-900" ]
[ Html.text <| "#" ++ tag
]
)
tags
)
contentUrl : { category : String, post : String } -> String
contentUrl { category, post } =
"/content/posts/" ++ category ++ "/" ++ post ++ ".md"
errorToString : Http.Error -> String
errorToString error =
case error of
BadUrl url ->
"The URL " ++ url ++ " was invalid"
Timeout ->
"Unable to reach the server, try again"
NetworkError ->
"Unable to reach the server, check your network connection"
BadStatus 500 ->
"The server had a problem, try again later"
BadStatus 400 ->
"Verify your information and try again"
BadStatus _ ->
"The content can't be found, please check your url"
BadBody errorMessage ->
errorMessage
errorView : String -> Html msg
errorView error =
Html.div
[ class "border border-red-400 text-red-700 px-4 py-3 rounded relative" ]
[ Html.strong [ class "text-red-400" ] [ Html.text "Something bad has happened!" ]
, Html.br [] []
, Html.text ("Error: " ++ error)
]
-76
View File
@@ -1,76 +0,0 @@
module View exposing
( View, map
, none, fromString
, toBrowserDocument
)
{-|
@docs View, map
@docs none, fromString
@docs toBrowserDocument
-}
import Browser
import Html exposing (Html)
import Html.Attributes exposing (class)
import Route exposing (Route)
import Shared.Model
type alias View msg =
{ title : String
, body : List (Html msg)
}
{-| Used internally by Elm Land to create your application
so it works with Elm's expected `Browser.Document msg` type.
-}
toBrowserDocument :
{ shared : Shared.Model.Model
, route : Route ()
, view : View msg
}
-> Browser.Document msg
toBrowserDocument { view } =
{ title = view.title ++ " | Avinal's personal website"
, body =
[ Html.main_ [ class "container mx-auto bg-neutral-800" ]
view.body
]
}
{-| Used internally by Elm Land to connect your pages together.
-}
map : (msg1 -> msg2) -> View msg1 -> View msg2
map fn view =
{ title = view.title
, body = List.map (Html.map fn) view.body
}
{-| Used internally by Elm Land whenever transitioning between
authenticated pages.
-}
none : View msg
none =
{ title = "Avinal Kumar | Personal Website"
, body = []
}
{-| If you customize the `View` module, anytime you run `elm-land add page`,
the generated page will use this when adding your `view` function.
That way your app will compile after adding new pages, and you can see
the new page working in the web browser!
-}
fromString : String -> View msg
fromString moduleName =
{ title = moduleName
, body = []
}
-270
View File
@@ -1,270 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* PrismJS 1.29.0
https://prismjs.com/download.html#themes=prism-okaidia&languages=markup+css+clike+javascript+bash+basic+brainfuck+c+cpp+cmake+diff+docker+elm+git+go+go-module+graphql+haskell+http+java+json+json5+jsonp+makefile+markdown+matlab+mermaid+powershell+protobuf+python+rest+rust+shell-session+sql+toml+typescript+vim+wasm+yaml&plugins=line-numbers+toolbar+match-braces+diff-highlight */
code[class*=language-],
pre[class*=language-] {
color: #f8f8f2;
background: 0 0;
text-shadow: 0 1px rgba(0, 0, 0, .3);
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none
}
pre[class*=language-] {
padding: 1em;
margin: .5em 0;
overflow: auto;
border-radius: .3em
}
:not(pre)>code[class*=language-],
pre[class*=language-] {
background: #0b0b0b
}
:not(pre)>code[class*=language-] {
padding: .1em;
border-radius: .3em;
white-space: normal
}
.token.cdata,
.token.comment,
.token.doctype,
.token.prolog {
color: #8292a2
}
.token.punctuation {
color: #f8f8f2
}
.token.namespace {
opacity: .7
}
.token.constant,
.token.deleted,
.token.property,
.token.symbol,
.token.tag {
color: #f92672
}
.token.boolean,
.token.number {
color: #ae81ff
}
.token.attr-name,
.token.builtin,
.token.char,
.token.inserted,
.token.selector,
.token.string {
color: #a6e22e
}
.language-css .token.string,
.style .token.string,
.token.entity,
.token.operator,
.token.url,
.token.variable {
color: #f8f8f2
}
.token.atrule,
.token.attr-value,
.token.class-name,
.token.function {
color: #e6db74
}
.token.keyword {
color: #66d9ef
}
.token.important,
.token.regex {
color: #fd971f
}
.token.bold,
.token.important {
font-weight: 700
}
.token.italic {
font-style: italic
}
.token.entity {
cursor: help
}
pre[class*=language-].line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber
}
pre[class*=language-].line-numbers>code {
position: relative;
white-space: inherit
}
.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
width: 3em;
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none
}
.line-numbers-rows>span {
display: block;
counter-increment: linenumber
}
.line-numbers-rows>span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: .8em;
text-align: right
}
div.code-toolbar {
position: relative
}
div.code-toolbar>.toolbar {
position: absolute;
z-index: 10;
top: .3em;
right: .2em;
transition: opacity .3s ease-in-out;
opacity: 0
}
div.code-toolbar:hover>.toolbar {
opacity: 1
}
div.code-toolbar:focus-within>.toolbar {
opacity: 1
}
div.code-toolbar>.toolbar>.toolbar-item {
display: inline-block
}
div.code-toolbar>.toolbar>.toolbar-item>a {
cursor: pointer
}
div.code-toolbar>.toolbar>.toolbar-item>button {
background: 0 0;
border: 0;
color: inherit;
font: inherit;
line-height: normal;
overflow: visible;
padding: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none
}
div.code-toolbar>.toolbar>.toolbar-item>a,
div.code-toolbar>.toolbar>.toolbar-item>button,
div.code-toolbar>.toolbar>.toolbar-item>span {
color: #bbb;
font-size: .8em;
padding: 0 .5em;
background: #f5f2f0;
background: rgba(224, 224, 224, .2);
box-shadow: 0 2px 0 0 rgba(0, 0, 0, .2);
border-radius: .5em
}
div.code-toolbar>.toolbar>.toolbar-item>a:focus,
div.code-toolbar>.toolbar>.toolbar-item>a:hover,
div.code-toolbar>.toolbar>.toolbar-item>button:focus,
div.code-toolbar>.toolbar>.toolbar-item>button:hover,
div.code-toolbar>.toolbar>.toolbar-item>span:focus,
div.code-toolbar>.toolbar>.toolbar-item>span:hover {
color: inherit;
text-decoration: none
}
.token.punctuation.brace-hover,
.token.punctuation.brace-selected {
outline: solid 1px
}
.rainbow-braces .token.punctuation.brace-level-1,
.rainbow-braces .token.punctuation.brace-level-5,
.rainbow-braces .token.punctuation.brace-level-9 {
color: #e50;
opacity: 1
}
.rainbow-braces .token.punctuation.brace-level-10,
.rainbow-braces .token.punctuation.brace-level-2,
.rainbow-braces .token.punctuation.brace-level-6 {
color: #0b3;
opacity: 1
}
.rainbow-braces .token.punctuation.brace-level-11,
.rainbow-braces .token.punctuation.brace-level-3,
.rainbow-braces .token.punctuation.brace-level-7 {
color: #26f;
opacity: 1
}
.rainbow-braces .token.punctuation.brace-level-12,
.rainbow-braces .token.punctuation.brace-level-4,
.rainbow-braces .token.punctuation.brace-level-8 {
color: #e0e;
opacity: 1
}
pre.diff-highlight>code .token.deleted:not(.prefix),
pre>code.diff-highlight .token.deleted:not(.prefix) {
background-color: rgba(255, 0, 0, .1);
color: inherit;
display: block
}
pre.diff-highlight>code .token.inserted:not(.prefix),
pre>code.diff-highlight .token.inserted:not(.prefix) {
background-color: rgba(0, 255, 128, .1);
color: inherit;
display: block
}
-3
View File
@@ -1,3 +0,0 @@
import "./web-components/Calcom.js";
export const onReady = ({ app, env }) => { };
-55
View File
@@ -1,55 +0,0 @@
customElements.define(
"cal-com",
class extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
(function (C, A, L) {
let p = function (a, ar) {
a.q.push(ar);
};
let d = C.document;
C.Cal =
C.Cal ||
function () {
let cal = C.Cal;
let ar = arguments;
if (!cal.loaded) {
cal.ns = {};
cal.q = cal.q || [];
d.head.appendChild(d.createElement("script")).src = A;
cal.loaded = true;
}
if (ar[0] === L) {
const api = function () {
p(api, arguments);
};
const namespace = ar[1];
api.q = api.q || [];
typeof namespace === "string"
? (cal.ns[namespace] = api) && p(api, ar)
: p(cal, ar);
return;
}
p(cal, ar);
};
})(window, "https://app.cal.com/embed/embed.js", "init");
Cal("init", { origin: "https://app.cal.com" });
Cal("inline", {
elementOrSelector: "#calcom-widget",
calLink: "avinal",
});
Cal("ui", {
theme: "dark",
styles: {
branding: { brandColor: "#009fb1" },
},
hideEventTypeDetails: false,
});
console.log("These errors are not produced by the Elm app :)");
}
}
);