diff --git a/BUILDIT.md b/BUILDIT.md index 3c40e0fd..f89204b0 100644 --- a/BUILDIT.md +++ b/BUILDIT.md @@ -15,17 +15,45 @@ it in **30 minutes**. 🏁 -# TODO: fill-in the gaps during the [Rebuild `#207`](https://github.com/dwyl/auth/issues/207) +- [Build Log 👩‍💻](#build-log-) +- [TODO](#todo) +- [1. Setup the `auth` App](#1-setup-the-auth-app) + - [1. Add Tailwind](#1-add-tailwind) + - [1.6 `Petal.build` Components](#16-petalbuild-components) + - [1.7 `mix format`](#17-mix-format) +- [ERD `before` adding `groups`](#erd-before-adding-groups) +- [10. Groups](#10-groups) + - [10.1 Create Schema](#101-create-schema) + - [10.2 _Test_ Groups Schema](#102-test-groups-schema) + - [10.3 Create `LiveView` for `groups`](#103-create-liveview-for-groups) + - [10.4 Update `router.ex`](#104-update-routerex) +- [TODO: Add Screenshot of Groups Live Page!](#todo-add-screenshot-of-groups-live-page) + - [10.5 Update Tests](#105-update-tests) + - [10.6 Group _Members_](#106-group-members) + +
+ +# TODO + +We will fill-in the gaps during the [Rebuild `#207`](https://github.com/dwyl/auth/issues/207) For now I'm just adding the parts that are being added to the "old" version of **`auth`** so that we can _easily_ re-create them in the re-build. -## 1.6 Petal.build Components +# 1. Setup the `auth` App + +## 1. Add Tailwind + +Follow the instructions in: +https://github.com/dwyl/learn-tailwind#part-2-tailwind-in-phoenix + + +## 1.6 `Petal.build` Components https://petal.build/components/ -# 1.7 `mix format` +## 1.7 `mix format` See: https://github.com/dwyl/mvp/issues/183 diff --git a/assets/css/app.css b/assets/css/app.css index 5af4fd2b..626fc077 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -1,3 +1,7 @@ +@import "tailwindcss/base"; +@import "tailwindcss/components"; +@import "tailwindcss/utilities"; + /* This file is for your main application css. */ /* @import "./phoenix.css"; */ @@ -54,3 +58,46 @@ display: block; margin: -1rem 0 2rem; } + +.select-wrapper select { + @apply text-sm border-gray-300 rounded-md shadow-sm disabled:bg-gray-100 disabled:cursor-not-allowed focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:focus:border-primary-500 dark:bg-gray-800 dark:text-gray-300 focus:outline-none ; +} + +label.has-error:not(.phx-no-feedback) { + @apply !text-red-900 dark:!text-red-200; +} + +textarea.has-error:not(.phx-no-feedback), input.has-error:not(.phx-no-feedback), select.has-error:not(.phx-no-feedback) { + @apply !border-red-500 focus:!border-red-500 !text-red-900 !placeholder-red-700 !bg-red-50 dark:!text-red-100 dark:!placeholder-red-300 dark:!bg-red-900 focus:!ring-red-500; +} + +input[type=file_input].has-error:not(.phx-no-feedback) { + @apply !border-red-500 !rounded-md focus:!border-red-500 !text-red-900 !placeholder-red-700 !bg-red-50 file:!border-none dark:!border-none dark:!bg-[#160B0B] dark:text-red-400; +} + +input[type=checkbox].has-error:not(.phx-no-feedback) { + @apply !border-red-500 !text-red-900 dark:!text-red-200; +} + +input[type=radio].has-error:not(.phx-no-feedback) { + @apply !border-red-500; +} + +/* Modal animation */ +.animate-fade-in-scale { + animation: 0.2s ease-in 0s normal forwards 1 fade-in-scale-keys; +} + +.animate-fade-in { + animation: 0.2s ease-out 0s normal forwards 1 fade-in-keys; +} + +@keyframes fade-in-scale-keys{ + 0% { scale: 0.95; opacity: 0; } + 100% { scale: 1.0; opacity: 1; } +} + +@keyframes fade-in-keys{ + 0% { opacity: 0; } + 100% { opacity: 1; } +} \ No newline at end of file diff --git a/assets/js/app.js b/assets/js/app.js index ed2dcae3..496094fb 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -1,6 +1,5 @@ // We import the CSS which is extracted to its own file by esbuild. // Remove this line if you add a your own CSS build pipeline (e.g postcss). -import "../css/app.css" // Include phoenix_html to handle method=PUT/DELETE in forms and buttons. import "phoenix_html" diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js new file mode 100644 index 00000000..9ef85110 --- /dev/null +++ b/assets/tailwind.config.js @@ -0,0 +1,29 @@ +// See the Tailwind configuration guide for advanced usage +// https://tailwindcss.com/docs/configuration + +const plugin = require('tailwindcss/plugin'); +const colors = require("tailwindcss/colors"); + +module.exports = { + content: [ + './js/**/*.js', + '../lib/*_web.ex', + '../lib/*_web/**/*.*ex', + "../deps/petal_components/**/*.*ex", + ], + theme: { + extend: { + colors: { + primary: colors.blue, + secondary: colors.pink, + }, + }, + }, + plugins: [ + require('@tailwindcss/forms'), + 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 index bfb823e5..d1115a1d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -45,3 +45,14 @@ config :esbuild, config :auth_plug, api_key: System.get_env("AUTH_API_KEY") + +config :tailwind, + version: "3.2.0", + default: [ + args: ~w( + --config=tailwind.config.js + --input=css/app.css + --output=../priv/static/assets/app.css + ), + cd: Path.expand("../assets", __DIR__) + ] diff --git a/lib/auth_web.ex b/lib/auth_web.ex index 46c539bf..553705cf 100644 --- a/lib/auth_web.ex +++ b/lib/auth_web.ex @@ -80,6 +80,7 @@ defmodule AuthWeb do quote do # Use all HTML functionality (forms, tags, etc) use Phoenix.HTML + use PetalComponents # Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc) import Phoenix.LiveView.Helpers diff --git a/lib/auth_web/templates/layout/live.html.heex b/lib/auth_web/templates/layout/live.html.heex index 3cec5dda..35bd05e3 100644 --- a/lib/auth_web/templates/layout/live.html.heex +++ b/lib/auth_web/templates/layout/live.html.heex @@ -1,4 +1,20 @@ - +<.container class="my-10"> + <.alert + color="info" + class="mb-5" + label={live_flash(@flash, :info)} + phx-click="lv:clear-flash" + phx-value-key="info" + /> + + <.alert + color="danger" + class="mb-5" + label={live_flash(@flash, :error)} + phx-click="lv:clear-flash" + phx-value-key="error" + /> + <%= @inner_content %> - \ No newline at end of file + \ No newline at end of file diff --git a/mix.exs b/mix.exs index 537a20e1..363fae6c 100644 --- a/mix.exs +++ b/mix.exs @@ -88,6 +88,13 @@ defmodule Auth.Mixfile do # Useful functions: https://github.com/dwyl/useful {:useful, "~> 1.0.8"}, + # Tailwind CSS + # See: https://github.com/dwyl/learn-tailwind + {:tailwind, "~> 0.1", runtime: Mix.env() == :dev}, + + # https://petal.build/components + {:petal_components, "~> 0.18"}, + # Ping to Wake Heroku Instance: https://github.com/dwyl/ping {:ping, "~> 1.1.0"}, @@ -116,7 +123,11 @@ defmodule Auth.Mixfile do # See the documentation for `Mix` for more info on aliases. defp aliases do [ - "assets.deploy": ["esbuild default --minify", "phx.digest"], + "assets.deploy": [ + "tailwind default --minify", + "esbuild default --minify", + "phx.digest" + ], c: ["coveralls.html"], "ecto.setup": ["ecto.create --quiet", "ecto.migrate --quiet", "seeds"], "ecto.reset": ["ecto.drop", "ecto.setup"], diff --git a/mix.lock b/mix.lock index 5e946da5..8d613b9c 100644 --- a/mix.lock +++ b/mix.lock @@ -31,6 +31,7 @@ "floki": {:hex, :floki, "0.33.1", "f20f1eb471e726342b45ccb68edb9486729e7df94da403936ea94a794f072781", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "461035fd125f13fdf30f243c85a0b1e50afbec876cbf1ceefe6fddd2e6d712c6"}, "gettext": {:hex, :gettext, "0.19.1", "564953fd21f29358e68b91634799d9d26989f8d039d7512622efb3c3b1c97892", [:mix], [], "hexpm", "10c656c0912b8299adba9b061c06947511e3f109ab0d18b44a866a4498e77222"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.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.3.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", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, + "heroicons": {:hex, :heroicons, "0.5.1", "cca0dcca07af5f74d8a7d111e40418d3615d65e6773c0ea10e20cef070fd30aa", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.2", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "4b096d0a1d50e9054df9b12cc637c9f65c3972ff086791d3f2d1846f0653117e"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.4.2", "c479398b6de798c03eb5d04a0a9a9159d73508f83f6590a00b8eacba3619cf4c", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "aef6c28585d06a9109ad591507e508854c5559561f950bbaea773900dd369b0e"}, "httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"}, @@ -47,6 +48,7 @@ "mochiweb": {:hex, :mochiweb, "2.22.0", "f104d6747c01a330c38613561977e565b788b9170055c5241ac9dd6e4617cba5", [:rebar3], [], "hexpm", "cbbd1fd315d283c576d1c8a13e0738f6dafb63dc840611249608697502a07655"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, + "petal_components": {:hex, :petal_components, "0.18.5", "f7abd370d179e8ab1eff491a7a85526984ead78b41190b03f6ec5df04932cdbf", [:mix], [{:heroicons, "~> 0.5.0", [hex: :heroicons, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_ecto, "~> 4.4", [hex: :phoenix_ecto, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "d38982b0e9fa39884cfaf5e49bdc77a6be16b17b73fc19001b2a27fe4b672dca"}, "phoenix": {:hex, :phoenix, "1.6.14", "57678366dc1d5bad49832a0fc7f12c2830c10d3eacfad681bfe9602cd4445f04", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d48c0da00b3d4cd1aad6055387917491af9f6e1f1e96cedf6c6b7998df9dba26"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, @@ -64,6 +66,7 @@ "sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "stream_data": {:hex, :stream_data, "0.5.0", "b27641e58941685c75b353577dc602c9d2c12292dd84babf506c2033cd97893e", [:mix], [], "hexpm", "012bd2eec069ada4db3411f9115ccafa38540a3c78c4c0349f151fc761b9e271"}, + "tailwind": {:hex, :tailwind, "0.1.9", "25ba09d42f7bfabe170eb67683a76d6ec2061952dc9bd263a52a99ba3d24bd4d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "9213f87709c458aaec313bb5f2df2b4d2cedc2b630e4ae821bf3c54c47a56d0b"}, "telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},