improvement: add basic live view native, various other small fixes

This commit is contained in:
Zach Daniel 2022-09-09 00:31:50 -04:00
parent 41fca4aec7
commit 30d55df185
40 changed files with 196 additions and 108 deletions

View file

@ -0,0 +1,54 @@
{
"silver-phoenix": "#EAEBF3",
"base-dark": {
"DEFAULT": "#5E627D",
"50": "#C2C4D1",
"100": "#B6B8C8",
"200": "#9FA2B7",
"300": "#878BA5",
"400": "#707594",
"500": "#5E627D",
"600": "#46495D",
"700": "#2E303D",
"800": "#16171D",
"900": "#000000"
},
"base-light": {
"50": "#f9fafb",
"100": "#f3f4f6",
"200": "#e5e7eb",
"300": "#d1d5db",
"400": "#9ca3af",
"500": "#6b7280",
"600": "#4b5563",
"700": "#374151",
"800": "#1f2937",
"900": "#111827"
},
"primary-dark": {
"DEFAULT": "#FF5757",
"50": "#FFE1E1",
"100": "#FFD1D1",
"200": "#FFB3B3",
"300": "#FF9494",
"400": "#FF7676",
"500": "#FF5757",
"600": "#FF1F1F",
"700": "#E60000",
"800": "#AE0000",
"900": "#760000"
},
"primary-light": {
"DEFAULT": "#FF914D",
"50": "#FFE6D7",
"100": "#FFDDC7",
"200": "#FFCAA9",
"300": "#FFB78A",
"400": "#FFA46C",
"500": "#FF914D",
"600": "#FF6E15",
"700": "#DC5400",
"800": "#A43F00",
"900": "#6C2900"
}
}

View file

