Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ mix tableau.new <app_name> [<flags>]

Flags

--template Template syntax to use. Options are heex, temple, eex. (required)
--assets Asset framework to use. Options are vanilla, tailwind. (optional, defaults to vanilla)
--template Template syntax to use. Options are heex, temple, eex. (optional, defaults to eex)
--js JS bundler to use. Options are vanilla, bun, esbuild (optional, defaults to vanilla)
--css CSS framework to use. Options are vanilla, tailwind. (optional, defaults to vanilla)
--help Shows this help text.
--version Shows task version.

Example

mix tableau.new my_awesome_site --template temple
mix tableau.new my_awesome_site --template eex --assets tailwind
mix tableau.new my_awesome_site --template eex --css tailwind
```
116 changes: 69 additions & 47 deletions lib/mix/tasks/tableau.new.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ defmodule Mix.Tasks.Tableau.New do

Flags

--template Template syntax to use. Options are heex, temple, eex. (required)
--assets Asset framework to use. Options are vanilla, tailwind. (optional, defaults to vanilla)
--template Template syntax to use. Options are heex, temple, eex. (optional, defaults to eex)
--js JS bundler to use. Options are vanilla, bun, esbuild (optional, defaults to vanilla)
--css Asset framework to use. Options are vanilla, tailwind. (optional, defaults to vanilla)
--help Shows this help text.
--version Shows task version.

Example

mix tableau.new my_awesome_site --template temple
mix tableau.new my_awesome_site --template eex --assets tailwind
mix tableau.new my_awesome_site
mix tableau.new my_awesome_site --template temple --js bun --css tailwind
"""
@moduledoc @help
@shortdoc "Generate a new Tableau website"
Expand All @@ -25,15 +26,16 @@ defmodule Mix.Tasks.Tableau.New do
{opts, argv} =
OptionParser.parse!(argv,
strict: [
assets: :string,
js: :string,
css: :string,
template: :string,
help: :boolean,
version: :boolean
]
)

opts =
case Keyword.validate(opts, [:assets, :template, help: false, version: false]) do
case Keyword.validate(opts, [:css, :js, :template, help: false, version: false]) do
{:ok, opts} ->
opts

Expand All @@ -56,13 +58,21 @@ defmodule Mix.Tasks.Tableau.New do

[app | _] = argv
Mix.Generator.create_directory(app)
templates = Path.join(:code.priv_dir(:tableau_new), "templates")
templates = :tableau_new |> :code.priv_dir() |> Path.join("templates")

css =
if opts[:js] == "bun" and opts[:css] == "tailwind" do
"tailwind-bun"
else
opts[:css]
end

assigns = [
app: app,
app_module: Macro.camelize(app),
template: opts[:template],
assets: opts[:assets]
js: opts[:js],
css: css
]

Mix.Generator.copy_template(
Expand All @@ -84,81 +94,83 @@ defmodule Mix.Tasks.Tableau.New do
)

Mix.Generator.create_file(Path.join(app, "_pages/.keep"), "")
Mix.Generator.create_file(Path.join(app, "_wip/.keep"), "")

Mix.Generator.create_file(Path.join(app, "_posts/.keep"), "")
Mix.Generator.create_file(Path.join(app, "_draft/.keep"), "")

Mix.Generator.create_file(Path.join(app, "extra/.keep"), "")

for source <- Path.wildcard(Path.join(templates, "primary/**/*.{ex,exs}")) do
target =
Path.relative_to(source, Path.join(templates, "primary"))
|> String.replace("app_name", app)

Mix.Generator.copy_template(source, Path.join(app, target), assigns)
copy_templates(source, templates, "primary", app, assigns)
end

case opts[:template] do
"temple" ->
for source <- Path.wildcard(Path.join(templates, "temple/**/*.{ex,exs}")) do
target =
Path.relative_to(source, Path.join(templates, "temple"))
|> String.replace("app_name", app)

Mix.Generator.copy_template(source, Path.join(app, target), assigns)
copy_templates(source, templates, "temple", app, assigns)
end

"heex" ->
for source <- Path.wildcard(Path.join(templates, "heex/**/*.{ex,exs}")) do
target =
Path.relative_to(source, Path.join(templates, "heex"))
|> String.replace("app_name", app)

Mix.Generator.copy_template(source, Path.join(app, target), assigns)
copy_templates(source, templates, "heex", app, assigns)
end

"eex" ->
template when template in ["eex", nil] ->
for source <- Path.wildcard(Path.join(templates, "eex/**/*.{ex,exs}")) do
target =
Path.relative_to(source, Path.join(templates, "eex"))
|> String.replace("app_name", app)

Mix.Generator.copy_template(source, Path.join(app, target), assigns)
copy_templates(source, templates, "eex", app, assigns)
end

nil ->
value ->
Mix.shell().error("""
The --template option is required.
Unknown template value: --template=#{value}

See help text for more information.
""")

System.halt(1)
end

case opts[:js] do
"esbuild" ->
for source <- Path.wildcard(Path.join(templates, "esbuild/**/*.{css,js}")) do
copy_templates(source, templates, "esbuild", app, assigns)
end

"bun" ->
for source <- Path.wildcard(Path.join(templates, "bun/**/*.{css,js,json}")) do
copy_templates(source, templates, "bun", app, assigns)
end

js when js in ["vanilla", nil] ->
for source <- Path.wildcard(Path.join(templates, "no_assets/**/*.{js}")) do
copy_templates(source, templates, "no_assets", app, assigns)
end

js ->
Mix.shell().error("""
Unknown js value: --js=#{js}

See help text for more information.
""")

_ ->
Mix.shell().error("Unknown template value: --template=#{opts[:template]}")
System.halt(1)
end

case opts[:assets] do
case opts[:css] do
"tailwind" ->
for source <- Path.wildcard(Path.join(templates, "tailwind/**/*.{css,js}")) do
target =
Path.relative_to(source, Path.join(templates, "tailwind"))
|> String.replace("app_name", app)

Mix.Generator.copy_template(source, Path.join(app, target), assigns)
copy_templates(source, templates, "tailwind", app, assigns)
end

assets when assets in ["vanilla", nil] ->
css when css in ["vanilla", nil] ->
for source <- Path.wildcard(Path.join(templates, "no_assets/**/*.{css}")) do
target =
Path.relative_to(source, Path.join(templates, "no_assets"))
|> String.replace("app_name", app)

Mix.Generator.copy_template(source, Path.join(app, target), assigns)
copy_templates(source, templates, "no_assets", app, assigns)
end

_ ->
css ->
Mix.shell().error("""
Unknown assets value: --assets=#{opts[:assets]}
Unknown css value: --css=#{css}

See help text for more information.
""")
Expand All @@ -181,4 +193,14 @@ defmodule Mix.Tasks.Tableau.New do
mix tableau.server
""")
end

defp copy_templates(source, templates, app, kind, assigns) do
target =
source
|> Path.relative_to(Path.join(templates, kind))
|> String.replace("app_name", app)
|> then(&Path.join(app, &1))

Mix.Generator.copy_template(source, target, assigns)
end
end
Empty file.
12 changes: 12 additions & 0 deletions priv/templates/bun/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "<%= @app %>",
"main": "site.js",
"devDependencies": {
"@types/bun": "latest"
},
"dependencies": {<%= if @css == "tailwind-bun" do %>
"tailwindcss": "^4.1.0",
"@tailwindcss/cli": "^4.1.0",
"@tailwindcss/typography": "^0.5.16"<% end %>
}
}
3 changes: 2 additions & 1 deletion priv/templates/eex/lib/layouts/root_layout.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ defmodule <%= @app_module %>.RootLayout do
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<title>
<%%= [@page[:title], <%= @app_module %>]
<%%= [@page[:title], "<%= @app %>"]
|> Enum.filter(& &1)
|> Enum.intersperse("|")
|> Enum.join(" ") %>
</title>

<link rel="stylesheet" href="/css/site.css" />
<script src="/js/site.js"></script>
</head>

<body>
Expand Down
Empty file.
3 changes: 2 additions & 1 deletion priv/templates/heex/lib/layouts/root_layout.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ defmodule <%= @app_module %>.RootLayout do
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<title>
<%%= [@page[:title], <%= @app_module %>]
<%%= [@page[:title], "<%= @app %>"]
|> Enum.filter(& &1)
|> Enum.intersperse("|")
|> Enum.join(" ") %>
</title>

<link rel="stylesheet" href="/css/site.css" />
<script src="/js/site.js" />
</head>

<body>
Expand Down
Empty file.
43 changes: 36 additions & 7 deletions priv/templates/primary/config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Config
config :tableau, :reloader,
patterns: [
~r"^lib/.*.ex",
~r"^(_posts|_pages)/.*.md",<%= if @assets == "tailwind" do %>
~r"^(_posts|_pages)/.*.md",<%= if @css == "tailwind" or @js == "esbuild" do %>
~r"^assets/.*.(css|js)"<% else %>~r"^extra/.*.(css|js)"<% end %>
]

Expand All @@ -15,9 +15,15 @@ config :web_dev_utils, :reload_log, true
config :temple,
engine: EEx.SmartEngine,
attributes: {Temple, :attributes}
<% end %>

<%= if @assets == "tailwind" do %>
<% end %><%= if @js == "esbuild" do %>
config :esbuild,
version: "0.25.5",
default: [
args: ~w(js/site.js --bundle --target=es2016 --outdir=../_site/js),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
<% end %><%= if @css == "tailwind" do %>
config :tailwind,
version: "4.1.0",
default: [
Expand All @@ -26,9 +32,32 @@ config :tailwind,
--output=_site/css/site.css
)
]

config :tableau, :assets, tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}
<% end %>
<% end %><%= if @js == "bun" do %>
config :bun,
version: "1.2.4",
install: [
args: ~w(install)
],
default: [
args: ~w(
build
assets/js/site.js
--outdir=_site/js
)
]<% end %><%= if @css == "tailwind-bun" do %>,
css: [
args: ~w(
run tailwindcss
--input=assets/css/site.css
--output=_site/css/site.css
)
]<% end %>
config :tableau, :assets, [<%= if @css == "tailwind" do %>
tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]},<% end %><%= if @js == "esbuild" do %>
esbuild: {Esbuild, :install_and_run, [:default, ~w(--watch)]},<% end %><%= if @js == "bun" do %>
bun: {Bun, :install_and_run, [:default, ~w(--watch)]},<% end %><%= if @css == "tailwind-bun" do %>
tailwind: {Bun, :install_and_run, [:css, ~w(--watch)]},<% end %>
]

config :tableau, :config,
url: "http://localhost:4999",
Expand Down
6 changes: 5 additions & 1 deletion priv/templates/primary/gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ erl_crash.dump
*.ez

# Ignore package tarball (built via "mix hex.build").
tableau_new-*.tar
<%= @app %>-*.tar

/_site/

/node_modules/

# Temporary files, for example, from tests.
/tmp/
8 changes: 5 additions & 3 deletions priv/templates/primary/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ defmodule <%= @app_module %>.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:tableau, "~> 0.25"}<%= if @assets == "tailwind" do %>,
{:tableau, "~> 0.26"}<%= if @css == "tailwind" do %>,
{:tailwind, "~> 0.3", runtime: Mix.env() == :dev}<% end %><%= if @template == "temple" do %>,
{:temple, "~> 0.12"}<% end %><%= if @template == "heex" do %>,
{:phoenix_live_view, "~> 1.0"}<% end %>
{:phoenix_live_view, "~> 1.0"}<% end %><%= if @js == "esbuild" do %>,
{:esbuild, "~> 0.10", runtime: Mix.env() == :dev}<% end %><%= if @js == "bun" do %>,
{:bun, "~> 1.5", runtime: Mix.env() == :dev}<% end %>

# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
Expand All @@ -35,7 +37,7 @@ defmodule <%= @app_module %>.MixProject do

defp aliases do
[
build: ["tableau.build"<%= if @assets == "tailwind" do %>, "tailwind default --minify"<% end %>]
build: ["tableau.build"<%= if @css == "tailwind" do %>, "tailwind default --minify"<% end %><%= if @js == "esbuild" do %>, "esbuild default --minify"<% end %>]
]
end
end
3 changes: 2 additions & 1 deletion priv/templates/temple/lib/layouts/root_layout.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ defmodule <%= @app_module %>.RootLayout do
meta name: "viewport", content: "width=device-width, initial-scale=1.0"

title do
[@page[:title], <%= Macro.to_string(@app_module) %>]
[@page[:title], <%= @app %>]
|> Enum.filter(& &1)
|> Enum.intersperse("|")
|> Enum.join(" ")
end

link rel: "stylesheet", href: "/css/site.css"
script src: "/js/site.js"
end

body do
Expand Down