Merge branch 'page-templates' into 'master'

feat: Add good basic page templates

See merge request mythic-insight/legendary!13
This commit is contained in:
Robert Prehn 2020-07-30 16:05:09 +00:00
commit a01763919d
61 changed files with 292 additions and 306 deletions

View file

@ -7,6 +7,7 @@ defmodule Admin.Router do
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :put_layout, {CoreWeb.LayoutView, :app}
end
pipeline :require_admin do

View file

@ -1,33 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title><%= I18n.t! "en", "site.title" %></title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head>
<body>
<header>
<section class="container">
<nav role="navigation">
<ul>
<li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
<%= if function_exported?(Routes, :live_dashboard_path, 2) do %>
<li><%= link "LiveDashboard", to: Routes.live_dashboard_path(@conn, :home) %></li>
<% end %>
</ul>
</nav>
<a href="https://phoenixframework.org/" class="phx-logo">
<img src="<%= Routes.static_path(@conn, "/images/phoenix.png") %>" alt="Phoenix Framework Logo"/>
</a>
</section>
</header>
<main role="main" class="container">
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<%= @inner_content %>
</main>
</body>
</html>

View file

@ -9,23 +9,23 @@ defmodule App.Application do
children = [
App.Repo,
# Start the Telemetry supervisor
App.Telemetry,
AppWeb.Telemetry,
# Start the Endpoint (http/https)
App.Endpoint
# Start a worker by calling: App.Worker.start_link(arg)
# {App.Worker, arg}
AppWeb.Endpoint
# Start a worker by calling: AppWeb.Worker.start_link(arg)
# {AppWeb.Worker, arg}
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: App.Supervisor]
opts = [strategy: :one_for_one, name: AppWeb.Supervisor]
Supervisor.start_link(children, opts)
end
# Tell Phoenix to update the endpoint configuration
# whenever the application is updated.
def config_change(changed, _new, removed) do
App.Endpoint.config_change(changed, removed)
AppWeb.Endpoint.config_change(changed, removed)
:ok
end
end

View file

@ -1,7 +0,0 @@
defmodule App.PageController do
use App, :controller
def index(conn, _params) do
render(conn, "index.html")
end
end

View file

@ -1,33 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>App · Phoenix Framework</title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head>
<body>
<header>
<section class="container">
<nav role="navigation">
<ul>
<li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
<%= if function_exported?(Routes, :live_dashboard_path, 2) do %>
<li><%= link "LiveDashboard", to: Routes.live_dashboard_path(@conn, :home) %></li>
<% end %>
</ul>
</nav>
<a href="https://phoenixframework.org/" class="phx-logo">
<img src="<%= Routes.static_path(@conn, "/images/phoenix.png") %>" alt="Phoenix Framework Logo"/>
</a>
</section>
</header>
<main role="main" class="container">
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<%= @inner_content %>
</main>
</body>
</html>

View file

@ -1,3 +0,0 @@
defmodule App.LayoutView do
use App, :view
end

View file

@ -1,3 +0,0 @@
defmodule App.PageView do
use App, :view
end

View file