@ -1,5 +1,7 @@
const colors = require("tailwindcss/colors");
let customColors = require("./tailwind.colors.json");
module.exports = {
mode: "jit",
content: ["./js/**/*.js", "../lib/*_web/**/*.*ex"],
@ -22,60 +24,7 @@ module.exports = {
"dark-grid": `linear-gradient(to bottom, rgb(24, 25, 32, 80%) 20%, rgb(24, 25, 32, 50%) 40%, rgb(24, 25, 32, 40%) 80%, rgb(24, 25, 32, 60%) 20%), url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ada3bf' fill-opacity='0.26'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`,
"light-grid": `linear-gradient(to bottom, rgb(255, 255, 255, 90%) 20%, rgb(255, 255, 255, 85%) 30%, rgb(255, 255, 255, 80%) 80%, rgb(255, 255, 255, 95%) 20%), url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23312a3b' fill-opacity='0.42'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");`,
},
colors: {
"silver-phoenix": "#EAEBF3",
"base-dark": {
DEFAULT: "#5E627D",
50: "#C2C4D1",
100: "#B6B8C8",
200: "#9FA2B7",
300: "#878BA5",
400: "#707594",
500: "#5E627D",
600: "#46495D",
700: "#2E303D",
800: "#16171D",
900: "#000000",
},
"base-light": {
50: "#f9fafb",
100: "#f3f4f6",
200: "#e5e7eb",
300: "#d1d5db",
400: "#9ca3af",
500: "#6b7280",
600: "#4b5563",
700: "#374151",
800: "#1f2937",
900: "#111827",
},
"primary-dark": {
DEFAULT: "#FF5757",
50: "#FFE1E1",
100: "#FFD1D1",
200: "#FFB3B3",
300: "#FF9494",
400: "#FF7676",
500: "#FF5757",
600: "#FF1F1F",
700: "#E60000",
800: "#AE0000",
900: "#760000",
},
"primary-light": {
DEFAULT: "#FF914D",
50: "#FFE6D7",
100: "#FFDDC7",
200: "#FFCAA9",
300: "#FFB78A",
400: "#FFA46C",
500: "#FF914D",
600: "#FF6E15",
700: "#DC5400",
800: "#A43F00",
900: "#6C2900",
},
},
colors: customColors
},
},
variants: {

30
lib/ash_hq/colors.ex Normal file
View file

@ -0,0 +1,30 @@
defmodule AshHq.Colors do
@moduledoc "Static values for tailwind colors"
@colors "assets/tailwind.colors.json"
|> File.read!()
|> Jason.decode!()
for {key, value} when is_binary(value) <- @colors do
# sobelow_skip ["DOS.BinToAtom"]
def unquote(:"#{String.replace(key, "-", "_")}")() do
unquote(value)
end
end
for {key, value} when is_map(value) <- @colors do
for {suffix, value} when is_binary(value) <- value do
if suffix == "DEFAULT" do
# sobelow_skip ["DOS.BinToAtom"]
def unquote(:"#{String.replace(key, "-", "_")}")() do
unquote(value)
end
else
# sobelow_skip ["DOS.BinToAtom"]
def unquote(:"#{String.replace(key, "-", "_")}_#{String.replace(suffix, "-", "_")}")() do
unquote(value)
end
end
end
end
end

View file

@ -18,6 +18,7 @@ defmodule AshHq.Docs.Extensions.Search.Transformers.AddSearchStructure do
require Ash.Query
alias Spark.Dsl.Transformer
# sobelow_skip ["DOS.BinToAtom"]
def transform(dsl_state) do
name_attribute = Transformer.get_option(dsl_state, [:search], :name_attribute) || :name

View file

@ -101,8 +101,10 @@ defmodule AshHq.Docs.Importer do
end
end
# sobelow_skip ["Misc.BinToTerm", "Traversal.FileModule"]
defp add_text([], _, _), do: []
# sobelow_skip ["Misc.BinToTerm", "Traversal.FileModule"]
defp add_text(guides, name, version) do
path = Path.expand("tmp")
tarball_path = Path.expand(Path.join(["tmp", "tarballs"]))

View file

@ -1,4 +1,5 @@
defmodule AshHq.MailingList.EmailNotifier do
@moduledoc "Sends emails from events in the MailingList api"
use Ash.Notifier
def notify(%Ash.Notifier.Notification{

View file

@ -35,6 +35,5 @@ defmodule AshHq.MailingList.Emails do
|> html_body(body)
|> text_body(body)
|> AshHq.Mailer.deliver!()
|> IO.inspect()
end
end

View file

@ -1,4 +1,5 @@
defmodule AshHq.MailingList.Registry do
@moduledoc false
use Ash.Registry,
extensions: [Ash.Registry.ResourceValidations]

View file

@ -1,8 +1,14 @@
defmodule AshHq.MailingList.Email do
@moduledoc false
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
notifiers: AshHq.MailingList.EmailNotifier
resource do
description "An email for the mailing list"
end
postgres do
repo AshHq.Repo
table "emails"

View file

@ -61,7 +61,8 @@ defmodule AshHqWeb do
def component do
quote do
use Phoenix.Component
use Surface.Component
import AshHq.Colors
unquote(view_helpers())
end

View file

@ -2,12 +2,20 @@ defmodule AshHqWeb.Components.CalloutText do
@moduledoc "Highlights some text on the page"
use Surface.Component
slot default, required: true
import AshHq.Colors
prop text, :string, required: true
def render(%{__context__: %{platform: :ios}} = assigns) do
~F"""
<text color={primary_light_600()}>{@text}</text>
"""
end
def render(assigns) do
~F"""
<span class="text-primary-light-600 dark:text-primary-dark-400 font-bold">
<#slot />
{@text}
</span>
"""
end

View file

@ -7,7 +7,7 @@ defmodule AshHqWeb.Components.Search do
alias AshHqWeb.Components.CalloutText
alias AshHqWeb.DocRoutes
alias Surface.Components.{Form, LiveRedirect}
alias Surface.Components.Form.{Checkbox, Label, Select}
alias Surface.Components.Form.{Checkbox, Label}
prop(open, :boolean, default: false)
prop(close, :event, required: true)
@ -122,7 +122,7 @@ defmodule AshHqWeb.Components.Search do
<Heroicons.Solid.ChevronRightIcon class="h-6 w-6" />
<div class="font-bold text-lg">
{#if item.name_matches}
<CalloutText>{item_name(item)}</CalloutText>
<CalloutText text={item_name(item)} />
{#else}
{item_name(item)}
{/if}

View file

@ -1,4 +1,5 @@
defmodule AshHqWeb.Components.VersionPills do
@moduledoc "Renders pills for selected versions"
use Surface.LiveComponent
alias Surface.Components.Form

View file

@ -0,0 +1,11 @@
defmodule AshHqWeb.InitAssigns do
@moduledoc "Sets the platform being used with liveview"
import Phoenix.LiveView
def on_mount(:default, _params, _session, socket) do
case get_connect_params(socket) do
%{"_platform" => "ios"} -> {:cont, socket |> assign(:platform, :ios)}
_ -> {:cont, socket |> assign(:platform, :web)}
end
end
end

View file

@ -54,7 +54,7 @@ defmodule AshHqWeb.Pages.Docs do
<Heroicons.Outline.ChevronRightIcon class="w-3 h-3" />
{/for}
<span class="dark:text-white">
<CalloutText>{List.last(path)}</CalloutText>
<CalloutText text={List.last(path)} />
</span>
{/case}
</div>
@ -192,7 +192,7 @@ defmodule AshHqWeb.Pages.Docs do
<Heroicons.Outline.LinkIcon class="h-3 m-3" />
</a>
<div class="flex flex-row space-x-2">
<CalloutText>{option.name}</CalloutText>
<CalloutText text={option.name}/>
{render_tags(assigns, option)}
</div>
</div>
@ -235,7 +235,7 @@ defmodule AshHqWeb.Pages.Docs do
<a href={"##{DocRoutes.sanitize_name(option.name)}"}>
<Heroicons.Outline.LinkIcon class="h-3 m-3" />
</a>
<CalloutText>{option.name}</CalloutText>
<CalloutText text={option.name}/>
{render_tags(assigns, option)}
</div>
</td>

View file

@ -5,18 +5,37 @@ defmodule AshHqWeb.Pages.Home do
alias AshHqWeb.Components.{CalloutText, CodeExample, SearchBar}
alias Surface.Components.Form
alias Surface.Components.Form.{Field, TextInput, Submit}
alias Surface.Components.Form.{Field, Submit, TextInput}
import AshHqWeb.Components.CodeExample, only: [to_code: 1]
data(signed_up, :boolean, default: false)
data(email_form, :any)
data signed_up, :boolean, default: false
data email_form, :any
def render(%{__context__: %{platform: :ios}} = assigns) do
~F"""
<vstack>
<hstack>
<text>Build</text> <CalloutText text="powerful"/><text> and </text> <CalloutText text="composable"/> <text> applications</text>
</hstack>
<hstack>
<text>with a </text> <CalloutText text="flexible" /> <text> tool-chain. </text>
</hstack>
<hstack>
<text font="callout">A declarative foundation for ambitious applications.</text>
</hstack>
<hstack>
<text font="callout">Model your domain, derive the rest.</text>
</hstack>
</vstack>
"""
end
def render(assigns) do
~F"""
<div class="antialiased">
<div class="my-2 dark:bg-base-dark-900 dark:bg-dark-grid bg-light-grid flex flex-col items-center pt-4 md:pt-12 lg:pt-24">
<div class="text-3xl md:text-5xl px-4 md:px-12 font-bold max-w-5xl mx-auto mt-2 md:text-center">
Build <CalloutText>powerful</CalloutText> and <CalloutText>composable</CalloutText> applications with a <CalloutText>flexible</CalloutText> tool-chain.
Build <CalloutText text="powerful" /> and <CalloutText text="composable" /> applications with a <CalloutText text="flexible" /> tool-chain.
</div>
<div class="text-xl font-light text-base-dark-700 dark:text-base-light-100 max-w-4xl mx-auto px-4 md:px-0 mt-4 md:text-center">
A declarative foundation for ambitious applications. Model your domain, derive the rest.

View file

@ -33,7 +33,7 @@ defmodule AshHqWeb.Router do
pipe_through :browser
live_session :main,
on_mount: {AshHqWeb.LiveUserAuth, :live_user},
on_mount: [{AshHqWeb.InitAssigns, :default}, {AshHqWeb.LiveUserAuth, :live_user}],
root_layout: {AshHqWeb.LayoutView, "root.html"} do
live "/", AppViewLive, :home
live "/docs/", AppViewLive, :docs_dsl
@ -48,7 +48,10 @@ defmodule AshHqWeb.Router do
end
live_session :unauthenticated_only,
on_mount: {AshHqWeb.LiveUserAuth, :live_user_not_allowed},
on_mount: [
{AshHqWeb.InitAssigns, :default},
{AshHqWeb.LiveUserAuth, :live_user_not_allowed}
],
root_layout: {AshHqWeb.LayoutView, "root.html"} do
live "/users/log_in", AppViewLive, :log_in
live "/users/register", AppViewLive, :register
@ -57,7 +60,7 @@ defmodule AshHqWeb.Router do
end
live_session :authenticated_only,
on_mount: {AshHqWeb.LiveUserAuth, :live_user_required},
on_mount: [{AshHqWeb.InitAssigns, :default}, {AshHqWeb.LiveUserAuth, :live_user_required}],
root_layout: {AshHqWeb.LayoutView, "root.html"} do
live "/users/settings", AppViewLive, :user_settings
end
@ -91,11 +94,6 @@ defmodule AshHqWeb.Router do
get "/users/confirm/:token", UserConfirmationController, :confirm
end
# Other scopes may use custom stacks.
# scope "/api", AshHqWeb do
# pipe_through :api
# end
# Enables LiveDashboard only for development
#
# If you want to use the LiveDashboard in production, you should put

View file

@ -1,3 +1 @@
<main class="container">
<%= @inner_content %>
</main>

View file

@ -0,0 +1 @@
<%= @inner_content %>

View file

@ -1,3 +1 @@
<main class="container">
<%= @inner_content %>
</main>

View file

@ -1,30 +1,41 @@
defmodule AshHqWeb.AppViewLive do
# credo:disable-for-this-file Credo.Check.Readability.MaxLineLength
use Surface.LiveView,
container: {:div, class: "h-full"}
alias AshHqWeb.Components.{Search, SearchBar}
alias AshHqWeb.Pages.{Docs, Home, LogIn, Register, ResetPassword, UserSettings}
alias Phoenix.LiveView.JS
alias Surface.Components.Context
require Ash.Query
data(configured_theme, :string, default: :system)
data(searching, :boolean, default: false)
data(selected_versions, :map, default: %{})
data(libraries, :list, default: [])
data(selected_types, :map, default: %{})
data(sidebar_state, :map, default: %{})
data(current_user, :map)
data configured_theme, :string, default: :system
data searching, :boolean, default: false
data selected_versions, :map, default: %{}
data libraries, :list, default: []
data selected_types, :map, default: %{}
data sidebar_state, :map, default: %{}
data current_user, :map
data(library, :any, default: nil)
data(extension, :any, default: nil)
data(docs, :any, default: nil)
data(library_version, :any, default: nil)
data(guide, :any, default: nil)
data(doc_path, :list, default: [])
data(dsls, :list, default: [])
data(dsl, :any, default: nil)
data(options, :list, default: [])
data(module, :any, default: nil)
data library, :any, default: nil
data extension, :any, default: nil
data docs, :any, default: nil
data library_version, :any, default: nil
data guide, :any, default: nil
data doc_path, :list, default: []
data dsls, :list, default: []
data dsl, :any, default: nil
data options, :list, default: []
data module, :any, default: nil
def render(%{platform: :ios} = assigns) do
~F"""
{#case @live_action}
{#match :home}
<Home id="home" />
{/case}
"""
end
def render(assigns) do
~F"""
@ -411,6 +422,7 @@ defmodule AshHqWeb.AppViewLive do
defp load_docs(socket), do: socket
def mount(_params, session, socket) do
socket = Context.put(socket, platform: socket.assigns.platform)
configured_theme = session["theme"] || "system"
configured_library_versions =
@ -556,13 +568,11 @@ defmodule AshHqWeb.AppViewLive do
defp assign_guide(socket) do
guide =
cond do
socket.assigns[:params]["guide"] && socket.assigns.library_version ->
if socket.assigns[:params]["guide"] && socket.assigns.library_version do
Enum.find(socket.assigns.library_version.guides, fn guide ->
guide.route == Enum.join(socket.assigns[:params]["guide"], "/")
end)
true ->
else
nil
end

View file

@ -43,7 +43,7 @@ defmodule AshHq.MixProject do
{:spark, "~> 0.1"},
# {:spark, path: "../spark", override: true},
{:earmark, "~> 1.5.0-pre1", override: true},
{:surface, "~> 0.7.3"},
{:surface, "~> 0.8.1"},
{:surface_heroicons, "~> 0.6.0"},
# Syntax Highlighting
{:makeup, "~> 1.1"},

View file

@ -59,7 +59,7 @@
"nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"phoenix": {:hex, :phoenix, "1.6.11", "29f3c0fd12fa1fc4d4b05e341578e55bc78d96ea83a022587a7e276884d397e4", [:mix], [{: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", "1664e34f80c25ea4918fbadd957f491225ef601c0e00b4e644b1a772864bfbc2"},
"phoenix": {:hex, :phoenix, "1.6.12", "f8f8ac077600f84419806dd53114b2e77aedde7a502e74181a7d886355aa0643", [:mix], [{: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", "2d6cf5583c9c20f7103c40e6014ef802d96553b8e5d6585ad6e627bd5ddb0d12"},
"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"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"},
@ -81,7 +81,7 @@
"spark": {:hex, :spark, "0.1.18", "2cf48ea8f695da7e413ff5e16e83c0dbd6e9810a61a67fc6601b702199e9baf3", [:mix], [{:libgraph, "~> 0.13.3", [hex: :libgraph, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "e4e7bd47de30a2830cc5d1f12c6db5d8ead9c5ba336e5d8f2ff26495d4e3f41d"},
"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"},
"surface": {:hex, :surface, "0.7.5", "01ca44bf3afb478a8b55db52d67dfdba86e699332a7040b2e327b7b6061c91a6", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.4", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.9", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "33532b412560a32b63e151cafaa424279e0a3f8a047bdb6a86568e39ace260b8"},
"surface": {:hex, :surface, "0.8.1", "3228df8a82fea8daf8daefaa343b30be04d524ae41c657f5c5bb9ea4f711fc28", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.6", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.9", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "8a824660bc7a4cc4dd77ca986591b2935f27f6de01332df41ec3f5335213d114"},
"surface_heroicons": {:hex, :surface_heroicons, "0.6.0", "04e171843439d2d52c868f8adf5294c49505f504a74a0200179e49c447d6f354", [:mix], [{:surface, ">= 0.5.0", [hex: :surface, repo: "hexpm", optional: false]}], "hexpm", "1136c88a8de44a63c050cec9b0b64f771127dfd96feabab4cd0bde8b6b727ba2"},
"swoosh": {:hex, :swoosh, "1.7.4", "f967d9b2659e81bab241b96267aae1001d35c2beea2df9c03dcf47b007bf566f", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1553d994b4cf069162965e63de1e1c53d8236e127118d21e56ce2abeaa3f25b4"},
"table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"},

Binary file not shown.

BIN
priv/static/images/cats/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB