added content, post display
This commit is contained in:
parent
ae9fff231b
commit
a6186ba639
36 changed files with 751 additions and 199 deletions
lib
home73k
home73k_web
|
@ -18,9 +18,16 @@ defmodule Home73k.Blog do
|
|||
def list_posts, do: @posts
|
||||
def list_tags, do: @tags
|
||||
|
||||
# defmodule NotFoundError do
|
||||
# defexception [:message, plug_status: 404]
|
||||
# end
|
||||
defmodule NotFoundError do
|
||||
defexception [:message, plug_status: 404]
|
||||
end
|
||||
|
||||
def get_post_by_id!(id) do
|
||||
case Enum.find(list_posts(), nil, &(&1.id == id)) do
|
||||
%Post{} = post -> post
|
||||
nil -> raise NotFoundError, "post with id=#{id} not found"
|
||||
end
|
||||
end
|
||||
|
||||
# def get_posts_by_tag!(tag) do
|
||||
# case Enum.filter(list_posts(), &(tag in &1.tags)) do
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
defmodule Home73k.Blog.Post do
|
||||
@enforce_keys [:title, :slug, :date, :author, :tags, :lede, :body, :corpus]
|
||||
defstruct [:title, :slug, :date, :author, :tags, :lede, :body, :corpus]
|
||||
@enforce_keys [:title, :id, :date, :author, :tags, :lede, :body, :corpus]
|
||||
defstruct [:title, :id, :date, :author, :tags, :lede, :body, :corpus]
|
||||
|
||||
@strip_words ~w(the and are for not but had has was all any too one you his her can that with have this will your from they want been much some very them into which then now get its youll youre)
|
||||
@strip_words ~w(the and are for not but had has was all any too one you his her can that with have this will your from they want been much some very them into which then now get its youll youre isnt wasnt)
|
||||
|
||||
@doc """
|
||||
The public parse!/1 function begins the post parse process by reading
|
||||
|
@ -36,7 +36,7 @@ defmodule Home73k.Blog.Post do
|
|||
# """
|
||||
defp parse_frontmatter([fm, md]) do
|
||||
case parse_frontmatter_string(fm) do
|
||||
{%{} = parsed_fm, _} -> {set_post_slug(parsed_fm), String.trim(md)}
|
||||
{%{} = parsed_fm, _} -> {set_post_id(parsed_fm), String.trim(md)}
|
||||
{:error, _} -> nil
|
||||
end
|
||||
end
|
||||
|
@ -46,6 +46,11 @@ defmodule Home73k.Blog.Post do
|
|||
# """ parse_lede/1
|
||||
# Look for lede/excerpt/summary in content and extract it if present.
|
||||
# We return updated frontmatter, and content with <!--more--> stripped.
|
||||
defp parse_lede({%{lede: lede} = fm, md}) do
|
||||
lede = String.trim(lede) |> Earmark.as_html!()
|
||||
{Map.put(fm, :lede, lede), md}
|
||||
end
|
||||
|
||||
defp parse_lede({fm, md}) do
|
||||
{lede, body_md} = String.split(md, "<!--more-->", parts: 2) |> extract_lede()
|
||||
{Map.put(fm, :lede, lede), String.replace(body_md, "<!--more-->", " ")}
|
||||
|
@ -58,6 +63,8 @@ defmodule Home73k.Blog.Post do
|
|||
# TODO: handle syntax highlighting
|
||||
defp parse_body({fm, md}) do
|
||||
Map.put(fm, :body, Earmark.as_html!(md))
|
||||
# TODO: Earmark.as_ast(md) |> parse_body(fm)
|
||||
# def parse_body({:ok, ast, _}, fm)
|
||||
end
|
||||
|
||||
defp parse_body(_), do: nil
|
||||
|
@ -66,12 +73,15 @@ defmodule Home73k.Blog.Post do
|
|||
# Create a searchable word list for the post, for live searching
|
||||
defp build_corpus(%{title: title, lede: lede, body: body, tags: tags} = post_data) do
|
||||
# initialize corpus string from: title, lede, body, tags
|
||||
corpus = (tags ++ [title, (lede && lede) || " ", body]) |> Enum.join(" ") |> String.downcase()
|
||||
|
||||
# scrub out (but replace with spaces):
|
||||
# code blocks, html tags, html entities, newlines, forward and back slashes
|
||||
html_scrub_regex = ~r/(<pre><code(.|\n)*?<\/code><\/pre>)|(<(.|\n)+?>)|(&#(.)+?;)|(&(.)+?;)|\n|\/|\\/
|
||||
corpus = Regex.replace(html_scrub_regex, corpus, " ")
|
||||
# grab text only, rejecting HTML
|
||||
# downcase & scrub line breaks, slashes
|
||||
corpus =
|
||||
(tags ++ [title, (lede && lede) || " ", body])
|
||||
|> Enum.join(" ")
|
||||
|> Floki.parse_fragment!()
|
||||
|> Floki.text()
|
||||
|> String.downcase()
|
||||
|> String.replace(["\n", "/", "\\", "(", ")", ":", "=", "_", ".", ",", "[", "]"], " ")
|
||||
|
||||
# restrict corpus to letters & numbers,
|
||||
# then split to words (space delim), trimming as we go
|
||||
|
@ -108,8 +118,7 @@ defmodule Home73k.Blog.Post do
|
|||
# """
|
||||
defp parse_frontmatter_string(fm) do
|
||||
try do
|
||||
String.trim_leading(fm, "-")
|
||||
|> Code.eval_string()
|
||||
Code.eval_string(fm)
|
||||
rescue
|
||||
_ -> {:error, nil}
|
||||
end
|
||||
|
@ -124,22 +133,23 @@ defmodule Home73k.Blog.Post do
|
|||
|
||||
defp extract_lede([body]), do: {nil, body}
|
||||
|
||||
# """ set_frontmatter_slug
|
||||
# If no slug in frontmatter, convert title to slug and add to map
|
||||
# """ set_post_id
|
||||
# If no id in frontmatter, convert title to id and add to map
|
||||
# """
|
||||
defp set_post_slug(%{slug: _} = fm), do: fm
|
||||
defp set_post_id(%{id: _} = fm), do: fm
|
||||
|
||||
defp set_post_slug(%{title: title} = fm) do
|
||||
Map.put(fm, :slug, parse_title_to_slug(title))
|
||||
defp set_post_id(%{title: title} = fm) do
|
||||
Map.put(fm, :id, parse_title_to_id(title))
|
||||
end
|
||||
|
||||
# """ parse_title_to_slug
|
||||
# Takes a post title and returns a slug cleansed for URI request path
|
||||
# """ parse_title_to_id
|
||||
# Takes a post title and returns a id cleansed for URI request path
|
||||
# """
|
||||
defp parse_title_to_slug(title) do
|
||||
title = String.downcase(title)
|
||||
def parse_title_to_id(title) do
|
||||
title_text = Floki.parse_fragment!(title) |> Floki.text() |> String.downcase()
|
||||
|
||||
Regex.replace(~r/[^a-z0-9 ]/, title, "")
|
||||
~r/[^a-z0-9 ]/
|
||||
|> Regex.replace(title_text, "")
|
||||
|> String.split(" ", trim: true)
|
||||
|> Stream.reject(&reject_word?/1)
|
||||
|> Enum.join("-")
|
||||
|
@ -147,7 +157,7 @@ defmodule Home73k.Blog.Post do
|
|||
|
||||
# """ reject_word?
|
||||
# Returns true to reject short or common words
|
||||
# Used by parse_title_to_slug and build_corpus
|
||||
# Used by parse_title_to_id and build_corpus
|
||||
# """
|
||||
defp reject_word?(word), do: String.length(word) < 3 || word in @strip_words
|
||||
end
|
||||
|
|
|
@ -5,6 +5,10 @@ defmodule Home73kWeb.HomeController do
|
|||
render(conn, "index.html")
|
||||
end
|
||||
|
||||
def about(conn, _params) do
|
||||
render(conn, "about.html", page_title: "About")
|
||||
end
|
||||
|
||||
def resume(conn, _params) do
|
||||
render(conn, "resume.html", page_title: "Résumé")
|
||||
end
|
||||
|
|
|
@ -23,7 +23,7 @@ defmodule Home73kWeb.Endpoint do
|
|||
plug Plug.Static,
|
||||
at: "/",
|
||||
from: :home73k,
|
||||
gzip: true,
|
||||
gzip: (Mix.env() not in [:dev, :test]),
|
||||
only: ~w(css fonts images js favicon.ico robots.txt DF185CEE29A3D443_public_key.asc)
|
||||
|
||||
# Code reloading can be explicitly enabled under the
|
||||
|
|
54
lib/home73k_web/live/blog_live.ex
Normal file
54
lib/home73k_web/live/blog_live.ex
Normal file
|
@ -0,0 +1,54 @@
|
|||
defmodule Home73kWeb.BlogLive do
|
||||
use Home73kWeb, :live_view
|
||||
|
||||
alias Home73k.Blog
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
socket
|
||||
|> live_okreply()
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_params(_params, _url, socket) do
|
||||
socket
|
||||
|> assign(:page_title, "Blog")
|
||||
|> assign(:posts, Blog.list_posts())
|
||||
|> live_noreply()
|
||||
end
|
||||
|
||||
# @impl true
|
||||
# def handle_event("suggest", %{"q" => query}, socket) do
|
||||
# {:noreply, assign(socket, results: search(query), query: query)}
|
||||
# end
|
||||
|
||||
# @impl true
|
||||
# def handle_event("search", %{"q" => query}, socket) do
|
||||
# case search(query) do
|
||||
# %{^query => vsn} ->
|
||||
# {:noreply, redirect(socket, external: "https://hexdocs.pm/#{query}/#{vsn}")}
|
||||
|
||||
# _ ->
|
||||
# {:noreply,
|
||||
# socket
|
||||
# |> put_flash(:error, "No dependencies found matching \"#{query}\"")
|
||||
# |> assign(results: %{}, query: query)}
|
||||
# end
|
||||
# end
|
||||
|
||||
# defp search(query) do
|
||||
# if not Home73kWeb.Endpoint.config(:code_reloader) do
|
||||
# raise "action disabled when not in development"
|
||||
# end
|
||||
|
||||
# for {app, desc, vsn} <- Application.started_applications(),
|
||||
# app = to_string(app),
|
||||
# String.starts_with?(app, query) and not List.starts_with?(desc, ~c"ERTS"),
|
||||
# into: %{},
|
||||
# do: {app, vsn}
|
||||
# end
|
||||
|
||||
defp format_date(date) do
|
||||
Calendar.strftime(date, "%B %-d, %Y")
|
||||
end
|
||||
end
|
41
lib/home73k_web/live/blog_live.html.leex
Normal file
41
lib/home73k_web/live/blog_live.html.leex
Normal file
|
@ -0,0 +1,41 @@
|
|||
<main class="container d-flex justify-content-center">
|
||||
|
||||
<div class="col-12 col-md-10 col-lg-8 col-xl-7 col-xxl-6 pb-2 mb-4 mt-3">
|
||||
|
||||
<%= for post <- @posts do %>
|
||||
|
||||
<div class="post border-bottom border-gray pb-4 mb-3">
|
||||
|
||||
<h2 class="post-title fs-2 fw-normal mb-2">
|
||||
<%= live_redirect "#{post.title}", to: Routes.post_path(@socket, :show, post) %>
|
||||
</h2>
|
||||
|
||||
<div class="post-date font-monospace text-gray-500 <%= if length(post.tags) == 0, do: "mb-3" %>">
|
||||
<%= icon_div @socket, "mdi-calendar-clock", [class: "icon baseline"] %>
|
||||
<%= post.date |> format_date() %>
|
||||
</div>
|
||||
|
||||
<%= if length(post.tags) > 0 do %>
|
||||
<div class="post-tags fs-6 mb-3">
|
||||
<%= icon_div @socket, "mdi-tag-multiple", [class: "icon baseline"] %>
|
||||
<%= for {tag, i} <- Enum.with_index(post.tags) do %>
|
||||
#<%= tag %><%= i < (length(post.tags) - 1) && "," || "" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="post-lede lead">
|
||||
<%= raw post.lede %>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<%= live_redirect raw("Read more…"), to: Routes.post_path(@socket, :show, post), class: "fs-6" %>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
|
@ -1,48 +0,0 @@
|
|||
defmodule Home73kWeb.PageLive do
|
||||
use Home73kWeb, :live_view
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok,
|
||||
assign(socket, query: "", results: %{}, page_title: "~")
|
||||
|> put_flash(:success, "Log in was a success. Good for you.")
|
||||
|> put_flash(:error, "Lorem ipsum dolor sit amet consectetur adipisicing elit.")
|
||||
|> put_flash(
|
||||
:info,
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatibus dolore sunt quia aperiam sint id reprehenderit? Dolore incidunt alias inventore accusantium nulla optio, ducimus eius aliquam hic, pariatur voluptate distinctio."
|
||||
)
|
||||
|> put_flash(:warning, "Oh no, there's nothing to worry about!")
|
||||
|> put_flash(:primary, "Something in the brand color.")}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("suggest", %{"q" => query}, socket) do
|
||||
{:noreply, assign(socket, results: search(query), query: query)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("search", %{"q" => query}, socket) do
|
||||
case search(query) do
|
||||
%{^query => vsn} ->
|
||||
{:noreply, redirect(socket, external: "https://hexdocs.pm/#{query}/#{vsn}")}
|
||||
|
||||
_ ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, "No dependencies found matching \"#{query}\"")
|
||||
|> assign(results: %{}, query: query)}
|
||||
end
|
||||
end
|
||||
|
||||
defp search(query) do
|
||||
if not Home73kWeb.Endpoint.config(:code_reloader) do
|
||||
raise "action disabled when not in development"
|
||||
end
|
||||
|
||||
for {app, desc, vsn} <- Application.started_applications(),
|
||||
app = to_string(app),
|
||||
String.starts_with?(app, query) and not List.starts_with?(desc, ~c"ERTS"),
|
||||
into: %{},
|
||||
do: {app, vsn}
|
||||
end
|
||||
end
|
|
@ -1,48 +0,0 @@
|
|||
<section class="phx-hero">
|
||||
<h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
|
||||
<p>Peace of mind from prototype to production</p>
|
||||
|
||||
<form phx-change="suggest" phx-submit="search">
|
||||
<input type="text" name="q" value="<%= @query %>" placeholder="Live dependency search" list="results" autocomplete="off"/>
|
||||
<datalist id="results">
|
||||
<%= for {app, _vsn} <- @results do %>
|
||||
<option value="<%= app %>"><%= app %></option>
|
||||
<% end %>
|
||||
</datalist>
|
||||
<button type="submit" phx-disable-with="Searching...">Go to Hexdocs</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="row">
|
||||
<article class="column">
|
||||
<h2>Resources</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://hexdocs.pm/phoenix/overview.html">Guides & Docs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/phoenixframework/phoenix">Source</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/phoenixframework/phoenix/blob/v1.5/CHANGELOG.md">v1.5 Changelog</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
<article class="column">
|
||||
<h2>Help</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://elixirforum.com/c/phoenix-forum">Forum</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://webchat.freenode.net/?channels=elixir-lang">#elixir-lang on Freenode IRC</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://twitter.com/elixirphoenix">Twitter @elixirphoenix</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://elixir-slackin.herokuapp.com/">Elixir on Slack</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
61
lib/home73k_web/live/post_live.ex
Normal file
61
lib/home73k_web/live/post_live.ex
Normal file
|
@ -0,0 +1,61 @@
|
|||
defmodule Home73kWeb.PostLive do
|
||||
use Home73kWeb, :live_view
|
||||
|
||||
alias Home73k.Blog
|
||||
|
||||
@impl true
|
||||
def mount(%{"id" => id}, session, socket) do
|
||||
# IO.inspect(params, label: "postlive params")
|
||||
IO.inspect(session, label: "postlive session")
|
||||
|
||||
post = Blog.get_post_by_id!(id)
|
||||
|
||||
socket
|
||||
|> assign(:page_title, "Blog \\ #{post.title}")
|
||||
|> assign(:post, post)
|
||||
|> live_okreply()
|
||||
end
|
||||
|
||||
# @impl true
|
||||
# def handle_params(params, _url, socket) do
|
||||
# socket
|
||||
# |> assign(:page_title, "Blog")
|
||||
# |> assign(:posts, Blog.list_posts())
|
||||
# |> live_noreply()
|
||||
# end
|
||||
|
||||
# @impl true
|
||||
# def handle_event("suggest", %{"q" => query}, socket) do
|
||||
# {:noreply, assign(socket, results: search(query), query: query)}
|
||||
# end
|
||||
|
||||
# @impl true
|
||||
# def handle_event("search", %{"q" => query}, socket) do
|
||||
# case search(query) do
|
||||
# %{^query => vsn} ->
|
||||
# {:noreply, redirect(socket, external: "https://hexdocs.pm/#{query}/#{vsn}")}
|
||||
|
||||
# _ ->
|
||||
# {:noreply,
|
||||
# socket
|
||||
# |> put_flash(:error, "No dependencies found matching \"#{query}\"")
|
||||
# |> assign(results: %{}, query: query)}
|
||||
# end
|
||||
# end
|
||||
|
||||
# defp search(query) do
|
||||
# if not Home73kWeb.Endpoint.config(:code_reloader) do
|
||||
# raise "action disabled when not in development"
|
||||
# end
|
||||
|
||||
# for {app, desc, vsn} <- Application.started_applications(),
|
||||
# app = to_string(app),
|
||||
# String.starts_with?(app, query) and not List.starts_with?(desc, ~c"ERTS"),
|
||||
# into: %{},
|
||||
# do: {app, vsn}
|
||||
# end
|
||||
|
||||
defp format_date(date) do
|
||||
Calendar.strftime(date, "%B %-d, %Y")
|
||||
end
|
||||
end
|
36
lib/home73k_web/live/post_live.html.leex
Normal file
36
lib/home73k_web/live/post_live.html.leex
Normal file
|
@ -0,0 +1,36 @@
|
|||
<main class="container d-flex justify-content-center">
|
||||
|
||||
<div class="col-12 col-md-10 col-lg-9 col-xl-8 col-xxl-7 pb-2 mb-4 mt-3">
|
||||
|
||||
<div class="post border-bottom border-gray pb-4 mb-3">
|
||||
|
||||
<h2 class="post-title fs-2 fw-normal mb-2"><%= raw @post.title %></h2>
|
||||
|
||||
<div class="post-date font-monospace text-gray-500 <%= if length(@post.tags) == 0, do: "mb-3" %>">
|
||||
<%= icon_div @socket, "mdi-calendar-clock", [class: "icon baseline"] %>
|
||||
<%= @post.date |> format_date() %>
|
||||
</div>
|
||||
|
||||
<%= if length(@post.tags) > 0 do %>
|
||||
<div class="post-tags fs-6 mb-3">
|
||||
<%= icon_div @socket, "mdi-tag-multiple", [class: "icon baseline"] %>
|
||||
<%= for {tag, i} <- Enum.with_index(@post.tags) do %>
|
||||
#<%= tag %><%= i < (length(@post.tags) - 1) && "," || "" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="post-lede lead">
|
||||
<%= raw @post.lede %>
|
||||
</div>
|
||||
|
||||
<div class="post-body">
|
||||
<%= raw @post.body %>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
|
@ -18,9 +18,12 @@ defmodule Home73kWeb.Router do
|
|||
pipe_through :browser
|
||||
|
||||
get "/", HomeController, :index
|
||||
get "/about", HomeController, :about
|
||||
get "/resume", HomeController, :resume
|
||||
get "/folio", HomeController, :folio
|
||||
live "/live", PageLive, :index
|
||||
live "/blog", BlogLive, :index
|
||||
# live "/blog/page/:page", BlogLive, :older
|
||||
live "/blog/:id", PostLive, :show
|
||||
end
|
||||
|
||||
# Other scopes may use custom stacks.
|
||||
|
|
48
lib/home73k_web/templates/home/about.html.eex
Normal file
48
lib/home73k_web/templates/home/about.html.eex
Normal file
|
@ -0,0 +1,48 @@
|
|||
<main class="container d-flex justify-content-center">
|
||||
|
||||
<div class="col-12 col-md-10 col-lg-8 col-xl-7 col-xxl-6 border-bottom border-gray pb-3 mb-5 mt-3">
|
||||
|
||||
<h2 class="fs-2 fw-600 mb-0">About</h2>
|
||||
|
||||
<div class="fs-5 font-monospace text-gray-500">Adam Piontek. Human.</div>
|
||||
|
||||
|
||||
<figure class="my-4 border-start border-gray border-5 ps-3 py-2">
|
||||
<blockquote class="blockquote">
|
||||
<p>“Probabilities collapse. I become increasingly unlikely.”</p>
|
||||
</blockquote>
|
||||
<figcaption class="blockquote-footer text-gray-400 mb-0">
|
||||
Robert Charles Wilson, <cite title="Divided by Infinity">Divided by Infinity</cite>
|
||||
</figcaption>
|
||||
</figure>
|
||||
|
||||
<div class="post-body">
|
||||
<p>
|
||||
From Minnesota, via California, now New York. I'm always learning, and I often think most things should slow down a little, though I'm still working on that practice for myself. I've been a tech nerd since my teens in the 1990s, but didn't begin to take it seriously until around 2009.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I'm now a Desktop Systems Engineer with a large global law firm, involved in desktop & mobile security, testing, deployment, and elevated user support.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I enjoy spending time with my many pets, talking science fiction & politics, going hiking, and tinkering with programming projects. I've written a few things I'm reasonably proud of — for work, for family, for myself — including this website!
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This site is powered by a custom little <%= link "Phoenix", to: "https://phoenixframework.org/" %> project hosted on a <%= link "Linode", to: "https://www.linode.com/" %> VPS, where I also run instances of <%= link "Gitea", to: "https://gitea.io/" %>, <%= link "Miniflux", to: "https://miniflux.app/" %>, <%= link "ZNC", to: "https://znc.in/" %>, <%= link "The Lounge", to: "https://thelounge.chat/" %>, <%= link "Calibre-Web", to: "https://github.com/janeczku/calibre-web" %>, <%= link "BicBucStriim", to: "https://projekte.textmulch.de/bicbucstriim/" %>, a little <%= link "hubot", to: "https://hubot.github.com/" %> for my family's group chat (Discord for now), and some other odds & ends.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
At home, between a plucky Raspberry Pi 4 running Ubuntu Linux, and a beefier Windows machine, I also run: <%= link "Jellyfin", to: "https://jellyfin.org/" %>, <%= link "Plex", to: "https://www.plex.tv/" %>, and several apps via Docker, including <%= link "audioserve", to: "https://github.com/izderadicka/audioserve" %>, <%= link "Komga", to: "https://komga.org/" %>, <%= link "Unifi Controller", to: "https://github.com/jacobalberty/unifi-docker" %>, and a group of others (like <%= link "transmission-openvpn", to: "https://hub.docker.com/r/haugene/transmission-openvpn/" %> and <%= link "nzbget", to: "https://hub.docker.com/r/linuxserver/nzbget" %> (Arr!))
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I'm very lucky to have some super amazing people in my life, always reminding me of how little I know, enabling beautiful experiences, and appreciating places and systems I otherwise wouldn't give a second thought to.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
|
@ -13,11 +13,11 @@
|
|||
|
||||
<div class="col-12 col-sm-10 col-md-7 col-lg-6 col-xl-5 col-xxl-4 justify-content-start ms-lg-3">
|
||||
|
||||
<h2 class="font-monospace fs-2 fw-600 mb-0">
|
||||
<h2 class="font-monospace fs-2 fw-500 mb-0">
|
||||
<%= icon_div @conn, "mdi-account-hard-hat", [class: "icon baseline me-2"] %><span>Working on it!</span>
|
||||
</h2>
|
||||
|
||||
<div class="font-monospace fs-5">I've made some things over the years (like this site!), and at some point I'll highlight some here.</div>
|
||||
<div class="font-monospace text-gray-200 fs-5">I've made some things over the years (like this site!), and at some point I'll highlight some here.</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
|
||||
<div class="col-auto justify-content-start ms-lg-3">
|
||||
|
||||
<h2 class="font-monospace fs-2 fw-600 mb-0">
|
||||
<h2 class="font-monospace fs-2 fw-500 mb-0">
|
||||
<%= icon_div @conn, "mdi-account", [class: "icon baseline me-2"] %><span>Adam Piontek</span>
|
||||
</h2>
|
||||
|
||||
<div class="font-monospace fs-5">Desktop Systems Engineer. Human.</div>
|
||||
<div class="font-monospace text-gray-500 fs-5">Desktop Systems Engineer. Human.</div>
|
||||
|
||||
<div id="social-icons" class="mt-1">
|
||||
<%= for s <- socials(@conn) do %>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<main class="container-fluid h-100 d-flex justify-content-center align-items-center">
|
||||
<main class="container-fluid d-flex justify-content-center align-items-center">
|
||||
|
||||
<div class="d-flex flex-column mt-5">
|
||||
|
||||
<div class="col-auto justify-content-start">
|
||||
|
||||
<h2 class="font-monospace fs-2 fw-600 mb-0">
|
||||
<h2 class="font-monospace fs-2 fw-500 mb-0">
|
||||
<%= icon_div @conn, "mdi-account", [class: "icon baseline me-2"] %><span>Adam Piontek</span>
|
||||
</h2>
|
||||
|
||||
<div class="font-monospace fs-5">Desktop Systems Engineer.</div>
|
||||
<div class="font-monospace text-gray-500 fs-5">Desktop Systems Engineer.</div>
|
||||
|
||||
<div id="social-icons" class="mt-1">
|
||||
<%= for s <- socials_prof(@conn) do %>
|
||||
|
@ -24,21 +24,21 @@
|
|||
|
||||
<div class="separator mt-4 mb-2">qualifications</div>
|
||||
|
||||
<ul>
|
||||
<ul class="text-gray-200">
|
||||
<%= for qualif <- resume_qualifs() do %>
|
||||
<%= content_tag :li, qualif %>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
<div class="separator mt-4 mb-2">experience</div>
|
||||
<div class="separator mt-4 mb-n2">experience</div>
|
||||
|
||||
<%= for %{employer: employer, positions: positions} <- resume_experience() do %>
|
||||
<div class="fs-5 border-bottom border-gray mt"><%= employer%></div>
|
||||
<div class="fs-5 border-bottom border-gray mt-3 mb-2"><%= employer%></div>
|
||||
<div class="mb-3">
|
||||
<%= for position <- positions do %>
|
||||
<div>
|
||||
<span><%= position.title %></span>
|
||||
<span class="text-gray-300">· <%= position.start %> — <%= position.end %></span>
|
||||
<span class="text-gray-200"><%= position.title %></span>
|
||||
<span class="text-gray-500">· <%= position.start %> — <%= position.end %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-dark px-1 px-sm-2 px-lg-3 px-xl-4 px-xxl-5 py-3">
|
||||
<nav class="navbar <%= if navbar_fixed?(@conn), do: "fixed-top" %> navbar-expand-lg navbar-dark bg-dark px-1 px-sm-2 px-lg-3 px-xl-4 px-xxl-5 py-3">
|
||||
<div class="container-fluid">
|
||||
|
||||
<h1 class="my-0 py-0 lh-base">
|
||||
<%= link to: Routes.home_path(@conn, :index), class: "navbar-brand fs-1 text-secondary" do %>
|
||||
<%= icon_div @conn, "mdi-desktop-classic", [class: "icon baseline"] %>
|
||||
<span class="fw-light" style="font-family: Righteous;">\\73k</span>
|
||||
<span class="fw-light font-brand">\\73k</span>
|
||||
<% end %>
|
||||
</h1>
|
||||
|
||||
|
@ -41,7 +41,13 @@
|
|||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<%= link nav_link_opts(@conn, to: Routes.page_path(@conn, :index), class: "nav-link font-monospace fs-6") do %>
|
||||
<%= link nav_link_opts(@conn, to: Routes.home_path(@conn, :about), class: "nav-link font-monospace fs-6") do %>
|
||||
<%= icon_div @conn, "mdi-information", [class: "icon baseline"] %><span>\About</span>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<%= link nav_link_opts(@conn, to: Routes.blog_path(@conn, :index), class: "nav-link font-monospace fs-6") do %>
|
||||
<%= icon_div @conn, "mdi-typewriter", [class: "icon baseline"] %><span>\Blog</span>
|
||||
<% end %>
|
||||
</li>
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
defmodule Home73kWeb.LayoutView do
|
||||
use Home73kWeb, :view
|
||||
|
||||
def navbar_fixed?(conn) do
|
||||
[Routes.home_path(conn, :index), Routes.home_path(conn, :folio)]
|
||||
|> Enum.member?(Phoenix.Controller.current_path(conn))
|
||||
end
|
||||
|
||||
def nav_link_opts(conn, opts) do
|
||||
case Keyword.get(opts, :to) == Phoenix.Controller.current_path(conn) do
|
||||
false -> opts
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue