Skip to content

Commit be96992

Browse files
merge develop
2 parents cce41c4 + 737378e commit be96992

97 files changed

Lines changed: 1100 additions & 877 deletions

File tree

Some content is hidden

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

.formatter.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[
22
import_deps: [:ecto, :phoenix],
3-
plugins: [Phoenix.LiveView.HTMLFormatter, TailwindFormatter.MultiFormatter, DoctestFormatter],
3+
plugins: [TailwindFormatter, DoctestFormatter, Phoenix.LiveView.HTMLFormatter],
44
heex_line_length: 300,
55
inputs: [
66
"*.{heex,ex,exs}",

.github/workflows/style.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ jobs:
1616

1717
strategy:
1818
matrix:
19-
otp: [26.x]
20-
elixir: [1.14.x]
19+
otp: [27.x]
20+
elixir: [1.17.x]
2121

2222
steps:
2323
- name: ☁️ Checkout repository

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ jobs:
2323

2424
strategy:
2525
matrix:
26-
otp: [26.x]
27-
elixir: [1.14.x]
26+
otp: [27.x]
27+
elixir: [1.17.x]
2828

2929
services:
3030
db:

.tool-versions

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
elixir 1.14.4-otp-26
2-
erlang 26.1.1
1+
elixir 1.17.2-otp-27
2+
erlang 27.0

assets/js/app.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {LiveSocket} from "phoenix_live_view"
2525
import "../vendor/alpine.js";
2626
import topbar from "../vendor/topbar"
2727
import { QrScanner, InitSorting, StickyScroll, ScrollToTop } from "./hooks";
28+
import phxFeedbackDom from "./shims/phx_feedback_dom.js"
2829

2930
let Hooks = {
3031
QrScanner: QrScanner,
@@ -37,16 +38,13 @@ let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("
3738
let liveSocket = new LiveSocket("/live", Socket, {
3839
params: { _csrf_token: csrfToken },
3940
hooks: Hooks,
40-
dom: {
41+
dom: phxFeedbackDom({
4142
onBeforeElUpdated(from, to) {
42-
// If the element we are updating is an Alpine component...
4343
if (from._x_dataStack) {
44-
// Then temporarily clone it (with it's data) to the "to" element.
45-
// This should simulate LiveView being aware of Alpine changes.
4644
window.Alpine.clone(from, to);
4745
}
48-
},
49-
},
46+
}
47+
}),
5048
});
5149

5250
// Show progress bar on live navigation and form submits

assets/js/hooks/qr_reading.js

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ function parseURL(url) {
1414
export const QrScanner = {
1515

1616
mounted() {
17-
const config = { fps: 4, qrbox: (width, height) => {return { width: width * 0.8, height: height * 0.9 }}};
18-
this.scanner = new Html5Qrcode(this.el.id, { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] });
17+
const config = { fps: 4, qrbox: (width, height) => { return { width: width * 0.8, height: height * 0.9 } } };
18+
this.scanner = new Html5Qrcode(this.el.id, { formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE] });
19+
this.isScanning = false;
1920

2021
const onScanSuccess = (decodedText, decodedResult) => {
2122
const pathname = parseURL(decodedText);
@@ -28,13 +29,16 @@ export const QrScanner = {
2829

2930
const startScanner = () => {
3031
this.scanner.start({ facingMode: "environment" }, config, onScanSuccess)
31-
.then((_) => {
32-
if (this.el.dataset.on_start)
33-
Function("hook", this.el.dataset.on_start)(this);
34-
}, (e) => {
35-
if (this.el.dataset.on_error)
36-
Function("hook", this.el.dataset.on_error)(this);
37-
});
32+
.then((_) => {
33+
this.isScanning = true;
34+
if (this.el.dataset.on_start)
35+
Function("hook", this.el.dataset.on_start)(this);
36+
})
37+
.catch((e) => {
38+
this.isScanning = false;
39+
if (this.el.dataset.on_error)
40+
Function("hook", this.el.dataset.on_error)(this);
41+
});
3842
}
3943

4044
if (this.el.dataset.ask_perm) {
@@ -46,9 +50,13 @@ export const QrScanner = {
4650
},
4751

4852
destroyed() {
49-
this.scanner.stop().then((_) => {
50-
if (this.el.dataset.on_stop)
51-
Function("hook", this.el.dataset.on_stop)(this);
52-
});
53+
if (this.isScanning) {
54+
this.scanner.stop().then((_) => {
55+
if (this.el.dataset.on_stop)
56+
Function("hook", this.el.dataset.on_stop)(this);
57+
}).catch((e) => {
58+
console.warn("Failed to stop the scanner:", e);
59+
});
60+
}
5361
}
5462
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// https://gist.github.com/chrismccord/c4c60328c6ac5ec29e167bb115315d82
2+
// maintain backwards compatibility of phx-feedback-for, which was removed in LiveView 1.0
3+
// find all phx-feedback-for containers and show/hide phx-no-feedback class based on used inputs
4+
import {isUsedInput} from "phoenix_live_view"
5+
6+
let resetFeedbacks = (container, feedbacks) => {
7+
feedbacks = feedbacks || Array.from(container.querySelectorAll("[phx-feedback-for]"))
8+
.map(el => [el, el.getAttribute("phx-feedback-for")])
9+
10+
feedbacks.forEach(([feedbackEl, name]) => {
11+
let query = `[name="${name}"], [name="${name}[]"]`
12+
let isUsed = Array.from(container.querySelectorAll(query)).find(input => isUsedInput(input))
13+
if(isUsed || !feedbackEl.hasAttribute("phx-feedback-for")){
14+
feedbackEl.classList.remove("phx-no-feedback")
15+
} else {
16+
feedbackEl.classList.add("phx-no-feedback")
17+
}
18+
})
19+
}
20+
21+
export default phxFeedbackDom = (dom) => {
22+
window.addEventListener("reset", e => resetFeedbacks(document))
23+
let feedbacks
24+
let submitPending = false
25+
let inputPending = false
26+
window.addEventListener("submit", e => submitPending = e.target)
27+
window.addEventListener("input", e => inputPending = e.target)
28+
// extend provided dom options with our own.
29+
// accumulate phx-feedback-for containers for each patch and reset feedbacks when patch ends
30+
return {
31+
onPatchStart(container){
32+
feedbacks = []
33+
dom.onPatchStart && dom.onPatchStart(container)
34+
},
35+
onNodeAdded(node){
36+
if(node.hasAttribute && node.hasAttribute("phx-feedback-for")){
37+
feedbacks.push([node, node.getAttribute("phx-feedback-for")])
38+
}
39+
dom.onNodeAdded && dom.onNodeAdded(node)
40+
},
41+
onBeforeElUpdated(from, to){
42+
let fromFor = from.getAttribute("phx-feedback-for")
43+
let toFor = to.getAttribute("phx-feedback-for")
44+
if(fromFor || toFor){ feedbacks.push([from, fromFor || toFor], [to, toFor || fromFor]) }
45+
46+
dom.onBeforeElUpdated && dom.onBeforeElUpdated(from, to)
47+
},
48+
onPatchEnd(container){
49+
resetFeedbacks(container, feedbacks)
50+
// we might not find some feedback nodes if they are skipped in the patch
51+
// therefore we explicitly reset feedbacks for all nodes when the patch
52+
// follows a submit or input event
53+
if(inputPending || submitPending){
54+
resetFeedbacks(container)
55+
inputPending = null
56+
submitPending = null
57+
}
58+
dom.onPatchEnd && dom.onPatchEnd(container)
59+
}
60+
}
61+
}

assets/tailwind.config.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,19 @@ module.exports = {
1515
theme: {
1616
extend: {
1717
colors: {
18-
primary: colors.orange,
18+
primary: {
19+
'50': '#fef4ee',
20+
'100': '#fce6d8',
21+
'200': '#f8c9b0',
22+
'300': '#f3a47e',
23+
'400': '#ed7950',
24+
'500': '#e85227',
25+
'600': '#d9391d',
26+
'700': '#b42a1a',
27+
'800': '#90231c',
28+
'900': '#74201a',
29+
'950': '#3e0e0c',
30+
},
1931
secondary: colors.sky,
2032
success: colors.green,
2133
danger: colors.red,

config/dev.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,9 @@ config :phoenix, :stacktrace_depth, 20
7777
# Initialize plugs at runtime for faster development compilation
7878
config :phoenix, :plug_init_mode, :runtime
7979

80+
config :phoenix_live_view,
81+
# Include HEEx debug annotations as HTML comments in rendered markup
82+
debug_heex_annotations: true
83+
8084
# Other configurations for the app
8185
config :pdf_generator, raise_on_missing_wkhtmltopdf_binary: false

lib/atomic/accounts.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ defmodule Atomic.Accounts do
491491
{:error, %Ecto.Changeset{}}
492492
493493
"""
494-
def update_user(%User{} = user, attrs \\ %{}, _after_save \\ &{:ok, &1}) do
494+
def update_user(%User{} = user, attrs \\ %{}) do
495495
user
496496
|> User.changeset(attrs)
497497
|> Repo.update()

0 commit comments

Comments
 (0)