diff --git a/assets/css/app.css b/assets/css/app.css
index 982f70d2..3e29bd9f 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -12,3 +12,15 @@
@apply p-4 lg:p-6 xl:p-8;
}
}
+
+@layer utilities {
+ .min-h-dvh {
+ min-height: 100vh;
+ }
+
+ @supports (min-height: 100dvh) {
+ .min-h-dvh {
+ min-height: 100dvh;
+ }
+ }
+}
diff --git a/assets/js/app.js b/assets/js/app.js
index 2fd7c72d..99f12892 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -16,16 +16,12 @@
//
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
-import 'phoenix_html';
+import "phoenix_html";
// Establish Phoenix Socket and LiveView configuration.
-import { Socket } from 'phoenix';
-import { LiveSocket } from 'phoenix_live_view';
-import topbar from '../vendor/topbar';
-import Sortable from '../vendor/sortable';
-
-function playSound(url) {
- new Audio(url).play();
-}
+import { Socket } from "phoenix";
+import { LiveSocket } from "phoenix_live_view";
+import topbar from "../vendor/topbar";
+import Sortable from "../vendor/sortable";
let Hooks = {};
@@ -33,17 +29,22 @@ Hooks.LocaleTime = {
mounted() {
const dt = new Date(this.el.textContent);
const locale = document.documentElement.lang;
- const options = { year: 'numeric', month: 'long', day: 'numeric' };
+ const options = { year: "numeric", month: "long", day: "numeric" };
this.el.textContent = dt.toLocaleString(locale, options);
},
};
+let correctSound = new Audio("/audios/correct.mp3");
+let incorrectSound = new Audio("/audios/incorrect.mp3");
+
+function playSound(isCorrect) {
+ const sound = isCorrect ? correctSound : incorrectSound;
+ sound.play();
+}
+
Hooks.LessonSoundEffect = {
mounted() {
- this.handleEvent('option-selected', ({ isCorrect }) => {
- const fileName = isCorrect ? '/correct.mp3' : '/incorrect.mp3';
- playSound('/audios' + fileName);
- });
+ this.handleEvent("option-selected", ({ isCorrect }) => playSound(isCorrect));
},
};
@@ -51,16 +52,13 @@ Hooks.Sortable = {
mounted() {
let group = this.el.dataset.group;
let isDragging = false;
- this.el.addEventListener(
- 'focusout',
- (e) => isDragging && e.stopImmediatePropagation()
- );
+ this.el.addEventListener("focusout", (e) => isDragging && e.stopImmediatePropagation());
let sorter = new Sortable(this.el, {
group: group ? { name: group, pull: true, put: true } : undefined,
animation: 150,
- filter: '.filtered',
- dragClass: 'drag-item',
- ghostClass: 'drag-ghost',
+ filter: ".filtered",
+ dragClass: "drag-item",
+ ghostClass: "drag-ghost",
onStart: (e) => (isDragging = true), // prevent phx-blur from firing while dragging
onEnd: (e) => {
isDragging = false;
@@ -70,11 +68,7 @@ Hooks.Sortable = {
to: e.to.dataset,
...e.item.dataset,
};
- this.pushEventTo(
- this.el,
- this.el.dataset['drop'] || 'reposition',
- params
- );
+ this.pushEventTo(this.el, this.el.dataset["drop"] || "reposition", params);
},
});
},
@@ -85,13 +79,10 @@ Hooks.ClearFlash = {
const kind = this.el.dataset.kind;
const delay = 5000;
- setTimeout(() => this.el.classList.add('opacity-0'), delay);
+ setTimeout(() => this.el.classList.add("opacity-0"), delay);
// Make sure we also clear the flash. Otherwise, it will be displayed for other items too.
- setTimeout(
- () => this.pushEventTo('#' + this.el.id, 'lv:clear-flash', { key: kind }),
- delay + 1000
- );
+ setTimeout(() => this.pushEventTo("#" + this.el.id, "lv:clear-flash", { key: kind }), delay + 1000);
},
};
@@ -103,13 +94,10 @@ Uploaders.S3 = function (entries, onViewError) {
onViewError(() => xhr.abort());
- xhr.onload = () =>
- xhr.status >= 200 && xhr.status < 300
- ? entry.progress(100)
- : entry.error();
+ xhr.onload = () => (xhr.status >= 200 && xhr.status < 300 ? entry.progress(100) : entry.error());
xhr.onerror = () => entry.error();
- xhr.upload.addEventListener('progress', (event) => {
+ xhr.upload.addEventListener("progress", (event) => {
if (event.lengthComputable) {
let percent = Math.round((event.loaded / event.total) * 100);
if (percent < 100) {
@@ -118,25 +106,23 @@ Uploaders.S3 = function (entries, onViewError) {
}
});
- xhr.open('PUT', url, true);
- xhr.setRequestHeader('credentials', 'same-origin parameter');
+ xhr.open("PUT", url, true);
+ xhr.setRequestHeader("credentials", "same-origin parameter");
xhr.send(entry.file);
});
};
-let csrfToken = document
- .querySelector("meta[name='csrf-token']")
- .getAttribute('content');
-let liveSocket = new LiveSocket('/live', Socket, {
+let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content");
+let liveSocket = new LiveSocket("/live", Socket, {
hooks: Hooks,
uploaders: Uploaders,
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(1000));
-window.addEventListener('phx:page-loading-stop', (_info) => topbar.hide());
+topbar.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" });
+window.addEventListener("phx:page-loading-start", (_info) => topbar.show(1000));
+window.addEventListener("phx:page-loading-stop", (_info) => topbar.hide());
// connect if there are any LiveViews on the page
liveSocket.connect();
diff --git a/lib/components/modal.ex b/lib/components/modal.ex
index 6dbed7f0..e621aae5 100644
--- a/lib/components/modal.ex
+++ b/lib/components/modal.ex
@@ -47,7 +47,7 @@ defmodule UneebeeWeb.Components.Modal do
phx-window-keydown={JS.exec("data-cancel", to: "##{@id}")}
phx-key="escape"
phx-click-away={JS.exec("data-cancel", to: "##{@id}")}
- class="shadow-gray-700/10 ring-gray-700/10 relative hidden h-screen bg-white p-8 shadow-lg ring-1 transition lg:h-auto lg:rounded-2xl"
+ class="shadow-gray-700/10 ring-gray-700/10 relative hidden min-h-dvh bg-white p-8 shadow-lg ring-1 transition lg:h-auto lg:rounded-2xl"
>