Skip to content

Commit 12eb0e4

Browse files
committed
ran mix phx.new petal_stack_tutorial
0 parents commit 12eb0e4

Some content is hidden

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

44 files changed

+2544
-0
lines changed

.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+
]

.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
petal_stack_tutorial-*.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+

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# PetalStackTutorial
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

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 */

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+

assets/tailwind.config.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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/petal_stack_tutorial_web.ex",
12+
"../lib/petal_stack_tutorial_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-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])),
29+
plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])),
30+
plugin(({addVariant}) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])),
31+
plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])),
32+
33+
// Embeds Heroicons (https://heroicons.com) into your app.css bundle
34+
// See your `CoreComponents.icon/1` for more information.
35+
//
36+
plugin(function({matchComponents, theme}) {
37+
let iconsDir = path.join(__dirname, "../deps/heroicons/optimized")
38+
let values = {}
39+
let icons = [
40+
["", "/24/outline"],
41+
["-solid", "/24/solid"],
42+
["-mini", "/20/solid"],
43+
["-micro", "/16/solid"]
44+
]
45+
icons.forEach(([suffix, dir]) => {
46+
fs.readdirSync(path.join(iconsDir, dir)).forEach(file => {
47+
let name = path.basename(file, ".svg") + suffix
48+
values[name] = {name, fullPath: path.join(iconsDir, dir, file)}
49+
})
50+
})
51+
matchComponents({
52+
"hero": ({name, fullPath}) => {
53+
let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "")
54+
let size = theme("spacing.6")
55+
if (name.endsWith("-mini")) {
56+
size = theme("spacing.5")
57+
} else if (name.endsWith("-micro")) {
58+
size = theme("spacing.4")
59+
}
60+
return {
61+
[`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
62+
"-webkit-mask": `var(--hero-${name})`,
63+
"mask": `var(--hero-${name})`,
64+
"mask-repeat": "no-repeat",
65+
"background-color": "currentColor",
66+
"vertical-align": "middle",
67+
"display": "inline-block",
68+
"width": size,
69+
"height": size
70+
}
71+
}
72+
}, {values})
73+
})
74+
]
75+
}

assets/vendor/topbar.js

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/**
2+
* @license MIT
3+
* topbar 2.0.0, 2023-02-04
4+
* https://buunguyen.github.io/topbar
5+
* Copyright (c) 2021 Buu Nguyen
6+
*/
7+
(function (window, document) {
8+
"use strict";
9+
10+
// https://gist.github.com/paulirish/1579671
11+
(function () {
12+
var lastTime = 0;
13+
var vendors = ["ms", "moz", "webkit", "o"];
14+
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
15+
window.requestAnimationFrame =
16+
window[vendors[x] + "RequestAnimationFrame"];
17+
window.cancelAnimationFrame =
18+
window[vendors[x] + "CancelAnimationFrame"] ||
19+
window[vendors[x] + "CancelRequestAnimationFrame"];
20+
}
21+
if (!window.requestAnimationFrame)
22+
window.requestAnimationFrame = function (callback, element) {
23+
var currTime = new Date().getTime();
24+
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
25+
var id = window.setTimeout(function () {
26+
callback(currTime + timeToCall);
27+
}, timeToCall);
28+
lastTime = currTime + timeToCall;
29+
return id;
30+
};
31+
if (!window.cancelAnimationFrame)
32+
window.cancelAnimationFrame = function (id) {
33+
clearTimeout(id);
34+
};
35+
})();
36+
37+
var canvas,
38+
currentProgress,
39+
showing,
40+
progressTimerId = null,
41+
fadeTimerId = null,
42+
delayTimerId = null,
43+
addEvent = function (elem, type, handler) {
44+
if (elem.addEventListener) elem.addEventListener(type, handler, false);
45+
else if (elem.attachEvent) elem.attachEvent("on" + type, handler);
46+
else elem["on" + type] = handler;
47+
},
48+
options = {
49+
autoRun: true,
50+
barThickness: 3,
51+
barColors: {
52+
0: "rgba(26, 188, 156, .9)",
53+
".25": "rgba(52, 152, 219, .9)",
54+
".50": "rgba(241, 196, 15, .9)",
55+
".75": "rgba(230, 126, 34, .9)",
56+
"1.0": "rgba(211, 84, 0, .9)",
57+
},
58+
shadowBlur: 10,
59+
shadowColor: "rgba(0, 0, 0, .6)",
60+
className: null,
61+
},
62+
repaint = function () {
63+
canvas.width = window.innerWidth;
64+
canvas.height = options.barThickness * 5; // need space for shadow
65+
66+
var ctx = canvas.getContext("2d");
67+
ctx.shadowBlur = options.shadowBlur;
68+
ctx.shadowColor = options.shadowColor;
69+
70+
var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
71+
for (var stop in options.barColors)
72+
lineGradient.addColorStop(stop, options.barColors[stop]);
73+
ctx.lineWidth = options.barThickness;
74+
ctx.beginPath();
75+
ctx.moveTo(0, options.barThickness / 2);
76+
ctx.lineTo(
77+
Math.ceil(currentProgress * canvas.width),
78+
options.barThickness / 2
79+
);
80+
ctx.strokeStyle = lineGradient;
81+
ctx.stroke();
82+
},
83+
createCanvas = function () {
84+
canvas = document.createElement("canvas");
85+
var style = canvas.style;
86+
style.position = "fixed";
87+
style.top = style.left = style.right = style.margin = style.padding = 0;
88+
style.zIndex = 100001;
89+
style.display = "none";
90+
if (options.className) canvas.classList.add(options.className);
91+
document.body.appendChild(canvas);
92+
addEvent(window, "resize", repaint);
93+
},
94+
topbar = {
95+
config: function (opts) {
96+
for (var key in opts)
97+
if (options.hasOwnProperty(key)) options[key] = opts[key];
98+
},
99+
show: function (delay) {
100+
if (showing) return;
101+
if (delay) {
102+
if (delayTimerId) return;
103+
delayTimerId = setTimeout(() => topbar.show(), delay);
104+
} else {
105+
showing = true;
106+
if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId);
107+
if (!canvas) createCanvas();
108+
canvas.style.opacity = 1;
109+
canvas.style.display = "block";
110+
topbar.progress(0);
111+
if (options.autoRun) {
112+
(function loop() {
113+
progressTimerId = window.requestAnimationFrame(loop);
114+
topbar.progress(
115+
"+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2)
116+
);
117+
})();
118+
}
119+
}
120+
},
121+
progress: function (to) {
122+
if (typeof to === "undefined") return currentProgress;
123+
if (typeof to === "string") {
124+
to =
125+
(to.indexOf("+") >= 0 || to.indexOf("-") >= 0
126+
? currentProgress
127+
: 0) + parseFloat(to);
128+
}
129+
currentProgress = to > 1 ? 1 : to;
130+
repaint();
131+
return currentProgress;
132+
},
133+
hide: function () {
134+
clearTimeout(delayTimerId);
135+
delayTimerId = null;
136+
if (!showing) return;
137+
showing = false;
138+
if (progressTimerId != null) {
139+
window.cancelAnimationFrame(progressTimerId);
140+
progressTimerId = null;
141+
}
142+
(function loop() {
143+
if (topbar.progress("+.1") >= 1) {
144+
canvas.style.opacity -= 0.05;
145+
if (canvas.style.opacity <= 0.05) {
146+
canvas.style.display = "none";
147+
fadeTimerId = null;
148+
return;
149+
}
150+
}
151+
fadeTimerId = window.requestAnimationFrame(loop);
152+
})();
153+
},
154+
};
155+
156+
if (typeof module === "object" && typeof module.exports === "object") {
157+
module.exports = topbar;
158+
} else if (typeof define === "function" && define.amd) {
159+
define(function () {
160+
return topbar;
161+
});
162+
} else {
163+
this.topbar = topbar;
164+
}
165+
}.call(this, window, document));

0 commit comments

Comments
 (0)