M .vscode/settings.json => .vscode/settings.json +1 -1
@@ 1,5 1,5 @@
{
"files.associations": {
- "*.html": "mustache"
+ "*.thtml": "mustache"
}
}=
\ No newline at end of file
R => +0 -0
R => +0 -0
R => +0 -0
R bricks/highlight.html => bricks/highlight.thtml +0 -0
R bricks/navbar.html => bricks/navbar.thtml +1 -2
@@ 6,8 6,7 @@
<a href="/">home</a>
<a href="/projects.html">projects</a>
<a href="/thoughts/">thoughts</a>
- <a href="/pastes/">pastes</a>
<hr>
<a href="/colophon.html">colophon</a>
</nav>
-</div>>
\ No newline at end of file
+</div>
D build.exs => build.exs +0 -371
@@ 1,371 0,0 @@
-require Mix
-require EEx
-
-Mix.install([
- {:tzdata, "~> 1.1"},
- {:mustache, "~> 0.5.0"}
-])
-
-Calendar.put_time_zone_database(Tzdata.TimeZoneDatabase)
-
-defmodule Git do
- def get_file_commit(path) do
- {ts_string, 0} = System.cmd("git", ["log", "--format=%ct", path])
- String.to_integer(String.trim_trailing(ts_string))
- end
-end
-
-defmodule Templates do
- binfo_template = """
- commit=<%= commit %>lightningcss=<%= lightningcss %>html_minifier_next=<%= html_minifier_next %>uglifyjs=<%= uglifyjs %>build_time=<%= build_time %>
- """
-
- pastelink_template = """
- <a href="/<%= location %>.html"><%= name %></a> | <%= date %>
- """
-
- EEx.function_from_string(
- :def,
- :build_info,
- binfo_template,
- [
- :commit,
- :lightningcss,
- :html_minifier_next,
- :uglifyjs,
- :build_time
- ]
- )
-
- EEx.function_from_string(
- :def,
- :pastelink,
- pastelink_template,
- [
- :location,
- :name,
- :date
- ]
- )
-
- def ogp(title, url, description) do
- """
- <meta property="og:type" content="website">
- <meta property="og:title" content="#{title}">
- <meta property="og:url" content="#{url}">
- <meta property="og:image" content="https://m1kadev.nl/static/logo.png">
- <meta property="og:description" content="#{description}">
- <meta property="og:locale" content="en_GB" />
- <meta property="og:site_name" content="m1kadev.nl" />
- """
- end
-end
-
-defmodule Builders do
- def html(input_path) do
- output_path = String.replace_prefix(input_path, "src", "build")
-
- {_, 0} =
- System.cmd("html-minifier-next", [
- "--preset",
- "conservative",
- "-o",
- output_path,
- input_path
- ])
- end
-
- def css(input_path) do
- output_path = "build/" <> input_path
-
- {_, 0} =
- System.cmd("lightningcss", [
- "-m",
- "-o",
- output_path,
- input_path
- ])
- end
-
- def js(input_path) do
- output_path = "build/" <> input_path
-
- {_, 0} =
- System.cmd("uglifyjs", [
- "-c",
- "-o",
- output_path,
- input_path
- ])
- end
-
- def fxg(input_path, template, bricks) do
- own_template =
- input_path
- |> String.replace_prefix("pages", "templates/pages")
- |> String.replace_suffix("fxg", "html")
-
- case File.read(own_template) do
- {:ok, ctemplate} -> _fxg(input_path, ctemplate, bricks)
- _ -> _fxg(input_path, template, bricks)
- end
- end
-
- def paste(input_path, template, bricks) do
- {:ok, code} = File.read(input_path)
- IO.inspect(code)
-
- output = "build/" <> input_path <> ".html"
-
- lang = Path.extname(input_path) |> String.slice(1..-1//1)
- file = Path.basename(input_path)
- time = FileX.createdf(input_path)
-
- result =
- Mustache.render(
- template,
- Map.merge(
- %{
- filename: file,
- about_paste: "Created on " <> time,
- language: "<script src=\"static/" <> lang <> ".min.js\"></script>",
- codetag: "<pre><code class=\"language-" <> lang <> "\">",
- code: code,
- ogp:
- Templates.ogp(file, "https://m1kadev.nl/pastes/#{file}.html", "Created on " <> time)
- },
- bricks
- )
- )
-
- IO.inspect(input_path)
-
- :ok = File.write(output, result)
- end
-
- defp _fxg(input_path, template, bricks) do
- output_path =
- String.replace_prefix(input_path, "pages", "build")
- |> String.replace_suffix("fxg", "html")
-
- name =
- case Path.basename(input_path) |> Path.rootname() do
- "index" -> "home"
- x -> x
- end
-
- {content, 0} = System.cmd("fxg", [input_path])
-
- ogp =
- Templates.ogp(
- name,
- "https://m1kadev.nl/#{String.replace_prefix(output_path, "build/", "")}",
- ""
- )
-
- output =
- Mustache.render(
- template,
- Map.merge(
- %{
- fxg_content: content,
- location: name,
- ogp: ogp
- },
- bricks
- )
- )
-
- IO.inspect(output_path)
- :ok = File.write(output_path, output)
- end
-
- def thought(path, unix) do
- thought = File.read!(path)
- name = String.replace_prefix(path, "thoughts/", "")
-
- date = DateTime.from_unix!(unix) |> Calendar.strftime("%d/%m/%y (%H:%M)")
-
- """
- <div class="thought">
- <h3><a href="/thoughts/#{FileX.sanitised_name(name)}.html">#{name}</a></h3>
- <span>#{thought}</span>
- <small> -mika, #{date}</small>
- </div>
- """
- end
-end
-
-defmodule FileX do
- def createdf(path) do
- {:ok, %File.Stat{mtime: {{y, m, d}, _}}} = File.stat(path, time: :local)
- "#{d}/#{m}/#{y}"
- end
-
- def created(path) do
- {:ok, %File.Stat{mtime: x}} = File.stat(path, time: :posix)
- x
- end
-
- def sanitised_name(path) do
- Path.basename(path)
- |> String.trim_trailing(".html")
- |> String.replace("-", "_")
- |> String.replace(" ", "_")
- end
-end
-
-{commit, 0} = System.cmd("git", ["rev-parse", "HEAD"])
-
-{lightningcss, 0} = System.cmd("lightningcss", ["-V"])
-
-{html_minifier_next, 0} = System.cmd("html-minifier-next", ["-V"])
-
-{uglifyjs, 0} = System.cmd("uglifyjs", ["-V"])
-
-File.rm_rf("build")
-
-File.mkdir_p!("build")
-
-bricks =
- Path.wildcard("bricks/*.html")
- |> Map.new(fn x -> {FileX.sanitised_name(x), File.read!(x)} end)
-
-{:ok, main_template} = File.read("templates/base.html")
-
-Path.wildcard("pages/**/*.fxg")
-|> Task.async_stream(fn file -> Builders.fxg(file, main_template, bricks) end)
-|> Enum.to_list()
-
-File.mkdir_p!("build/static")
-
-Path.wildcard("static/**/*")
-|> Task.async_stream(fn file -> File.cp(file, "build/" <> file) end)
-|> Enum.to_list()
-
-File.mkdir_p!("build/scripts")
-
-Path.wildcard("scripts/**/*.js")
-|> Task.async_stream(fn file -> Builders.js(file) end)
-|> Enum.to_list()
-
-File.mkdir_p!("build/styles")
-
-Path.wildcard("styles/**/*.css")
-|> Task.async_stream(fn file -> Builders.css(file) end)
-|> Enum.to_list()
-
-File.mkdir_p("build/pastes")
-
-{:ok, paste_template} = File.read("templates/paste.html")
-
-pastes =
- Path.wildcard("pastes/**/*")
- |> Enum.map(fn path -> {path, Git.get_file_commit(path)} end)
- |> Enum.sort_by(fn {_, t} -> t end, :desc)
- |> Enum.map(fn {path, _} -> path end)
-
-pastes
-|> Task.async_stream(fn file -> Builders.paste(file, paste_template, bricks) end)
-|> Enum.to_list()
-
-paste_data =
- Map.new(pastes, fn x -> {x, FileX.createdf(x)} end)
- |> Enum.map(fn {x, y} -> Templates.pastelink(x, x, y) end)
- |> Enum.join("<br>")
-
-pastes_header = """
-<h1>my pastes</h1>
-<p>random code snippets i found useful or wanted to save :))</p>
-<hr>
-"""
-
-# main_template
-# |> String.replace("<content />", pastes_header <> "<p>" <> paste_data <> "</p>")
-paste_index =
- Mustache.render(
- main_template,
- Map.merge(bricks, %{
- fxg_content: pastes_header <> "<p>" <> paste_data <> "</p>",
- location: "pastes",
- ogp:
- Templates.ogp(
- "thoughts",
- "https://m1kadev.nl/pastes",
- "random code snippets i found useful or wanted to save :))"
- )
- })
- )
-
-File.write("build/pastes/index.html", paste_index)
-
-File.mkdir_p("build/thoughts")
-
-thoughts_template = File.read!("templates/thoughts.html")
-thought_template = File.read!("templates/thought.html")
-
-thought_paths =
- Path.wildcard("thoughts/**/*")
- |> Enum.map(fn path -> {path, Git.get_file_commit(path)} end)
- |> Enum.sort_by(fn {_, t} -> t end, :desc)
-
-thoughts = Enum.map(thought_paths, fn {path, date} -> Builders.thought(path, date) end)
-
-thoughts_html =
- Mustache.render(
- thoughts_template,
- Map.merge(bricks, %{
- fxg_content: Enum.join(thoughts, "<hr>"),
- location: "thoughts",
- ogp:
- Templates.ogp(
- "thoughts",
- "https://m1kadev.nl/thoughts",
- "important thoughts that needed publishing"
- )
- })
- )
-
-for {thought, {path, time}} <- Enum.zip(thoughts, thought_paths) do
- thought = FileX.sanitised_name(path)
- output_path = "build/thoughts/" <> thought <> ".html"
-
- when_said = DateTime.from_unix!(time) |> Calendar.strftime("%H:%M, %d/%m/%y")
- thought_txt = File.read!(path)
-
- thought_html =
- Mustache.render(
- thought_template,
- Map.merge(bricks, %{
- fxg_content: thought_txt,
- thought: thought,
- date: when_said,
- ogp:
- Templates.ogp(
- thought,
- "https://m1kadev.nl/#{String.replace_prefix(output_path, "build/", "")}",
- String.replace(thought_txt, "\"", """)
- )
- })
- )
-
- File.write(output_path, thought_html)
-end
-
-File.write("build/thoughts/index.html", thoughts_html)
-
-File.copy("favicon.ico", "build/favicon.ico")
-
-{:ok, date} = DateTime.now("Europe/Amsterdam")
-build_time = Calendar.strftime(date, "%H:%M:%S %d/%m/%y")
-
-File.write(
- "build/info.txt",
- Templates.build_info(
- commit,
- lightningcss |> String.split_at(13) |> elem(1),
- html_minifier_next,
- uglifyjs |> String.split_at(10) |> elem(1),
- build_time
- )
-)
A kethel/.formatter.exs => kethel/.formatter.exs +4 -0
@@ 0,0 1,4 @@
+# Used by "mix format"
+[
+ inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
+]
A kethel/.gitignore => kethel/.gitignore +25 -0
@@ 0,0 1,25 @@
+/node_modules
+
+# 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/
+
+# 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").
+kethel-*.tar
+
+# Temporary files, for example, from tests.
+/tmp/
A kethel/lib/bricks.ex => kethel/lib/bricks.ex +18 -0
@@ 0,0 1,18 @@
+defmodule Bricks do
+ @typedoc "A path, relative to mix.exs"
+ @type relative_path() :: binary()
+
+ @typedoc "The name of the brick"
+ @type brick_name() :: binary()
+
+ @typedoc "A valid mustache template"
+ @type mustache() :: binary()
+
+ @type bricks() :: %{brick_name() => mustache()}
+
+ @spec collect(relative_path()) :: bricks()
+ def collect(folder) do
+ Path.wildcard(folder <> "/bricks/*.thtml")
+ |> Map.new(fn x -> {FileX.trimmed_filename(x), File.read!(x)} end)
+ end
+end
A kethel/lib/common.ex => kethel/lib/common.ex +3 -0
@@ 0,0 1,3 @@
+defmodule Context do
+ defstruct project_root: "/", fxg: "fxg"
+end
A kethel/lib/filex.ex => kethel/lib/filex.ex +9 -0
@@ 0,0 1,9 @@
+defmodule FileX do
+ @typedoc "Any path"
+ @type path() :: binary()
+
+ @spec trimmed_filename(path()) :: binary()
+ def trimmed_filename(path) do
+ Path.basename(path) |> Path.rootname() |> String.replace("-", "_")
+ end
+end
A kethel/lib/pages.ex => kethel/lib/pages.ex +66 -0
@@ 0,0 1,66 @@
+require Rambo
+
+defmodule Pages do
+ defstruct [:source_files, :main_template, :project_root, :bricks]
+
+ defp trim_abs_path(path, project_root) do
+ # ROOT + pages/
+ begin = byte_size(project_root) + byte_size("pages/")
+ # remove extension
+ binary_part(path, begin, byte_size(path) - begin - byte_size(".fxg"))
+ end
+
+ @spec collect(%Context{}, Bricks.bricks()) :: %Pages{}
+ def collect(project_root, bricks) do
+ pages_root = project_root <> "/pages"
+
+ %Pages{
+ project_root: project_root,
+ source_files:
+ Path.wildcard(pages_root <> "/**/*.fxg")
+ |> Task.async_stream(fn path -> {trim_abs_path(path, project_root), File.read!(path)} end)
+ # we assume every file read succeeds :)) always be positive
+ |> Enum.map(fn {:ok, val} -> val end),
+ main_template: File.read!(project_root <> "/templates/base.thtml"),
+ bricks: bricks
+ }
+ end
+
+ @spec compile(%Pages{}) :: none()
+ def compile(pages) do
+ t_begin = System.monotonic_time(:millisecond)
+ Task.async_stream(pages.source_files, fn page -> compile_file(pages, page) end)
+ |> Enum.to_list()
+ t_end = System.monotonic_time(:millisecond)
+ t_end - t_begin
+ end
+
+ # doc "compiles a file, already read into process memory. Does not return the binary, but instantly writes it to disk"
+ @spec compile_file(%Pages{}, {}) :: none()
+ defp compile_file(pages, {page_path, page_data}) do
+ output_path = "#{pages.project_root}/build#{page_path}.html"
+ # check for a custom template
+ custom_template_path = "#{pages.project_root}/templates/pages#{page_path}.thtml"
+
+ template =
+ case File.read(custom_template_path) do
+ {:ok, custom_template} -> custom_template
+ {:error, :enoent} -> pages.main_template
+ {:error, err} -> raise err
+ end
+
+ mustache_context =
+ Map.merge(%{fxg_content: invoke_fxg(page_data), location: page_path}, pages.bricks)
+
+ page_rendered = Mustache.render(template, mustache_context)
+ File.write!(output_path, page_rendered)
+ IO.puts("[COMPILED] #{pages.project_root}/pages#{page_path}.fxg -> #{output_path}")
+ end
+
+ # doc "Invokes the fxg compiler, a la `fxg -`, piping `data` into the process stdin, and reading the stdout. "
+ @spec invoke_fxg(binary()) :: binary()
+ defp invoke_fxg(data) do
+ {:ok, res} = Rambo.run("fxg", ["-"], in: data)
+ res.out
+ end
+end
A kethel/lib/scripts.ex => kethel/lib/scripts.ex +50 -0
@@ 0,0 1,50 @@
+require Rambo
+
+defmodule Scripts do
+ defstruct [:scripts, :project_root]
+
+ defp ensure_file_structure(project_root) do
+ File.mkdir_p!("#{project_root}/build/scripts")
+ end
+
+ defp trim_abs_path(path, project_root) do
+ # ROOT + scripts/
+ begin = byte_size(project_root) + byte_size("scripts/")
+ # remove extension
+ binary_part(path, begin, byte_size(path) - begin)
+ end
+
+ def collect(project_root) do
+ %Scripts{
+ scripts:
+ Path.wildcard(project_root <> "/scripts/**/*.js")
+ |> Task.async_stream(fn script ->
+ {trim_abs_path(script, project_root), File.read!(script)}
+ end)
+ |> Enum.map(fn {:ok, val} -> val end),
+ project_root: project_root
+ }
+ end
+
+ def compile(scripts) do
+ t_begin = System.monotonic_time(:millisecond)
+
+ ensure_file_structure(scripts.project_root)
+
+ scripts.scripts
+ |> Task.async_stream(fn script -> compile_file(script, scripts.project_root) end)
+ |> Enum.map(fn {:ok, val} -> val end)
+
+ t_end = System.monotonic_time(:millisecond)
+ t_end - t_begin
+ end
+
+ # data | npx lightningcss -m
+ defp compile_file({path, data}, project_root) do
+ {:ok, %Rambo{out: out}} = Rambo.run("npx", ["uglifyjs"], in: data)
+ output_path = "#{project_root}/build/scripts#{path}"
+ File.write!(output_path, out)
+
+ IO.puts("[COMPILED] #{project_root}/scripts#{path} -> #{output_path}")
+ end
+end
A kethel/lib/statics.ex => kethel/lib/statics.ex +31 -0
@@ 0,0 1,31 @@
+defmodule Statics do
+ @moduledoc """
+ Statics is an exception, because we only copy the files. Therefore, the performance gain from reading files into memory for processing isn't worth it. The compile fuction gets called at load-time for all other asset types.
+ """
+
+ @spec ensure_file_structure(binary()) :: :ok
+ defp ensure_file_structure(project_root) do
+ File.mkdir_p!("#{project_root}/build/static/")
+ end
+
+ defp trim_abs_path(path, project_root) do
+ # ROOT + static
+ begin = byte_size(project_root) + byte_size("static/")
+ # remove extension
+ binary_part(path, begin, byte_size(path) - begin)
+ end
+
+ # we dont async_stream here because copying is (relatively speaking) inexpensive, and we want to keep more threads open for other (more expensive) compilation processes
+ def compile(project_root) do
+ ensure_file_structure(project_root)
+
+ for path <- Path.wildcard("#{project_root}/static/**/*") do
+ rel_path = trim_abs_path(path, project_root)
+ output_path = "#{project_root}/build/static#{rel_path}"
+
+ File.copy!(path, output_path)
+
+ IO.puts("[ COPIED ] #{path} -> #{output_path}")
+ end
+ end
+end
A kethel/lib/styles.ex => kethel/lib/styles.ex +50 -0
@@ 0,0 1,50 @@
+require Rambo
+
+defmodule Styles do
+ defstruct [:styles, :project_root]
+
+ defp ensure_file_structure(project_root) do
+ File.mkdir_p!("#{project_root}/build/styles")
+ end
+
+ defp trim_abs_path(path, project_root) do
+ # ROOT + styles/
+ begin = byte_size(project_root) + byte_size("styles/")
+ # remove extension
+ binary_part(path, begin, byte_size(path) - begin)
+ end
+
+ def collect(project_root) do
+ %Styles{
+ styles:
+ Path.wildcard(project_root <> "/styles/**/*.css")
+ |> Task.async_stream(fn style ->
+ {trim_abs_path(style, project_root), File.read!(style)}
+ end)
+ |> Enum.map(fn {:ok, val} -> val end),
+ project_root: project_root
+ }
+ end
+
+ def compile(styles) do
+ t_begin = System.monotonic_time(:millisecond)
+
+ ensure_file_structure(styles.project_root)
+
+ styles.styles
+ |> Task.async_stream(fn style -> compile_file(style, styles.project_root) end)
+ |> Enum.map(fn {:ok, val} -> val end)
+
+ t_end = System.monotonic_time(:millisecond)
+ t_end - t_begin
+ end
+
+ # data | npx lightningcss -m
+ defp compile_file({path, data}, project_root) do
+ {:ok, %Rambo{out: out}} = Rambo.run("npx", ["lightningcss", "-m"], in: data)
+ output_path = "#{project_root}/build/styles#{path}"
+ File.write!(output_path, out)
+
+ IO.puts("[COMPILED] #{project_root}/styles#{path} -> #{output_path}")
+ end
+end
A kethel/lib/thoughts.ex => kethel/lib/thoughts.ex +89 -0
@@ 0,0 1,89 @@
+defmodule Thoughts do
+ defstruct [:thoughts, :template, :bricks, :project_root, :index_template, :inline_template ]
+
+ @spec urlify(binary()) :: binary()
+ defp urlify(name) do
+ name
+ |> String.replace(" ", "_")
+ end
+
+ @spec trim_abs_path(binary(), binary()) :: binary()
+ defp trim_abs_path(path, project_root) do
+ # ROOT + thoughts/
+ begin = byte_size(project_root) + byte_size("/thoughts/")
+ binary_part(path, begin, byte_size(path) - begin)
+ end
+
+ @spec collect(binary(), %{binary() => binary()}) :: %Thoughts{}
+ def collect(project_root, bricks) do
+ %Thoughts{
+ thoughts:
+ Path.wildcard("#{project_root}/thoughts/*")
+ |> Enum.map(fn path -> {path, get_file_commit_date(path), File.read!(path)} end)
+ |> Enum.sort_by(fn {_, date, _ } -> date end, :desc),
+ inline_template: File.read!("#{project_root}/templates/inline_thought.thtml"),
+ template: File.read!("#{project_root}/templates/thought.thtml"),
+ index_template: File.read!("#{project_root}/templates/thoughts.thtml"),
+ bricks: bricks,
+ project_root: project_root
+ }
+ end
+
+ @spec ensure_folders(binary()) :: :ok
+ def ensure_folders(project_root) do
+ File.mkdir_p!("#{project_root}/build/thoughts/")
+ end
+
+ @spec compile(%Thoughts{}) :: pos_integer()
+ def compile(thoughts) do
+ t_begin = System.monotonic_time(:millisecond)
+ ensure_folders(thoughts.project_root)
+
+ thoughts.thoughts
+ |> Task.async_stream(fn thought ->
+ compile_file(thought, thoughts.template, thoughts.bricks, thoughts.project_root) end)
+ |> Enum.to_list()
+
+ # generate index
+ index_content = thoughts.thoughts
+ |> Enum.map(fn thought -> inline_thought(thought, thoughts) end)
+ |> Enum.join()
+ index = Mustache.render(thoughts.index_template, Map.merge(thoughts.bricks, %{fxg_content: index_content}))
+ File.write!("#{thoughts.project_root}/build/thoughts/index.html", index)
+ IO.puts("[COMPILED] #{thoughts.project_root}/build/thoughts/index.html")
+
+ t_end = System.monotonic_time(:millisecond)
+ t_end - t_begin
+ end
+
+ defp inline_thought({path, date, thought}, context) do
+ stripped_name = String.replace_prefix(path, "#{context.project_root}/thoughts/", "")
+ location = "https://m1kadev.nl/thoughts/#{urlify(stripped_name)}.html"
+ title = "<a href=\"#{location}\">#{stripped_name}</a>"
+ Mustache.render(context.inline_template, %{name: title, date: date, thought: thought})
+ end
+
+ defp compile_file({path, date, thought}, template, bricks, project_root) do
+ name = trim_abs_path(path, project_root)
+ output_path = "#{project_root}/build/thoughts/#{urlify(name)}.html"
+ mustache_context = Map.merge(bricks, %{thought: thought, name: name, date: date})
+
+ File.write!(output_path, Mustache.render(template, mustache_context))
+ IO.puts("[COMPILED] #{path} -> #{output_path}")
+ end
+
+ def get_file_commit_date(path) do
+ {ts_string, 0} = System.cmd("git", ["log", "--format=%ct", path])
+ String.trim_trailing(ts_string)
+ |> String.to_integer()
+ end
+
+ def to_rss({path, date, thought}, template, project_root) do
+ location = String.replace_prefix(path, project_root <> "/thoughts/", "")
+ link = "https://m1kadev.nl/thoughts/" <> urlify(location) <> ".html"
+ rfc_date = date
+ |> DateTime.from_unix!()
+ |> Calendar.strftime("%a, %d %b %Y %H:%M:%S %Z")
+ Mustache.render(template, %{title: location, date: rfc_date, description: thought, category: "thoughts", link: link } )
+ end
+end
A kethel/main.exs => kethel/main.exs +92 -0
@@ 0,0 1,92 @@
+args = System.argv()
+
+folder = Enum.at(args, 1)
+
+if folder != nil do
+ project_root = Path.expand(folder)
+
+ File.rm_rf!("#{project_root}/build")
+ File.mkdir_p("#{project_root}/build")
+
+ collection_time_start = System.monotonic_time(:millisecond)
+
+ # other contents depend on this, so we cant async it
+ bricks = Bricks.collect(project_root)
+
+ # special case, see module documentation
+ statics_task = Task.async(fn -> Statics.compile(project_root) end)
+
+ styles_task = Task.async(fn -> Styles.collect(project_root) end)
+ scripts_task = Task.async(fn -> Scripts.collect(project_root) end)
+ pages_task = Task.async(fn -> Pages.collect(project_root, bricks) end)
+ thoughts_task = Task.async(fn -> Thoughts.collect(project_root, bricks) end)
+
+ [styles, pages, scripts, thoughts] =
+ Task.await_many([styles_task, pages_task, scripts_task, thoughts_task], :infinity)
+
+ collection_time_end = System.monotonic_time(:millisecond)
+
+ compilation_time_start = System.monotonic_time(:millisecond)
+
+ pages_compile_task = Task.async(fn -> Pages.compile(pages) end)
+ styles_compile_task = Task.async(fn -> Styles.compile(styles) end)
+ scripts_compile_task = Task.async(fn -> Scripts.compile(scripts) end)
+ thoughts_compile_task = Task.async(fn -> Thoughts.compile(thoughts) end)
+
+ [ pages_time, styles_time, scripts_time, thoughts_time] = Task.await_many(
+ [
+ pages_compile_task,
+ styles_compile_task,
+ scripts_compile_task,
+ thoughts_compile_task
+ ],
+ :infinity
+ )
+
+ compilation_time_end = System.monotonic_time(:millisecond)
+
+ rss_header = File.read!("#{project_root}/rss/feed.txml")
+ rss_footer = "</channel></rss>"
+ rss_item_template = File.read!("#{project_root}/rss/item.txml")
+
+ rss_thoughts = thoughts.thoughts
+ |> Enum.take(10)
+ |> Enum.map(fn thought -> Thoughts.to_rss(thought, rss_item_template, project_root) end)
+ |> Enum.join();
+
+ File.write!("#{project_root}/build/rss.xml", rss_header <> rss_thoughts <> rss_footer)
+
+ IO.puts("[COMPILED] #{project_root}/build/rss.xml")
+
+ { lcss_version, 0 }= System.cmd("npx", [ "lightningcss", "-V" ])
+ { hmn_version, 0 } = System.cmd("npx", [ "html-minifier-next", "-V" ])
+ { ujs_version, 0 } = System.cmd("npx", [ "uglifyjs", "-V" ])
+ { git_commit, 0 } = System.cmd("git", [ "rev-parse", "HEAD" ])
+
+ { build_date, 0 } = System.cmd("date", ["+%H:%M %d/%m/%y"])
+
+ info_txt = """
+ commit=#{git_commit}
+ lightningcss=#{lcss_version}
+ html_minifier_next=#{hmn_version}
+ uglifyjs=#{ujs_version}
+ build_time=#{build_date}
+ """
+
+ File.write!("#{project_root}/build/info.txt", info_txt)
+
+ IO.puts("[COMPILED] #{project_root}/build/info.txt")
+
+ IO.puts("Finalising...");
+
+ File.cp!("#{project_root}/favicon.ico", "#{project_root}/build/favicon.ico")
+ IO.puts("")
+ IO.puts(:stderr, "===== BUILD RESULTS =====")
+ IO.puts(:stderr, "FILE READING (*.collect()) | #{collection_time_end - collection_time_start}ms")
+ IO.puts(:stderr, "Root page (compile) | #{pages_time}ms")
+ IO.puts(:stderr, "Styles (compile) | #{styles_time}ms")
+ IO.puts(:stderr, "Scripts (compile) | #{scripts_time}ms")
+ IO.puts(:stderr, "Thoughts (compile) | #{thoughts_time}ms")
+else
+ IO.puts(:stderr, "The root project folder should be provided on the command line")
+end
A kethel/mix.exs => kethel/mix.exs +20 -0
@@ 0,0 1,20 @@
+defmodule Kethel.MixProject do
+ use Mix.Project
+
+ def project do
+ [
+ app: :kethel,
+ version: "0.1.0",
+ elixir: "~> 1.18",
+ start_permanent: Mix.env() == :prod,
+ deps: deps()
+ ]
+ end
+
+ defp deps do
+ [
+ {:mustache, "~> 0.5.0"},
+ {:rambo, "~> 0.3.4"}
+ ]
+ end
+end
A kethel/mix.lock => kethel/mix.lock +13 -0
@@ 0,0 1,13 @@
+%{
+ "certifi": {:hex, :certifi, "2.15.0", "0e6e882fcdaaa0a5a9f2b3db55b1394dba07e8d6d9bcad08318fb604c6839712", [:rebar3], [], "hexpm", "b147ed22ce71d72eafdad94f055165c1c182f61a2ff49df28bcc71d1d5b94a60"},
+ "hackney": {:hex, :hackney, "1.25.0", "390e9b83f31e5b325b9f43b76e1a785cbdb69b5b6cd4e079aa67835ded046867", [:rebar3], [{:certifi, "~> 2.15.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.4", [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.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "7209bfd75fd1f42467211ff8f59ea74d6f2a9e81cbcee95a56711ee79fd6b1d4"},
+ "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
+ "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
+ "mimerl": {:hex, :mimerl, "1.4.0", "3882a5ca67fbbe7117ba8947f27643557adec38fa2307490c4c4207624cb213b", [:rebar3], [], "hexpm", "13af15f9f68c65884ecca3a3891d50a7b57d82152792f3e19d88650aa126b144"},
+ "mustache": {:hex, :mustache, "0.5.1", "1bfee8a68a8e72d47616541a93a632ae1684c1abc17c9eb5f7bfecb78d7496e5", [:mix], [], "hexpm", "524c9bbb6080a52d7b6806436b4e269e0224c785a228faf3293ef30a75016bfa"},
+ "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
+ "rambo": {:hex, :rambo, "0.3.4", "8962ac3bd1a633ee9d0e8b44373c7913e3ce3d875b4151dcd060886092d2dce7", [:mix], [], "hexpm", "0cc54ed089fbbc84b65f4b8a774224ebfe60e5c80186fafc7910b3e379ad58f1"},
+ "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
+ "tzdata": {:hex, :tzdata, "1.1.3", "b1cef7bb6de1de90d4ddc25d33892b32830f907e7fc2fccd1e7e22778ab7dfbc", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "d4ca85575a064d29d4e94253ee95912edfb165938743dbf002acdf0dcecb0c28"},
+ "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"},
+}
A kethel/package-lock.json => kethel/package-lock.json +878 -0
@@ 0,0 1,878 @@
+{
+ "name": "kethel",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "kethel",
+ "version": "0.1.0",
+ "license": "MIT",
+ "dependencies": {
+ "html-minifier-next": "^4.17.0",
+ "lightningcss-cli": "^1.30.2",
+ "uglify-js": "^3.19.3"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
+ "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@types/relateurl": {
+ "version": "0.2.33",
+ "resolved": "https://registry.npmjs.org/@types/relateurl/-/relateurl-0.2.33.tgz",
+ "integrity": "sha512-bTQCKsVbIdzLqZhLkF5fcJQreE4y1ro4DIyVrlDNSCJRRwHhB8Z+4zXXa8jN6eDvc2HbRsEYgbvrnGvi54EpSw==",
+ "license": "MIT"
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "license": "MIT"
+ },
+ "node_modules/camel-case": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
+ "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
+ "license": "MIT",
+ "dependencies": {
+ "pascal-case": "^3.1.2",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/capital-case": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz",
+ "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
+ "node_modules/change-case": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz",
+ "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==",
+ "license": "MIT",
+ "dependencies": {
+ "camel-case": "^4.1.2",
+ "capital-case": "^1.0.4",
+ "constant-case": "^3.0.4",
+ "dot-case": "^3.0.4",
+ "header-case": "^2.0.4",
+ "no-case": "^3.0.4",
+ "param-case": "^3.0.4",
+ "pascal-case": "^3.1.2",
+ "path-case": "^3.0.4",
+ "sentence-case": "^3.0.4",
+ "snake-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/commander": {
+ "version": "14.0.2",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz",
+ "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/constant-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz",
+ "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case": "^2.0.2"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dot-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
+ "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/entities": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.0.tgz",
+ "integrity": "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/header-case": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz",
+ "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==",
+ "license": "MIT",
+ "dependencies": {
+ "capital-case": "^1.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/html-minifier-next": {
+ "version": "4.17.0",
+ "resolved": "https://registry.npmjs.org/html-minifier-next/-/html-minifier-next-4.17.0.tgz",
+ "integrity": "sha512-7REp/offCDTw5QdWd2D14vv5MsTslrakD1LT5Nnows2praQvuFkP/pjV3YwtE9H+xRG9Mjr32UDE9zS2s+YUaw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/relateurl": "^0.2.33",
+ "change-case": "^4.1.2",
+ "commander": "^14.0.2",
+ "entities": "^7.0.0",
+ "lightningcss": "^1.28.2",
+ "relateurl": "^0.2.7",
+ "terser": "^5.44.1"
+ },
+ "bin": {
+ "html-minifier-next": "cli.js"
+ },
+ "funding": {
+ "url": "https://github.com/j9t/html-minifier-next?sponsor=1"
+ },
+ "peerDependencies": {
+ "@swc/core": "^1.15.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
+ "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.30.2",
+ "lightningcss-darwin-arm64": "1.30.2",
+ "lightningcss-darwin-x64": "1.30.2",
+ "lightningcss-freebsd-x64": "1.30.2",
+ "lightningcss-linux-arm-gnueabihf": "1.30.2",
+ "lightningcss-linux-arm64-gnu": "1.30.2",
+ "lightningcss-linux-arm64-musl": "1.30.2",
+ "lightningcss-linux-x64-gnu": "1.30.2",
+ "lightningcss-linux-x64-musl": "1.30.2",
+ "lightningcss-win32-arm64-msvc": "1.30.2",
+ "lightningcss-win32-x64-msvc": "1.30.2"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz",
+ "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli/-/lightningcss-cli-1.30.2.tgz",
+ "integrity": "sha512-vTm/775SqvQ74T0y4twiqjopXV6SnAFguuRpnbKUE9aXxqJGxWJoHS77ZRkJj3dKmnD61ejOawg3FBiTT8/3Tw==",
+ "hasInstallScript": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "bin": {
+ "lightningcss": "lightningcss"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-cli-android-arm64": "1.30.2",
+ "lightningcss-cli-darwin-arm64": "1.30.2",
+ "lightningcss-cli-darwin-x64": "1.30.2",
+ "lightningcss-cli-freebsd-x64": "1.30.2",
+ "lightningcss-cli-linux-arm-gnueabihf": "1.30.2",
+ "lightningcss-cli-linux-arm64-gnu": "1.30.2",
+ "lightningcss-cli-linux-arm64-musl": "1.30.2",
+ "lightningcss-cli-linux-x64-gnu": "1.30.2",
+ "lightningcss-cli-linux-x64-musl": "1.30.2",
+ "lightningcss-cli-win32-arm64-msvc": "1.30.2",
+ "lightningcss-cli-win32-x64-msvc": "1.30.2"
+ }
+ },
+ "node_modules/lightningcss-cli-android-arm64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-android-arm64/-/lightningcss-cli-android-arm64-1.30.2.tgz",
+ "integrity": "sha512-CcntRK9yNjFRiZKwW9m4sf5WYYNOGxlD4ROymyIb+KPbsrEBAZSaknoUM1aIhuhvB/TUTtVmPKvt/Zu0LeSR7g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-darwin-arm64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-darwin-arm64/-/lightningcss-cli-darwin-arm64-1.30.2.tgz",
+ "integrity": "sha512-Z2STTSes07R2R5tOPY85HipU+z1SwUBV2Yp5emAcqL+o5RsOAE1JWbkloQWa++8R6b/gxzD11VPM3WtCCqL8Gg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-darwin-x64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-darwin-x64/-/lightningcss-cli-darwin-x64-1.30.2.tgz",
+ "integrity": "sha512-N0IGWWsLnv81sDw9i/vvaisp55uDnhoapGBEJ8lMED064CsUHpLCK7L/5B8kFj8UI97zL+xb7KTTGOHkcC8skg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-freebsd-x64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-freebsd-x64/-/lightningcss-cli-freebsd-x64-1.30.2.tgz",
+ "integrity": "sha512-17pN+hnxU2fPOGhGzMhPf2KZrIFFwEtrIZYshGDM/jhskJmDq57DAt5esh7PVDUjNkD7JDt3a7E9xJEVltc2Kg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-linux-arm-gnueabihf": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-linux-arm-gnueabihf/-/lightningcss-cli-linux-arm-gnueabihf-1.30.2.tgz",
+ "integrity": "sha512-aaeEtZXqvNWDyHYCThugev1YPGlouvY9lE+o9QJg/Z5GTNb/1EM2TaTBGEwdG5m1ChYukc2lD5CPIEHjQ7qzSA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-linux-arm64-gnu": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-linux-arm64-gnu/-/lightningcss-cli-linux-arm64-gnu-1.30.2.tgz",
+ "integrity": "sha512-XhgByx2H85MeEWGtI0XR+ugtQRBc/bvRN8gSGdXa3YqVONmACsLj7shatVHmqVOaPgtnevKVKl7wtqfN9pW96A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-linux-arm64-musl": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-linux-arm64-musl/-/lightningcss-cli-linux-arm64-musl-1.30.2.tgz",
+ "integrity": "sha512-UR7/N/33b8sG9e07TccxJvWxvNdlMFglesdgv1fi+wMa8sbN3tBPXOGj67B5nlVWHskYD9bHLPahemRWxnNuHQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-linux-x64-gnu": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-linux-x64-gnu/-/lightningcss-cli-linux-x64-gnu-1.30.2.tgz",
+ "integrity": "sha512-W6U9LNo+4mCsEB22AIvtRVGp8NETN4by9U2AIRDzZbYZYb7W9+1H56xKzb/2ABQEAoDrh/7027I/XDheuGrlZg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-linux-x64-musl": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-linux-x64-musl/-/lightningcss-cli-linux-x64-musl-1.30.2.tgz",
+ "integrity": "sha512-Qe6hwTXmc37LnKPIyoY20EQgHsVoAeTUF389Bt7sJfK5JZPLm7EyVvqkO4DukCx4Dv4DSskU03o+qT1+s6UeVw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-win32-arm64-msvc": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-win32-arm64-msvc/-/lightningcss-cli-win32-arm64-msvc-1.30.2.tgz",
+ "integrity": "sha512-PZrkKHhYncBRh/Xe2Voa7t7ors+zUMU8hm5qOLgR0W5NfhbwwjLBXa3+fFF+BVdpTeyjLGF1ovzKIWSF1rMN/g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-cli-win32-x64-msvc": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-cli-win32-x64-msvc/-/lightningcss-cli-win32-x64-msvc-1.30.2.tgz",
+ "integrity": "sha512-5VUIS1Dcbkcy2SDr7vBlKfwpSx2BUlZwmvoRVWA+OkkLsQhVUtLUKheJJXsOFruBn9uV8FH8KPLkvTJzuGFLyQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz",
+ "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz",
+ "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz",
+ "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz",
+ "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz",
+ "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz",
+ "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz",
+ "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz",
+ "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz",
+ "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz",
+ "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lower-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
+ "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/no-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
+ "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
+ "license": "MIT",
+ "dependencies": {
+ "lower-case": "^2.0.2",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/param-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
+ "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/pascal-case": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
+ "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/path-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz",
+ "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/relateurl": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
+ "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/sentence-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz",
+ "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
+ "node_modules/snake-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
+ "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/terser": {
+ "version": "5.44.1",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
+ "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.15.0",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/terser/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "license": "MIT"
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/uglify-js": {
+ "version": "3.19.3",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
+ "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "uglifyjs": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/upper-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz",
+ "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/upper-case-first": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz",
+ "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ }
+ }
+}
A kethel/package.json => kethel/package.json +12 -0
@@ 0,0 1,12 @@
+{
+ "name": "kethel",
+ "version": "0.1.0",
+ "description": "My own build system",
+ "author": "m1kadev",
+ "license": "MIT",
+ "dependencies": {
+ "html-minifier-next": "^4.17.0",
+ "lightningcss-cli": "^1.30.2",
+ "uglify-js": "^3.19.3"
+ }
+}
M pages/colophon.fxg => pages/colophon.fxg +7 -1
@@ 2,4 2,10 @@
== about ==
-you're looking at a <#https://en.wiktionary.org/wiki/beautiful#English beautiful> site, with <#https://caddyserver.com/ caddy> as its backend. all source pages are written in my own markup language, <#https://github.com/m1kadev/fxg fxg>. site generation is done by a homebrewn <#https://github.com/m1kadev/www.m1kadev.nl/blob/main/build.exs elixir script>. all code (including <#https://github.com/m1kadev/fxg fxg>) is licenced under the MIT licence.>
\ No newline at end of file
+you're looking at a <#https://en.wiktionary.org/wiki/beautiful#English beautiful> site, with <#https://caddyserver.com/ caddy> as its backend.
+
+the site generator is a home-grown non-gmo <#https://github.com/m1kadev/www.m1kadev.nl/tree/main/kethel/ elixir app>. the internal markup language is <#https://github.com/m1kadev/fxg fxg>, made to be more legible than markdown.
+
+templating the final html is handled by <#https://mustache.github.io mustache>, a stateless templating library.
+
+css, js, and html parsing are handled by lightningcss, uglifyjs, and html-minifier-next, respectively.
A => +1 -0
@@ 0,0 1,1 @@
<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>m1kadev.nl updates :3</title><description>placeholder description</description><language>en</language>
A => +1 -0
@@ 0,0 1,1 @@
<item><title>{{title}}</title><description>{{description}}</description><link>{{link}}</link><pubDate>{{date}}</pubDate><category>{{category}}</category></item>
M styles/thoughts.css => styles/thoughts.css +5 -1
@@ 18,4 18,8 @@
.thought>small {
text-align: right;
display: block;
-}>
\ No newline at end of file
+}
+
+main hr:first-of-type {
+ display: none;
+}
R templates/base.html => templates/base.thtml +0 -0
A templates/inline_thought.thtml => templates/inline_thought.thtml +8 -0
@@ 0,0 1,8 @@
+<hr>
+<div class="thought">
+ <h2> {{ &name }} </h2>
+ <span>
+ {{ thought }}
+ </span>
+ <small>-mika, {{ date }}</small>
+</div>
R templates/pages/colophon.html => templates/pages/colophon.thtml +0 -0
R templates/pages/index.html => templates/pages/index.thtml +0 -0
R templates/paste.html => templates/paste.thtml +0 -0
R templates/thought.html => templates/thought.thtml +3 -3
@@ 7,7 7,7 @@
<link rel="stylesheet" href="/styles/thought.css">
- <title> {{ thought }} - m1kadev</title>
+ <title> {{ name }} - m1kadev</title>
{{ &ogp }}
@@ 19,9 19,9 @@
<div id="content">
<main>
- <h2> {{ thought }} </h2>
+ <h2> {{ name }} </h2>
<span id="thought">
- {{ &fxg_content }}
+ {{ thought }}
</span>
<small>-mika, {{ date }}</small>
<hr>
R templates/thoughts.html => templates/thoughts.thtml +0 -0