From 98f069a2f88b2c4781a9cb3387a050a57f44329a Mon Sep 17 00:00:00 2001 From: Nuno Miguel Date: Mon, 22 Dec 2025 18:16:37 +0000 Subject: [PATCH 1/9] feat: improve ui responsiveness --- .dockerignore | 46 ++++++++ Dockerfile | 101 ++++++++++++++++++ assets/package-lock.json | 18 ++++ assets/package.json | 5 + lib/ares/release.ex | 30 ++++++ lib/ares_web/components/core_components.ex | 2 +- .../components/layouts/root.html.heex | 2 +- lib/ares_web/components/navbar.ex | 48 ++++----- lib/ares_web/live/app/team-formation.ex | 14 ++- lib/ares_web/live/auth/registration.ex | 2 +- lib/ares_web/live/landing/home.html.heex | 66 ++++++------ rel/overlays/bin/migrate | 5 + rel/overlays/bin/migrate.bat | 1 + rel/overlays/bin/server | 5 + rel/overlays/bin/server.bat | 2 + 15 files changed, 277 insertions(+), 70 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 assets/package-lock.json create mode 100644 assets/package.json create mode 100644 lib/ares/release.ex create mode 100755 rel/overlays/bin/migrate create mode 100755 rel/overlays/bin/migrate.bat create mode 100755 rel/overlays/bin/server create mode 100755 rel/overlays/bin/server.bat diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..5d2adff0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,46 @@ +# This file excludes paths from the Docker build context. +# +# By default, Docker's build context includes all files (and folders) in the +# current directory. Even if a file isn't copied into the container it is still sent to +# the Docker daemon. +# +# There are multiple reasons to exclude files from the build context: +# +# 1. Prevent nested folders from being copied into the container (ex: exclude +# /assets/node_modules when copying /assets) +# 2. Reduce the size of the build context and improve build time (ex. /build, /deps, /doc) +# 3. Avoid sending files containing sensitive information +# +# More information on using .dockerignore is available here: +# https://docs.docker.com/engine/reference/builder/#dockerignore-file + +.dockerignore + +# Ignore git, but keep git HEAD and refs to access current commit hash if needed: +# +# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat +# d0b8727759e1e0e7aa3d41707d12376e373d5ecc +.git +!.git/HEAD +!.git/refs + +# Common development/test artifacts +/cover/ +/doc/ +/test/ +/tmp/ +.elixir_ls + +# Mix artifacts +/_build/ +/deps/ +*.ez + +# Generated on crash by the VM +erl_crash.dump + +# Static artifacts - These should be fetched and built inside the Docker image +# https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Release.html#module-docker +/assets/node_modules/ +/priv/static/assets/ +/priv/static/cache_manifest.json diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..b93797c6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,101 @@ +# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian +# instead of Alpine to avoid DNS resolution issues in production. +# +# https://hub.docker.com/r/hexpm/elixir/tags?name=ubuntu +# https://hub.docker.com/_/ubuntu/tags +# +# This file is based on these images: +# +# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image +# - https://hub.docker.com/_/debian/tags?name=trixie-20251208-slim - for the release image +# - https://pkgs.org/ - resource for finding needed packages +# - Ex: docker.io/hexpm/elixir:1.15.7-erlang-26.2.1-debian-trixie-20251208-slim +# +ARG ELIXIR_VERSION=1.15.7 +ARG OTP_VERSION=26.2.1 +ARG DEBIAN_VERSION=trixie-20251208-slim + +ARG BUILDER_IMAGE="docker.io/hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" +ARG RUNNER_IMAGE="docker.io/debian:${DEBIAN_VERSION}" + +FROM ${BUILDER_IMAGE} AS builder + +# install build dependencies +RUN apt-get update \ + && apt-get install -y --no-install-recommends build-essential git \ + && rm -rf /var/lib/apt/lists/* + +# prepare build dir +WORKDIR /app + +# install hex + rebar +RUN mix local.hex --force \ + && mix local.rebar --force + +# set build ENV +ENV MIX_ENV="prod" + +# install mix dependencies +COPY mix.exs mix.lock ./ +RUN mix deps.get --only $MIX_ENV +RUN mkdir config + +# copy compile-time config files before we compile dependencies +# to ensure any relevant config change will trigger the dependencies +# to be re-compiled. +COPY config/config.exs config/${MIX_ENV}.exs config/ +RUN mix deps.compile + +RUN mix assets.setup + +COPY priv priv + +COPY lib lib + +# Compile the release +RUN mix compile + +COPY assets assets + +# compile assets +RUN mix assets.deploy + +# Changes to config/runtime.exs don't require recompiling the code +COPY config/runtime.exs config/ + +COPY rel rel +RUN mix release + +# start a new build stage so that the final image will only contain +# the compiled release and other runtime necessities +FROM ${RUNNER_IMAGE} AS final + +RUN apt-get update \ + && apt-get install -y --no-install-recommends libstdc++6 openssl libncurses6 locales ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Set the locale +RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \ + && locale-gen + +ENV LANG=en_US.UTF-8 +ENV LANGUAGE=en_US:en +ENV LC_ALL=en_US.UTF-8 + +WORKDIR "/app" +RUN chown nobody /app + +# set runner ENV +ENV MIX_ENV="prod" + +# Only copy the final release from the build stage +COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/ares ./ + +USER nobody + +# If using an environment that doesn't automatically reap zombie processes, it is +# advised to add an init process such as tini via `apt-get install` +# above and adding an entrypoint. See https://github.com/krallin/tini for details +# ENTRYPOINT ["/tini", "--"] + +CMD ["/app/bin/server"] diff --git a/assets/package-lock.json b/assets/package-lock.json new file mode 100644 index 00000000..3ada4d7f --- /dev/null +++ b/assets/package-lock.json @@ -0,0 +1,18 @@ +{ + "name": "assets", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "tailwindcss": "^4.1.18" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", + "license": "MIT" + } + } +} diff --git a/assets/package.json b/assets/package.json new file mode 100644 index 00000000..924b89f2 --- /dev/null +++ b/assets/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "tailwindcss": "^4.1.18" + } +} diff --git a/lib/ares/release.ex b/lib/ares/release.ex new file mode 100644 index 00000000..220de49a --- /dev/null +++ b/lib/ares/release.ex @@ -0,0 +1,30 @@ +defmodule Ares.Release do + @moduledoc """ + Used for executing DB release tasks when run in production without Mix + installed. + """ + @app :ares + + def migrate do + load_app() + + for repo <- repos() do + {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true)) + end + end + + def rollback(repo, version) do + load_app() + {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version)) + end + + defp repos do + Application.fetch_env!(@app, :ecto_repos) + end + + defp load_app do + # Many platforms require SSL when connecting to the database + Application.ensure_all_started(:ssl) + Application.ensure_loaded(@app) + end +end diff --git a/lib/ares_web/components/core_components.ex b/lib/ares_web/components/core_components.ex index 25f730e0..9c758239 100644 --- a/lib/ares_web/components/core_components.ex +++ b/lib/ares_web/components/core_components.ex @@ -57,7 +57,7 @@ defmodule AresWeb.CoreComponents do id={@id} phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")} role="alert" - class="toast toast-top toast-end z-50" + class="toast toast-top toast-end z-100" {@rest} >
- <.navbar user={if @current_scope, do: @current_scope.user} fixed /> + <.navbar user={if @current_scope, do: @current_scope.user} />
{@inner_content}
diff --git a/lib/ares_web/components/navbar.ex b/lib/ares_web/components/navbar.ex index 782758aa..bce758b1 100644 --- a/lib/ares_web/components/navbar.ex +++ b/lib/ares_web/components/navbar.ex @@ -9,24 +9,17 @@ defmodule AresWeb.Components.Navbar do @doc """ Renders the navigation header with mobile menu support. """ - attr :fixed, :boolean, default: false attr :user, :map, default: nil def navbar(assigns) do ~H"""