Skip to content

Commit

Permalink
Merge pull request #24 from groupher/home-page
Browse files Browse the repository at this point in the history
feat(global): add home page
  • Loading branch information
mydearxym authored Mar 29, 2024
2 parents ea27d47 + b8e68d4 commit 6f6cad9
Show file tree
Hide file tree
Showing 29 changed files with 9,843 additions and 48 deletions.
11 changes: 9 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ FROM ${BUILDER_IMAGE} as builder

# install build dependencies
RUN apt-get update -y && apt-get install -y build-essential git \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
&& apt-get clean && rm -f /var/lib/apt/lists/*_*

# prepare build dir
WORKDIR /app

# install hex + rebar
RUN mix local.hex --force && \
mix local.rebar --force
mix local.rebar --force

# set build ENV
ENV MIX_ENV="prod"
Expand All @@ -50,6 +50,11 @@ COPY priv priv

COPY lib lib

COPY assets assets

# compile assets
RUN mix assets.deploy

# Compile the release
RUN mix compile

Expand Down Expand Up @@ -82,6 +87,8 @@ ENV MIX_ENV="prod"
# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/groupher_server ./

# NOTE: sometimes the /app/bin/migrate will not be executable, so we need to fix it
RUN chmod +x /app/bin/*
USER nobody

CMD ["/app/bin/server"]
5 changes: 5 additions & 0 deletions assets/css/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

/* This file is for your main application CSS */
44 changes: 44 additions & 0 deletions assets/js/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// If you want to use Phoenix channels, run `mix help phx.gen.channel`
// to get started and then uncomment the line below.
// import "./user_socket.js"

// You can include dependencies in two ways.
//
// The simplest option is to put them in assets/vendor and
// import them using relative paths:
//
// import "../vendor/some-package.js"
//
// Alternatively, you can `npm install some-package --prefix assets` and import
// them using a path starting with the package name:
//
// import "some-package"
//

// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
import "phoenix_html"
// Establish Phoenix Socket and LiveView configuration.
import {Socket} from "phoenix"
import {LiveSocket} from "phoenix_live_view"
import topbar from "../vendor/topbar"

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {
longPollFallbackMs: 2500,
params: {_csrf_token: csrfToken}
})

// Show progress bar on live navigation and form submits
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())

// connect if there are any LiveViews on the page
liveSocket.connect()

// expose liveSocket on window for web console debug logs and latency simulation:
// >> liveSocket.enableDebug()
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
// >> liveSocket.disableLatencySim()
window.liveSocket = liveSocket

75 changes: 75 additions & 0 deletions assets/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// See the Tailwind configuration guide for advanced usage
// https://tailwindcss.com/docs/configuration

const plugin = require("tailwindcss/plugin")
const fs = require("fs")
const path = require("path")

module.exports = {
content: [
"./js/**/*.js",
"../lib/groupher_server_web.ex",
"../lib/groupher_server_web/**/*.*ex"
],
theme: {
extend: {
colors: {
brand: "#18181B",
},
},
},
plugins: [
require("@tailwindcss/forms"),
// Allows prefixing tailwind classes with LiveView classes to add rules
// only when LiveView classes are applied, for example:
//
// <div class="phx-click-loading:animate-ping">
//
plugin(({addVariant}) => addVariant("phx-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])),
plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])),
plugin(({addVariant}) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])),
plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])),

