v1.0a
Browse files- .dockerignore +8 -0
- .gitignore +5 -0
- Dockerfile +36 -0
- Plan.md +27 -0
- assets/css/app.css +48 -0
- assets/js/app.js +35 -0
- config/config.exs +34 -0
- config/prod.exs +8 -0
- lib/hexalixir/game.ex +86 -0
- lib/hexalixir/grid.ex +37 -0
- lib/hexalixir_web/live/game_live.ex +48 -0
- lib/hexalixir_web/templates/game/index.html.heex +48 -0
- mix.exs +47 -0
.dockerignore
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
_build/
|
2 |
+
deps/
|
3 |
+
.git/
|
4 |
+
.gitignore
|
5 |
+
Dockerfile
|
6 |
+
README.md
|
7 |
+
test/
|
8 |
+
priv/static/
|
.gitignore
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/_build/
|
2 |
+
/deps/
|
3 |
+
/priv/static/
|
4 |
+
.elixir_ls/
|
5 |
+
.env
|
Dockerfile
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM elixir:1.14-alpine
|
2 |
+
|
3 |
+
# Install build dependencies
|
4 |
+
RUN apk add --no-cache build-base npm git python3
|
5 |
+
|
6 |
+
# Install hex and rebar
|
7 |
+
RUN mix local.hex --force && \
|
8 |
+
mix local.rebar --force
|
9 |
+
|
10 |
+
# Set working directory
|
11 |
+
WORKDIR /app
|
12 |
+
|
13 |
+
# Copy mix files
|
14 |
+
COPY mix.exs mix.lock ./
|
15 |
+
|
16 |
+
# Install mix dependencies
|
17 |
+
RUN mix deps.get
|
18 |
+
|
19 |
+
# Copy assets
|
20 |
+
COPY assets assets
|
21 |
+
COPY priv priv
|
22 |
+
COPY config config
|
23 |
+
COPY lib lib
|
24 |
+
|
25 |
+
# Compile the project
|
26 |
+
RUN mix do compile
|
27 |
+
|
28 |
+
# Build assets
|
29 |
+
RUN cd assets && npm install && npm run deploy
|
30 |
+
RUN mix phx.digest
|
31 |
+
|
32 |
+
ENV MIX_ENV=prod
|
33 |
+
ENV PORT=7860
|
34 |
+
|
35 |
+
# Run the Phoenix app
|
36 |
+
CMD ["mix", "phx.server"]
|
Plan.md
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Hexalixir/
|
2 |
+
├── .dockerignore
|
3 |
+
├── .gitignore
|
4 |
+
├── Dockerfile
|
5 |
+
├── README.md
|
6 |
+
├── config/
|
7 |
+
│ ├── config.exs
|
8 |
+
│ ├── dev.exs
|
9 |
+
│ └── prod.exs
|
10 |
+
├── lib/
|
11 |
+
│ ├── hexalixir/
|
12 |
+
│ │ ├── game.ex
|
13 |
+
│ │ └── grid.ex
|
14 |
+
│ ├── hexalixir_web/
|
15 |
+
│ │ ├── channels/
|
16 |
+
│ │ │ └── game_channel.ex
|
17 |
+
│ │ ├── controllers/
|
18 |
+
│ │ │ └── page_controller.ex
|
19 |
+
│ │ ├── templates/
|
20 |
+
│ │ │ └── game.html.heex
|
21 |
+
│ │ └── assets/
|
22 |
+
│ │ ├── css/
|
23 |
+
│ │ │ └── app.css
|
24 |
+
│ │ └── js/
|
25 |
+
│ │ └── game.js
|
26 |
+
├── mix.exs
|
27 |
+
└── mix.lock
|
assets/css/app.css
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
defmodule HexalixirWeb.GameLive do
|
2 |
+
use HexalixirWeb, :live_view
|
3 |
+
alias Hexalixir.{Game, Grid}
|
4 |
+
|
5 |
+
@impl true
|
6 |
+
def mount(_params, _session, socket) do
|
7 |
+
{:ok, assign(socket,
|
8 |
+
grid: Grid.new(),
|
9 |
+
saved_colors: %{1 => {nil, 6}, 2 => {nil, 6}},
|
10 |
+
game_won: false
|
11 |
+
)}
|
12 |
+
end
|
13 |
+
|
14 |
+
@impl true
|
15 |
+
def handle_event("click_tile", %{"x" => x, "y" => y}, socket) do
|
16 |
+
coords = {String.to_integer(x), String.to_integer(y)}
|
17 |
+
|
18 |
+
case Game.click_tile(coords) do
|
19 |
+
{:ok, new_grid, won} ->
|
20 |
+
{:noreply, assign(socket, grid: new_grid, game_won: won)}
|
21 |
+
|
22 |
+
{:error, _reason} ->
|
23 |
+
{:noreply, socket}
|
24 |
+
end
|
25 |
+
end
|
26 |
+
|
27 |
+
@impl true
|
28 |
+
def handle_event("save_color", %{"color" => color, "slot" => slot}, socket) do
|
29 |
+
slot = String.to_integer(slot)
|
30 |
+
Game.save_color(color, slot)
|
31 |
+
|
32 |
+
{:noreply, socket}
|
33 |
+
end
|
34 |
+
|
35 |
+
@impl true
|
36 |
+
def handle_event("use_saved_color", %{"x" => x, "y" => y, "slot" => slot}, socket) do
|
37 |
+
coords = {String.to_integer(x), String.to_integer(y)}
|
38 |
+
slot = String.to_integer(slot)
|
39 |
+
|
40 |
+
case Game.use_saved_color(coords, slot) do
|
41 |
+
{:ok, new_grid, won} ->
|
42 |
+
{:noreply, assign(socket, grid: new_grid, game_won: won)}
|
43 |
+
|
44 |
+
{:error, _reason} ->
|
45 |
+
{:noreply, socket}
|
46 |
+
end
|
47 |
+
end
|
48 |
+
end
|
assets/js/app.js
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import "phoenix_html"
|
2 |
+
import {Socket} from "phoenix"
|
3 |
+
import {LiveSocket} from "phoenix_live_view"
|
4 |
+
|
5 |
+
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
|
6 |
+
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
|
7 |
+
|
8 |
+
liveSocket.connect()
|
9 |
+
window.liveSocket = liveSocket
|
10 |
+
```
|
11 |
+
|
12 |
+
10. lib/hexalixir/application.ex:
|
13 |
+
```elixir
|
14 |
+
defmodule Hexalixir.Application do
|
15 |
+
use Application
|
16 |
+
|
17 |
+
@impl true
|
18 |
+
def start(_type, _args) do
|
19 |
+
children = [
|
20 |
+
HexalixirWeb.Telemetry,
|
21 |
+
{Phoenix.PubSub, name: Hexalixir.PubSub},
|
22 |
+
HexalixirWeb.Endpoint,
|
23 |
+
Hexalixir.Game
|
24 |
+
]
|
25 |
+
|
26 |
+
opts = [strategy: :one_for_one, name: Hexalixir.Supervisor]
|
27 |
+
Supervisor.start_link(children, opts)
|
28 |
+
end
|
29 |
+
|
30 |
+
@impl true
|
31 |
+
def config_change(changed, _new, removed) do
|
32 |
+
HexalixirWeb.Endpoint.config_change(changed, removed)
|
33 |
+
:ok
|
34 |
+
end
|
35 |
+
end
|
config/config.exs
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import Config
|
2 |
+
|
3 |
+
config :hexalixir, HexalixirWeb.Endpoint,
|
4 |
+
url: [host: "localhost"],
|
5 |
+
render_errors: [
|
6 |
+
formats: [html: HexalixirWeb.ErrorHTML, json: HexalixirWeb.ErrorJSON],
|
7 |
+
layout: false
|
8 |
+
],
|
9 |
+
pubsub_server: Hexalixir.PubSub,
|
10 |
+
live_view: [signing_salt: "YOUR_SECRET_SALT"]
|
11 |
+
|
12 |
+
config :esbuild,
|
13 |
+
version: "0.14.41",
|
14 |
+
default: [
|
15 |
+
args: ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets
|
16 |
+
--external:/fonts/* --external:/images/*),
|
17 |
+
cd: Path.expand("../assets", __DIR__),
|
18 |
+
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
|
19 |
+
]
|
20 |
+
|
21 |
+
config :tailwind,
|
22 |
+
version: "3.2.4",
|
23 |
+
default: [
|
24 |
+
args: ~w(
|
25 |
+
--config=tailwind.config.js
|
26 |
+
--input=css/app.css
|
27 |
+
--output=../priv/static/assets/app.css
|
28 |
+
),
|
29 |
+
cd: Path.expand("../assets", __DIR__)
|
30 |
+
]
|
31 |
+
|
32 |
+
config :phoenix, :json_library, Jason
|
33 |
+
|
34 |
+
import_config "#{config_env()}.exs"
|
config/prod.exs
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import Config
|
2 |
+
|
3 |
+
config :hexalixir, HexalixirWeb.Endpoint,
|
4 |
+
url: [host: "0.0.0.0"],
|
5 |
+
http: [port: 7860],
|
6 |
+
cache_static_manifest: "priv/static/cache_manifest.json"
|
7 |
+
|
8 |
+
config :logger, level: :info
|
lib/hexalixir/game.ex
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
defmodule Hexalixir.Game do
|
2 |
+
use GenServer
|
3 |
+
alias Hexalixir.Grid
|
4 |
+
|
5 |
+
# Client API
|
6 |
+
|
7 |
+
def start_link(_opts) do
|
8 |
+
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
|
9 |
+
end
|
10 |
+
|
11 |
+
def click_tile(coords) do
|
12 |
+
GenServer.call(__MODULE__, {:click_tile, coords})
|
13 |
+
end
|
14 |
+
|
15 |
+
def save_color(color, slot) do
|
16 |
+
GenServer.call(__MODULE__, {:save_color, color, slot})
|
17 |
+
end
|
18 |
+
|
19 |
+
def use_saved_color(coords, slot) do
|
20 |
+
GenServer.call(__MODULE__, {:use_saved_color, coords, slot})
|
21 |
+
end
|
22 |
+
|
23 |
+
# Server Callbacks
|
24 |
+
|
25 |
+
@impl true
|
26 |
+
def init(:ok) do
|
27 |
+
{:ok, %{
|
28 |
+
grid: Grid.new(),
|
29 |
+
saved_colors: %{1 => {nil, 6}, 2 => {nil, 6}}
|
30 |
+
}}
|
31 |
+
end
|
32 |
+
|
33 |
+
@impl true
|
34 |
+
def handle_call({:click_tile, coords}, _from, state) do
|
35 |
+
if Map.get(state.grid, coords) do
|
36 |
+
{:reply, {:error, :tile_already_colored}, state}
|
37 |
+
else
|
38 |
+
new_grid = color_tiles([coords | Grid.get_adjacent_coords(coords)], state.grid)
|
39 |
+
new_state = %{state | grid: new_grid}
|
40 |
+
|
41 |
+
{:reply, {:ok, new_grid, Grid.check_win(new_grid)}, new_state}
|
42 |
+
end
|
43 |
+
end
|
44 |
+
|
45 |
+
@impl true
|
46 |
+
def handle_call({:save_color, color, slot}, _from, state) do
|
47 |
+
new_state = put_in(state.saved_colors[slot], {color, 6})
|
48 |
+
{:reply, :ok, new_state}
|
49 |
+
end
|
50 |
+
|
51 |
+
@impl true
|
52 |
+
def handle_call({:use_saved_color, coords, slot}, _from, state) do
|
53 |
+
case state.saved_colors[slot] do
|
54 |
+
{nil, _} ->
|
55 |
+
{:reply, {:error, :no_color_saved}, state}
|
56 |
+
|
57 |
+
{color, 0} ->
|
58 |
+
{:reply, {:error, :no_uses_left}, state}
|
59 |
+
|
60 |
+
{color, uses} ->
|
61 |
+
if Map.get(state.grid, coords) do
|
62 |
+
{:reply, {:error, :tile_already_colored}, state}
|
63 |
+
else
|
64 |
+
new_grid = Map.put(state.grid, coords, color)
|
65 |
+
new_state = %{state |
|
66 |
+
grid: new_grid,
|
67 |
+
saved_colors: Map.put(state.saved_colors, slot, {color, uses - 1})
|
68 |
+
}
|
69 |
+
|
70 |
+
{:reply, {:ok, new_grid, Grid.check_win(new_grid)}, new_state}
|
71 |
+
end
|
72 |
+
end
|
73 |
+
end
|
74 |
+
|
75 |
+
# Private Functions
|
76 |
+
|
77 |
+
defp color_tiles(coords, grid) do
|
78 |
+
Enum.reduce(coords, grid, fn coord, acc ->
|
79 |
+
if Map.get(acc, coord) do
|
80 |
+
acc
|
81 |
+
else
|
82 |
+
Map.put(acc, coord, Grid.random_color())
|
83 |
+
end
|
84 |
+
end)
|
85 |
+
end
|
86 |
+
end
|
lib/hexalixir/grid.ex
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
defmodule Hexalixir.Grid do
|
2 |
+
@grid_size 20
|
3 |
+
|
4 |
+
def new do
|
5 |
+
for x <- 0..(@grid_size - 1),
|
6 |
+
y <- 0..(@grid_size - 1),
|
7 |
+
into: %{} do
|
8 |
+
{{x, y}, nil}
|
9 |
+
end
|
10 |
+
end
|
11 |
+
|
12 |
+
def get_adjacent_coords({x, y}) do
|
13 |
+
[
|
14 |
+
{x + 1, y}, {x - 1, y}, # right, left
|
15 |
+
{x, y + 1}, {x, y - 1}, # up, down
|
16 |
+
{x + 1, y - 1}, {x - 1, y + 1} # diagonals
|
17 |
+
]
|
18 |
+
|> Enum.filter(fn {x, y} ->
|
19 |
+
x >= 0 && x < @grid_size && y >= 0 && y < @grid_size
|
20 |
+
end)
|
21 |
+
end
|
22 |
+
|
23 |
+
def random_color do
|
24 |
+
["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF"]
|
25 |
+
|> Enum.random()
|
26 |
+
end
|
27 |
+
|
28 |
+
def check_win(grid) do
|
29 |
+
grid
|
30 |
+
|> Map.values()
|
31 |
+
|> Enum.reject(&is_nil/1)
|
32 |
+
|> case do
|
33 |
+
[] -> false
|
34 |
+
[color | rest] -> Enum.all?(rest, &(&1 == color))
|
35 |
+
end
|
36 |
+
end
|
37 |
+
end
|
lib/hexalixir_web/live/game_live.ex
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
defmodule HexalixirWeb.GameLive do
|
2 |
+
use HexalixirWeb, :live_view
|
3 |
+
alias Hexalixir.{Game, Grid}
|
4 |
+
|
5 |
+
@impl true
|
6 |
+
def mount(_params, _session, socket) do
|
7 |
+
{:ok, assign(socket,
|
8 |
+
grid: Grid.new(),
|
9 |
+
saved_colors: %{1 => {nil, 6}, 2 => {nil, 6}},
|
10 |
+
game_won: false
|
11 |
+
)}
|
12 |
+
end
|
13 |
+
|
14 |
+
@impl true
|
15 |
+
def handle_event("click_tile", %{"x" => x, "y" => y}, socket) do
|
16 |
+
coords = {String.to_integer(x), String.to_integer(y)}
|
17 |
+
|
18 |
+
case Game.click_tile(coords) do
|
19 |
+
{:ok, new_grid, won} ->
|
20 |
+
{:noreply, assign(socket, grid: new_grid, game_won: won)}
|
21 |
+
|
22 |
+
{:error, _reason} ->
|
23 |
+
{:noreply, socket}
|
24 |
+
end
|
25 |
+
end
|
26 |
+
|
27 |
+
@impl true
|
28 |
+
def handle_event("save_color", %{"color" => color, "slot" => slot}, socket) do
|
29 |
+
slot = String.to_integer(slot)
|
30 |
+
Game.save_color(color, slot)
|
31 |
+
|
32 |
+
{:noreply, socket}
|
33 |
+
end
|
34 |
+
|
35 |
+
@impl true
|
36 |
+
def handle_event("use_saved_color", %{"x" => x, "y" => y, "slot" => slot}, socket) do
|
37 |
+
coords = {String.to_integer(x), String.to_integer(y)}
|
38 |
+
slot = String.to_integer(slot)
|
39 |
+
|
40 |
+
case Game.use_saved_color(coords, slot) do
|
41 |
+
{:ok, new_grid, won} ->
|
42 |
+
{:noreply, assign(socket, grid: new_grid, game_won: won)}
|
43 |
+
|
44 |
+
{:error, _reason} ->
|
45 |
+
{:noreply, socket}
|
46 |
+
end
|
47 |
+
end
|
48 |
+
end
|
lib/hexalixir_web/templates/game/index.html.heex
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
defmodule HexalixirWeb.GameLive do
|
2 |
+
use HexalixirWeb, :live_view
|
3 |
+
alias Hexalixir.{Game, Grid}
|
4 |
+
|
5 |
+
@impl true
|
6 |
+
def mount(_params, _session, socket) do
|
7 |
+
{:ok, assign(socket,
|
8 |
+
grid: Grid.new(),
|
9 |
+
saved_colors: %{1 => {nil, 6}, 2 => {nil, 6}},
|
10 |
+
game_won: false
|
11 |
+
)}
|
12 |
+
end
|
13 |
+
|
14 |
+
@impl true
|
15 |
+
def handle_event("click_tile", %{"x" => x, "y" => y}, socket) do
|
16 |
+
coords = {String.to_integer(x), String.to_integer(y)}
|
17 |
+
|
18 |
+
case Game.click_tile(coords) do
|
19 |
+
{:ok, new_grid, won} ->
|
20 |
+
{:noreply, assign(socket, grid: new_grid, game_won: won)}
|
21 |
+
|
22 |
+
{:error, _reason} ->
|
23 |
+
{:noreply, socket}
|
24 |
+
end
|
25 |
+
end
|
26 |
+
|
27 |
+
@impl true
|
28 |
+
def handle_event("save_color", %{"color" => color, "slot" => slot}, socket) do
|
29 |
+
slot = String.to_integer(slot)
|
30 |
+
Game.save_color(color, slot)
|
31 |
+
|
32 |
+
{:noreply, socket}
|
33 |
+
end
|
34 |
+
|
35 |
+
@impl true
|
36 |
+
def handle_event("use_saved_color", %{"x" => x, "y" => y, "slot" => slot}, socket) do
|
37 |
+
coords = {String.to_integer(x), String.to_integer(y)}
|
38 |
+
slot = String.to_integer(slot)
|
39 |
+
|
40 |
+
case Game.use_saved_color(coords, slot) do
|
41 |
+
{:ok, new_grid, won} ->
|
42 |
+
{:noreply, assign(socket, grid: new_grid, game_won: won)}
|
43 |
+
|
44 |
+
{:error, _reason} ->
|
45 |
+
{:noreply, socket}
|
46 |
+
end
|
47 |
+
end
|
48 |
+
end
|
mix.exs
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
defmodule Hexalixir.MixProject do
|
2 |
+
use Mix.Project
|
3 |
+
|
4 |
+
def project do
|
5 |
+
[
|
6 |
+
app: :hexalixir,
|
7 |
+
version: "0.1.0",
|
8 |
+
elixir: "~> 1.14",
|
9 |
+
elixirc_paths: elixirc_paths(Mix.env()),
|
10 |
+
start_permanent: Mix.env() == :prod,
|
11 |
+
aliases: aliases(),
|
12 |
+
deps: deps()
|
13 |
+
]
|
14 |
+
end
|
15 |
+
|
16 |
+
def application do
|
17 |
+
[
|
18 |
+
mod: {Hexalixir.Application, []},
|
19 |
+
extra_applications: [:logger, :runtime_tools]
|
20 |
+
]
|
21 |
+
end
|
22 |
+
|
23 |
+
defp deps do
|
24 |
+
[
|
25 |
+
{:phoenix, "~> 1.7.0"},
|
26 |
+
{:phoenix_html, "~> 3.3"},
|
27 |
+
{:phoenix_live_reload, "~> 1.4", only: :dev},
|
28 |
+
{:phoenix_live_view, "~> 0.18.16"},
|
29 |
+
{:floki, ">= 0.30.0", only: :test},
|
30 |
+
{:esbuild, "~> 0.5", runtime: Mix.env() == :dev},
|
31 |
+
{:tailwind, "~> 0.1.8", runtime: Mix.env() == :dev},
|
32 |
+
{:telemetry_metrics, "~> 0.6"},
|
33 |
+
{:telemetry_poller, "~> 1.0"},
|
34 |
+
{:jason, "~> 1.2"},
|
35 |
+
{:plug_cowboy, "~> 2.5"}
|
36 |
+
]
|
37 |
+
end
|
38 |
+
|
39 |
+
defp aliases do
|
40 |
+
[
|
41 |
+
setup: ["deps.get", "assets.setup", "assets.build"],
|
42 |
+
"assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
|
43 |
+
"assets.build": ["tailwind default", "esbuild default"],
|
44 |
+
"assets.deploy": ["tailwind default --minify", "esbuild default --minify", "phx.digest"]
|
45 |
+
]
|
46 |
+
end
|
47 |
+
end
|