From e59536446c44e205e8198cf56e03b92c52397146 Mon Sep 17 00:00:00 2001 From: sloane Date: Fri, 8 Nov 2024 08:34:44 -0500 Subject: [PATCH 1/3] refactor: change tooling --- .formatter.exs | 5 -- .gitignore | 37 ++------ .mise.toml | 2 + .tool-versions | 3 - README.md | 24 +++-- assets/css/app.css | 17 ---- assets/js/app.js | 0 assets/tailwind.config.js | 28 ------ config/config.exs | 22 ----- lib/mix/tasks/site.build.ex | 15 ---- lib/mix/tasks/site.dev.ex | 37 -------- lib/mix/tasks/site.serve.ex | 28 ------ lib/mix/tasks/site.watch.ex | 28 ------ lib/sloane_sh.ex | 31 ------- lib/sloane_sh/asset.ex | 26 ------ lib/sloane_sh/assets/image.ex | 42 --------- lib/sloane_sh/assets/markdown.ex | 88 ------------------- lib/sloane_sh/assets/page.ex | 3 - lib/sloane_sh/assets/post.ex | 12 --- lib/sloane_sh/build.ex | 31 ------- lib/sloane_sh/config.ex | 37 -------- lib/sloane_sh/context.ex | 59 ------------- lib/sloane_sh/format.ex | 34 ------- lib/sloane_sh/front_matter.ex | 17 ---- lib/sloane_sh/layouts.ex | 43 --------- lib/sloane_sh/layouts/helpers.ex | 67 -------------- lib/sloane_sh/layouts/partials.ex | 36 -------- lib/sloane_sh/output_dirs.ex | 55 ------------ lib/sloane_sh/serve.ex | 21 ----- lib/sloane_sh/serve/plug.ex | 29 ------ lib/sloane_sh/watch.ex | 81 ----------------- mix.exs | 53 ----------- mix.lock | 39 -------- priv/site/images/heart.png | Bin 889 -> 0 bytes priv/site/layouts/page.html.eex | 4 - priv/site/layouts/post.html.eex | 5 -- priv/site/layouts/root.html.eex | 15 ---- priv/site/pages/home.md.eex | 29 ------ priv/site/pages/posts.html.eex | 11 --- priv/site/pages/search.html | 16 ---- priv/site/posts/2023-07-03-obsidianrc.md | 33 ------- priv/site/posts/2023-12-28-in-review-2023.md | 19 ---- priv/site/posts/2024-03-09-uses.md | 60 ------------- site/index.html.pm | 3 + site/index.ptree | 3 + site/pollen.rkt | 17 ++++ site/template.html.p | 10 +++ test/sloane_sh/front_matter_test.exs | 42 --------- test/sloane_sh_test.exs | 3 - test/test_helper.exs | 1 - 50 files changed, 59 insertions(+), 1262 deletions(-) delete mode 100644 .formatter.exs create mode 100644 .mise.toml delete mode 100644 .tool-versions delete mode 100644 assets/css/app.css delete mode 100644 assets/js/app.js delete mode 100644 assets/tailwind.config.js delete mode 100644 config/config.exs delete mode 100644 lib/mix/tasks/site.build.ex delete mode 100644 lib/mix/tasks/site.dev.ex delete mode 100644 lib/mix/tasks/site.serve.ex delete mode 100644 lib/mix/tasks/site.watch.ex delete mode 100644 lib/sloane_sh.ex delete mode 100644 lib/sloane_sh/asset.ex delete mode 100644 lib/sloane_sh/assets/image.ex delete mode 100644 lib/sloane_sh/assets/markdown.ex delete mode 100644 lib/sloane_sh/assets/page.ex delete mode 100644 lib/sloane_sh/assets/post.ex delete mode 100644 lib/sloane_sh/build.ex delete mode 100644 lib/sloane_sh/config.ex delete mode 100644 lib/sloane_sh/context.ex delete mode 100644 lib/sloane_sh/format.ex delete mode 100644 lib/sloane_sh/front_matter.ex delete mode 100644 lib/sloane_sh/layouts.ex delete mode 100644 lib/sloane_sh/layouts/helpers.ex delete mode 100644 lib/sloane_sh/layouts/partials.ex delete mode 100644 lib/sloane_sh/output_dirs.ex delete mode 100644 lib/sloane_sh/serve.ex delete mode 100644 lib/sloane_sh/serve/plug.ex delete mode 100644 lib/sloane_sh/watch.ex delete mode 100644 mix.exs delete mode 100644 mix.lock delete mode 100644 priv/site/images/heart.png delete mode 100644 priv/site/layouts/page.html.eex delete mode 100644 priv/site/layouts/post.html.eex delete mode 100644 priv/site/layouts/root.html.eex delete mode 100644 priv/site/pages/home.md.eex delete mode 100644 priv/site/pages/posts.html.eex delete mode 100644 priv/site/pages/search.html delete mode 100644 priv/site/posts/2023-07-03-obsidianrc.md delete mode 100644 priv/site/posts/2023-12-28-in-review-2023.md delete mode 100644 priv/site/posts/2024-03-09-uses.md create mode 100644 site/index.html.pm create mode 100644 site/index.ptree create mode 100644 site/pollen.rkt create mode 100644 site/template.html.p delete mode 100644 test/sloane_sh/front_matter_test.exs delete mode 100644 test/sloane_sh_test.exs delete mode 100644 test/test_helper.exs diff --git a/.formatter.exs b/.formatter.exs deleted file mode 100644 index 8ab6168..0000000 --- a/.formatter.exs +++ /dev/null @@ -1,5 +0,0 @@ -# Used by "mix format" -[ - inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"], - import_deps: [:typed_struct, :plug] -] diff --git a/.gitignore b/.gitignore index 33c53d6..054cd92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,7 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where third-party dependencies like ExDoc output generated docs. -/doc/ - -# Ignore .fetch files in case you like to edit your project deps locally. -/.fetch - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Ignore package tarball (built via "mix hex.build"). -sloane_sh-*.tar - -# Temporary files, for example, from tests. -/tmp/ - -/.elixir_ls/ - -/priv/output/ - .DS_Store + +compiled/ +/build/ + +*.html +*.css diff --git a/.mise.toml b/.mise.toml new file mode 100644 index 0000000..932e32a --- /dev/null +++ b/.mise.toml @@ -0,0 +1,2 @@ +[tools] +racket = "8.15" diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 7547e7c..0000000 --- a/.tool-versions +++ /dev/null @@ -1,3 +0,0 @@ -erlang 26.2.2 -elixir 1.16.1-otp-26 -nodejs 20.11.1 diff --git a/README.md b/README.md index 28e96c0..df8804c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,22 @@ -# SloaneSH - -_Sloane's personal static site generator powering [sloane.sh](https://sloane.sh)._ +# sloane.sh ## Setup -1. Clone the repo -2. Install Erlang and Elixir: `asdf install` -3. Install dependencies: `mix deps.get` +```sh +brew install --cask racket +raco pkg install pollen +``` +## Working on the site + +```sh +raco pollen start site +``` + +## Building the site + +```sh +mkdir -p build +raco pollen render site +raco pollen publish site build +``` diff --git a/assets/css/app.css b/assets/css/app.css deleted file mode 100644 index c7a0e25..0000000 --- a/assets/css/app.css +++ /dev/null @@ -1,17 +0,0 @@ -@import "tailwindcss/base"; -@import "tailwindcss/components"; -@import "tailwindcss/utilities"; - -body { - --pagefind-ui-border-width: 1px; -} - -@media (prefers-color-scheme: dark) { - #search { - --pagefind-ui-primary: #eeeeee; - --pagefind-ui-text: #eeeeee; - --pagefind-ui-background: rgb(64, 64, 64); - --pagefind-ui-border: rgb(163, 163, 163); - --pagefind-ui-tag: #152028; - } -} diff --git a/assets/js/app.js b/assets/js/app.js deleted file mode 100644 index e69de29..0000000 diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js deleted file mode 100644 index 15ebd3d..0000000 --- a/assets/tailwind.config.js +++ /dev/null @@ -1,28 +0,0 @@ -// See the Tailwind configuration guide for advanced usage -// https://tailwindcss.com/docs/configuration - -let plugin = require('tailwindcss/plugin') - -module.exports = { - content: [ - './js/**/*.js', - '../lib/sloane_sh/layouts/*.ex', - '../priv/site/**/*.*ex', - '../priv/site/**/*.md', - '../priv/site/**/*.html', - ], - theme: { - container: { - center: true, - }, - extend: {}, - }, - plugins: [ - require('@tailwindcss/forms'), - require('@tailwindcss/typography'), - plugin(({addVariant}) => addVariant('phx-no-feedback', ['&.phx-no-feedback', '.phx-no-feedback &'])), - plugin(({addVariant}) => addVariant('phx-click-loading', ['&.phx-click-loading', '.phx-click-loading &'])), - plugin(({addVariant}) => addVariant('phx-submit-loading', ['&.phx-submit-loading', '.phx-submit-loading &'])), - plugin(({addVariant}) => addVariant('phx-change-loading', ['&.phx-change-loading', '.phx-change-loading &'])) - ] -} diff --git a/config/config.exs b/config/config.exs deleted file mode 100644 index 7321caa..0000000 --- a/config/config.exs +++ /dev/null @@ -1,22 +0,0 @@ -import Config - -config :logger, :default_formatter, format: "$time $metadata[$level] $message\n" - -config :tailwind, - version: "3.4.1", - default: [ - args: ~w( - --config=tailwind.config.js - --input=css/app.css - --output=../priv/output/assets/css/app.css - ), - cd: Path.expand("../assets", __DIR__) - ] - -config :esbuild, - version: "0.20.1", - default: [ - args: ~w(js/app.js --bundle --outdir=../priv/output/assets/js), - cd: Path.expand("../assets", __DIR__), - env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} - ] diff --git a/lib/mix/tasks/site.build.ex b/lib/mix/tasks/site.build.ex deleted file mode 100644 index f93caf2..0000000 --- a/lib/mix/tasks/site.build.ex +++ /dev/null @@ -1,15 +0,0 @@ -defmodule Mix.Tasks.Site.Build do - @moduledoc "Build and output the site as HTML" - @shortdoc "build the site" - use Mix.Task - require Logger - - alias SloaneSH.Format - - @impl Mix.Task - def run(_args) do - Mix.Task.run("app.start") - {micro, :ok} = :timer.tc(&SloaneSH.build/0) - Logger.info("Built site in #{Format.time(micro)}") - end -end diff --git a/lib/mix/tasks/site.dev.ex b/lib/mix/tasks/site.dev.ex deleted file mode 100644 index 188f8d2..0000000 --- a/lib/mix/tasks/site.dev.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Mix.Tasks.Site.Dev do - @moduledoc "Build the site, watch for changes, and serve the built site" - @shortdoc "run site.watch and site.serve" - use Mix.Task - - @impl Mix.Task - def run(_args) do - Mix.Task.run("app.start") - - {:ok, watch_pid} = - Task.start_link(fn -> - Mix.Task.run("site.watch") - end) - - {:ok, serve_pid} = - Task.start_link(fn -> - Mix.Task.run("site.serve") - end) - - unless iex_running?() do - watch_ref = Process.monitor(watch_pid) - serve_ref = Process.monitor(serve_pid) - - receive do - {:DOWN, ^watch_ref, _, _, _} -> - :ok - - {:DOWN, ^serve_ref, _, _, _} -> - :ok - end - end - end - - defp iex_running? do - Code.ensure_loaded?(IEx) and IEx.started?() - end -end diff --git a/lib/mix/tasks/site.serve.ex b/lib/mix/tasks/site.serve.ex deleted file mode 100644 index 34a9d12..0000000 --- a/lib/mix/tasks/site.serve.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule Mix.Tasks.Site.Serve do - @moduledoc "Serve the built site. Only for use in development" - @shortdoc "serve the built site" - use Mix.Task - require Logger - - @impl Mix.Task - def run(_args) do - Mix.Task.run("app.start") - Logger.info("Starting development server...") - - {:ok, pid} = SloaneSH.serve() - - unless iex_running?() do - ref = Process.monitor(pid) - - receive do - {:DOWN, ^ref, _, _, _} -> - Logger.info("Development server terminated") - :ok - end - end - end - - defp iex_running? do - Code.ensure_loaded?(IEx) and IEx.started?() - end -end diff --git a/lib/mix/tasks/site.watch.ex b/lib/mix/tasks/site.watch.ex deleted file mode 100644 index 02c71fe..0000000 --- a/lib/mix/tasks/site.watch.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule Mix.Tasks.Site.Watch do - @moduledoc "Build and output the site as HTML watching for changes" - @shortdoc "build the site and watch for changes" - use Mix.Task - require Logger - - @impl Mix.Task - def run(_args) do - Mix.Task.run("app.start") - Logger.info("Starting site.watch...") - - {:ok, pid} = SloaneSH.watch() - - unless iex_running?() do - ref = Process.monitor(pid) - - receive do - {:DOWN, ^ref, _, _, _} -> - Logger.info("site.watch terminated") - :ok - end - end - end - - defp iex_running? do - Code.ensure_loaded?(IEx) and IEx.started?() - end -end diff --git a/lib/sloane_sh.ex b/lib/sloane_sh.ex deleted file mode 100644 index 3e90d5d..0000000 --- a/lib/sloane_sh.ex +++ /dev/null @@ -1,31 +0,0 @@ -defmodule SloaneSH do - @moduledoc """ - Sloane's personal static site generator powering [sloane.sh](https://sloane.sh). - """ - - alias SloaneSH.Build - alias SloaneSH.Context - alias SloaneSH.Serve - alias SloaneSH.Watch - - def build(_opts \\ []) do - context() - |> Build.run() - - :ok - end - - def watch(_opts \\ []) do - context() - |> Watch.start_link() - end - - def serve do - context() - |> Serve.start_link() - end - - def context do - Context.new() - end -end diff --git a/lib/sloane_sh/asset.ex b/lib/sloane_sh/asset.ex deleted file mode 100644 index 63fca9f..0000000 --- a/lib/sloane_sh/asset.ex +++ /dev/null @@ -1,26 +0,0 @@ -defmodule SloaneSH.Asset do - use TypedStruct - alias SloaneSH.Config - alias SloaneSH.Context - - typedstruct do - field :mod, module(), enforce: true - field :src, String.t(), enforce: true - field :src_contents, binary(), enforce: true - field :attrs, map(), enforce: true - end - - @callback extensions(cfg :: Config.t()) :: [String.t()] - - @callback attrs(cfg :: Config.t(), path :: String.t(), data :: binary()) :: - {:ok, map(), without_attrs :: term()} | {:ok, map()} | :error | {:error, term()} - - @callback render( - cfg :: Config.t(), - ctx :: Context.t(), - path :: String.t(), - data :: binary(), - attrs :: map() - ) :: - {:ok, [{dest :: String.t(), binary()}]} | :error | {:error, term()} -end diff --git a/lib/sloane_sh/assets/image.ex b/lib/sloane_sh/assets/image.ex deleted file mode 100644 index 1547660..0000000 --- a/lib/sloane_sh/assets/image.ex +++ /dev/null @@ -1,42 +0,0 @@ -defmodule SloaneSH.Assets.Image do - alias SloaneSH.Asset - alias SloaneSH.OutputDirs - - @behaviour Asset - - @impl Asset - def extensions(_cfg), do: ~w[.jpg .jpeg .png .webp .gif] - - @impl Asset - def attrs(_cfg, _path, data) do - {:ok, image} = Image.from_binary(data) - - aspect = Image.aspect(image) - {width, height, _} = Image.shape(image) - - {:ok, %{aspect: aspect, width: width, height: height}, image} - end - - @impl Asset - def render(cfg, _ctx, path, data, _attrs) do - formats = ~w[.webp .png .jpg] - - outputs = - for format <- formats do - format_path = OutputDirs.replace_ext(path, format) - output_path = OutputDirs.image(cfg, format_path) - - {:ok, converted} = - Image.write(data, :memory, - suffix: format, - strip_metadata: true, - minimize_file_size: true, - quality: 80 - ) - - {output_path, converted} - end - - {:ok, outputs} - end -end diff --git a/lib/sloane_sh/assets/markdown.ex b/lib/sloane_sh/assets/markdown.ex deleted file mode 100644 index 19ca77e..0000000 --- a/lib/sloane_sh/assets/markdown.ex +++ /dev/null @@ -1,88 +0,0 @@ -defmodule SloaneSH.Assets.Markdown do - @moduledoc """ - Helper to define markdown, html, and eex templating for pages and posts - """ - defmacro __using__(opts) do - type = Keyword.fetch!(opts, :type) - - quote do - import SloaneSH.Layouts.Helpers, warn: false - alias SloaneSH.Asset - alias SloaneSH.FrontMatter - alias SloaneSH.Layouts - alias SloaneSH.OutputDirs - - @behaviour Asset - - @impl Asset - def extensions(_cfg), do: ~w[.md .html .md.eex .html.eex] - - @impl Asset - def attrs(cfg, path, data) do - {:ok, attrs, without_attrs} = FrontMatter.parse(data) - - attrs = - Map.put_new_lazy(attrs, :permalink, fn -> - output = apply(OutputDirs, unquote(type), [cfg, path]) - permalink = OutputDirs.to_permalink(cfg, output) - end) - - attrs = handle_attrs(cfg, path, without_attrs, attrs) - - {:ok, attrs, without_attrs} - end - - @impl Asset - def render(cfg, ctx, path, data, attrs) do - output_path = - if attrs[:permalink] do - OutputDirs.from_permalink(cfg, attrs[:permalink]) - else - apply(OutputDirs, unquote(type), [cfg, path]) - end - - output = {output_path, do_render(ctx, path, data, attrs)} - {:ok, [output]} - end - - defp do_render(ctx, path, data, attrs) when is_binary(path) do - do_render(ctx, base_and_ext(path), data, attrs) - end - - defp do_render(ctx, {path, ".eex"}, data, attrs) do - eexed = eval_eex(data, "#{path}.eex", ctx, attrs) - do_render(ctx, base_and_ext(path), eexed, attrs) - end - - defp do_render(ctx, {path, ".md"}, data, attrs) do - html = Earmark.as_html!(data) - do_render(ctx, {path, ".html"}, html, attrs) - end - - defp do_render(ctx, {_path, ".html"}, data, attrs) do - apply(Layouts, unquote(type), [data, ctx, attrs]) - end - - defp base_and_ext(path) do - ext = Path.extname(path) - base = Path.basename(path, ext) - {base, ext} - end - - defp eval_eex(template, file, ctx, attrs) do - {result, _binding} = - template - |> EEx.compile_string(file: file) - |> Code.eval_quoted([ctx: ctx, attrs: attrs], __ENV__) - - result - end - - def handle_attrs(cfg, path, data, attrs) do - attrs - end - - defoverridable handle_attrs: 4 - end - end -end diff --git a/lib/sloane_sh/assets/page.ex b/lib/sloane_sh/assets/page.ex deleted file mode 100644 index 84065b7..0000000 --- a/lib/sloane_sh/assets/page.ex +++ /dev/null @@ -1,3 +0,0 @@ -defmodule SloaneSH.Assets.Page do - use SloaneSH.Assets.Markdown, type: :page -end diff --git a/lib/sloane_sh/assets/post.ex b/lib/sloane_sh/assets/post.ex deleted file mode 100644 index e09c69c..0000000 --- a/lib/sloane_sh/assets/post.ex +++ /dev/null @@ -1,12 +0,0 @@ -defmodule SloaneSH.Assets.Post do - use SloaneSH.Assets.Markdown, type: :post - require Logger - - def handle_attrs(_cfg, path, _data, attrs) do - unless Map.has_key?(attrs, :date) do - Logger.warning("Post missing date property: #{inspect(path)}") - end - - attrs - end -end diff --git a/lib/sloane_sh/build.ex b/lib/sloane_sh/build.ex deleted file mode 100644 index f8a7d97..0000000 --- a/lib/sloane_sh/build.ex +++ /dev/null @@ -1,31 +0,0 @@ -defmodule SloaneSH.Build do - require Logger - - alias SloaneSH.Context - - def run(%Context{} = ctx) do - assets = ctx.posts ++ ctx.pages ++ ctx.images - - File.mkdir_p!(ctx.config.output_dir) - - for asset <- assets do - case asset.mod.render(ctx.config, ctx, asset.src, asset.src_contents, asset.attrs) do - {:ok, output_files} -> - for {dest, content} <- output_files do - with :ok <- dest |> Path.dirname() |> File.mkdir_p(), - :ok <- File.write(dest, content) do - Logger.info("Wrote #{inspect(dest)}.") - else - {:error, err} -> - Logger.error("Failed to write #{inspect(dest)}, #{inspect(err)}") - end - end - - err -> - Logger.error("Failed to render #{inspect(asset.src)}, #{inspect(err)}") - end - end - - :ok - end -end diff --git a/lib/sloane_sh/config.ex b/lib/sloane_sh/config.ex deleted file mode 100644 index a616b2e..0000000 --- a/lib/sloane_sh/config.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule SloaneSH.Config do - @moduledoc """ - SloaneSH configuration - """ - use TypedStruct - - alias __MODULE__ - - typedstruct do - field :pages_dir, String.t(), enforce: true - field :posts_dir, String.t(), enforce: true - field :images_dir, String.t(), enforce: true - field :output_dir, String.t(), enforce: true - end - - def default do - priv = :code.priv_dir(:sloane_sh) |> resolve_link() - - %Config{ - pages_dir: Path.join(priv, "site/pages"), - posts_dir: Path.join(priv, "site/posts"), - images_dir: Path.join(priv, "site/images"), - output_dir: Path.join(priv, "output") - } - end - - defp resolve_link(path) do - case File.read_link(path) do - {:ok, link} -> - dir = Path.dirname(path) - Path.expand(link, dir) - - _ -> - path - end - end -end diff --git a/lib/sloane_sh/context.ex b/lib/sloane_sh/context.ex deleted file mode 100644 index a006a0f..0000000 --- a/lib/sloane_sh/context.ex +++ /dev/null @@ -1,59 +0,0 @@ -defmodule SloaneSH.Context do - @moduledoc """ - A SloaneSH build context containing configuration and reference to content - files. - """ - use TypedStruct - require Logger - - alias SloaneSH.Config - alias SloaneSH.Asset - alias SloaneSH.Assets.Page - alias SloaneSH.Assets.Post - alias SloaneSH.Assets.Image - alias __MODULE__ - - typedstruct do - field :config, Config.t(), enforce: true - field :pages, [Asset.t()], default: [] - field :posts, [Asset.t()], default: [] - field :images, [Asset.t()], default: [] - end - - def new(cfg \\ Config.default()) do - pages = load_assets(cfg, Page, cfg.pages_dir) - posts = load_assets(cfg, Post, cfg.posts_dir) - images = load_assets(cfg, Image, cfg.images_dir) - - %Context{config: cfg, pages: pages, posts: posts, images: images} - end - - defp load_assets(cfg, mod, src_dir) do - exts = mod.extensions(cfg) - - for src <- collect_src_files(src_dir, exts) do - contents = File.read!(src) - - case mod.attrs(cfg, src, contents) do - {:ok, attrs, src_contents} -> - %Asset{mod: mod, src: src, src_contents: src_contents, attrs: attrs} - - {:ok, attrs} -> - %Asset{mod: mod, src: src, src_contents: contents, attrs: attrs} - - _ -> - Logger.warning("Failed to parse attrs for #{inspect(src)}") - %Asset{mod: mod, src: src, src_contents: contents, attrs: %{}} - end - end - end - - defp collect_src_files(src_dir, exts) do - files = src_dir |> File.ls!() |> Enum.map(&Path.join(src_dir, &1)) - {src_files, rest} = Enum.split_with(files, &String.ends_with?(&1, exts)) - - other_dirs = Enum.filter(rest, &File.dir?/1) - - src_files ++ Enum.flat_map(other_dirs, &collect_src_files(&1, exts)) - end -end diff --git a/lib/sloane_sh/format.ex b/lib/sloane_sh/format.ex deleted file mode 100644 index 58a7056..0000000 --- a/lib/sloane_sh/format.ex +++ /dev/null @@ -1,34 +0,0 @@ -defmodule SloaneSH.Format do - @moduledoc """ - Functions to format various literals into human readable forms. - """ - - @millisecond 1000 - @second @millisecond ** 2 - @minute 60 * @second - @hour 60 * @minute - - @max_depth 2 - - def time(micro, depth \\ 0) - def time(_micro, depth) when depth >= @max_depth, do: [] - - time_units = [ - {@hour, "h"}, - {@minute, "m"}, - {@second, "s"}, - {@millisecond, "ms"} - ] - - for {division, unit} <- time_units do - def time(micro, depth) when micro >= unquote(division) do - count = "#{div(micro, unquote(division))}#{unquote(unit)}" - rem = rem(micro, unquote(division)) - [count, time(rem, depth + 1)] - end - end - - def time(micro, _depth) do - "#{micro}μs" - end -end diff --git a/lib/sloane_sh/front_matter.ex b/lib/sloane_sh/front_matter.ex deleted file mode 100644 index c4bca00..0000000 --- a/lib/sloane_sh/front_matter.ex +++ /dev/null @@ -1,17 +0,0 @@ -defmodule SloaneSH.FrontMatter do - @moduledoc """ - Parses TOML front matter out put files - """ - - def parse("+++" <> rest) do - [toml, body] = String.split(rest, ["+++\n", "+++\r\n"], parts: 2) - - with {:ok, attrs} <- Toml.decode(toml, keys: :atoms) do - {:ok, attrs, body} - end - end - - def parse(body) do - {:ok, %{}, body} - end -end diff --git a/lib/sloane_sh/layouts.ex b/lib/sloane_sh/layouts.ex deleted file mode 100644 index 8198124..0000000 --- a/lib/sloane_sh/layouts.ex +++ /dev/null @@ -1,43 +0,0 @@ -defmodule SloaneSH.Layouts do - @moduledoc """ - `EEx` based layouts - """ - require EEx - import SloaneSH.Layouts.Partials, warn: false - import SloaneSH.Layouts.Helpers, warn: false - - @layouts_dir Path.join(:code.priv_dir(:sloane_sh), "site/layouts") - - EEx.function_from_file(:def, :root, Path.join(@layouts_dir, "root.html.eex"), [ - :inner_content, - :ctx, - :attrs - ]) - - EEx.function_from_file(:defp, :page_layout, Path.join(@layouts_dir, "page.html.eex"), [ - :inner_content, - :ctx, - :attrs - ]) - - EEx.function_from_file(:defp, :post_layout, Path.join(@layouts_dir, "post.html.eex"), [ - :inner_content, - :ctx, - :attrs - ]) - - def page(inner_content, ctx, attrs) do - inner_content - |> page_layout(ctx, attrs) - |> root(ctx, attrs) - end - - def post(inner_content, ctx, attrs) do - inner_content - |> post_layout(ctx, attrs) - |> root(ctx, attrs) - end - - defp prefix_title(prefix, nil), do: prefix - defp prefix_title(prefix, page_title), do: [prefix, " | ", page_title] -end diff --git a/lib/sloane_sh/layouts/helpers.ex b/lib/sloane_sh/layouts/helpers.ex deleted file mode 100644 index ce8cabe..0000000 --- a/lib/sloane_sh/layouts/helpers.ex +++ /dev/null @@ -1,67 +0,0 @@ -defmodule SloaneSH.Layouts.Helpers do - require Logger - alias SloaneSH.Context - alias SloaneSH.OutputDirs - - def cx(classes) do - classes - |> Enum.map(fn - {_, _} = t -> t - c -> {c, true} - end) - |> Enum.filter(fn {_, v} -> !!v end) - |> Enum.map_join(" ", fn {class, _} -> class end) - end - - def sorted_post_attrs(%Context{} = ctx) do - {drafts, others} = - ctx.posts - |> Enum.map(& &1.attrs) - |> Enum.split_with(&is_nil(&1[:date])) - - others = Enum.sort_by(others, & &1[:date], {:desc, Date}) - - drafts ++ others - end - - def fmt_date(nil), do: "Draft" - def fmt_date(date), do: Timex.format!(date, "{Mfull} {D}, {YYYY}") - - def picture(ctx, src, alt \\ "", class \\ "") do - image = - Enum.find(ctx.images, fn i -> - output = OutputDirs.image(ctx.config, i.src) - src == OutputDirs.to_permalink(ctx.config, output) - end) - - if is_nil(image) do - Logger.warning("Could not find #{inspect(src)} to make picture element") - ~s|#{alt}| - else - [{_, src} | srcsets] = - [ - {"image/jpg", ".jpg"}, - {"image/webp", ".webp"}, - {"image/png", ".png"} - ] - |> Enum.map(fn {type, ext} -> - {type, OutputDirs.replace_ext(src, ext)} - end) - - EEx.eval_string( - ~S""" - - <%= for {type, srcset} <- srcsets do %> - - <% end %> - <%= alt %> - - """, - src: src, - srcsets: srcsets, - alt: alt, - class: class - ) - end - end -end diff --git a/lib/sloane_sh/layouts/partials.ex b/lib/sloane_sh/layouts/partials.ex deleted file mode 100644 index 2153656..0000000 --- a/lib/sloane_sh/layouts/partials.ex +++ /dev/null @@ -1,36 +0,0 @@ -defmodule SloaneSH.Layouts.Partials do - @moduledoc """ - HTML partials for use in HTML layouts - """ - require EEx - import SloaneSH.Layouts.Helpers, warn: false - - EEx.function_from_string( - :def, - :header, - ~S""" -
-
- <%= if attrs[:title] do %> -

