From a27c175068ee6ae7c44961854db5e9f1ba7d83a9 Mon Sep 17 00:00:00 2001 From: Alex Tavarez Date: Tue, 2 Sep 2025 17:44:55 -0400 Subject: [PATCH] Added module with functions for managing SASS/CSS themes of website --- lib/sukaato_web/theme.ex | 136 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 lib/sukaato_web/theme.ex diff --git a/lib/sukaato_web/theme.ex b/lib/sukaato_web/theme.ex new file mode 100644 index 0000000..4f278e9 --- /dev/null +++ b/lib/sukaato_web/theme.ex @@ -0,0 +1,136 @@ +defmodule SukaatoWeb.Theme do + @moduledoc """ + Manage website themes. + """ + + @rel_proj_root "../.." + @central_sass "export.sass" + @site_config Toml.decode_file(Path.expand(@rel_proj_root <> "/site.toml", __DIR__)) + @theme_filepath Path.expand(@rel_proj_root <> "/assets/sass/themes/" <> elem(@site_config, 1)["site"]["theme"] <> "/" <> @central_sass, __DIR__) + @theme_glob Path.expand(@rel_proj_root <> "/assets/sass/themes/*/" <> @central_sass, __DIR__) + @theme_linkpath Path.expand(@rel_proj_root <> "/assets/sass/app.sass", __DIR__) + + defp get_installed() do + path_list = Path.wildcard(@theme_glob) + extract_theme = fn theme_path -> Enum.at(Path.split(theme_path), length(Path.split(theme_path)) - 2) end + installed = Enum.map(path_list, fn p -> extract_theme.(p) end) + + installed + end + + @doc """ + List installed website themes. + """ + def list() do + get_installed() + end + + defp get_current() do + if File.exists?(@theme_linkpath) do + link_path = File.read_link(@theme_linkpath) + + if elem(link_path, 0) == :ok do + split_path = Path.split(elem(link_path, 1)) + current_theme = Enum.at(split_path, length(split_path) - 2) + {:ok, current_theme} + else + {:error, "link not traceable--sure its a link?"} + end + else + {:error, "symbolic link does not exist"} + end + end + + @doc """ + List website themes under project root's 'assets/sass/themes' path. + """ + def list(status) do + case status do + :installed -> + get_installed() + :current -> + elem(get_current(), 1) + end + end + + defp change_theme_path(theme_name) do + Path.expand(@rel_proj_root <> "/assets/sass/themes/" <> theme_name <> "/" <> @central_sass, __DIR__) + end + + @doc """ + Update website theme based on stored website settings, refreshes current theme otherwise. + """ + def update() do + if File.exists?(@theme_filepath) do + result = File.ln_s(@theme_filepath, @theme_linkpath) + + if result == :ok do + {:ok, @theme_linkpath} + else + {:error, {@theme_filepath, @theme_linkpath}} + end + else + link_path = File.read_link(@theme_linkpath) + + if Enum.at(link_path, 0) == :ok do + split_path = Path.split(Enum.at(link_path, 1)) + current_theme = Enum.at(split_path, length(split_path) - 2) + + # @TODO find some way to notify theme could not be found + current_path = change_theme_path(current_theme) + result = File.ln_s(current_path, @theme_linkpath) + + if result == :ok do + {:ok, "current theme '" <> current_theme <> "' reinstated as no declared theme"} + else + result = File.ln_s(change_theme_path("default"), @theme_linkpath) + + if result == :ok do + {:ok, "current theme '" <> current_theme <> "' unavailable, successful fallback to default theme"} + else + {:error, "current theme '" <> current_theme <> "' unavailable, failed fallback to default theme"} + end + end + else + {:error, @theme_linkpath} + end + end + end + + @doc """ + Update website theme in-memory, independent of stored website settings. + """ + def update(theme_name) do + theme_path = change_theme_path(theme_name) + + if File.exists?(theme_path) do + # @TODO find some way to notify theme could not be found + result = File.ln_s(theme_path, @theme_linkpath) + + if result == :ok do + {:ok, @theme_linkpath} + else + update() + end + else + update() + end + end + + def grab(), do: nil + + def unpack(), do: nil + + def install(), do: nil + + def remove(theme_name) do + theme_path = change_theme_path(theme_name) + + if theme_name != "default" do + result = File.rm_rf(theme_path) + result + else + {:error, theme_name <> " cannot be uninstalled"} + end + end +end