Current section
3 Versions
Jump to
Current section
3 Versions
Compare versions
26
files changed
+838
additions
-262
deletions
| @@ -5,10 +5,10 @@ | |
| 5 5 | |
| 6 6 | # Lit |
| 7 7 | |
| 8 | - Lit is a rapid admin generator for Phoenix apps. It creates custom templates and relies |
| 9 | - on the Phoenix html generator under the hood. |
| 8 | + Lit is an admin generator for Phoenix LiveView and Talwind apps. It creates custom templates and relies |
| 9 | + on the Phoenix live generator under the hood. The project is a fork from [Torch](https://github.com/mojotech/torch) |
| 10 10 | |
| 11 | -  |
| 11 | +  |
| 12 12 | |
| 13 13 | ## Installation |
| 14 14 | |
| @@ -19,47 +19,31 @@ To install Lit, perform the following steps: | |
| 19 19 | ```elixir |
| 20 20 | def deps do |
| 21 21 | [ |
| 22 | - {:lit, "~> 3.4"} |
| 22 | + {:lit, "~> 0.1.0"} |
| 23 23 | ] |
| 24 24 | end |
| 25 25 | ``` |
| 26 26 | |
| 27 | - 2. Add a `Plug.Static` plug to your `endpoint.ex`: |
| 28 | - |
| 29 | - ```elixir |
| 30 | - plug( |
| 31 | - Plug.Static, |
| 32 | - at: "/lit", |
| 33 | - from: {:lit, "priv/static"}, |
| 34 | - gzip: true, |
| 35 | - cache_control_for_etags: "public, max-age=86400" |
| 36 | - ) |
| 37 | - ``` |
| 38 | - |
| 39 | - 3. Configure Lit by adding the following to your `config.exs`. |
| 27 | + 2. Configure Lit by adding the following to your `config.exs`. |
| 40 28 | |
| 41 29 | ``` |
| 42 30 | config :lit, |
| 43 31 | otp_app: :my_app_name, |
| 44 | - template_format: "eex" || "slime" |
| 32 | + default_web_namespace: "admin" |
| 45 33 | ``` |
| 46 34 | |
| 47 | - 4. Run `mix lit.install` |
| 48 | - |
| 49 | - **NOTE:** You can also choose to use `slime` templates, but you will need to |
| 50 | - first [install Phoenix Slime](https://github.com/slime-lang/phoenix_slime) and |
| 51 | - then update your configuration to specify `template_format: "slime"`. |
| 35 | + 3. Run `mix lit.install` |
| 52 36 | |
| 53 37 | Now you're ready to start generating your admin! :tada: |
| 54 38 | |
| 55 39 | ## Usage |
| 56 40 | |
| 57 41 | Lit uses Phoenix generators under the hood. Lit injects it's own custom templates |
| 58 | - into your `priv/static` directory, then runs the `mix phx.gen.html` task with the options |
| 42 | + into your `priv/static` directory, then runs the `mix phx.gen.live` task with the options |
| 59 43 | you passed in. Finally, it uninstalls the custom templates so they don't interfere with |
| 60 44 | running the plain Phoenix generators. |
| 61 45 | |
| 62 | - In light of that fact, the `lit.gen.html` task takes all the same arguments as the `phx.gen.html`, |
| 46 | + In light of that fact, the `lit.gen.live` task takes all the same arguments as the `phx.gen.live`, |
| 63 47 | but does some extra configuration on either end. Checkout `mix help phx.gen.html` for more details |
| 64 48 | about the supported options and format. |
| 65 49 | |
| @@ -76,21 +60,9 @@ Add the resource to your browser scope in lib/my_app_web/router.ex: | |
| 76 60 | |
| 77 61 | resources "/posts", PostController |
| 78 62 | |
| 79 | - Ensure the following is added to your endpoint.ex: |
| 80 | - |
| 81 | - plug( |
| 82 | - Plug.Static, |
| 83 | - at: "/lit", |
| 84 | - from: {:lit, "priv/static"}, |
| 85 | - gzip: true, |
| 86 | - cache_control_for_etags: "public, max-age=86400", |
| 87 | - headers: [{"access-control-allow-origin", "*"}] |
| 88 | - ) |
| 89 | - |
| 90 | - :fire: Lit generated html for Posts! :fire: |
| 91 63 | ``` |
| 92 64 | |
| 93 | - Lit also installed an admin layout into your `my_app_web/templates/layout/lit.html.eex`. |
| 65 | + Lit also installed an admin layout into your `my_app_web/templates/admin/layout/lit.html.leex`. |
| 94 66 | You will want to update it to include your new navigation link: |
| 95 67 | |
| 96 68 | ``` |
| @@ -172,48 +144,4 @@ the above `eex` to work. | |
| 172 144 | |
| 173 145 | ## Styling |
| 174 146 | |
| 175 | - Lit generates two CSS themes you can use: `base.css` & `theme.css`. |
| 176 | - The base styles are basically bare bones, and the theme styles look like the screenshot |
| 177 | - above. Just change the stylesheet link in the `lit.html.eex` layout. |
| 178 | - |
| 179 | - If you want to use the theme, but override the colors, you'll need to include your |
| 180 | - own stylesheet with the specific overrides. |
| 181 | - |
| 182 | - ## Internationalization |
| 183 | - |
| 184 | - Lit comes with `.po` files for `en`, `ru`, `es` and `de` locales. If you are using |
| 185 | - lit and can provide us with translation files for other languages, please |
| 186 | - submit a Pull Request with the translation file. We'd love to add as many |
| 187 | - translations as possible. |
| 188 | - |
| 189 | - If you wish to add your own customized translations, you can configure Lit to |
| 190 | - use your own custom `MessagesBackend` and adding it in your Lit configuration |
| 191 | - settings in `config.exs`. You can find the all messages that can be customized |
| 192 | - in the default [i18n/backend.ex](lib/lit/i18n/backend.ex) file. |
| 193 | - |
| 194 | - If you are customizing a backend for a "standard" spoken language, please submit |
| 195 | - back a proper `.po` translation file for us to include in the official Lit |
| 196 | - releases so other users can take advantage. |
| 197 | - |
| 198 | - **Example** |
| 199 | - |
| 200 | - ```elixir |
| 201 | - defmodule MyApp.CustomMessagesBackend do |
| 202 | - def message("Contains"), do: "** CUSTOM Contains **" |
| 203 | - def message("Equals"), do: "** CUSTOM Equals ****" |
| 204 | - def message("< Prev"), do: "<--" |
| 205 | - def message("Next >"), do: "-->" |
| 206 | - |
| 207 | - # You can add a fallback so it won't break with newly added messages or |
| 208 | - # messages you did not customize |
| 209 | - def message(text), do: Lit.I18n.Backend.message(text) |
| 210 | - end |
| 211 | - ``` |
| 212 | - |
| 213 | - ```elixir |
| 214 | - # config.exs |
| 215 | - config :lit, |
| 216 | - otp_app: :my_app_name, |
| 217 | - i18n_backend: MyApp.CustomMessagesBackend |
| 218 | - template_format: "eex" || "slime" |
| 219 | - ``` |
| 147 | + Lit depends on that you use Tailwind in your application. The generated codes has comes with utilitu classes. |
| @@ -12,8 +12,9 @@ | |
| 12 12 | <<"lib/lit/i18n/backend.ex">>,<<"lib/lit/views">>, |
| 13 13 | <<"lib/lit/views/page_view.ex">>,<<"lib/lit/views/flash_view.ex">>, |
| 14 14 | <<"lib/lit/views/table_view.ex">>,<<"lib/lit/views/filter_view.ex">>, |
| 15 | - <<"lib/lit/views/pagination_view.ex">>,<<"lib/lit/i18n.ex">>,<<"lib/mix">>, |
| 16 | - <<"lib/mix/tasks">>,<<"lib/mix/tasks/lit.uninstall.ex">>, |
| 15 | + <<"lib/lit/views/pagination_view.ex">>,<<"lib/lit/i18n.ex">>, |
| 16 | + <<"lib/lit_web">>,<<"lib/lit_web/live">>,<<"lib/lit_web/live/admin">>, |
| 17 | + <<"lib/mix">>,<<"lib/mix/tasks">>,<<"lib/mix/tasks/lit.uninstall.ex">>, |
| 17 18 | <<"lib/mix/tasks/lit.gen.live.ex">>,<<"lib/mix/tasks/lit.install.ex">>, |
| 18 19 | <<"lib/mix/tasks/lit.gen.html.ex">>,<<"lib/mix/lit.ex">>, |
| 19 20 | <<"lib/gettext.ex">>,<<"priv">>,<<"priv/gettext">>, |
| @@ -30,8 +31,9 @@ | |
| 30 31 | <<"priv/static/lit.js">>,<<"priv/static/theme.css.map">>, |
| 31 32 | <<"priv/static/base.css.map">>,<<"priv/static/lit-logo.png">>, |
| 32 33 | <<"priv/static/lit.js.map">>,<<"priv/static/base.css">>, |
| 33 | - <<"priv/templates">>,<<"priv/templates/slime">>, |
| 34 | - <<"priv/templates/slime/phx.gen.html">>, |
| 34 | + <<"priv/templates">>,<<"priv/templates/lit.install">>, |
| 35 | + <<"priv/templates/lit.install/pagination_component.ex">>, |
| 36 | + <<"priv/templates/slime">>,<<"priv/templates/slime/phx.gen.html">>, |
| 35 37 | <<"priv/templates/slime/phx.gen.html/edit.html.slime">>, |
| 36 38 | <<"priv/templates/slime/phx.gen.html/index.html.slime">>, |
| 37 39 | <<"priv/templates/slime/phx.gen.html/form.html.slime">>, |
| @@ -51,6 +53,16 @@ | |
| 51 53 | <<"priv/templates/common/phx.gen.html/controller.ex">>, |
| 52 54 | <<"priv/templates/common/phx.gen.html/controller_test.exs">>, |
| 53 55 | <<"priv/templates/common/phx.gen.html/view.ex">>, |
| 56 | + <<"priv/templates/phx.gen.live">>, |
| 57 | + <<"priv/templates/phx.gen.live/modal_component.ex">>, |
| 58 | + <<"priv/templates/phx.gen.live/index.html.leex">>, |
| 59 | + <<"priv/templates/phx.gen.live/show.ex">>, |
| 60 | + <<"priv/templates/phx.gen.live/live_test.exs">>, |
| 61 | + <<"priv/templates/phx.gen.live/index.ex">>, |
| 62 | + <<"priv/templates/phx.gen.live/form_component.html.leex">>, |
| 63 | + <<"priv/templates/phx.gen.live/show.html.leex">>, |
| 64 | + <<"priv/templates/phx.gen.live/form_component.ex">>, |
| 65 | + <<"priv/templates/phx.gen.live/live_helpers.ex">>, |
| 54 66 | <<"priv/templates/phx.gen.context">>, |
| 55 67 | <<"priv/templates/phx.gen.context/_grid.sass">>, |
| 56 68 | <<"priv/templates/phx.gen.context/test_cases.exs">>, |
| @@ -93,4 +105,4 @@ | |
| 93 105 | {<<"optional">>,false}, |
| 94 106 | {<<"repository">>,<<"hexpm">>}, |
| 95 107 | {<<"requirement">>,<<"~> 3.1">>}]]}. |
| 96 | - {<<"version">>,<<"0.1.0">>}. |
| 108 | + {<<"version">>,<<"0.1.1">>}. |
| @@ -39,7 +39,7 @@ defmodule Lit.FilterView do | |
| 39 39 | |
| 40 40 | iex> params = %{"post" => %{"title_contains" => "test"}} |
| 41 41 | ...> filter_select(:post, :title, params) |> safe_to_string() |
| 42 | - "<select class=\\"filter-type\\" id=\\"filters_\\" name=\\"filters[]\\"><option value=\\"post[title_contains]\\" selected>Contains</option><option value=\\"post[title_equals]\\">Equals</option></select>" |
| 42 | + "<select class=\\"focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3\\" id=\\"filters_\\" name=\\"filters[]\\"><option value=\\"post[title_contains]\\" selected>Contains</option><option value=\\"post[title_equals]\\">Equals</option></select>" |
| 43 43 | """ |
| 44 44 | @spec filter_select(prefix, field, map) :: Phoenix.HTML.safe() |
| 45 45 | def filter_select(prefix, field, params) do |
| @@ -51,7 +51,7 @@ defmodule Lit.FilterView do | |
| 51 51 | {message("Equals"), "#{prefix}[#{field}_equals]"} |
| 52 52 | ] |
| 53 53 | |
| 54 | - select(:filters, "", opts, class: "filter-type", value: "#{prefix}[#{selected}]") |
| 54 | + select(:filters, "", opts, class: "focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3", value: "#{prefix}[#{selected}]") |
| 55 55 | end |
| 56 56 | |
| 57 57 | @doc """ |
| @@ -62,7 +62,7 @@ defmodule Lit.FilterView do | |
| 62 62 | |
| 63 63 | iex> params = %{"post" => %{"updated_at_after" => "01/01/2019"}} |
| 64 64 | ...> filter_date_select(:post, :updated_at, params) |> safe_to_string() |
| 65 | - "<select class=\\"filter-type\\" id=\\"filters_\\" name=\\"filters[]\\"><option value=\\"post[updated_at_before]\\">Before</option><option value=\\"post[updated_at_after]\\" selected>After</option></select>" |
| 65 | + "<select class=\\"focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3\\" id=\\"filters_\\" name=\\"filters[]\\"><option value=\\"post[updated_at_before]\\">Before</option><option value=\\"post[updated_at_after]\\" selected>After</option></select>" |
| 66 66 | """ |
| 67 67 | @spec filter_date_select(prefix, field, map) :: Phoenix.HTML.safe() |
| 68 68 | def filter_date_select(prefix, field, params) do |
| @@ -74,7 +74,7 @@ defmodule Lit.FilterView do | |
| 74 74 | {message("After"), "#{prefix}[#{field}_after]"} |
| 75 75 | ] |
| 76 76 | |
| 77 | - select(:filters, "", opts, class: "filter-type", value: "#{prefix}[#{selected}]") |
| 77 | + select(:filters, "", opts, class: "focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3", value: "#{prefix}[#{selected}]") |
| 78 78 | end |
| 79 79 | |
| 80 80 | @doc """ |
| @@ -84,7 +84,7 @@ defmodule Lit.FilterView do | |
| 84 84 | |
| 85 85 | iex> params = %{"post" => %{"rating_greater_than" => 0}} |
| 86 86 | ...> number_filter_select(:post, :rating, params) |> safe_to_string() |
| 87 | - "<select class=\\"filter-type\\" id=\\"filters_\\" name=\\"filters[]\\"><option value=\\"post[rating_equals]\\">Equals</option><option value=\\"post[rating_greater_than]\\" selected>Greater Than</option><option value=\\"post[rating_greater_than_or]\\">Greater Than Or Equal</option><option value=\\"post[rating_less_than]\\">Less Than</option></select>" |
| 87 | + "<select class=\\"focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3\\" id=\\"filters_\\" name=\\"filters[]\\"><option value=\\"post[rating_equals]\\">Equals</option><option value=\\"post[rating_greater_than]\\" selected>Greater Than</option><option value=\\"post[rating_greater_than_or]\\">Greater Than Or Equal</option><option value=\\"post[rating_less_than]\\">Less Than</option></select>" |
| 88 88 | """ |
| 89 89 | @spec number_filter_select(prefix, field, map) :: Phoenix.HTML.safe() |
| 90 90 | def number_filter_select(prefix, field, params) do |
| @@ -98,7 +98,7 @@ defmodule Lit.FilterView do | |
| 98 98 | {message("Less Than"), "#{prefix}[#{field}_less_than]"} |
| 99 99 | ] |
| 100 100 | |
| 101 | - select(:filters, "", opts, class: "filter-type", value: "#{prefix}[#{selected}]") |
| 101 | + select(:filters, "", opts, class: "focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3", value: "#{prefix}[#{selected}]") |
| 102 102 | end |
| 103 103 | |
| 104 104 | @doc """ |
| @@ -108,13 +108,13 @@ defmodule Lit.FilterView do | |
| 108 108 | |
| 109 109 | iex> params = %{"post" => %{"rating_equals" => 5}} |
| 110 110 | ...> filter_number_input(:post, :rating, params) |> safe_to_string() |
| 111 | - "<input id=\\"post_rating_equals\\" name=\\"post[rating_equals]\\" type=\\"number\\" value=\\"5\\">" |
| 111 | + "<input class=\\"focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3\\" id=\\"post_rating_equals\\" name=\\"post[rating_equals]\\" type=\\"number\\" value=\\"5\\">" |
| 112 112 | """ |
| 113 113 | @spec filter_number_input(prefix, field, map) :: Phoenix.HTML.safe() |
| 114 114 | def filter_number_input(prefix, field, params) do |
| 115 115 | prefix_str = to_string(prefix) |
| 116 116 | {name, value} = find_param(params[prefix_str], field, :number) |
| 117 | - text_input(prefix, String.to_atom(name), value: value, type: "number") |
| 117 | + text_input(prefix, String.to_atom(name), value: value, type: "number", class: "focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3") |
| 118 118 | end |
| 119 119 | |
| 120 120 | @doc """ |
| @@ -124,13 +124,13 @@ defmodule Lit.FilterView do | |
| 124 124 | |
| 125 125 | iex> params = %{"post" => %{"title_contains" => "test"}} |
| 126 126 | iex> filter_string_input(:post, :title, params) |> safe_to_string() |
| 127 | - "<input id=\\"post_title_contains\\" name=\\"post[title_contains]\\" type=\\"text\\" value=\\"test\\">" |
| 127 | + "<input class=\\"focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3\\" id=\\"post_title_contains\\" name=\\"post[title_contains]\\" type=\\"text\\" value=\\"test\\">" |
| 128 128 | """ |
| 129 129 | @spec filter_string_input(prefix, field, map) :: Phoenix.HTML.safe() |
| 130 130 | def filter_string_input(prefix, field, params) do |
| 131 131 | prefix_str = to_string(prefix) |
| 132 132 | {name, value} = find_param(params[prefix_str], field) |
| 133 | - text_input(prefix, String.to_atom(name), value: value) |
| 133 | + text_input(prefix, String.to_atom(name), value: value, class: "focus:border-blue-400 focus:ring-2 focus:ring-blue-200 focus:outline-none w-full text-base placeholder-gray-400 border border-gray-300 rounded py-1.5 px-3") |
| 134 134 | end |
| 135 135 | |
| 136 136 | @doc """ |
| @@ -207,7 +207,7 @@ defmodule Lit.FilterView do | |
| 207 207 | |
| 208 208 | iex> params = %{"post" => %{"draft_equals" => "false"}} |
| 209 209 | iex> filter_boolean_input(:post, :draft, params) |> safe_to_string() |
| 210 | - "<input name=\\"post[draft_equals]\\" type=\\"hidden\\" value=\\"false\\"><input id=\\"post_draft_equals\\" name=\\"post[draft_equals]\\" type=\\"checkbox\\" value=\\"true\\">" |
| 210 | + "<input name=\\"post[draft_equals]\\" type=\\"hidden\\" value=\\"false\\"><input class=\\"form-checkbox\\" id=\\"post_draft_equals\\" name=\\"post[draft_equals]\\" type=\\"checkbox\\" value=\\"true\\">" |
| 211 211 | """ |
| 212 212 | @spec filter_boolean_input(prefix, field, map) :: Phoenix.HTML.safe() |
| 213 213 | def filter_boolean_input(prefix, field, params) do |
| @@ -217,7 +217,7 @@ defmodule Lit.FilterView do | |
| 217 217 | string when is_binary(string) -> string == "true" |
| 218 218 | end |
| 219 219 | |
| 220 | - checkbox(prefix, :"#{field}_equals", value: value) |
| 220 | + checkbox(prefix, :"#{field}_equals", value: value, class: "form-checkbox") |
| 221 221 | end |
| 222 222 | |
| 223 223 | defp lit_date_input(name, value) do |
| @@ -90,6 +90,20 @@ defmodule Mix.Lit do | |
| 90 90 | ]) |
| 91 91 | end |
| 92 92 | |
| 93 | + def inject_templates("phx.gen.live", _) do |
| 94 | + copy_from("priv/templates/phx.gen.live", [ |
| 95 | + {"show.ex", "priv/templates/phx.gen.live/show.ex"}, |
| 96 | + {"index.ex", "priv/templates/phx.gen.live/index.ex"}, |
| 97 | + {"form_component.ex", "priv/templates/phx.gen.live/form_component.ex"}, |
| 98 | + {"form_component.html.leex", "priv/templates/phx.gen.live/form_component.html.leex"}, |
| 99 | + {"index.html.leex", "priv/templates/phx.gen.live/index.html.leex"}, |
| 100 | + {"show.html.leex", "priv/templates/phx.gen.live/show.html.leex"}, |
| 101 | + {"live_test.exs", "priv/templates/phx.gen.live/live_test.exs"}, |
| 102 | + {"modal_component.ex", "priv/templates/phx.gen.live/modal_component.ex"}, |
| 103 | + {"live_helpers.ex", "priv/templates/phx.gen.live/live_helpers.ex"}, |
| 104 | + ]) |
| 105 | + end |
| 106 | + |
| 93 107 | def inject_templates("phx.gen.context", _format) do |
| 94 108 | copy_from("priv/templates/phx.gen.context", [ |
| 95 109 | {"access_no_schema.ex", "priv/templates/phx.gen.context/access_no_schema.ex"}, |
| @@ -29,11 +29,12 @@ defmodule Mix.Tasks.Lit.Gen.Html do | |
| 29 29 | Enum.each(@commands, &Mix.Lit.inject_templates(&1, format)) |
| 30 30 | |
| 31 31 | # Run the Phoenix generator |
| 32 | - if format == "slime" do |
| 33 | - Mix.Task.run("phx.gen.html.slime", args) |
| 34 | - else |
| 35 | - Mix.Task.run("phx.gen.html", args) |
| 36 | - end |
| 32 | + Mix.Task.run("phx.gen.html", args) |
| 33 | + # if format == "slime" do |
| 34 | + # Mix.Task.run("phx.gen.html.slime", args) |
| 35 | + # else |
| 36 | + # Mix.Task.run("phx.gen.html", args) |
| 37 | + # end |
| 37 38 | |
| 38 39 | # Remove the injected templates from priv/ so they will not |
| 39 40 | # affect future Phoenix generator commands |
Loading more files…