Skip to content

Commit 3d2e8ee

Browse files
init back with phoenix (#1)
Co-authored-by: Jonathan Lagneaux <[email protected]>
1 parent a0d3d2b commit 3d2e8ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2810
-0
lines changed

server/.formatter.exs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
import_deps: [:ecto, :ecto_sql, :phoenix],
3+
subdirectories: ["priv/*/migrations"],
4+
plugins: [Phoenix.LiveView.HTMLFormatter],
5+
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
6+
]

server/.gitignore

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where 3rd-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# Ignore .fetch files in case you like to edit your project deps locally.
14+
/.fetch
15+
16+
# If the VM crashes, it generates a dump, let's ignore it too.
17+
erl_crash.dump
18+
19+
# Also ignore archive artifacts (built via "mix archive.build").
20+
*.ez
21+
22+
# Temporary files, for example, from tests.
23+
/tmp/
24+
25+
# Ignore package tarball (built via "mix hex.build").
26+
server-*.tar
27+
28+
# Ignore assets that are produced by build tools.
29+
/priv/static/assets/
30+
31+
# Ignore digested assets cache.
32+
/priv/static/cache_manifest.json
33+
34+
# In case you use Node.js/npm, you want to ignore these.
35+
npm-debug.log
36+
/assets/node_modules/
37+
38+
.elixir_ls
39+