<%= attrs[:title] %>

- <% end %> - <%= if attrs[:date] do %> - <%= fmt_date(attrs[:date]) %> - <% end %> -
-
-
- sloane.sh - <%= picture(ctx, "/assets/images/heart.png", "a purple heart emoji", "w-4 h-4") %> -
- -
-
- """, - [:ctx, :attrs] - ) -end diff --git a/lib/sloane_sh/output_dirs.ex b/lib/sloane_sh/output_dirs.ex deleted file mode 100644 index dcd7dee..0000000 --- a/lib/sloane_sh/output_dirs.ex +++ /dev/null @@ -1,55 +0,0 @@ -defmodule SloaneSH.OutputDirs do - def page(cfg, src) do - path = Path.relative_to(src, cfg.pages_dir) - - cfg.output_dir |> Path.join(path) |> prettify_html_path() - end - - def post(cfg, src) do - path = Path.relative_to(src, cfg.posts_dir) - path = Path.join("post", path) - - cfg.output_dir |> Path.join(path) |> prettify_html_path() - end - - def image(cfg, src) do - path = Path.relative_to(src, cfg.images_dir) - path = Path.join("assets/images", path) - - cfg.output_dir |> Path.join(path) - end - - def prettify_html_path(path) do - file = Path.basename(path) - [without_extension | _] = String.split(file, ".", parts: 2) - - suffix = - if without_extension == "index" do - "index.html" - else - Path.join(without_extension, "index.html") - end - - String.replace_suffix(path, file, suffix) - end - - def to_permalink(cfg, output_path) do - output_path - |> Path.relative_to(cfg.output_dir) - |> String.trim_trailing("index.html") - |> String.replace_prefix("", "/") - |> String.trim_trailing("/") - end - - def from_permalink(cfg, permalink) do - Path.join([cfg.output_dir, permalink, "/index.html"]) - end - - def replace_ext(path, new_ext) do - ext = Path.extname(path) - base = Path.basename(path, ext) - dir = Path.dirname(path) - - Path.join(dir, base <> new_ext) - end -end diff --git a/lib/sloane_sh/serve.ex b/lib/sloane_sh/serve.ex deleted file mode 100644 index bd4bc7e..0000000 --- a/lib/sloane_sh/serve.ex +++ /dev/null @@ -1,21 +0,0 @@ -defmodule SloaneSH.Serve do - @moduledoc """ - Task to use `Bandit` to start `SloaneSH.Serve.Plug` - """ - use Supervisor - - alias __MODULE__ - - def start_link(ctx) do - Supervisor.start_link(__MODULE__, ctx, name: __MODULE__) - end - - @impl Supervisor - def init(_ctx) do - children = [ - {Bandit, plug: Serve.Plug} - ] - - Supervisor.init(children, strategy: :one_for_one) - end -end diff --git a/lib/sloane_sh/serve/plug.ex b/lib/sloane_sh/serve/plug.ex deleted file mode 100644 index 2c6299b..0000000 --- a/lib/sloane_sh/serve/plug.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule SloaneSH.Serve.Plug do - @moduledoc """ - Basic HTTP server for testing and local development. - - Inspired by https://github.com/mbuhot/plug_static_index_html - """ - use Plug.Builder - - plug Plug.Logger - plug :rewrite_for_index_html - plug Plug.Static, at: "/", from: {:sloane_sh, "priv/output"} - plug :not_found - - def rewrite_for_index_html(conn, _) do - if String.match?(conn.request_path, ~r[.+\..+$]) do - conn - else - %{ - conn - | request_path: Path.join(conn.request_path, "index.html"), - path_info: conn.path_info ++ ["index.html"] - } - end - end - - def not_found(conn, _) do - send_resp(conn, 404, "Not found") - end -end diff --git a/lib/sloane_sh/watch.ex b/lib/sloane_sh/watch.ex deleted file mode 100644 index cad827e..0000000 --- a/lib/sloane_sh/watch.ex +++ /dev/null @@ -1,81 +0,0 @@ -defmodule SloaneSH.Watch do - use GenServer - use TypedStruct - require Logger - - alias SloaneSH.Build - alias SloaneSH.Context - alias SloaneSH.Layouts - - typedstruct do - field :ctx, Context.t(), enforce: true - field :watcher_pid, pid(), enforce: true - end - - def start_link(%Context{} = ctx, opts \\ []) do - GenServer.start_link(__MODULE__, ctx, opts) - end - - @impl GenServer - def init(%Context{} = ctx) do - {:ok, watcher_pid} = - FileSystem.start_link( - dirs: [ - # ctx.config.layouts_dir, - "priv/site/layouts", - "lib/sloane_sh/layouts", - ctx.config.pages_dir, - ctx.config.posts_dir - ] - ) - - :ok = FileSystem.subscribe(watcher_pid) - - Task.start_link(fn -> - Tailwind.install_and_run(:default, ~w[--watch]) - end) - - Task.start_link(fn -> - Esbuild.install_and_run(:default, ~w[--watch]) - end) - - state = %__MODULE__{ctx: ctx, watcher_pid: watcher_pid} - - {:ok, state, {:continue, :build}} - end - - @impl GenServer - def handle_continue(:build, %{ctx: ctx} = state) do - Build.run(ctx) - - {:noreply, state} - end - - @impl GenServer - def handle_info({:file_event, pid, {path, _events}}, %{watcher_pid: pid} = state) do - if String.match?(path, ~r/layouts/) do - recompile_layouts() - end - - ctx = Context.new() - - {:noreply, %{state | ctx: ctx}, {:continue, :build}} - end - - @impl GenServer - def handle_info({:file_event, pid, :stop}, %{watcher_pid: pid}) do - Logger.warning("File watcher stopped") - {:stop, :watcher_stopped, pid} - end - - defp recompile_layouts do - helpers_source = Layouts.Helpers.module_info(:compile)[:source] |> List.to_string() - partials_source = Layouts.Partials.module_info(:compile)[:source] |> List.to_string() - layouts_source = Layouts.module_info(:compile)[:source] |> List.to_string() - - {:ok, _, _} = - Kernel.ParallelCompiler.compile([helpers_source, partials_source, layouts_source]) - - :ok - end -end diff --git a/mix.exs b/mix.exs deleted file mode 100644 index fbc854b..0000000 --- a/mix.exs +++ /dev/null @@ -1,53 +0,0 @@ -defmodule SloaneSH.MixProject do - use Mix.Project - - def project do - [ - app: :sloane_sh, - version: "0.1.0", - elixir: "~> 1.15", - start_permanent: Mix.env() == :prod, - deps: deps(), - aliases: aliases() - ] - end - - # Run "mix help compile.app" to learn about applications. - def application do - [ - extra_applications: [:logger] - ] - end - - # Run "mix help deps" to learn about dependencies. - defp deps do - [ - {:file_system, "~> 1.0.0"}, - {:typed_struct, "~> 0.3.0"}, - {:earmark, "~> 1.4"}, - {:earmark_parser, "~> 1.4"}, - {:plug, "~> 1.15"}, - {:bandit, "~> 1.2"}, - {:tailwind, "~> 0.2"}, - {:toml, "~> 0.7"}, - {:esbuild, "~> 0.8"}, - {:timex, "~> 3.7"}, - {:image, "~> 0.42"} - ] - end - - defp aliases do - [ - "assets.deploy": [ - "tailwind default --minify", - "esbuild default --minify --sourcemap --target=chrome58,firefox57,safari11,edge16" - ], - "site.index": "cmd npx -y pagefind --site priv/output/", - "site.deploy": [ - "site.build", - "site.index", - "assets.deploy" - ] - ] - end -end diff --git a/mix.lock b/mix.lock deleted file mode 100644 index 199a838..0000000 --- a/mix.lock +++ /dev/null @@ -1,39 +0,0 @@ -%{ - "bandit": {:hex, :bandit, "1.2.2", "569fe5d0efb107c9af37a1e37e25ce2ceec293101a2d4bc512876fc3207192b5", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "2f89adb7281c78d4e75733e0a9e1b24f46f84d2993963d6fa57d0eafadec5f03"}, - "castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"}, - "cc_precompiler": {:hex, :cc_precompiler, "0.1.9", "e8d3364f310da6ce6463c3dd20cf90ae7bbecbf6c5203b98bf9b48035592649b", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "9dcab3d0f3038621f1601f13539e7a9ee99843862e66ad62827b0c42b2f58a54"}, - "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, - "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, - "earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, - "elixir_make": {:hex, :elixir_make, "0.7.8", "505026f266552ee5aabca0b9f9c229cbb496c689537c9f922f3eb5431157efc7", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "7a71945b913d37ea89b06966e1342c85cfe549b15e6d6d081e8081c493062c07"}, - "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"}, - "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"}, - "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, - "floki": {:hex, :floki, "0.35.4", "cc947b446024732c07274ac656600c5c4dc014caa1f8fb2dfff93d275b83890d", [:mix], [], "hexpm", "27fa185d3469bd8fc5947ef0f8d5c4e47f0af02eb6b070b63c868f69e3af0204"}, - "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.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, - "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.42.0", "aa561f15b53c40ac571e7880083cecf1419ff405fc45dc95675c58aa308eaa22", [: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.7", [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]}, {: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", "19972043abadc40e2d77dc38fc57f52382859791f89a962b0f1425ae64262f7d"}, - "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, - "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, - "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, - "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, - "phoenix_html": {:hex, :phoenix_html, "4.0.0", "4857ec2edaccd0934a923c2b0ba526c44a173c86b847e8db725172e9e51d11d6", [:mix], [], "hexpm", "cee794a052f243291d92fa3ccabcb4c29bb8d236f655fb03bcbdc3a8214b8d13"}, - "plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"}, - "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, - "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"}, - "tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"}, - "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, - "thousand_island": {:hex, :thousand_island, "1.3.2", "bc27f9afba6e1a676dd36507d42e429935a142cf5ee69b8e3f90bff1383943cd", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0e085b93012cd1057b378fce40cbfbf381ff6d957a382bfdd5eca1a98eec2535"}, - "timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"}, - "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"}, - "typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"}, - "tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "vix": {:hex, :vix, "0.26.0", "027f10b6969b759318be84bd0bd8c88af877445e4e41cf96a0460392cea5399c", [:make, :mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.1.4 or ~> 0.2", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7.3 or ~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "71b0a79ae7f199cacfc8e679b0e4ba25ee47dc02e182c5b9097efb29fbe14efd"}, - "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, -} diff --git a/priv/site/images/heart.png b/priv/site/images/heart.png deleted file mode 100644 index a04245735cde9029b83cf8fb72adbe44bc09cfff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 889 zcmV-<1BU#GP)HoC|D|4@j2Z zYPE8Ge*KD@X5;ZLEl?)TJ!M1wqAT{qycm#3v=ft`RU`_m`+S zS}54a7!<~Ukp6!lz(cKW+uhpcqJ>z(zHW~$Po+5rh-c_}8GZkABYs83ov2&hcpm$)mZxAu<49 z1u~OI!@{tmCUfO;cx;{2>hk|gkg(zmNtA|vX7gAE!=m>T2mVAUTUK~v4dChtxENx6 zRs;$`RC5F1as&c2{S^wivVv1JdcZ0AXQ+sFWyPQzGz~7%=cPI}DCf$YftG?7+z!8! zjD=ip6AoZbdIUZTE#&S^NFR123l-t`e#TUuEKEqLW|Ts#D&mALhku-YNJvhPaidvZ zy)2+7&_rHvFPG^Np~=)%`5+=-w09!!XK?8wo$k(&h$*t+a--F-xUw4#+kK6kLw`;L zkOk9j=nUtI?*~NRD_RkUHdX|_G@1=H(HwCC`fZ+KjavPdZf@TQ5oA1bQjk}lXs`H^ zP{8tv@ExX!c|oVbI*SN0iPab_`q#0%37b;4=x;$_j&<|~q*m-AwPJTx4=QO_>=eB= z0DfsbW`P{9%VaiONyL>@KscE82?y;Ht;$4THx*sdfut1hPsCLcaU;{mK^Tbx>!@$l z-%d4vv;rc9Df&$`jgM%F>SWHw59*jto7(n`q>Gm&AR@v(p+{I8BoWoANNMC_At~5+ z(o*$4UGgQv^MR#wTuFUE4se8C--3YG zX*L?kTo3^J1eNAy-G#j~a`0(=KrRWr4;B`HR;sm>&&kEe_JM2(GsXP{Ez%TSPL9Q8 P00000NkvXXu0mjf^p2b} diff --git a/priv/site/layouts/page.html.eex b/priv/site/layouts/page.html.eex deleted file mode 100644 index 9257303..0000000 --- a/priv/site/layouts/page.html.eex +++ /dev/null @@ -1,4 +0,0 @@ -<%= header(ctx, attrs) %> -
- <%= inner_content %> -
diff --git a/priv/site/layouts/post.html.eex b/priv/site/layouts/post.html.eex deleted file mode 100644 index 8a116e5..0000000 --- a/priv/site/layouts/post.html.eex +++ /dev/null @@ -1,5 +0,0 @@ -<%= header(ctx, attrs) %> - -
- <%= inner_content %> -
diff --git a/priv/site/layouts/root.html.eex b/priv/site/layouts/root.html.eex deleted file mode 100644 index a9dafd2..0000000 --- a/priv/site/layouts/root.html.eex +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - <%= prefix_title("sloane.sh", attrs[:page_title]) %> - - - - <%= inner_content %> - - - - diff --git a/priv/site/pages/home.md.eex b/priv/site/pages/home.md.eex deleted file mode 100644 index 3d272f2..0000000 --- a/priv/site/pages/home.md.eex +++ /dev/null @@ -1,29 +0,0 @@ -+++ -page_title = "home" -permalink = "/" -+++ - -hey, i'm sloane! i'm a professional software engineer and an amateur musician, photographer, wife, chef, and pet mom. - -### around the web - - - -### writing - -i write more than i share but here are some things that have made it out of my drafts folder recently - -<%= for post <- Enum.take(sorted_post_attrs(ctx), 3) do %> - - <%= fmt_date(post[:date]) %>: [<%= post[:title] %>](<%= post[:permalink] %>) -<% end %> - - -### projects - -