@ -1,12 +1,12 @@
defmodule App do
defmodule AppWeb do
@moduledoc """
The entrypoint for defining your web interface, such
as controllers, views, channels and so on.
This can be used in your application as:
use App, :controller
use App, :view
use AppWeb, :controller
use AppWeb, :view
The definitions below will be executed for every view,
controller, etc, so keep them short and clean, focused
@ -19,19 +19,19 @@ defmodule App do
def controller do
quote do
use Phoenix.Controller, namespace: App
use Phoenix.Controller, namespace: AppWeb
import Plug.Conn
import App.Gettext
alias App.Router.Helpers, as: Routes
import AppWeb.Gettext
alias AppWeb.Router.Helpers, as: Routes
end
end
def view do
quote do
use Phoenix.View,
root: "lib/app/templates",
namespace: App
root: "lib/app_web/templates",
namespace: AppWeb
# Import convenience functions from controllers
import Phoenix.Controller,
@ -54,7 +54,7 @@ defmodule App do
def channel do
quote do
use Phoenix.Channel
import App.Gettext
import AppWeb.Gettext
end
end
@ -66,9 +66,10 @@ defmodule App do
# Import basic rendering functionality (render, render_layout, etc)
import Phoenix.View
import App.ErrorHelpers
import App.Gettext
alias App.Router.Helpers, as: Routes
import CoreWeb.Helpers
import AppWeb.ErrorHelpers
import AppWeb.Gettext
alias AppWeb.Router.Helpers, as: Routes
end
end

View file

@ -1,8 +1,8 @@
defmodule App.UserSocket do
defmodule AppWeb.UserSocket do
use Phoenix.Socket
## Channels
# channel "room:*", App.RoomChannel
# channel "room:*", AppWeb.RoomChannel
# Socket params are passed from the client and can
# be used to verify and authenticate a user. After
@ -27,7 +27,7 @@ defmodule App.UserSocket do
# Would allow you to broadcast a "disconnect" event and terminate
# all active sockets and channels for a given user:
#
# App.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{})
# AppWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{})
#
# Returning `nil` makes this socket anonymous.
@impl true

View file

View file

@ -1,4 +1,4 @@
defmodule App.Endpoint do
defmodule AppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :app
# The session will be stored in the cookie and signed,
@ -10,7 +10,7 @@ defmodule App.Endpoint do
signing_salt: "VQMRz57g"
]
socket "/socket", App.UserSocket,
socket "/socket", AppWeb.UserSocket,
websocket: true,
longpoll: false
@ -50,5 +50,5 @@ defmodule App.Endpoint do
plug Plug.MethodOverride
plug Plug.Head
plug Plug.Session, @session_options
plug App.Router
plug AppWeb.Router
end

View file

@ -1,11 +1,11 @@
defmodule App.Gettext do
defmodule AppWeb.Gettext do
@moduledoc """
A module providing Internationalization with a gettext-based API.
By using [Gettext](https://hexdocs.pm/gettext),
your module gains a set of macros for translations, for example:
import App.Gettext
import AppWeb.Gettext
# Simple translation
gettext("Here is the string to translate")

View file

@ -1,5 +1,5 @@
defmodule App.Router do
use App, :router
defmodule AppWeb.Router do
use AppWeb, :router
pipeline :browser do
plug :accepts, ["html"]
@ -7,20 +7,21 @@ defmodule App.Router do
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :put_layout, {CoreWeb.LayoutView, :app}
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", App do
scope "/", AppWeb do
pipe_through :browser
get "/", PageController, :index
end
# Other scopes may use custom stacks.
# scope "/api", App do
# scope "/api", AppWeb do
# pipe_through :api
# end
@ -36,7 +37,7 @@ defmodule App.Router do
scope "/" do
pipe_through :browser
live_dashboard "/dashboard", metrics: App.Telemetry
live_dashboard "/dashboard", metrics: AppWeb.Telemetry
end
end
end

View file

@ -1,4 +1,4 @@
defmodule App.Telemetry do
defmodule AppWeb.Telemetry do
use Supervisor
import Telemetry.Metrics
@ -49,7 +49,7 @@ defmodule App.Telemetry do
[
# A module, function and arguments to be invoked periodically.
# This function must call :telemetry.execute/3 and a metric must be added above.
# {App, :count_users, []}
# {AppWeb, :count_users, []}
]
end
end

View file

@ -1,4 +1,4 @@
defmodule App.ErrorHelpers do
defmodule AppWeb.ErrorHelpers do
@moduledoc """
Conveniences for translating and building error messages.
"""
@ -39,9 +39,9 @@ defmodule App.ErrorHelpers do
# should be written to the errors.po file. The :count option is
# set by Ecto and indicates we should also apply plural rules.
if count = opts[:count] do
Gettext.dngettext(App.Gettext, "errors", msg, msg, count, opts)
Gettext.dngettext(AppWeb.Gettext, "errors", msg, msg, count, opts)
else
Gettext.dgettext(App.Gettext, "errors", msg, opts)
Gettext.dgettext(AppWeb.Gettext, "errors", msg, opts)
end
end
end

View file

@ -1,5 +1,5 @@
defmodule App.ErrorView do
use App, :view
defmodule AppWeb.ErrorView do
use AppWeb, :view
# If you want to customize a particular status code
# for a certain format, you may uncomment below.

View file

@ -0,0 +1,3 @@
defmodule AppWeb.LayoutView do
use AppWeb, :view
end

View file

@ -0,0 +1,3 @@
defmodule AppWeb.PageView do
use AppWeb, :view
end

View file

@ -37,6 +37,7 @@ defmodule App.MixProject do
# Type `mix help deps` for examples and options.
defp deps do
[
{:core, in_umbrella: true},
{:ecto_sql, "~> 3.4"},
{:phoenix, "~> 1.5.3"},
{:phoenix_ecto, "~> 4.0"},

View file

@ -1,5 +1,19 @@
<h1>Edit <%= schema.human_singular %></h1>
<div class="ui top padded container">
<div class="ui grid">
<div class="row">
<div class="eight wide column">
<h1 class="ui header">Edit <%= schema.human_singular %></h1>
</div>
<div class="eight wide right aligned column">
<span><%%= link "Back", to: Routes.<%= schema.route_helper %>_path(@conn, :index), class: "ui button" %></span>
</div>
</div>
<%%= render "form.html", Map.put(assigns, :action, Routes.<%= schema.route_helper %>_path(@conn, :update, @<%= schema.singular %>)) %>
<span><%%= link "Back", to: Routes.<%= schema.route_helper %>_path(@conn, :index) %></span>
<div class="centered row">
<div class="center aligned column">
<%%= changeset_error_block(@changeset) %>
<%%= render "form.html", Map.put(assigns, :action, Routes.<%= schema.route_helper %>_path(@conn, :update, @<%= schema.singular %>)) %>
</div>
</div>
</div>
</div>

View file

@ -1,15 +1,10 @@
<%%= form_for @changeset, @action, fn f -> %>
<%%= if @changeset.action do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below.</p>
</div>
<%% end %>
<%= for {label, input, error} <- inputs, input do %>
<%= label %>
<%= input %>
<%= error %>
<%%= form_for @changeset, @action, [class: "ui large form"], fn f -> %>
<div class="ui stacked left aligned segment">
<%= for input <- Mix.Legendary.inputs(schema) do %>
<%= input %>
<% end %>
<div>
<%%= submit "Save" %>
<div>
<%%= submit "Save", class: "ui primary fluid large submit button" %>
</div>
</div>
<%% end %>

View file

@ -1,26 +1,46 @@
<h1>Listing <%= schema.human_plural %></h1>
<div class="ui top padded container">
<div class="ui grid">
<div class="row">
<div class="eight wide column">
<h1 class="ui header"><%= schema.human_plural %></h1>
</div>
<div class="eight wide right aligned column">
<span><%%= link "New <%= schema.human_singular %>", to: Routes.<%= schema.route_helper %>_path(@conn, :new), class: "ui primary button" %></span>
</div>
</div>
</div>
<table>
<thead>
<tr>
<%= for {k, _} <- schema.attrs do %> <th><%= Phoenix.Naming.humanize(Atom.to_string(k)) %></th>
<% end %>
<th></th>
</tr>
</thead>
<tbody>
<%%= for <%= schema.singular %> <- @<%= schema.plural %> do %>
<tr>
<%= for {k, _} <- schema.attrs do %> <td><%%= <%= schema.singular %>.<%= k %> %></td>
<% end %>
<td>
<span><%%= link "Show", to: Routes.<%= schema.route_helper %>_path(@conn, :show, <%= schema.singular %>) %></span>
<span><%%= link "Edit", to: Routes.<%= schema.route_helper %>_path(@conn, :edit, <%= schema.singular %>) %></span>
<span><%%= link "Delete", to: Routes.<%= schema.route_helper %>_path(@conn, :delete, <%= schema.singular %>), method: :delete, data: [confirm: "Are you sure?"] %></span>
</td>
</tr>
<%% end %>
</tbody>
</table>
<span><%%= link "New <%= schema.human_singular %>", to: Routes.<%= schema.route_helper %>_path(@conn, :new) %></span>
<table class="ui celled table">
<thead>
<tr>
<%= for {k, _} <- schema.attrs do %> <th><%= Phoenix.Naming.humanize(Atom.to_string(k)) %></th>
<% end %>
<th></th>
</tr>
</thead>
<tbody>
<%%= case @<%= schema.plural %> do %>
<%%= [] -> %>
<tr>
<td colspan="<%= schema.attrs |> Enum.count() %>">
No results.
</td>
</tr>
<%%= _ -> %>
<%%= for <%= schema.singular %> <- @<%= schema.plural %> do %>
<tr>
<%= for {k, _} <- schema.attrs do %> <td><%%= <%= schema.singular %>.<%= k %> %></td>
<% end %>
<td>
<div class="ui list">
<span class="item"><%%= link "Show", to: Routes.<%= schema.route_helper %>_path(@conn, :show, <%= schema.singular %>) %></span>
<span class="item"><%%= link "Edit", to: Routes.<%= schema.route_helper %>_path(@conn, :edit, <%= schema.singular %>) %></span>
<span class="item"><%%= link "Delete", to: Routes.<%= schema.route_helper %>_path(@conn, :delete, <%= schema.singular %>), method: :delete, data: [confirm: "Are you sure?"] %></span>
</div>
</td>
</tr>
<%% end %>
<%% end %>
</tbody>
</table>
</div>

View file

@ -1,5 +1,19 @@
<h1>New <%= schema.human_singular %></h1>
<div class="ui top padded container">
<div class="ui grid">
<div class="row">
<div class="eight wide column">
<h1 class="ui header">New <%= schema.human_singular %></h1>
</div>
<div class="eight wide right aligned column">
<span><%%= link "Back", to: Routes.<%= schema.route_helper %>_path(@conn, :index), class: "ui button" %></span>
</div>
</div>
<%%= render "form.html", Map.put(assigns, :action, Routes.<%= schema.route_helper %>_path(@conn, :create)) %>
<span><%%= link "Back", to: Routes.<%= schema.route_helper %>_path(@conn, :index) %></span>
<div class="centered row">
<div class="center aligned column">
<%%= changeset_error_block(@changeset) %>
<%%= render "form.html", Map.put(assigns, :action, Routes.<%= schema.route_helper %>_path(@conn, :create)) %>
</div>
</div>
</div>
</div>

View file

@ -1,13 +1,26 @@
<h1>Show <%= schema.human_singular %></h1>
<div class="ui top padded container">
<div class="ui grid">
<div class="row">
<div class="eight wide column">
<h1 class="ui header"><%= schema.human_singular %></h1>
</div>
<div class="eight wide right aligned column">
<%%= link "Edit", to: Routes.<%= schema.route_helper %>_path(@conn, :edit, @<%= schema.singular %>), class: "ui button primary" %>
<span><%%= link "Back", to: Routes.<%= schema.route_helper %>_path(@conn, :index), class: "ui button" %></span>
</div>
</div>
</div>
<ul>
<%= for {k, _} <- schema.attrs do %>
<li>
<strong><%= Phoenix.Naming.humanize(Atom.to_string(k)) %>:</strong>
<%%= @<%= schema.singular %>.<%= k %> %>
</li>
<% end %>
</ul>
<span><%%= link "Edit", to: Routes.<%= schema.route_helper %>_path(@conn, :edit, @<%= schema.singular %>) %></span>
<span><%%= link "Back", to: Routes.<%= schema.route_helper %>_path(@conn, :index) %></span>
<div class="ui segment">
<div class="ui list">
<%= for {k, _} <- schema.attrs do %>
<div class="item">
<div class="content">
<strong><%= Phoenix.Naming.humanize(Atom.to_string(k)) %>:</strong>
<%%= @<%= schema.singular %>.<%= k %> %>
</div>
</div>
<% end %>
</div>
</div>
</div>

View file

View file

@ -1,8 +0,0 @@
defmodule App.PageControllerTest do
use App.ConnCase
test "GET /", %{conn: conn} do
conn = get(conn, "/")
assert html_response(conn, 200) =~ "Welcome to Phoenix!"
end
end

View file

@ -1,14 +1,14 @@
defmodule App.ErrorViewTest do
defmodule AppWeb.ErrorViewTest do
use App.ConnCase, async: true
# Bring render/3 and render_to_string/3 for testing custom views
import Phoenix.View
test "renders 404.html" do
assert render_to_string(App.ErrorView, "404.html", []) == "Not Found"
assert render_to_string(AppWeb.ErrorView, "404.html", []) == "Not Found"
end
test "renders 500.html" do
assert render_to_string(App.ErrorView, "500.html", []) == "Internal Server Error"
assert render_to_string(AppWeb.ErrorView, "500.html", []) == "Internal Server Error"
end
end

View file

@ -24,7 +24,7 @@ defmodule App.ChannelCase do
import App.ChannelCase
# The default endpoint for testing
@endpoint App.Endpoint
@endpoint AppWeb.Endpoint
end
end

View file

@ -27,7 +27,7 @@ defmodule App.ConnCase do
alias App.Router.Helpers, as: Routes
# The default endpoint for testing
@endpoint App.Endpoint
@endpoint AppWeb.Endpoint
end
end

View file

@ -10,6 +10,7 @@ defmodule AuthWeb.Router do
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :put_layout, {CoreWeb.LayoutView, :app}
end
pipeline :api do

View file

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title><%= I18n.t! "en", "site.title" %></title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head>
<body>
<style type="text/css">
body {
background-color: #DADADA;
}
main > .grid {
height: 100vh;
}
.image {
margin-top: -100px;
}
.column {
max-width: 450px;
}
</style>
<main role="main" class="container">
<%= @inner_content %>
</main>
</body>
</html>

View file

@ -8,6 +8,7 @@ defmodule Content.Router do
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :put_layout, {CoreWeb.LayoutView, :app}
end
pipeline :api do
@ -38,8 +39,6 @@ defmodule Content.Router do
put "/posts/preview", PostsController, :preview
post "/posts/preview", PostsController, :preview
get "/menus/:id/edit", MenusController, :edit
put "/menus/:id", MenusController, :update
end
scope "/", Content do

View file

@ -1,27 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title><%= I18n.t! "en", "site.title" %></title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head>
<body>
<main role="main" class="container">
<%= render "_side_menu.html", assigns %>
<!-- Page Contents -->
<div class="pusher">
<div class="ui inverted vertical masthead center aligned segment">
<%= render "_menu.html", assigns %>
</div>
<%= flash_block(@conn) %>
<%= @inner_content %>
</div>
</main>
</body>
</html>

View file

@ -0,0 +1,8 @@
// Menu buttons get a little spacing
.masthead .ui.menu .ui.button {
margin-left: 0.5em;
}
[class*="top padded"] {
padding-top: 4em;
}

View file

@ -68,6 +68,7 @@ defmodule CoreWeb do
import Phoenix.View
import CoreWeb.ErrorHelpers
import CoreWeb.Helpers
import CoreWeb.Gettext
alias CoreWeb.Router.Helpers, as: Routes
end

View file

@ -7,6 +7,7 @@ defmodule CoreWeb.Router do
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :put_layout, {CoreWeb.LayoutView, :app}
end
pipeline :api do

View file

@ -9,12 +9,12 @@
<% end %>
<div class="right item">
<%= if Pow.Plug.current_user(@conn) do %>
<%= link "Sign out", to: AuthWeb.Router.Helpers.pow_session_path(@conn, :delete), method: :delete, class: "ui inverted button" %>
<%= link "Sign out", to: AuthWeb.Router.Helpers.pow_session_path(%URI{path: "/auth"}, :delete), method: :delete, class: "ui inverted button" %>
<% else %>
<%= link to: AuthWeb.Router.Helpers.pow_session_path(@conn, :new), class: "ui inverted button" do %>
<%= link to: AuthWeb.Router.Helpers.pow_session_path(%URI{path: "/auth"}, :new), class: "ui inverted button" do %>
Log in
<% end %>
<%= link to: AuthWeb.Router.Helpers.pow_registration_path(@conn, :new), class: "ui inverted button" do %>
<%= link to: AuthWeb.Router.Helpers.pow_registration_path(%URI{path: "/auth"}, :new), class: "ui inverted button" do %>
Sign Up
<% end %>
<% end %>

View file

@ -4,12 +4,12 @@
<a class="item" href="/admin">Admin</a>
<% end %>
<%= if Pow.Plug.current_user(@conn) do %>
<%= link "Sign out", to: AuthWeb.Router.Helpers.pow_session_path(@conn, :delete), method: :delete, class: "item" %>
<%= link "Sign out", to: AuthWeb.Router.Helpers.pow_session_path(%URI{path: "/auth"}, :delete), method: :delete, class: "item" %>
<% else %>
<%= link to: AuthWeb.Router.Helpers.pow_session_path(@conn, :new), class: "item" do %>
<%= link to: AuthWeb.Router.Helpers.pow_session_path(%URI{path: "/auth"}, :new), class: "item" do %>
Log in
<% end %>
<%= link to: AuthWeb.Router.Helpers.pow_registration_path(@conn, :new), class: "item" do %>
<%= link to: AuthWeb.Router.Helpers.pow_registration_path(%URI{path: "/auth"}, :new), class: "item" do %>
Sign Up
<% end %>
<% end %>

View file

@ -10,9 +10,18 @@
</head>
<body>
<main role="main" class="container">
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<%= @inner_content %>
<%= render "_side_menu.html", assigns %>
<!-- Page Contents -->
<div class="pusher">
<div class="ui inverted vertical masthead center aligned segment">
<%= render "_menu.html", assigns %>
</div>
<%= flash_block(@conn) %>
<%= @inner_content %>
</div>
</main>
</body>
</html>

View file

@ -27,16 +27,17 @@ defmodule CoreWeb.Helpers do
"""
end
def styled_input(f, field, opts \\ []) do
styled_input(f, field, opts) do
def styled_input(f, field, opts \\ [], options \\ nil) do
styled_input(f, field, opts, options) do
""
end
end
def styled_input(f, field, opts, do: content) do
def styled_input(f, field, opts, options, do: content) do
{icon, rest_opts} = Keyword.pop(opts, :icon, "")
{classes, rest_opts} = Keyword.pop(rest_opts, :class, "")
{label_text, rest_opts} = Keyword.pop(rest_opts, :label)
{input_helper, rest_opts} = Keyword.pop(rest_opts, :input_helper, :text_input)
~E"""
<div class="field <%= error_class(f, field) %>">
<%= if label_text do %>
@ -47,7 +48,11 @@ defmodule CoreWeb.Helpers do
<div class="ui left icon <%= classes %> input">
<i class="<%= icon %> icon"></i>
<%= text_input f, field, rest_opts %>
<%= if options == nil do %>
<%= apply(Phoenix.HTML.Form, input_helper, [f, field, rest_opts]) %>
<% else %>
<%= apply(Phoenix.HTML.Form, input_helper, [f, field, options, rest_opts]) %>
<% end %>
<%= content %>
</div>
<%= error_tag f, field, class: "ui pointing red basic label" %>

View file

@ -0,0 +1,35 @@
defmodule Mix.Legendary do
alias Mix.Phoenix.{Schema}
@doc false
def inputs(%Schema{} = schema) do
Enum.map(schema.attrs, fn
{_, {:references, _}} ->
nil
{key, :integer} ->
~s(<%= styled_input f, #{inspect(key)}, input_helper: :number_input %>)
{key, :float} ->
~s(<%= styled_input f, #{inspect(key)}, input_helper: :number_input, step: "any" %>)
{key, :decimal} ->
~s(<%= styled_input f, #{inspect(key)}, input_helper: :number_input, step: "any" %>)
{key, :boolean} ->
~s(<%= styled_input f, #{inspect(key)}, input_helper: :checkbox %>)
{key, :text} ->
~s(<%= styled_input f, #{inspect(key)}, input_helper: :textarea %>)
{key, :date} ->
~s(<%= styled_input f, #{inspect(key)}, input_helper: :date_select %>)
{key, :time} ->
~s(<%= styled_input f, #{inspect(key)}, input_helper: :time_select %>)
{key, :utc_datetime} ->
~s(<%= styled_input f, #{inspect(key)}, input_helper: :datetime_select %>)
{key, :naive_datetime} ->
~s(<%= styled_input f, #{inspect(key)}, input_helper: :datetime_select %>)
{key, {:array, :integer}} ->
~s(<%= styled_input f, #{inspect(key)}, [input_helper: :multiple_select], ["1": 1, "2": 2] %>)
{key, {:array, _}} ->
~s(<%= styled_input f, #{inspect(key)}, [input_helper: :multiple_select], ["Option 1": "option1", "Option 2": "option2"] %>)
{key, _} ->
~s(<%= styled_input f, #{inspect(key)} %>)
end)
end
end

View file

@ -1,5 +1,5 @@
defmodule <%= module %>Channel do
use <%= web_module %>, :channel
use <%= module %>, :channel
@impl true
def join("<%= singular %>:lobby", payload, socket) do

View file

@ -1,9 +1,9 @@
defmodule <%= module %>ChannelTest do
use <%= web_module %>.ChannelCase
use <%= module %>.ChannelCase
setup do
{:ok, _, socket} =
<%= web_module %>.UserSocket
<%= module %>.UserSocket
|> socket("user_id", %{some: :assign})
|> subscribe_and_join(<%= module %>Channel, "<%= singular %>:lobby")

View file

@ -1,5 +1,5 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Controller do
use <%= inspect context.web_module %>, :controller
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Controller do
use <%= inspect context.module %>, :controller
alias <%= inspect context.module %>
alias <%= inspect schema.module %>

View file

@ -1,5 +1,5 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ControllerTest do
use <%= inspect context.web_module %>.ConnCase
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ControllerTest do
use <%= inspect context.module %>.ConnCase
import <%= inspect context.module %>Fixtures

View file

@ -1,3 +1,3 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>View do
use <%= inspect context.web_module %>, :view
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>View do
use <%= inspect context.module %>, :view
end

View file

@ -1,11 +1,11 @@
defmodule <%= inspect context.web_module %>.ChangesetView do
use <%= inspect context.web_module %>, :view
defmodule <%= inspect context.module %>.ChangesetView do
use <%= inspect context.module %>, :view
@doc """
Traverses and translates changeset errors.
See `Ecto.Changeset.traverse_errors/2` and
`<%= inspect context.web_module %>.ErrorHelpers.translate_error/1` for more details.
`<%= inspect context.module %>.ErrorHelpers.translate_error/1` for more details.
"""
def translate_errors(changeset) do
Ecto.Changeset.traverse_errors(changeset, &translate_error/1)

View file

@ -1,10 +1,10 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Controller do
use <%= inspect context.web_module %>, :controller
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Controller do
use <%= inspect context.module %>, :controller
alias <%= inspect context.module %>
alias <%= inspect schema.module %>
action_fallback <%= inspect context.web_module %>.FallbackController
action_fallback <%= inspect context.module %>.FallbackController
def index(conn, _params) do
<%= schema.plural %> = <%= inspect context.alias %>.list_<%= schema.plural %>()

View file

@ -1,5 +1,5 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ControllerTest do
use <%= inspect context.web_module %>.ConnCase
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ControllerTest do
use <%= inspect context.module %>.ConnCase
import <%= inspect context.module %>Fixtures

View file

@ -1,16 +1,16 @@
defmodule <%= inspect context.web_module %>.FallbackController do
defmodule <%= inspect context.module %>.FallbackController do
@moduledoc """
Translates controller action results into valid `Plug.Conn` responses.
See `Phoenix.Controller.action_fallback/1` for more details.
"""
use <%= inspect context.web_module %>, :controller
use <%= inspect context.module %>, :controller
<%= if schema.generate? do %># This clause handles errors returned by Ecto's insert/update/delete.
def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
conn
|> put_status(:unprocessable_entity)
|> put_view(<%= inspect context.web_module %>.ChangesetView)
|> put_view(<%= inspect context.module %>.ChangesetView)
|> render("error.json", changeset: changeset)
end
@ -18,7 +18,7 @@ defmodule <%= inspect context.web_module %>.FallbackController do
def call(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)
|> put_view(<%= inspect context.web_module %>.ErrorView)
|> put_view(<%= inspect context.module %>.ErrorView)
|> render(:"404")
end
end

View file

@ -1,6 +1,6 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>View do
use <%= inspect context.web_module %>, :view
alias <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>View
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>View do
use <%= inspect context.module %>, :view
alias <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>View
def render("index.json", %{<%= schema.plural %>: <%= schema.plural %>}) do
%{data: render_many(<%= schema.plural %>, <%= inspect schema.alias %>View, "<%= schema.singular %>.json")}

View file

@ -1,5 +1,5 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent do
use <%= inspect context.web_module %>, :live_component
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent do
use <%= inspect context.module %>, :live_component
alias <%= inspect context.module %>

View file

@ -1,5 +1,5 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.Index do
use <%= inspect context.web_module %>, :live_view
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.Index do
use <%= inspect context.module %>, :live_view
alias <%= inspect context.module %>
alias <%= inspect schema.module %>

View file

@ -1,7 +1,7 @@
<h1>Listing <%= schema.human_plural %></h1>
<%%= if @live_action in [:new, :edit] do %>
<%%= live_modal @socket, <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent,
<%%= live_modal @socket, <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent,
id: @<%= schema.singular %>.id || :new,
title: @page_title,
action: @live_action,

View file

@ -1,15 +1,15 @@
defmodule <%= inspect context.web_module %>.LiveHelpers do
defmodule <%= inspect context.module %>.LiveHelpers do
import Phoenix.LiveView.Helpers
@doc """
Renders a component inside the `<%= inspect context.web_module %>.ModalComponent` component.
Renders a component inside the `<%= inspect context.module %>.ModalComponent` component.
The rendered modal receives a `:return_to` option to properly update
the URL when the modal is closed.
## Examples
<%%= live_modal @socket, <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent,
<%%= live_modal @socket, <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent,
id: @<%= schema.singular %>.id || :new,
action: @live_action,
<%= schema.singular %>: @<%= schema.singular %>,
@ -18,6 +18,6 @@ defmodule <%= inspect context.web_module %>.LiveHelpers do
def live_modal(socket, component, opts) do
path = Keyword.fetch!(opts, :return_to)
modal_opts = [id: :modal, return_to: path, component: component, opts: opts]
live_component(socket, <%= inspect context.web_module %>.ModalComponent, modal_opts)
live_component(socket, <%= inspect context.module %>.ModalComponent, modal_opts)
end
end

View file

@ -1,5 +1,5 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>LiveTest do
use <%= inspect context.web_module %>.ConnCase
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>LiveTest do
use <%= inspect context.module %>.ConnCase
import Phoenix.LiveViewTest
import <%= inspect context.module %>Fixtures

View file

@ -1,5 +1,5 @@
defmodule <%= inspect context.web_module %>.ModalComponent do
use <%= inspect context.web_module %>, :live_component
defmodule <%= inspect context.module %>.ModalComponent do
use <%= inspect context.module %>, :live_component
@impl true
def render(assigns) do

View file

@ -1,5 +1,5 @@
defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.Show do
use <%= inspect context.web_module %>, :live_view
defmodule <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.Show do
use <%= inspect context.module %>, :live_view
alias <%= inspect context.module %>

View file

@ -1,7 +1,7 @@
<h1>Show <%= schema.human_singular %></h1>
<%%= if @live_action in [:edit] do %>
<%%= live_modal @socket, <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent,
<%%= live_modal @socket, <%= inspect context.module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent,
id: @<%= schema.singular %>.id,
title: @page_title,
action: @live_action,

View file

@ -1,9 +1,5 @@
use Mix.Config
config :app,
ecto_repos: [App.Repo],
generators: [context_app: false]
# Configures the endpoint
config :app, App.Endpoint,
url: [host: "localhost"],
@ -17,7 +13,8 @@ config :admin,
generators: [context_app: false]
config :app,
ecto_repos: [App.Repo]
ecto_repos: [App.Repo],
generators: [context_app: :app]
# Configures the endpoint
config :admin, Admin.Endpoint,
@ -27,6 +24,14 @@ config :admin, Admin.Endpoint,
pubsub_server: Admin.PubSub,
live_view: [signing_salt: "g5ltUbnQ"]
# Configures the endpoint
config :app, AppWeb.Endpoint,
url: [host: "localhost"],
secret_key_base: "r2eN53mJ9RmlGz9ZQ7xf43P3Or59aaO9rdf5D3hRcsuiH44pGW9kPGfl5mt9N1Gi",
render_errors: [view: AppWeb.ErrorView, accepts: ~w(html json), layout: false],
pubsub_server: AppWeb.PubSub,
live_view: [signing_salt: "g5ltUbnQ"]
# Configure Mix tasks and generators
config :auth,
ecto_repos: [Auth.Repo]
@ -67,7 +72,7 @@ config :core,
{Content.Router, "/pages"},
{AuthWeb.Router, "/auth"},
{Admin.Router, "/admin"},
{App.Router, "/app"},
{AppWeb.Router, "/app"},
],
email_from: "example@example.org"
@ -77,7 +82,7 @@ config :content,
config :content, Content.Endpoint, server: false
config :auth_web, AuthWeb.Endpoint, server: false
config :admin, Admin.Endpoint, server: false
config :app, App.Endpoint, server: false
config :app, AppWeb.Endpoint, server: false
import_config "../apps/*/config/config.exs"