server/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Server
2+
3+
To start your Phoenix server:
4+
5+
* Run `mix setup` to install and setup dependencies
6+
* Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server`
7+
8+
Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
9+
10+
Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html).
11+
12+
## Learn more
13+
14+
* Official website: https://www.phoenixframework.org/
15+
* Guides: https://hexdocs.pm/phoenix/overview.html
16+
* Docs: https://hexdocs.pm/phoenix
17+
* Forum: https://elixirforum.com/c/phoenix-forum
18+
* Source: https://github.com/phoenixframework/phoenix

server/assets/css/app.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import "tailwindcss/base";
2+
@import "tailwindcss/components";
3+
@import "tailwindcss/utilities";
4+
5+
/* This file is for your main application CSS */

server/assets/js/app.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// If you want to use Phoenix channels, run `mix help phx.gen.channel`
2+
// to get started and then uncomment the line below.
3+
// import "./user_socket.js"
4+
5+
// You can include dependencies in two ways.
6+
//
7+
// The simplest option is to put them in assets/vendor and
8+
// import them using relative paths:
9+
//
10+
// import "../vendor/some-package.js"
11+
//
12+
// Alternatively, you can `npm install some-package --prefix assets` and import
13+
// them using a path starting with the package name:
14+
//
15+
// import "some-package"
16+
//
17+
18+
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
19+
import "phoenix_html"
20+
// Establish Phoenix Socket and LiveView configuration.
21+
import {Socket} from "phoenix"
22+
import {LiveSocket} from "phoenix_live_view"
23+
import topbar from "../vendor/topbar"
24+
25+
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
26+
let liveSocket = new LiveSocket("/live", Socket, {
27+
longPollFallbackMs: 2500,
28+
params: {_csrf_token: csrfToken}
29+
})
30+
31+
// Show progress bar on live navigation and form submits
32+
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
33+
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
34+
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())
35+
36+
// connect if there are any LiveViews on the page
37+
liveSocket.connect()
38+
39+
// expose liveSocket on window for web console debug logs and latency simulation:
40+
// >> liveSocket.enableDebug()
41+
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
42+
// >> liveSocket.disableLatencySim()
43+
window.liveSocket = liveSocket
44+

server/assets/js/user_socket.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// NOTE: The contents of this file will only be executed if
2+
// you uncomment its entry in "assets/js/app.js".
3+
4+
// Bring in Phoenix channels client library:
5+
import {Socket} from "phoenix"
6+
7+
// And connect to the path in "lib/server_web/endpoint.ex". We pass the
8+
// token for authentication. Read below how it should be used.
9+
let socket = new Socket("/socket", {params: {token: window.userToken}})
10+
11+
// When you connect, you'll often need to authenticate the client.
12+
// For example, imagine you have an authentication plug, `MyAuth`,
13+
// which authenticates the session and assigns a `:current_user`.
14+
// If the current user exists you can assign the user's token in
15+
// the connection for use in the layout.
16+
//
17+
// In your "lib/server_web/router.ex":
18+
//
19+
// pipeline :browser do
20+
// ...
21+
// plug MyAuth
22+
// plug :put_user_token
23+
// end
24+
//
25+
// defp put_user_token(conn, _) do
26+
// if current_user = conn.assigns[:current_user] do
27+
// token = Phoenix.Token.sign(conn, "user socket", current_user.id)
28+
// assign(conn, :user_token, token)
29+
// else
30+
// conn
31+
// end
32+
// end
33+
//
34+
// Now you need to pass this token to JavaScript. You can do so
35+
// inside a script tag in "lib/server_web/templates/layout/app.html.heex":
36+
//
37+
// <script>window.userToken = "<%= assigns[:user_token] %>";</script>
38+
//
39+
// You will need to verify the user token in the "connect/3" function
40+
// in "lib/server_web/channels/user_socket.ex":
41+
//
42+
// def connect(%{"token" => token}, socket, _connect_info) do
43+
// # max_age: 1209600 is equivalent to two weeks in seconds
44+
// case Phoenix.Token.verify(socket, "user socket", token, max_age: 1_209_600) do
45+
// {:ok, user_id} ->
46+
// {:ok, assign(socket, :user, user_id)}
47+
//
48+
// {:error, reason} ->
49+
// :error
50+
// end
51+
// end
52+
//
53+
// Finally, connect to the socket:
54+
socket.connect()
55+
56+
// Now that you are connected, you can join channels with a topic.
57+
// Let's assume you have a channel with a topic named `room` and the
58+
// subtopic is its id - in this case 42:
59+
let channel = socket.channel("room:42", {})
60+
channel.join()
61+
.receive("ok", resp => { console.log("Joined successfully", resp) })
62+
.receive("error", resp => { console.log("Unable to join", resp) })
63+
64+
export default socket

server/assets/tailwind.config.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// See the Tailwind configuration guide for advanced usage
2+
// https://tailwindcss.com/docs/configuration
3+
4+
const plugin = require("tailwindcss/plugin")
5+
const fs = require("fs")
6+
const path = require("path")
7+
8+
module.exports = {
9+
content: [
10+
"./js/**/*.js",
11+
"../lib/server_web.ex",
12+
"../lib/server_web/**/*.*ex"
13+
],
14+
theme: {
15+
extend: {
16+
colors: {
17+
brand: "#FD4F00",
18+
}
19+
},
20+
},
21+
plugins: [
22+
require("@tailwindcss/forms"),
23+
// Allows prefixing tailwind classes with LiveView classes to add rules
24+
// only when LiveView classes are applied, for example:
25+
//
26+
// <div class="phx-click-loading:animate-ping">
27+
//
28+
plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])),
29+
plugin(({addVariant}) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])),
30+
plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])),
31+
32+
// Embeds Heroicons (https://heroicons.com) into your app.css bundle
33+
// See your `CoreComponents.icon/1` for more information.
34+
//
35+
plugin(function({matchComponents, theme}) {
36+
let iconsDir = path.join(__dirname, "../deps/heroicons/optimized")
37+
let values = {}
38+
let icons = [
39+
["", "/24/outline"],
40+
["-solid", "/24/solid"],
41+
["-mini", "/20/solid"],
42+
["-micro", "/16/solid"]
43+
]
44+
icons.forEach(([suffix, dir]) => {
45+
fs.readdirSync(path.join(iconsDir, dir)).forEach(file => {
46+
let name = path.basename(file, ".svg") + suffix
47+
values[name] = {name, fullPath: path.join(iconsDir, dir, file)}
48+
})
49+
})
50+
matchComponents({
51+
"hero": ({name, fullPath}) => {
52+
let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "")
53+
let size = theme("spacing.6")
54+
if (name.endsWith("-mini")) {
55+
size = theme("spacing.5")
56+
} else if (name.endsWith("-micro")) {
57+
size = theme("spacing.4")
58+
}
59+
return {
60+
[`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
61+
"-webkit-mask": `var(--hero-${name})`,
62+
"mask": `var(--hero-${name})`,
63+
"mask-repeat": "no-repeat",
64+
"background-color": "currentColor",
65+
"vertical-align": "middle",
66+
"display": "inline-block",
67+
"width": size,
68+
"height": size
69+
}
70+
}
71+
}, {values})
72+
})
73+
]
74+
}

0 commit comments

Comments
 (0)