diff --git a/.mise.toml b/.mise.toml new file mode 100644 index 0000000..6557d98 --- /dev/null +++ b/.mise.toml @@ -0,0 +1,4 @@ +[tools] +elixir="1.17.0" +erlang="27.0" +flyctl="0.1.104" diff --git a/.vscode/settings.json b/.vscode/settings.json index aa4fe4e..9edf5dc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,7 @@ { - "editor.defaultFormatter": "saratravi.elixir-formatter", + "files.associations": { + "*.heex": "phoenix-heex", + }, "emmet.includeLanguages": { "phoenix-heex": "html" }, @@ -10,7 +12,8 @@ "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[phoenix-heex]": { - "editor.defaultFormatter": "RoyalMist.vscode-eex-format" + "editor.formatOnSave": true, + "editor.defaultFormatter": "JakeBecker.elixir-ls" }, "grammarly.selectors": [ { diff --git a/Dockerfile b/Dockerfile index 4b59aaf..c61971b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,9 +12,9 @@ # - https://pkgs.org/ - resource for finding needed packages # - Ex: hexpm/elixir:1.13.4-erlang-25.0.4-debian-bullseye-20210902-slim # -ARG ELIXIR_VERSION=1.16.2 -ARG OTP_VERSION=26.2.3 -ARG DEBIAN_VERSION=buster-20240130-slim +ARG ELIXIR_VERSION=1.17.0 +ARG OTP_VERSION=27.0 +ARG DEBIAN_VERSION=buster-20240612-slim ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}" diff --git a/config/config.exs b/config/config.exs index 9aea051..c2c160a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -15,7 +15,7 @@ config :pepicrft, :metadata, github_url: "https://github.com/pepicrft", language: "en-us", twitter_handle: "@pepicrft", - mastodon_url: "https://mastodon.social/@pepicrft", + mastodon_url: "https://masto.pepicrft.me/@pedro", linkedin_url: "https://www.linkedin.com/in/pedro-pi%C3%B1era-buendia-9765a9125/", author: "Pedro Piñera" diff --git a/lib/pepicrft_web/components/core_components.ex b/lib/pepicrft_web/components/core_components.ex index e9fcfaa..a75dcfa 100644 --- a/lib/pepicrft_web/components/core_components.ex +++ b/lib/pepicrft_web/components/core_components.ex @@ -21,32 +21,22 @@ defmodule PepicrftWeb.CoreComponents do end ~H""" -
+
- """ - end - - def description(assigns) do - ~H""" -

- I created XcodeProj - and Tuist. My work is trusted by companies like Adidas, American Express, and Etsy. I enjoy building delightful tools for developers and open-source communities. -

+ """ end diff --git a/lib/pepicrft_web/components/layouts.ex b/lib/pepicrft_web/components/layouts.ex index c6f3d72..58ca6df 100644 --- a/lib/pepicrft_web/components/layouts.ex +++ b/lib/pepicrft_web/components/layouts.ex @@ -8,7 +8,4 @@ defmodule PepicrftWeb.Layouts do url = %{url | path: "/blog/feed.xml"} url |> URI.to_string() end - - def something do - end end diff --git a/lib/pepicrft_web/components/layouts/root.html.heex b/lib/pepicrft_web/components/layouts/root.html.heex index 3b9a1c1..64d8f1c 100644 --- a/lib/pepicrft_web/components/layouts/root.html.heex +++ b/lib/pepicrft_web/components/layouts/root.html.heex @@ -6,7 +6,6 @@ - @@ -27,29 +26,30 @@ -
- -
+
<%= @inner_content %>
- - diff --git a/lib/pepicrft_web/controllers/blog_html/show.html.heex b/lib/pepicrft_web/controllers/blog_html/show.html.heex index 40de686..70f3a5f 100644 --- a/lib/pepicrft_web/controllers/blog_html/show.html.heex +++ b/lib/pepicrft_web/controllers/blog_html/show.html.heex @@ -1,13 +1,8 @@ -<% {:ok, time_ago_date} = Elixir.Timex.Format.DateTime.Formatters.Relative.format(@post.date, "{relative}") %> -

<%= time_ago_date %>

+ +<% date_as_string = Timex.format!(@post.date, "%Y.%m.%d", :strftime) %>

<%= @post.title %>

+

<%= date_as_string %>

<%= raw @post.body %>
- - -
- About Pedro Piñera - <.description/> -
diff --git a/lib/pepicrft_web/controllers/home_controller.ex b/lib/pepicrft_web/controllers/home_controller.ex index 70b7677..5280a04 100644 --- a/lib/pepicrft_web/controllers/home_controller.ex +++ b/lib/pepicrft_web/controllers/home_controller.ex @@ -8,4 +8,28 @@ defmodule PepicrftWeb.HomeController do def about(conn, _params) do render(conn, :about) end + + def projects(conn, _params) do + render(conn, :projects) + end + + def feed(conn, _params) do + %{body: statuses} = + Req.get!("https://masto.pepicrft.me/api/v1/accounts/112545800553693985/statuses") + + render(conn, :feed, statuses: statuses) + end + + def photos(conn, _params) do + %{body: statuses} = + Req.get!( + "https://camera.pepicrft.me/api/pixelfed/v1/accounts/702760890334240769/statuses?only_media=true&min_id=1" + ) + + render(conn, :photos, statuses: statuses) + end + + def now(conn, _params) do + render(conn, :now) + end end diff --git a/lib/pepicrft_web/controllers/home_html/about.html.heex b/lib/pepicrft_web/controllers/home_html/about.html.heex index cd62d08..c349cd8 100644 --- a/lib/pepicrft_web/controllers/home_html/about.html.heex +++ b/lib/pepicrft_web/controllers/home_html/about.html.heex @@ -1,12 +1,12 @@

- About + About 🧑🏻‍💻

Hola 👋,

- I'm a Berlin-based builder. For the past ten years, I have been a hands-on and adaptable problem solver, collaborating with start-ups and e-commerce platforms and building open-source solutions like Tuist. I'm currently bootstrapping Tuist Cloud. + I'm a Berlin-based builder. For the past ten years, I have been a hands-on and adaptable problem solver, collaborating with start-ups and e-commerce platforms and building open-source solutions like Tuist. I'm currently working with Marek on turning Tuist into a sustainable business.

My work is trusted by Shopify, American Express, SoundCloud, Bloomberg, Stripe, Google, Monday, Just Eat, Etsy, and Adidas. diff --git a/lib/pepicrft_web/controllers/home_html/feed.html.heex b/lib/pepicrft_web/controllers/home_html/feed.html.heex new file mode 100644 index 0000000..e184eba --- /dev/null +++ b/lib/pepicrft_web/controllers/home_html/feed.html.heex @@ -0,0 +1,34 @@ +

+ Feed 📋 +

+ +
+ <%= for status <- @statuses do %> + <% content = status["content"] %> + <% media = status["media_attachments"] %> + <% url = status["url"] %> + <%= if String.trim(content) != "" do %> +
+ Link + <%= raw content %> + <%= if media != [] do %> +
+ <%= for m <- media do %> + <%= case m["type"] do %> + <% "gifv" -> %> + + <% _ -> %> + + {m["description"]} + + <% end %> + <% end %> +
+ <% end %> +
+
+ <% end %> + <% end %> +
diff --git a/lib/pepicrft_web/controllers/home_html/index.html.heex b/lib/pepicrft_web/controllers/home_html/index.html.heex index 683d5b9..f66cb7b 100644 --- a/lib/pepicrft_web/controllers/home_html/index.html.heex +++ b/lib/pepicrft_web/controllers/home_html/index.html.heex @@ -1,2 +1,4 @@ -<.description/> +

+ Writing ✏️ +

<.posts_component posts={Pepicrft.Blog.all_posts()}/> diff --git a/lib/pepicrft_web/controllers/home_html/now.html.heex b/lib/pepicrft_web/controllers/home_html/now.html.heex new file mode 100644 index 0000000..fff9b19 --- /dev/null +++ b/lib/pepicrft_web/controllers/home_html/now.html.heex @@ -0,0 +1,37 @@ +

+ Now +

+ +

+The following is a list of things that I'm doing, thinking about, or working on right now. +

+ +

+ Mental health +

+ +

I'm working on better understanding my emotions and reverting some anxiety-inducing habits that I've developed over the years.

+ + +

+ Work +

+

+I'm learning a lot about business while trying to build a company upon the open-source work that I've been doing for the past few years. It's a whole new world of ideas of concepts for me, but I'm quite liking it. It reminds me of my childhood working at my family cafe, but at a different scale. +

+ + +

+ The web platform +

+

+I haven't worked much with the web in the past, and whenever I did, it was mostly to build my personal website by using a template, a static site generator, and working with many abstractions (e.g. TailwindCSS). This time, I'm playing with the web in its most raw form–writing HTML, CSS, and JavaScript from scratch. I'm getting familiar with the semantics of HTML elements, as well as the common CSS properties. +

+ +

+ Elixir +

+ +

+As part of my work on Tuist, I'm learning a lot about Elixir, and the more I learn, the more I like it. I'm fascinated by the language's simplicity and the way it leverages the Erlang VM to build robust and fault-tolerant systems. I'm also learning about OTP, the framework that Elixir provides to build distributed systems. +

diff --git a/lib/pepicrft_web/controllers/home_html/photos.html.heex b/lib/pepicrft_web/controllers/home_html/photos.html.heex new file mode 100644 index 0000000..c5bb3ae --- /dev/null +++ b/lib/pepicrft_web/controllers/home_html/photos.html.heex @@ -0,0 +1,15 @@ +

+ Photos 📸 +

+ +
+ <%= for status <- @statuses do %> + <% %{"url" => url, "content" => content, "media_attachments" => [ %{"url" => image_url, "description" => image_alt} | _]} = status %> +
+

+ <%= content %> +

+ {image_alt}/ +
+ <% end %> +
diff --git a/lib/pepicrft_web/controllers/home_html/projects.html.heex b/lib/pepicrft_web/controllers/home_html/projects.html.heex new file mode 100644 index 0000000..860292a --- /dev/null +++ b/lib/pepicrft_web/controllers/home_html/projects.html.heex @@ -0,0 +1,32 @@ +

+ Projects 📦 +

+ +

+The following sections describe the projects that I created and/or that I contribute/d to. +

+ +

+ Tuist +

+ +

+Tuist is a Swifty toolchain to build better Apple apps faster. I created it in 2017, and we are currently working on building a long-term business around it by +

+ +

+ XcodeProj +

+ +

+XcodeProj is an open-source Swift package to read, update, and write Xcode projects. I created it in 2017 as part of Tuist, and it has become a popular library in the Swift community. +

+ + +

+ Shopify CLI +

+ +

+Shopify CLI I overhauled the tech stack of the Shopify CLI, which developers use to build for the platform, to align it with the platform's technologies. +

diff --git a/lib/pepicrft_web/router.ex b/lib/pepicrft_web/router.ex index 54df444..a5b4167 100644 --- a/lib/pepicrft_web/router.ex +++ b/lib/pepicrft_web/router.ex @@ -19,10 +19,14 @@ defmodule PepicrftWeb.Router do end scope "/", PepicrftWeb do - pipe_through :browser + pipe_through [:browser, :put_current_url] get "/", HomeController, :index get "/about", HomeController, :about + get "/projects", HomeController, :projects + get "/feed", HomeController, :feed + get "/photos", HomeController, :photos + get "/now", HomeController, :now get "/blog/:year/:month/:day/:title", BlogController, :show for page <- Pepicrft.Pages.all_pages() do @@ -69,4 +73,8 @@ defmodule PepicrftWeb.Router do forward "/mailbox", Plug.Swoosh.MailboxPreview end end + + def put_current_url(conn, _params) do + Plug.Conn.assign(conn, :request_path, conn.request_path) + end end diff --git a/mix.exs b/mix.exs index 8134411..b04e264 100644 --- a/mix.exs +++ b/mix.exs @@ -69,7 +69,8 @@ defmodule Pepicrft.MixProject do {:phoenix_html_sanitizer, "~> 1.1.1"}, {:image, "~> 0.48.0"}, {:file_system, "~> 0.2"}, - {:remote_ip, "~> 1.1"} + {:remote_ip, "~> 1.1"}, + {:req, "~> 0.5.0"} ] end diff --git a/mix.lock b/mix.lock index 150a352..1a65ddf 100644 --- a/mix.lock +++ b/mix.lock @@ -18,9 +18,11 @@ "ex_doc": {:hex, :ex_doc, "0.34.0", "ab95e0775db3df71d30cf8d78728dd9261c355c81382bcd4cefdc74610bef13e", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "60734fb4c1353f270c3286df4a0d51e65a2c1d9fba66af3940847cc65a8066d7"}, "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"}, "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"}, "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, + "hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"}, "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "abfb393ad888d57700f4d0f119c2643c8a9d98856f9b8a92001be7efad1419d6"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "image": {:hex, :image, "0.48.0", "a9dbe8fa4f2ff803c1263128dc186ac5705adeafd9f8ab4baa666070150867fb", [:mix], [{:bumblebee, "~> 0.3", [hex: :bumblebee, repo: "hexpm", optional: true]}, {:evision, "~> 0.1.33", [hex: :evision, repo: "hexpm", optional: true]}, {:exla, "~> 0.5", [hex: :exla, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:kino, "~> 0.11", [hex: :kino, repo: "hexpm", optional: true]}, {:nx, "~> 0.5", [hex: :nx, repo: "hexpm", optional: true]}, {:nx_image, "~> 0.1", [hex: :nx_image, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.1 or ~> 3.2 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: true]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: true]}, {:rustler, "> 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: false]}, {:vix, "~> 0.23", [hex: :vix, repo: "hexpm", optional: false]}], "hexpm", "fb3a8aab8d6377e9aa9541e4a42f9ddc95cab125c9fe05f6c8e21889acf2f5cc"}, @@ -32,9 +34,12 @@ "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, + "mint": {:hex, :mint, "1.6.1", "065e8a5bc9bbd46a41099dfea3e0656436c5cbcb6e741c80bd2bad5cd872446f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4fc518dcc191d02f433393a72a7ba3f6f94b101d094cb6bf532ea54c89423780"}, "mochiweb": {:hex, :mochiweb, "2.22.0", "f104d6747c01a330c38613561977e565b788b9170055c5241ac9dd6e4617cba5", [:rebar3], [], "hexpm", "cbbd1fd315d283c576d1c8a13e0738f6dafb63dc840611249608697502a07655"}, "modulex": {:hex, :modulex, "0.7.0", "f25dfb787f432a936815fe6b824fc85c008d83278554a58fb3825c2e85333b0d", [:mix], [{:boundary, "~> 0.10", [hex: :boundary, repo: "hexpm", optional: false]}], "hexpm", "34033198548fd01b82575d3caaa9f6bf56edc54228a6ecb86898fdcf26175e68"}, + "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "nimble_publisher": {:git, "https://github.com/dashbitco/nimble_publisher", "5d35d42493b94b35f1ccec39da640cf8b69acc95", [ref: "5d35d42493b94b35f1ccec39da640cf8b69acc95"]}, "pandex": {:hex, :pandex, "0.2.0", "d100a16fd4c510722fcd9306f9a3abfe017251b6d9b78bf101726ea4d998b7ab", [:mix], [], "hexpm", "a68b16a634ccd94d2c3791d6d44d670b459b2e0a5ecefb3d3bdcc065dc442f4b"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, @@ -53,6 +58,7 @@ "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "remote_ip": {:hex, :remote_ip, "1.1.0", "cb308841595d15df3f9073b7c39243a1dd6ca56e5020295cb012c76fbec50f2d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "616ffdf66aaad6a72fc546dabf42eed87e2a99e97b09cbd92b10cc180d02ed74"}, + "req": {:hex, :req, "0.5.0", "6d8a77c25cfc03e06a439fb12ffb51beade53e3fe0e2c5e362899a18b50298b3", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "dda04878c1396eebbfdec6db6f3d4ca609e5c8846b7ee88cc56eb9891406f7a3"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"}, "swoosh": {:hex, :swoosh, "1.16.7", "9dd0c172b4519a023f58e94d3ea79480b469dd4c0cd5369fabfbfd2e39bf5545", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.1.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "21073982816cff3410e90c0d80ebfd5a0bf4839c7b39db20bc69a6df123bbf35"}, diff --git a/priv/posts/2024-05-20-blue-ocean-company.md b/priv/posts/2024-05-20-blue-ocean-company.md deleted file mode 100644 index de346fa..0000000 --- a/priv/posts/2024-05-20-blue-ocean-company.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "Building a blue ocean company" -description: "Traditionally, companies try to outcompete others in existing red ocean markets. However, we are building Tuist to be a blue ocean company, focusing on creating value through innovation" -tags: ["Business", "Tuist"] ---- - -As a business founder, I noticed it’s common to look at a business through the lenses of outcompeting companies in an existing market. Often companies do so through a better value-cost tradeoff. However, I notice that it’s not an approach that aligns with me because it often leads to little innovation and cargo-culting solutions without questioning whether they are still relevant. - -I believe this is the common approach to creating businesses when they are backed by investment. Investors need certainty, and there’s nothing like the certainty of knowing a given market and the value in it. The idea of redefining or defining a market sounds risky. But not for us. **We’d like [Tuist](https://tuist.io) to be a blue ocean company.** - -For us, growth follows great ideas and a true passion for the craft. When growth is the main goal, you likely find yourself lost shooting at the moon trying to create problems and needs and convincing people that they have them. But **when the focus is on the problem and the craft, a lot of wonderful things happen.** Not only they can unlock new growth opportunities, but they turn you into a company that can sustain better long-term. - -I find a lot of joy in experiencing growth following innovative craft. - -We are shaping the Tuist environment to be a space for innovation. I spend time looking at what happens in other ecosystems with curiosity, and wondering how those ideas could cross-pollinate into the Apple ecosystem. The connection of ideas also leads to new unique ideas that had never been seen before, and that’s beautiful. I also love challenging solutions that, despite being far from ideal in terms of development, became the norm and no one dares to present an alternative. For example, developers in the Apple ecosystem love writing Swift, *so why are we still writing CI pipelines in YAML or automation in Ruby?* Those are questions that I love to ask myself. And you know what, I'm not afraid to challenge the status quo. Nor do we have a superior entity that we need to justify our decisions. We are free to innovate and create new market opportunities. - -Being able to devote my full time to Tuist is one of the best things that has happened to me in the past year, -and I don't regret a single day of it. diff --git a/priv/posts/2024-06-12-mental-breakdowns.md b/priv/posts/2024-06-12-mental-breakdowns.md index a61dfe9..b20497c 100644 --- a/priv/posts/2024-06-12-mental-breakdowns.md +++ b/priv/posts/2024-06-12-mental-breakdowns.md @@ -39,3 +39,11 @@ At which moment did I deprioritize it? How do you deal with emotional breakdowns? + +```language-elixir +defmodule Tuist do + def run do + IO.puts("Tuist is running") + end +end +``` diff --git a/priv/static/styles/app.css b/priv/static/styles/app.css index efe114a..d78a293 100644 --- a/priv/static/styles/app.css +++ b/priv/static/styles/app.css @@ -1,20 +1,7 @@ @import "./openprops.css"; @import "./base.css"; -@import "./root.css"; +@import "./layout.css"; @import "./blog.css"; - -/* -The styling of this website follows the Enduring CSS methodology, https://ecss.benfrain.com, -using variables from Open Props, https://open-props.style. - -As a cheatsheet, the naming convention for Enduring CSS is: - -.[namespace][-ModuleOrComponent][_ChildNode][-variant] -*/ - -:root { - font-family: "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica", "Arial", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - font-size: var(--font-size-3); - line-height: var(--font-lineheight-2); -} - +@import "./feed.css"; +@import "./photos.css"; +@import "./core_components.css"; diff --git a/priv/static/styles/base.css b/priv/static/styles/base.css index 08a115f..346ec1b 100644 --- a/priv/static/styles/base.css +++ b/priv/static/styles/base.css @@ -1,32 +1,90 @@ +/* +The styling of this website follows the Enduring CSS methodology, https://ecss.benfrain.com, +using variables from Open Props, https://open-props.style. + +As a cheatsheet, the naming convention for Enduring CSS is: + +.[namespace][-ModuleOrComponent][_ChildNode][-variant] +*/ + +:root { + font-family: "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica", "Arial", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-size: var(--font-size-1); + line-height: var(--font-lineheight-2); + color: var(--gray-12); +} + +@media (prefers-color-scheme: dark) { + :root { + color: white; + background-color: var(--gray-12); + } +} + a { - color: var(--indigo-9); + color: var(--gray-12); + + &:visited { + color: var(--gray-12); + } +} + +@media (prefers-color-scheme: dark) { + a { + color: white; + + &:visited { + color: white; + } + } } h1 { - margin-top: var(--size-10); - margin-bottom: var(--size-6); - font-size: var(--font-size-5); - font-weight: var(--font-weight-7) + margin-top: 0px; + margin-bottom: var(--size-2); + font-size: var(--font-size-1); + font-weight: var(--font-weight-6); + + & a { + text-decoration: none; + &:hover { + text-decoration: underline; + } + } } h2 { - margin-top: var(--size-8); - margin-bottom: var(--size-6); - font-size: var(--font-size-3); - font-weight: var(--font-weight-6) + margin-bottom: var(--size-1); + margin-bottom: var(--size-1); + font-size: var(--font-size-1); + font-weight: var(--font-weight-6); + + & a { + text-decoration: none; + &:hover { + text-decoration: underline; + } + } } h3 { - margin-top: var(--size-6); - margin-bottom: var(--size-6); - font-size: var(--font-size-3); - font-weight: var(--font-weight-5) + margin-top: var(--size-3); + margin-bottom: var(--size-3); + font-size: var(--font-size-1); + font-weight: var(--font-weight-5); + + & a { + text-decoration: none; + &:hover { + text-decoration: underline; + } + } } h4 { margin-top: var(--size-4); margin-bottom: var(--size-4); - font-size: var(--font-size-3); + font-size: var(--font-size-1); font-weight: var(--font-weight-4) } @@ -34,7 +92,6 @@ p { margin-top: var(--size-3); margin-bottom: var(--size-3); font-weight: var(--font-weight-4); - font-size: var(--font-size-1); } b { diff --git a/priv/static/styles/blog.css b/priv/static/styles/blog.css index 9fcc6ec..7d2424d 100644 --- a/priv/static/styles/blog.css +++ b/priv/static/styles/blog.css @@ -1,99 +1,52 @@ .pp-Posts { + margin-block-start: 0px; + margin-block-end: 0px; + padding-left: 0px; + display: flex; + flex-direction: column; + & > * + * { - margin-top: var(--size-7) + margin-top: var(--size-2); } } -.pp-PostItem_Link { +.pp-PostItem { display: block; text-decoration: none; - box-shadow: var(--shadow-2); -} - -.pp-PostItem { - padding: var(--size-4); - border-style: solid; - border-color: var(--gray-4); - border-width: var(--border-size-1); - - & > * + * { - margin-top: var(--size-2) - } } -@media(prefers-color-scheme: dark) { - .pp-PostItem { - border-color: var(--gray-9); - } +.pp-PostItem__Link { + display: flex; + flex-direction: row; + gap: var(--size-4); + text-decoration: none; } .pp-PostItem_Title { margin-bottom: var(--size-1); - text-align: center; + text-align: start; text-decoration: none; - color: black; -} + font-weight: var(--font-weight-4); -@media(prefers-color-scheme: dark) { - .pp-PostItem_Title { - color: white; + &:hover { + text-decoration: underline; } } .pp-PostItem_Date { - font-size: 0.80rem; text-align: center; - color: var(--gray-7); -} - -@media(prefers-color-scheme: dark) { - .pp-PostItem_Date { - color: var(--gray-4); - } -} - -.pp-PostItem_Description { - color: black; -} - -@media(prefers-color-scheme: dark) { - .pp-PostItem_Description { - color: var(--gray-6); - } + font-weight: var(--font-weight-3); } .pp-Post_Title { - margin-top: var(--size-1); - text-align: center; - letter-spacing: -0.02em; -} -@media(prefers-color-scheme: dark) { - .pp-Post_Title { - color: white; - } + text-align: start; } .pp-Post_TimeAgo { - text-align: center; - font-size: var(--font-size-0); + margin-top: 0px; + text-align: start; margin-bottom: var(--size-1); - color: var(--gray-8) -} - -@media(prefers-color-scheme: dark) { - .pp-Post_TimeAgo { - color: var(--gray-4); - } -} - -.pp-Post_Body { - margin-top: var(--size-8); -} - -@media(prefers-color-scheme: dark) { - .pp-Post_Body { - color: var(--gray-4); - } + font-weight: var(--font-weight-3); } .pp-Blog_About-Title { @@ -102,5 +55,4 @@ text-transform: uppercase; text-decoration: none; font-size: 0.85rem; - color: var(--gray-7); } diff --git a/priv/static/styles/bundle.css b/priv/static/styles/bundle.css deleted file mode 100644 index 8b13789..0000000 --- a/priv/static/styles/bundle.css +++ /dev/null @@ -1 +0,0 @@ - diff --git a/priv/static/styles/core_components.css b/priv/static/styles/core_components.css new file mode 100644 index 0000000..e69de29 diff --git a/priv/static/styles/feed.css b/priv/static/styles/feed.css new file mode 100644 index 0000000..4ec602b --- /dev/null +++ b/priv/static/styles/feed.css @@ -0,0 +1,68 @@ +.pp-Feed-List { + & > * + * { + margin-top: var(--size-4); + } + + & hr { + border: none; + border-top: 1px dotted transparent; /* Make the default border transparent */ + color: #fff; + background-color: #fff; + height: 1px; + width: 50%; + margin: 0; /* Remove default margins */ + text-align: left; /* Ensure text (or other elements) align left */ + background: repeating-linear-gradient( + to right, + var(--gray-12) 0, + var(--gray-12) 2px, + /* Length of the dot */ transparent 2px, + transparent 10px /* Space between dots */ + ); + } +} + +@media (prefers-color-scheme: dark) { + .pp-Feed-List { + & hr { + background: repeating-linear-gradient( + to right, + white 0, + white 2px, + /* Length of the dot */ transparent 2px, + transparent 10px /* Space between dots */ + ); + } + } +} + +.pp-Feed-List_Post { + margin: var(--size-4) 0px; + display: flex; + flex-direction: column; + align-items: start; + word-wrap: break-word; + + & .invisible { + display: none; + } +} + +.pp-Feed-List_Post_Link { + align-self: end; + font-weight: var(--font-weight-4); +} + +.pp-Feed-List_Post_Media { + display: grid; + gap: var(--size-2); + grid-template-columns: repeat(4, 1fr); +} + +.pp-Feed-List_Post_Media_Image { + width: 100%; + object-fit: contain; + border-style: solid; + border-width: 1px; + border-color: black; +} diff --git a/priv/static/styles/layout.css b/priv/static/styles/layout.css new file mode 100644 index 0000000..b8316cb --- /dev/null +++ b/priv/static/styles/layout.css @@ -0,0 +1,119 @@ +@media (width >= 768px) { + .pp-Body { + max-width: var(--size-md); + margin-left: auto; + margin-right: auto; + padding-top: var(--size-5); + } +} + +.pp-Body { + max-width: var(--size-md); + margin-left: auto; + margin-right: auto; + padding: var(--size-5); + display: flex; + flex-direction: row; + align-items: flex-start; + + & > * + * { + margin-left: var(--size-6); + } +} + +.pp-Main { + flex: 1; + display: flex; + flex-direction: column; + align-items: stretch; + max-width: 100%; + margin-left: 0px; + margin-top: 0px; + margin-left: var(--size-6); + gap: var(--size-2); +} + +@media (max-width: 1024px) { + .pp-Main { + margin-left: 0px; + padding-bottom: var(--size-10); + } +} + +.pp-Navigation { + text-wrap: nowrap; + display: flex; + flex: 0; + flex-direction: column; + height: auto; + gap: var(--size-4) +} + +@media (max-width: 1024px) { + .pp-Navigation { + border-width: 1px 0px 0px 0px; + border-style: solid; + border-color: var(--gray-12); + background-color: white; + z-index: 20; + position: fixed; + left: 0px; + right: 0px; + bottom: 0px; + display: flex; + flex-direction: row; + padding: var(--size-3) 0px; + overflow-x: scroll; + + &::-webkit-scrollbar { + display: none; + } + } +} + +@media (prefers-color-scheme: dark) { + .pp-Navigation { + border-color: white; + background-color: var(--gray-12); + } +} + +.pp-Navigation_List { + display: grid; + grid-template-columns: 1fr 10px; + gap: 0px; + margin-top: 0px; + margin-bottom: 0px; +} + +@media (max-width: 1024px) { + .pp-Navigation_List { + padding-inline-start: var(--size-4); + padding-inline-end: var(--size-4); + display: flex; + flex-direction: row; + gap: var(--size-4); + } +} + +.pp-Navigation_List_Link { + justify-self: end; + text-decoration: none; + + &:hover { + text-decoration: underline; + } +} + +.pp-Navigation_List_Title { + display: block; + text-align: end; + text-decoration: none; + font-weight: 600; +} + +@media (max-width: 1024px) { + .pp-Navigation_List_Arrow { + display: none; + } +} diff --git a/priv/static/styles/photos.css b/priv/static/styles/photos.css new file mode 100644 index 0000000..56ffc97 --- /dev/null +++ b/priv/static/styles/photos.css @@ -0,0 +1,4 @@ +.pp-Photos_Image { + max-width: 100%; + object-fit: fill; +} diff --git a/priv/static/styles/root.css b/priv/static/styles/root.css deleted file mode 100644 index d5032be..0000000 --- a/priv/static/styles/root.css +++ /dev/null @@ -1,92 +0,0 @@ -@media (width >= 768px) { - .pp-Body { - max-width: var(--size-md); - margin-left: auto; - margin-right: auto; - padding-top: var(--size-5); - } -} - -.pp-Body { - max-width: var(--size-md); - margin-left: auto; - margin-right: auto; - padding: var(--size-5); - - & > * + * { - margin-top: var(--size-6); - } -} - -@media(prefers-color-scheme: dark) { - .pp-Body { - background-color: var(--gray-11); - } -} - -.pp-Main { - & > * + * { - margin-top: var(--size-7); - } -} - -.pp-Header_Navigation { - display: flex; - flex-direction: column; - align-items: center; - - /* & :first-child { - margin-right: auto; - } */ - - & > * + * { - margin-top: 0.75rem; - } -} - -.pp-Header_Navigation-Avatar { - height: var(--size-8); - border-radius: 50%; -} - -.pp-Header_Navigation-Title { - display: block; - text-transform: uppercase; - text-decoration: none; - font-size: 0.85rem; - color: var(--gray-7); -} - -@media(prefers-color-scheme: dark) { - .pp-Header_Navigation-Title { - color: var(--gray-3); - } -} - -.pp-Header_Navigation-Description { - color: var(--gray-7); - font-size: 0.85rem; - text-align: center; - -} - -@media(prefers-color-scheme: dark) { - .pp-Header_Navigation-Description { - color: var(--gray-3); - } -} - -.pp-Footer_Navigation { - display: flex; - justify-content: center; - flex-direction: row; - font-size: var(--font-size-1); - padding-top: var(--size-8); - - & > * + * { - margin-left: 0.75rem; - } -} - -.pp-Footer_Navigation-Item { -}