Getting started

Overview

Moon Design System is a collection of reusable components set up and grouped according to simple and clear standards. Moon DS component collection is the single source of truth that can be used to build any number of applications.

Requirements

Moon Design System can be used for new and existing Phoenix project that uses LiveView

Moon Surface components can be used from SLIM and EEX templates , but recommended format is Surface v0.9.x + Tailwind + Moon Surface Components

NB! You need to be using the latest version of Tailwind CSS for the system to work.

Installing elixir, erlang & node.js

We do use adsf here. Add .tool-versions file to the root of your projects:

# .tool-versions

erlang 25.2
elixir 1.14.1
nodejs 14.17.6

And run asdf install

Project creating

Create new Phoenix project (if needed) with LiveView enabled. Do not fetch dependencies.

mix archive install hex phx_new
    mix phx.new my_super_app --live
    cd my_super_app
  

Installing dependencies

Add Moon Library to mix.exs deps section:

# mix.exs

...
{:moon, git: "[email protected]:coingaming/moon.git"}
# or
{:moon, git: "https://github.com/coingaming/moon.git"}

and fetch dependencies.

mix deps.get

Make sure your phoenix* dependenciesversions do not conflict with the same in moon library.

Add surface & esbuild configurations to the project's confix.exs:

# config/config.exs

...
import_config "../deps/moon/config/surface.exs"

config :surface, :components, [
  # put here your app configs for surface
]

config :esbuild,
  version: "0.16.4",
  default: [
    args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
    cd: Path.expand("../assets", __DIR__),
    env: %{"NODE_PATH" => "/root/project/lib/moon_web/components/deps:./node_modules"}
  ]

Compile project and dependencies

mix compile

Initialize Surface as described here. Please make sure that surface compiler is configured.

mix surface.init

Moon CSS/JS assets adding

Add two Plug.Static plugs to your endpoint.ex

# lib/my_super_app/web/endpoint.ex

...
plug(Plug.Static,
  at: "/moon/assets",
  from: :moon,
  gzip: true,
  only: ~w(assets themes images fonts svgs favicon.ico robots.txt),
  cache_control_for_etags: "public, max-age=86400"
)

plug(Plug.Static,
  at: "/moon_icons/",
  from: :moon_icons,
  gzip: true,
  cache_control_for_etags: "public, max-age=86400"
)
...

Import Moon Surface css and themes to project's assets/app.css:

/* assets/css/app.css */

/*
  this is a default theme - used on surface.moon.io
  feel free to copy and modify it
*/
@import '../../deps/moon/priv/static/themes/moon.css';

/*
  Not really required. Only few classes for components
  are from there. All tailwind imports are already there,
  so you can remove them from your own app.css
  also can import _components.css instead
  @import '../../deps/moon/assets/css/_components.css';
*/
@import '../../deps/moon/assets/css/app.css';


Copy assets/package.json from deps/moon folder, or take two sections from there:

scripts:

# assets.package.json

"scripts": {
  "deploy": "NODE_ENV=production tailwindcss -i css/app.css -o ../priv/static/assets/app.css --postcss --minify",
  "build": "tailwindcss -i css/app.css -o ../priv/static/assets/app.css --postcss",
  "watch": "tailwindcss -i css/app.css -o ../priv/static/assets/app.css --postcss --watch"
},

dependencies:

# assets.package.json

"dependencies": {
  "@tailwindcss/forms": "^0.4.0",
  "autoprefixer": "^10.4.2",
  "postcss": "^8.4.5",
  "postcss-import": "^14.0.2",
  "tailwindcss": "^3.1.7",

  "@popperjs/core": "^2.11.6"
},

Create file assets/postcss.config.js

// assets/postcss.config.js

module.exports = {
  plugins: {
    'postcss-import': {},
    tailwindcss: {},
    autoprefixer: {}
  }
}

Create file assets/tailwind.config.js

// assets/tailwind.config.js

const tailwind_config = require("../deps/moon/assets/tailwind.config.js");

tailwind_config.content = [
  "../lib/**/*.ex",
  "../lib/**/*.heex",
  "../lib/**/*.eex",
  "./js/**/*.js",

  "../deps/moon/lib/**/*.ex",
  "../deps/moon/lib/**/*.heex",
  "../deps/moon/lib/**/*.eex",
  "../deps/moon/assets/js/**/*.js",
];
module.exports = tailwind_config;

Edit your assets/js/app.js

// assets/js/app.js

...
import Hooks from "./_hooks"

// the next line should be added
import MoonHooks from "../../deps/moon/assets/js/hooks"

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}, hooks: {
    ...MoonHooks, // here we do use imported hooks
    ...Hooks
}})

Add/modify assets-related aliases in your mix.exs file

# mix.exs

...
defp aliases do
  [
    setup: ["deps.get", "assets.setup", "assets.build"],
    "assets.setup": ["cmd --cd assets npm i", "esbuild.install --if-missing"],
    "assets.build": ["cmd --cd assets npm run build", "esbuild default"],
    "assets.deploy": [
      "cmd --cd assets npm run deploy",
      "NODE_ENV=production esbuild default --minify",
      "phx.digest"
    ]
  ]
end

Setup assets

mix assets.setup

Add theme-related class (find it in imported theme CSS file) and direction related attribute to your root HTML component, e.g. body in lib/my_super_app_web/components/layouts/root.html.heex

<!-- lib/my_super_app_web/components/layouts/root.html.heex -->
<!-- class name should be taken from theme imported -->
...
<body class="... theme-moon-light" dir="ltr">
...

Run project

mix phx.server