// Embeds Heroicons (https://heroicons.com) into your app.css bundle
// See your `CoreComponents.icon/1` for more information.
//
plugin(function({matchComponents, theme}) {
let iconsDir = path.join(__dirname, "../deps/heroicons/optimized")
let values = {}
let icons = [
["", "/24/outline"],
["-solid", "/24/solid"],
["-mini", "/20/solid"],
["-micro", "/16/solid"]
]
icons.forEach(([suffix, dir]) => {
fs.readdirSync(path.join(iconsDir, dir)).forEach(file => {
let name = path.basename(file, ".svg") + suffix
values[name] = {name, fullPath: path.join(iconsDir, dir, file)}
})
})
matchComponents({
"hero": ({name, fullPath}) => {
let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "")
let size = theme("spacing.6")
if (name.endsWith("-mini")) {
size = theme("spacing.5")
} else if (name.endsWith("-micro")) {
size = theme("spacing.4")
}
return {
[`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
"-webkit-mask": `var(--hero-${name})`,
"mask": `var(--hero-${name})`,
"mask-repeat": "no-repeat",
"background-color": "currentColor",
"vertical-align": "middle",
"display": "inline-block",
"width": size,
"height": size
}
}
}, {values})
})
]
}
165 changes: 165 additions & 0 deletions assets/vendor/topbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/**
* @license MIT
* topbar 2.0.0, 2023-02-04
* https://buunguyen.github.io/topbar
* Copyright (c) 2021 Buu Nguyen
*/
(function (window, document) {
"use strict";

// https://gist.github.com/paulirish/1579671
(function () {
var lastTime = 0;
var vendors = ["ms", "moz", "webkit", "o"];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame =
window[vendors[x] + "RequestAnimationFrame"];
window.cancelAnimationFrame =
window[vendors[x] + "CancelAnimationFrame"] ||
window[vendors[x] + "CancelRequestAnimationFrame"];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function (callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function () {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function (id) {
clearTimeout(id);
};
})();

var canvas,
currentProgress,
showing,
progressTimerId = null,
fadeTimerId = null,
delayTimerId = null,
addEvent = function (elem, type, handler) {
if (elem.addEventListener) elem.addEventListener(type, handler, false);
else if (elem.attachEvent) elem.attachEvent("on" + type, handler);
else elem["on" + type] = handler;
},
options = {
autoRun: true,
barThickness: 3,
barColors: {
0: "rgba(26, 188, 156, .9)",
".25": "rgba(52, 152, 219, .9)",
".50": "rgba(241, 196, 15, .9)",
".75": "rgba(230, 126, 34, .9)",
"1.0": "rgba(211, 84, 0, .9)",
},
shadowBlur: 10,
shadowColor: "rgba(0, 0, 0, .6)",
className: null,
},
repaint = function () {
canvas.width = window.innerWidth;
canvas.height = options.barThickness * 5; // need space for shadow

var ctx = canvas.getContext("2d");
ctx.shadowBlur = options.shadowBlur;
ctx.shadowColor = options.shadowColor;

var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
for (var stop in options.barColors)
lineGradient.addColorStop(stop, options.barColors[stop]);
ctx.lineWidth = options.barThickness;
ctx.beginPath();
ctx.moveTo(0, options.barThickness / 2);
ctx.lineTo(
Math.ceil(currentProgress * canvas.width),
options.barThickness / 2
);
ctx.strokeStyle = lineGradient;
ctx.stroke();
},
createCanvas = function () {
canvas = document.createElement("canvas");
var style = canvas.style;
style.position = "fixed";
style.top = style.left = style.right = style.margin = style.padding = 0;
style.zIndex = 100001;
style.display = "none";
if (options.className) canvas.classList.add(options.className);
document.body.appendChild(canvas);
addEvent(window, "resize", repaint);
},
topbar = {
config: function (opts) {
for (var key in opts)
if (options.hasOwnProperty(key)) options[key] = opts[key];
},
show: function (delay) {
if (showing) return;
if (delay) {
if (delayTimerId) return;
delayTimerId = setTimeout(() => topbar.show(), delay);
} else {
showing = true;
if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId);
if (!canvas) createCanvas();
canvas.style.opacity = 1;
canvas.style.display = "block";
topbar.progress(0);
if (options.autoRun) {
(function loop() {
progressTimerId = window.requestAnimationFrame(loop);
topbar.progress(
"+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2)
);
})();
}
}
},
progress: function (to) {
if (typeof to === "undefined") return currentProgress;
if (typeof to === "string") {
to =
(to.indexOf("+") >= 0 || to.indexOf("-") >= 0
? currentProgress
: 0) + parseFloat(to);
}
currentProgress = to > 1 ? 1 : to;
repaint();
return currentProgress;
},
hide: function () {
clearTimeout(delayTimerId);
delayTimerId = null;
if (!showing) return;
showing = false;
if (progressTimerId != null) {
window.cancelAnimationFrame(progressTimerId);
progressTimerId = null;
}
(function loop() {
if (topbar.progress("+.1") >= 1) {
canvas.style.opacity -= 0.05;
if (canvas.style.opacity <= 0.05) {
canvas.style.display = "none";
fadeTimerId = null;
return;
}
}
fadeTimerId = window.requestAnimationFrame(loop);
})();
},
};

if (typeof module === "object" && typeof module.exports === "object") {
module.exports = topbar;
} else if (typeof define === "function" && define.amd) {
define(function () {
return topbar;
});
} else {
this.topbar = topbar;
}
}.call(this, window, document));
27 changes: 26 additions & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ config :groupher_server, ecto_repos: [GroupherServer.Repo]
config :groupher_server, GroupherServerWeb.Endpoint,
url: [host: "localhost"],
adapter: Bandit.PhoenixAdapter,
render_errors: [view: GroupherServerWeb.ErrorView, accepts: ~w(json)],
render_errors: [
formats: [html: GroupherServerWeb.ErrorHTML, json: GroupherServerWeb.ErrorJSON],
layout: false
],
pubsub_server: GroupherServer.PubSub

# Configures Elixir's Logger
Expand Down Expand Up @@ -181,3 +184,25 @@ import_config "#{config_env()}.exs"
if File.exists?("config/#{config_env()}.secret.exs") do
import_config "#{config_env()}.secret.exs"
end

# Configure esbuild (the version is required)
config :esbuild,
version: "0.17.11",
groupher_server: [
args:
~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]

# Configure tailwind (the version is required)
config :tailwind,
version: "3.4.0",
groupher_server: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/assets/app.css
),
cd: Path.expand("../assets", __DIR__)
]
8 changes: 7 additions & 1 deletion config/mock.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ config :groupher_server, GroupherServerWeb.Endpoint,
http: [port: 4001],
debug_errors: true,
code_reloader: true,
server: true,
check_origin: false,
watchers: []
# for local dev usage, for session/cookie
secret_key_base: "0iBUiKYT+sUJxPPD3+aUyOPlsvl/Uk9K9VFBTzoC+zc8PEKQfW4Ay4SH7piuXpVA",
watchers: [
esbuild: {Esbuild, :install_and_run, [:groupher_server, ~w(--sourcemap=inline --watch)]},
tailwind: {Tailwind, :install_and_run, [:groupher_server, ~w(--watch)]}
]

config :groupher_server, Helper.Guardian,
issuer: "groupher_server",
Expand Down
3 changes: 2 additions & 1 deletion config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ config :logger, :console, format: "[$level] $message\n"
# import_config "prod.secret.exs"

config :groupher_server, GroupherServerWeb.Endpoint,
secret_key_base: System.get_env("SECRET_KEY_BASE")
secret_key_base: System.get_env("SECRET_KEY_BASE"),
cache_static_manifest: "priv/static/cache_manifest.json"

config :groupher_server, Helper.Guardian,
issuer: "groupher_server",
Expand Down
Loading

0 comments on commit 6f6cad9

Please sign in to comment.