🌱 screen.garden

- -real-time collaboration across obsidian and the web. currently in closed beta. diff --git a/priv/site/pages/posts.html.eex b/priv/site/pages/posts.html.eex deleted file mode 100644 index f40d4c8..0000000 --- a/priv/site/pages/posts.html.eex +++ /dev/null @@ -1,11 +0,0 @@ -+++ -page_title = "posts" -+++ - -
    - <%= for post <- sorted_post_attrs(ctx) do %> -
  • - <%= fmt_date(post[:date]) %>: <%= post[:title] %> -
  • - <% end %> -
diff --git a/priv/site/pages/search.html b/priv/site/pages/search.html deleted file mode 100644 index 8e75ffd..0000000 --- a/priv/site/pages/search.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - -
diff --git a/priv/site/posts/2023-07-03-obsidianrc.md b/priv/site/posts/2023-07-03-obsidianrc.md deleted file mode 100644 index b327357..0000000 --- a/priv/site/posts/2023-07-03-obsidianrc.md +++ /dev/null @@ -1,33 +0,0 @@ -+++ -date = 2023-07-23 -title = "obsidianrc - a programmer's approach to obsidian" -page_title = "obsidian" -+++ - -my biggest hangup with obsidian has always been that it isn't vim. as a longtime vim user i'm used to being able to fully customize and extend my editing experience. - -there are many existing community plugins that make it easy to customize some parts of obsidian but whenever i would have an idea or a desired workflow that didn't fit into one of those existing boxes i was stuck. - -i had three options, roughly in order of immediate work required: - -1. adapt my own workflows to fit the existing options -1. contribute to an existing community plugin and hope that the original author has time to review, merge in, and publish my change -1. build my own plugin to do exactly what i want - -so today i had an idea for another, hopefully easier option: obsidianrc - -an obsidianrc is a personal, custom plugin that resembles an "[rc](https://superuser.com/questions/144339/vimrc-screenrc-bashrc-kshrc-etc-what-does-the-rc-mean)" file like a `.vimrc`. it has no one purpose but instead is a grab-bag of whatever the author needed at the time. an obsidian user's obsidianrc evolves with her as she comes up with new workflows or changes her existing workflows. - -the freedom of the obsidianrc is that it never needs to be used by anyone but its author. it's a workbench covered in jigs. if any bit of functionality ever sticks out as generally useful the code is easily (famous last words perhaps...) extracted into its own plugin and published in the community plugin repo. - -## create your own obsidianrc - -1. use the [obsidian-sample-plugin](https://github.com/obsidianmd/obsidian-sample-plugin) template -1. name your repo `obsidianrc` -1. install your obsidianrc in your vault -1. fill your obsidianrc with whatever need whenever you need it -1. (optional) use [BRAT](https://github.com/TfTHacker/obsidian42-brat) to install your obsidianrc and keep it up-to-date - -## what's in my obsidianrc? - -well at time of writing, not much. but you can take a look for yourself: [sloanelybutsurely/obsidianrc](https://github.com/sloanelybutsurely/obsidianrc) diff --git a/priv/site/posts/2023-12-28-in-review-2023.md b/priv/site/posts/2023-12-28-in-review-2023.md deleted file mode 100644 index 091f259..0000000 --- a/priv/site/posts/2023-12-28-in-review-2023.md +++ /dev/null @@ -1,19 +0,0 @@ -+++ -date = 2023-12-28 -title = "in review: 2023" -page_title = "in review: 2023" -+++ - -- **january**: visited family in florida -- **february**: switched to injections (dolls, i implore you to do the same) -- **march**: back in florida for an elastic on-site (and an evening at disney world) -- **april**: saw caroline polachek live -- **may**: visited a friend in kentucky -- **june**: was in a friend’s wedding, had brunch with friends passing through town, performed with the columbus gay men’s chorus, pride!! 🏳️‍🌈 -- **july**: vacationed in northern michigan, went to a minor league baseball game, saw an airshow (hayley’s first!), started a new job -- **august**: went to the state fair -- **september**: just enjoyed the last bits of summer -- **october**: saw kim petras live in DC, started working towards my private pilot certificate -- **november**: celebrated my 30th birthday -- **december**: celebrated the holidays and rang in the new year with family and friends - diff --git a/priv/site/posts/2024-03-09-uses.md b/priv/site/posts/2024-03-09-uses.md deleted file mode 100644 index 6dc87c7..0000000 --- a/priv/site/posts/2024-03-09-uses.md +++ /dev/null @@ -1,60 +0,0 @@ -+++ -title = "\"Uses This\"" -page_title = "uses" -permalink = "/uses" -date = 2024-03-09 -+++ - -> **Have you considered adding a `/uses/` page to your own site, answering the same questions?** -> \- [Daniel](https://wafer.baby/@d) of [usesthis.com](https://usesthis.com/) - -## Who are you, and what do you do? - -I'm a professional software engineer and once engineering manager. I work a day job but I'm also working with a good friend and former boss to bring [screen.garden](https://screen.garden), a real-time collaboration tool for PKMs and the web, to life. - -In my free time I sing with a local queer TTBB chorus, play table-top RPGs, watch Formula 1, and play video games. - -## What hardware do you use? - -I work atop a sit-stand desk I bought when I first started working remotely in 2017. It stays in the "sit" position 99% of the time. For work I use whatever machine my employer provides. Right now that's a 14in M3 MacBook Pro. Personally, I have an M1 MacBook Air which I love. A single thunderbolt cable runs from either of those machines to a [CalDigit TS4](https://www.caldigit.com/thunderbolt-station-4/) which connects it to power, ethernet, a USB hub, and my display. - -I use just the one display, a [GIGABYTE M32U](https://www.gigabyte.com/Monitor/M32U), which is a 32 inch, 4k, 144Hz monitor. Whenever someone is talking about replacing their monitor I always bring up refresh rate. It's one of those things that sounds like you wouldn't notice but it actually makes looking at a screen for most of your day a lot more pleasant. I've sat a no-name-brand monitor light and a Logitech webcam atop it. - -I have a collection of mechanical keyboards ([ErgoDox EZ](https://ergodox-ez.com/), [Keyboardio Atreus](https://shop.keyboard.io/products/keyboardio-atreus), to name a couple) which all live in a drawer while I type away on my [Glorious GMMK Pro](https://www.gloriousgaming.com/products/glorious-gmmk-pro-75-barebone-black) with [Glorious Panda tactile switches](https://www.gloriousgaming.com/products/glorious-panda-mechanical-switches?variant=37691905933487). I think Glorious's branding is a bit "cringe" to say the least but they were the only custom keyboard option I could get same-day at the nearby Micro Center when I needed to replace my [Pok3r](https://drop.com/buy/vortex-poker-iii-compact-keyboard) following a coffee spill incident. - -I talk to my coworkers and friends through a [Blue Yeti mic](https://www.bestbuy.com/site/blue-microphones-blue-yeti-professional-multi-pattern-usb-condenser-microphone/9737441.p?skuId=9737441) that I bought when a former employer gave everyone a couple hundred dollars for work-from-home equipment in early 2020 (despite my having already worked from my home my entire tenure there). - -At the edges of my desk are piles of scrunchies, a couple hair clips, my AirPods Pros, a pair of Sennheiser HD 600s, my iPhone 14 Pro Max (I always go "Max" or "Plus" for the extra battery life), an [Aquaphor lip balm stick](https://www.aquaphorus.com/products/lip-care/lip-repair-stick), some hand lotion, and a nice candle. - -Away from my desk I have a collection of cameras but the one I use the most is my Leica M6 which I usually shoot with a Voigtlander Nokton Classic 35mm f/1.4. I digitize my negatives with a beat-up Sony a6000, a cheap macro lens, and a [Valoi easy35](https://www.valoi.co/easy35). - -I have a couple Apple TV 4ks to stream content from the cloud and also the Plex Media Server running on a Synology NAS. I have a couple TVs in different rooms but the Xbox Series X stays connected to the 65 inch LG C1 OLED (once again which a high refresh rate). - -Finally, currently sitting on my nightstand wrapped in some FiiO IEMs is a 5th iPod Classic (aka an iPod Video) whose hard disk I've [replaced with a 512gb microSD card](https://www.iflash.xyz/). It's really incredible how well it still works. - -## And what software? - -These days I'm macOS all-the-way. I'm fully integrated into the ecosystem and the ergonomics and reliability of development on the platform is unparalleled in my opinion. Obviously I use a ton of software so I'll limit (mostly) to things I keep pinned to my dock (although most of the time I'm launching things from [Alfred](https://www.alfredapp.com/)): - -- [Firefox](https://www.mozilla.org/en-US/firefox/new/) to browse the web -- [Fantastical](https://flexibits.com/fantastical) to manage several calendar accounts. I could just use Calendar.app but there are few features (like travel time and automatic event merging) that keep me renewing my subscription. -- Mail.app for emails... -- [Things 3](https://culturedcode.com/things/) makes sure I get things done. I switched from an Android phone to an iPhone many years ago just so I could use Things while I was away from my computer. -- [Kitty](https://sw.kovidgoyal.net/kitty/) to run all of my command line apps. I always work within a `tmux` session so my terminal emulator doesn't really matter all that much (because I'm never using tabs or splits or whatever) but Kitty is quick and the [alternative icon](https://github.com/DinkDonk/kitty-icon) I use for it is really cute. I'm a vim user (neovim really) and have been since 2015. My neovim setup could be its own post... -- Music - I switch between two libraries: 1. My local library which I sync with my iPod and 2. My iCloud, Apple Music backed library -- [Dash 6](https://kapeli.com/dash) (usually via Alfred) to quickly reference documentation. Elixir / Hex package docs support is incredible -- [Obsidian](https://obsidian.md) for personal, work, and TTRPG notes. I keep my plugins list slip with just Templater, DataView, Tasks, Periodic Notes, and of course screen.garden. -- [Readwise Reader](https://readwise.io/read) as my read-later service - -I have to shout-out Lightroom with [Negative Lab Pro](https://www.negativelabpro.com/) for converting scans/photos of film negatives. - - -## What would be your dream setup? - -I've obviously spoiled myself already so I'd keep most things the same but... - -I'd love a thunderbolt KVM of some kind that would let me swap _quickly_ between machines at the press of a button. I also feel like I'd benefit from a larger desk. - -I think about replacing my webcam with the Sony a6000 and replacing that with a newer, higher resolution mirrorless camera. - -I'm really hoping the ARM desktop / server market continues to become more accessible to the consumer market because the Synology NAS is looking a little worse-for-wear these days. I've thought about replacing it with a custom build x64 machine but the additional power consumption and heat keep me from doing it (I'm spoiled by these Apple ARM machines...). diff --git a/site/index.html.pm b/site/index.html.pm new file mode 100644 index 0000000..a8af549 --- /dev/null +++ b/site/index.html.pm @@ -0,0 +1,3 @@ +#lang pollen + +hey, i'm sloane! i'm a professional software engineer and an amateur musician, photographer, wife, chef, and pet mom. diff --git a/site/index.ptree b/site/index.ptree new file mode 100644 index 0000000..969f11d --- /dev/null +++ b/site/index.ptree @@ -0,0 +1,3 @@ +#lang pollen + +index.html diff --git a/site/pollen.rkt b/site/pollen.rkt new file mode 100644 index 0000000..6472f96 --- /dev/null +++ b/site/pollen.rkt @@ -0,0 +1,17 @@ +#lang racket/base +(require pollen/decode pollen/misc/tutorial txexpr) +(provide (all-defined-out)) + +(define site-name "sloane.sh") +(define email "sloane@fastmail.com") + +(define txexpr-elements-proc decode-paragraphs) +(define string-proc (compose1 smart-quotes smart-dashes)) + +(define (root . elements) + (txexpr 'root empty (decode-elements elements + #:txexpr-elements-proc txexpr-elements-proc + #:string-proc string-proc))) + +(module setup racket/base + (provide (all-defined-out))) diff --git a/site/template.html.p b/site/template.html.p new file mode 100644 index 0000000..43f22ae --- /dev/null +++ b/site/template.html.p @@ -0,0 +1,10 @@ + + + + + ◊|site-name| + + + ◊(->html doc) + + diff --git a/test/sloane_sh/front_matter_test.exs b/test/sloane_sh/front_matter_test.exs deleted file mode 100644 index 001c281..0000000 --- a/test/sloane_sh/front_matter_test.exs +++ /dev/null @@ -1,42 +0,0 @@ -defmodule SloaneSH.FrontMatterTest do - use ExUnit.Case - - alias SloaneSH.FrontMatter - - test "parses TOML front matter" do - document = ~S""" - +++ - foo = "bar" - +++ - # Hello, World! - - This is a document with front matter. - """ - - assert {:ok, %{foo: "bar"}, "# Hello, World!" <> _} = FrontMatter.parse(document, %{}) - end - - test "returns an empty map is the document doesn't have front matter" do - document = ~S""" - # Hello, World! - - This is a document with front matter. - """ - - assert {:ok, %{} = map, document} = FrontMatter.parse(document, %{}) - assert %{} = map - end - - test "errors in TOML front matter produce an error" do - document = ~S""" - +++ - foo = "bar - +++ - # Hello, World! - - This is a document with front matter. - """ - - assert {:error, _} = FrontMatter.parse(document, %{}) - end -end diff --git a/test/sloane_sh_test.exs b/test/sloane_sh_test.exs deleted file mode 100644 index a7ada2d..0000000 --- a/test/sloane_sh_test.exs +++ /dev/null @@ -1,3 +0,0 @@ -defmodule SloaneSHTest do - use ExUnit.Case -end diff --git a/test/test_helper.exs b/test/test_helper.exs deleted file mode 100644 index 869559e..0000000 --- a/test/test_helper.exs +++ /dev/null @@ -1 +0,0 @@ -ExUnit.start() -- 2.39.5 From 10c06f09c7945d2d74d68a998496060343f42619 Mon Sep 17 00:00:00 2001 From: sloane Date: Sat, 9 Nov 2024 11:14:44 -0500 Subject: [PATCH 2/3] initial layout of new site --- site/pollen.rkt | 6 +++++- site/style.css.pp | 1 + site/template.html.p | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 site/style.css.pp diff --git a/site/pollen.rkt b/site/pollen.rkt index 6472f96..0310490 100644 --- a/site/pollen.rkt +++ b/site/pollen.rkt @@ -2,16 +2,20 @@ (require pollen/decode pollen/misc/tutorial txexpr) (provide (all-defined-out)) +#| site globals |# (define site-name "sloane.sh") (define email "sloane@fastmail.com") +#| custom elements |# + +#| plain text decoding |# (define txexpr-elements-proc decode-paragraphs) (define string-proc (compose1 smart-quotes smart-dashes)) - (define (root . elements) (txexpr 'root empty (decode-elements elements #:txexpr-elements-proc txexpr-elements-proc #:string-proc string-proc))) +#| setup |# (module setup racket/base (provide (all-defined-out))) diff --git a/site/style.css.pp b/site/style.css.pp new file mode 100644 index 0000000..7a85c9c --- /dev/null +++ b/site/style.css.pp @@ -0,0 +1 @@ +#lang pollen diff --git a/site/template.html.p b/site/template.html.p index 43f22ae..75086fa 100644 --- a/site/template.html.p +++ b/site/template.html.p @@ -3,8 +3,17 @@ ◊|site-name| + +
+ ◊|site-name| + +
◊(->html doc) -- 2.39.5 From 009284f1935818f61be15367d228b4f4af0ad013 Mon Sep 17 00:00:00 2001 From: sloane Date: Sat, 9 Nov 2024 11:38:03 -0500 Subject: [PATCH 3/3] add tufte css --- site/index.html.pm | 8 +- site/pollen.rkt | 28 ++- site/template.html.p | 9 +- site/tufte.css.pp | 452 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 485 insertions(+), 12 deletions(-) create mode 100644 site/tufte.css.pp diff --git a/site/index.html.pm b/site/index.html.pm index a8af549..353fae7 100644 --- a/site/index.html.pm +++ b/site/index.html.pm @@ -1,3 +1,9 @@ #lang pollen -hey, i'm sloane! i'm a professional software engineer and an amateur musician, photographer, wife, chef, and pet mom. +◊title{Hi, I'm Sloane!} + +◊section{ + I'm a professional software engineer and an amateur musician, photographer, wife, chef, and pet mom. + + ◊code{sloane.sh} is my place on the web; however, it is currently under construction. Please check back later. +} diff --git a/site/pollen.rkt b/site/pollen.rkt index 0310490..7e8d591 100644 --- a/site/pollen.rkt +++ b/site/pollen.rkt @@ -2,19 +2,41 @@ (require pollen/decode pollen/misc/tutorial txexpr) (provide (all-defined-out)) +#| utilities |# +(define (splice xs) + (apply append (for/list ([x (in-list xs)]) + (if (and (txexpr? x) (member (get-tag x) '(splice-me))) + (get-elements x) + (list x))))) + #| site globals |# (define site-name "sloane.sh") (define email "sloane@fastmail.com") #| custom elements |# +(define (title . elements) + (txexpr 'h1 empty elements)) +(define (subtitle . elements) + (txexpr 'p '((class "subtitle")) elements)) +(define (heading . elements) + (txexpr 'h2 empty elements)) +(define (low-level-heading . elements) + (txexpr 'h3 empty elements)) + +(define (side-note label . elements) + `(splice-me + (label ((for ,label) (class "margin-toggle sidenote-number"))) + (input ((id ,label) (class "margin-toggle")(type "checkbox"))) + (span ((class "sidenote")) ,@elements))) #| plain text decoding |# -(define txexpr-elements-proc decode-paragraphs) +(define txexpr-elements-proc (compose1 decode-paragraphs splice)) (define string-proc (compose1 smart-quotes smart-dashes)) (define (root . elements) - (txexpr 'root empty (decode-elements elements + (txexpr 'article empty (decode-elements elements #:txexpr-elements-proc txexpr-elements-proc - #:string-proc string-proc))) + #:string-proc string-proc + #:exclude-tags '(pre)))) #| setup |# (module setup racket/base diff --git a/site/template.html.p b/site/template.html.p index 75086fa..ef8c210 100644 --- a/site/template.html.p +++ b/site/template.html.p @@ -3,17 +3,10 @@ ◊|site-name| + -
- ◊|site-name| - -
◊(->html doc) diff --git a/site/tufte.css.pp b/site/tufte.css.pp new file mode 100644 index 0000000..d001b89 --- /dev/null +++ b/site/tufte.css.pp @@ -0,0 +1,452 @@ +#lang pollen +@charset "UTF-8"; + +/* Import ET Book styles + adapted from https://github.com/edwardtufte/et-book/blob/gh-pages/et-book.css */ + +@font-face { + font-family: "et-book"; + src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot"); + src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff") format("woff"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf") format("truetype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg#etbookromanosf") format("svg"); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "et-book"; + src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot"); + src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff") format("woff"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf") format("truetype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg#etbookromanosf") format("svg"); + font-weight: normal; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "et-book"; + src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot"); + src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff") format("woff"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf") format("truetype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg#etbookromanosf") format("svg"); + font-weight: bold; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "et-book-roman-old-style"; + src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot"); + src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff") format("woff"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf") format("truetype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg#etbookromanosf") format("svg"); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +/* Tufte CSS styles */ +html { + font-size: 15px; +} + +body { + width: 87.5%; + margin-left: auto; + margin-right: auto; + padding-left: 12.5%; + font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif; + background-color: #fffff8; + color: #111; + max-width: 1400px; + counter-reset: sidenote-counter; +} + +/* Adds dark mode */ +@media (prefers-color-scheme: dark) { + body { + background-color: #151515; + color: #ddd; + } +} + +h1 { + font-weight: 400; + margin-top: 4rem; + margin-bottom: 1.5rem; + font-size: 3.2rem; + line-height: 1; +} + +h2 { + font-style: italic; + font-weight: 400; + margin-top: 2.1rem; + margin-bottom: 1.4rem; + font-size: 2.2rem; + line-height: 1; +} + +h3 { + font-style: italic; + font-weight: 400; + font-size: 1.7rem; + margin-top: 2rem; + margin-bottom: 1.4rem; + line-height: 1; +} + +hr { + display: block; + height: 1px; + width: 55%; + border: 0; + border-top: 1px solid #ccc; + margin: 1em 0; + padding: 0; +} + +p.subtitle { + font-style: italic; + margin-top: 1rem; + margin-bottom: 1rem; + font-size: 1.8rem; + display: block; + line-height: 1; +} + +.numeral { + font-family: et-book-roman-old-style; +} + +.danger { + color: red; +} + +article { + padding: 5rem 0rem; +} + +section { + padding-top: 1rem; + padding-bottom: 1rem; +} + +p, +dl, +ol, +ul { + font-size: 1.4rem; + line-height: 2rem; +} + +p { + margin-top: 1.4rem; + margin-bottom: 1.4rem; + padding-right: 0; + vertical-align: baseline; +} + +/* Chapter Epigraphs */ +div.epigraph { + margin: 5em 0; +} + +div.epigraph > blockquote { + margin-top: 3em; + margin-bottom: 3em; +} + +div.epigraph > blockquote, +div.epigraph > blockquote > p { + font-style: italic; +} + +div.epigraph > blockquote > footer { + font-style: normal; +} + +div.epigraph > blockquote > footer > cite { + font-style: italic; +} +/* end chapter epigraphs styles */ + +blockquote { + font-size: 1.4rem; +} + +blockquote p { + width: 55%; + margin-right: 40px; +} + +blockquote footer { + width: 55%; + font-size: 1.1rem; + text-align: right; +} + +section > p, +section > footer, +section > table { + width: 55%; +} + +/* 50 + 5 == 55, to be the same width as paragraph */ +section > dl, +section > ol, +section > ul { + width: 50%; + -webkit-padding-start: 5%; +} + +dt:not(:first-child), +li:not(:first-child) { + margin-top: 0.25rem; +} + +figure { + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; + max-width: 55%; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + margin: 0 0 3em 0; +} + +figcaption { + float: right; + clear: right; + margin-top: 0; + margin-bottom: 0; + font-size: 1.1rem; + line-height: 1.6; + vertical-align: baseline; + position: relative; + max-width: 40%; +} + +figure.fullwidth figcaption { + margin-right: 24%; +} + +a:link, +a:visited { + color: inherit; + text-underline-offset: 0.1em; + text-decoration-thickness: 0.05em; +} + +/* Sidenotes, margin notes, figures, captions */ +img { + max-width: 100%; +} + +.sidenote, +.marginnote { + float: right; + clear: right; + margin-right: -60%; + width: 50%; + margin-top: 0.3rem; + margin-bottom: 0; + font-size: 1.1rem; + line-height: 1.3; + vertical-align: baseline; + position: relative; +} + +.sidenote-number { + counter-increment: sidenote-counter; +} + +.sidenote-number:after, +.sidenote:before { + font-family: et-book-roman-old-style; + position: relative; + vertical-align: baseline; +} + +.sidenote-number:after { + content: counter(sidenote-counter); + font-size: 1rem; + top: -0.5rem; + left: 0.1rem; +} + +.sidenote:before { + content: counter(sidenote-counter) " "; + font-size: 1rem; + top: -0.5rem; +} + +blockquote .sidenote, +blockquote .marginnote { + margin-right: -82%; + min-width: 59%; + text-align: left; +} + +div.fullwidth, +table.fullwidth { + width: 100%; +} + +div.table-wrapper { + overflow-x: auto; + font-family: "Trebuchet MS", "Gill Sans", "Gill Sans MT", sans-serif; +} + +.sans { + font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif; + letter-spacing: .03em; +} + +code, pre > code { + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 1.0rem; + line-height: 1.42; + -webkit-text-size-adjust: 100%; /* Prevent adjustments of font size after orientation changes in iOS. See https://github.com/edwardtufte/tufte-css/issues/81#issuecomment-261953409 */ +} + +.sans > code { + font-size: 1.2rem; +} + +h1 > code, +h2 > code, +h3 > code { + font-size: 0.80em; +} + +.marginnote > code, +.sidenote > code { + font-size: 1rem; +} + +pre > code { + font-size: 0.9rem; + width: 52.5%; + margin-left: 2.5%; + overflow-x: auto; + display: block; +} + +pre.fullwidth > code { + width: 90%; +} + +.fullwidth { + max-width: 90%; + clear:both; +} + +span.newthought { + font-variant: small-caps; + font-size: 1.2em; +} + +input.margin-toggle { + display: none; +} + +label.sidenote-number { + display: inline-block; + max-height: 2rem; /* should be less than or equal to paragraph line-height */ +} + +label.margin-toggle:not(.sidenote-number) { + display: none; +} + +.iframe-wrapper { + position: relative; + padding-bottom: 56.25%; /* 16:9 */ + padding-top: 25px; + height: 0; +} + +.iframe-wrapper iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +@media (max-width: 760px) { + body { + width: 84%; + padding-left: 8%; + padding-right: 8%; + } + + hr, + section > p, + section > footer, + section > table { + width: 100%; + } + + pre > code { + width: 97%; + } + + section > dl, + section > ol, + section > ul { + width: 90%; + } + + figure { + max-width: 90%; + } + + figcaption, + figure.fullwidth figcaption { + margin-right: 0%; + max-width: none; + } + + blockquote { + margin-left: 1.5em; + margin-right: 0em; + } + + blockquote p, + blockquote footer { + width: 100%; + } + + label.margin-toggle:not(.sidenote-number) { + display: inline; + } + + .sidenote, + .marginnote { + display: none; + } + + .margin-toggle:checked + .sidenote, + .margin-toggle:checked + .marginnote { + display: block; + float: left; + left: 1rem; + clear: both; + width: 95%; + margin: 1rem 2.5%; + vertical-align: baseline; + position: relative; + } + + label { + cursor: pointer; + } + + div.table-wrapper, + table { + width: 85%; + } + + img { + width: 100%; + } +} -- 2.39.5