part 1
This commit is contained in:
parent
b98cb3e145
commit
2c9cc0c20f
8 changed files with 149 additions and 31 deletions
|
@ -16,29 +16,35 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
|
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
|
||||||
import "phoenix_html"
|
import "phoenix_html";
|
||||||
// Establish Phoenix Socket and LiveView configuration.
|
// Establish Phoenix Socket and LiveView configuration.
|
||||||
import {Socket} from "phoenix"
|
import { Socket } from "phoenix";
|
||||||
import {LiveSocket} from "phoenix_live_view"
|
import { LiveSocket } from "phoenix_live_view";
|
||||||
import topbar from "../vendor/topbar"
|
import topbar from "../vendor/topbar";
|
||||||
|
|
||||||
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
|
import darkModeHook from "../vendor/dark_mode";
|
||||||
|
let Hooks = {};
|
||||||
|
Hooks.DarkThemeToggle = darkModeHook;
|
||||||
|
|
||||||
|
let csrfToken = document
|
||||||
|
.querySelector("meta[name='csrf-token']")
|
||||||
|
.getAttribute("content");
|
||||||
let liveSocket = new LiveSocket("/live", Socket, {
|
let liveSocket = new LiveSocket("/live", Socket, {
|
||||||
longPollFallbackMs: 2500,
|
longPollFallbackMs: 2500,
|
||||||
params: {_csrf_token: csrfToken}
|
params: { _csrf_token: csrfToken },
|
||||||
})
|
hooks: Hooks,
|
||||||
|
});
|
||||||
|
|
||||||
// Show progress bar on live navigation and form submits
|
// Show progress bar on live navigation and form submits
|
||||||
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
|
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-start", (_info) => topbar.show(300));
|
||||||
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())
|
window.addEventListener("phx:page-loading-stop", (_info) => topbar.hide());
|
||||||
|
|
||||||
// connect if there are any LiveViews on the page
|
// connect if there are any LiveViews on the page
|
||||||
liveSocket.connect()
|
liveSocket.connect();
|
||||||
|
|
||||||
// expose liveSocket on window for web console debug logs and latency simulation:
|
// expose liveSocket on window for web console debug logs and latency simulation:
|
||||||
// >> liveSocket.enableDebug()
|
// >> liveSocket.enableDebug()
|
||||||
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
|
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
|
||||||
// >> liveSocket.disableLatencySim()
|
// >> liveSocket.disableLatencySim()
|
||||||
window.liveSocket = liveSocket
|
window.liveSocket = liveSocket;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ const path = require("path");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ["./js/**/*.js", "../lib/exmr_web.ex", "../lib/exmr_web/**/*.*ex"],
|
content: ["./js/**/*.js", "../lib/exmr_web.ex", "../lib/exmr_web/**/*.*ex"],
|
||||||
|
darkMode: "class",
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
|
|
46
assets/vendor/dark_mode.js
vendored
Normal file
46
assets/vendor/dark_mode.js
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
const localStorageKey = "theme";
|
||||||
|
|
||||||
|
const isDark = () => {
|
||||||
|
if (localStorage.getItem(localStorageKey) === "dark") return true;
|
||||||
|
if (localStorage.getItem(localStorageKey) === "light") return false;
|
||||||
|
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setupThemeToggle = () => {
|
||||||
|
toggleVisibility = (dark) => {
|
||||||
|
const themeToggleDarkIcon = document.getElementById(
|
||||||
|
"theme-toggle-dark-icon",
|
||||||
|
);
|
||||||
|
const themeToggleLightIcon = document.getElementById(
|
||||||
|
"theme-toggle-light-icon",
|
||||||
|
);
|
||||||
|
if (themeToggleDarkIcon == null || themeToggleLightIcon == null) return;
|
||||||
|
const show = dark ? themeToggleDarkIcon : themeToggleLightIcon;
|
||||||
|
const hide = dark ? themeToggleLightIcon : themeToggleDarkIcon;
|
||||||
|
show.classList.remove("hidden", "text-transparent");
|
||||||
|
hide.classList.add("hidden", "text-transparent");
|
||||||
|
if (dark) {
|
||||||
|
document.documentElement.classList.add("dark");
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove("dark");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
localStorage.setItem(localStorageKey, dark ? "dark" : "light");
|
||||||
|
} catch (_err) { }
|
||||||
|
};
|
||||||
|
toggleVisibility(isDark());
|
||||||
|
document
|
||||||
|
.getElementById("theme-toggle")
|
||||||
|
.addEventListener("click", function() {
|
||||||
|
toggleVisibility(!isDark());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const darkModeHook = {
|
||||||
|
mounted() {
|
||||||
|
setupThemeToggle();
|
||||||
|
},
|
||||||
|
updated() { },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default darkModeHook;
|
|
@ -232,7 +232,7 @@ defmodule ExmrWeb.CoreComponents do
|
||||||
type={@type}
|
type={@type}
|
||||||
class={[
|
class={[
|
||||||
"phx-submit-loading:opacity-75 rounded-lg bg-zinc-900 hover:bg-zinc-700 py-2 px-3",
|
"phx-submit-loading:opacity-75 rounded-lg bg-zinc-900 hover:bg-zinc-700 py-2 px-3",
|
||||||
"text-sm font-semibold leading-6 text-white active:text-white/80",
|
"text-sm font-semibold leading-6",
|
||||||
@class
|
@class
|
||||||
]}
|
]}
|
||||||
{@rest}
|
{@rest}
|
||||||
|
@ -429,10 +429,10 @@ defmodule ExmrWeb.CoreComponents do
|
||||||
~H"""
|
~H"""
|
||||||
<header class={[@actions != [] && "flex items-center justify-between gap-6", @class]}>
|
<header class={[@actions != [] && "flex items-center justify-between gap-6", @class]}>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-lg font-semibold leading-8 text-zinc-800">
|
<h1 class="text-lg font-semibold leading-8 text-zinc-800 dark:text-zinc-200">
|
||||||
<%= render_slot(@inner_block) %>
|
<%= render_slot(@inner_block) %>
|
||||||
</h1>
|
</h1>
|
||||||
<p :if={@subtitle != []} class="mt-2 text-sm leading-6 text-zinc-600">
|
<p :if={@subtitle != []} class="mt-2 text-sm leading-6 text-zinc-600 dark:text-zinc-100">
|
||||||
<%= render_slot(@subtitle) %>
|
<%= render_slot(@subtitle) %>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
57
lib/exmr_web/components/dark_mode.ex
Normal file
57
lib/exmr_web/components/dark_mode.ex
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
defmodule DarkMode do
|
||||||
|
@moduledoc """
|
||||||
|
A component to toggle dark mode.
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Phoenix.Component
|
||||||
|
|
||||||
|
def button(assigns) do
|
||||||
|
~H"""
|
||||||
|
<button
|
||||||
|
id="theme-toggle"
|
||||||
|
type="button"
|
||||||
|
phx-update="ignore"
|
||||||
|
phx-hook="DarkThemeToggle"
|
||||||
|
class="text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-700 rounded-lg text-sm p-2"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
id="theme-toggle-dark-icon"
|
||||||
|
class="w-5 h-5 text-transparent hidden"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
id="theme-toggle-light-icon"
|
||||||
|
class="w-5 h-5 text-transparent"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Toggle early based on <html class="dark">
|
||||||
|
const themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
|
||||||
|
const themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
|
||||||
|
if (themeToggleDarkIcon != null && themeToggleLightIcon != null) {
|
||||||
|
let dark = document.documentElement.classList.contains('dark');
|
||||||
|
const show = dark ? themeToggleDarkIcon : themeToggleLightIcon
|
||||||
|
const hide = dark ? themeToggleLightIcon : themeToggleDarkIcon
|
||||||
|
show.classList.remove('hidden', 'text-transparent');
|
||||||
|
hide.classList.add('hidden', 'text-transparent');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,19 +8,27 @@
|
||||||
<%= assigns[:page_title] || "Exmr" %>
|
<%= assigns[:page_title] || "Exmr" %>
|
||||||
</.live_title>
|
</.live_title>
|
||||||
<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
|
<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
|
||||||
|
<script>
|
||||||
|
if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove('dark')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
|
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-white">
|
<body class="bg-white dark:bg-zinc-950 dark:text-zinc-100">
|
||||||
<ul class="relative z-10 flex items-center gap-4 px-4 sm:px-6 lg:px-8 justify-end">
|
<ul class="relative z-10 flex items-center gap-4 px-4 sm:px-6 lg:px-8 justify-end">
|
||||||
|
<DarkMode.button />
|
||||||
<%= if @current_user do %>
|
<%= if @current_user do %>
|
||||||
<li class="text-[0.8125rem] leading-6 text-zinc-900">
|
<li class="text-[0.8125rem] leading-6 text-zinc-900 dark:text-zinc-300">
|
||||||
<%= @current_user.email %>
|
<%= @current_user.email %>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<.link
|
<.link
|
||||||
href={~p"/users/settings"}
|
href={~p"/users/settings"}
|
||||||
class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
|
class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700 dark:text-zinc-300 dark:hover:text-zinc-100"
|
||||||
>
|
>
|
||||||
Settings
|
Settings
|
||||||
</.link>
|
</.link>
|
||||||
|
@ -29,7 +37,7 @@
|
||||||
<.link
|
<.link
|
||||||
href={~p"/users/log_out"}
|
href={~p"/users/log_out"}
|
||||||
method="delete"
|
method="delete"
|
||||||
class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
|
class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700 dark:text-zinc-300 dark:hover:text-zinc-100"
|
||||||
>
|
>
|
||||||
Log out
|
Log out
|
||||||
</.link>
|
</.link>
|
||||||
|
@ -38,7 +46,7 @@
|
||||||
<li>
|
<li>
|
||||||
<.link
|
<.link
|
||||||
href={~p"/users/register"}
|
href={~p"/users/register"}
|
||||||
class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
|
class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700 dark:text-zinc-300 dark:hover:text-zinc-100"
|
||||||
>
|
>
|
||||||
Register
|
Register
|
||||||
</.link>
|
</.link>
|
||||||
|
@ -46,7 +54,7 @@
|
||||||
<li>
|
<li>
|
||||||
<.link
|
<.link
|
||||||
href={~p"/users/log_in"}
|
href={~p"/users/log_in"}
|
||||||
class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
|
class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700 dark:text-zinc-300 dark:hover:text-zinc-100"
|
||||||
>
|
>
|
||||||
Log in
|
Log in
|
||||||
</.link>
|
</.link>
|
||||||
|
|
|
@ -47,22 +47,22 @@
|
||||||
v<%= Application.spec(:exmr, :vsn) %>
|
v<%= Application.spec(:exmr, :vsn) %>
|
||||||
</small>
|
</small>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-[2rem] mt-4 font-semibold leading-10 tracking-tighter text-zinc-900 text-balance">
|
<p class="text-[2rem] mt-4 font-semibold leading-10 tracking-tighter text-zinc-900 dark:text-zinc-200/90 text-balance">
|
||||||
hell yeah
|
hell yeah
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-4 text-base leading-7 text-zinc-600">
|
<p class="mt-4 text-base leading-7 text-zinc-600 dark:text-zinc-300">
|
||||||
y'all really though i'm gonna be serious? lol
|
y'all really though i'm gonna be serious? lol
|
||||||
</p>
|
</p>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="w-full sm:w-auto">
|
<div class="w-full sm:w-auto">
|
||||||
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-3">
|
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-3">
|
||||||
<a
|
<a
|
||||||
href="https://github.com/phoenixframework/phoenix"
|
href="https://git.vavakado.com/vavakado/exmr"
|
||||||
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-zinc-900 sm:py-6"
|
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-zinc-900 sm:py-6"
|
||||||
>
|
>
|
||||||
<span class="absolute inset-0 rounded-2xl bg-zinc-50 transition group-hover:bg-zinc-100 sm:group-hover:scale-105">
|
<span class="absolute inset-0 rounded-2xl bg-zinc-50 transition group-hover:bg-zinc-100 dark:bg-zinc-800 dark:group-hover:bg-zinc-900/95 sm:group-hover:scale-105">
|
||||||
</span>
|
</span>
|
||||||
<span class="relative flex items-center gap-4 sm:flex-col">
|
<span class="relative flex items-center gap-4 sm:flex-col dark:text-white">
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true" class="h-6 w-6">
|
<svg viewBox="0 0 24 24" aria-hidden="true" class="h-6 w-6">
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fill-rule="evenodd"
|
||||||
|
@ -79,9 +79,9 @@
|
||||||
href="https://mas.to/@vavakado"
|
href="https://mas.to/@vavakado"
|
||||||
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-zinc-900 sm:py-6"
|
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-zinc-900 sm:py-6"
|
||||||
>
|
>
|
||||||
<span class="absolute inset-0 rounded-2xl bg-zinc-50 transition group-hover:bg-zinc-100 sm:group-hover:scale-105">
|
<span class="absolute inset-0 rounded-2xl bg-zinc-50 transition group-hover:bg-zinc-100 sm:group-hover:scale-105 dark:bg-zinc-800 dark:group-hover:bg-zinc-900/95">
|
||||||
</span>
|
</span>
|
||||||
<span class="relative flex items-center gap-4 sm:flex-col">
|
<span class="relative flex items-center gap-4 sm:flex-col dark:text-white">
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true" class="h-6 w-6">
|
<svg viewBox="0 0 24 24" aria-hidden="true" class="h-6 w-6">
|
||||||
<path d="M11.19 12.195c2.016-.24 3.77-1.475 3.99-2.603.348-1.778.32-4.339.32-4.339 0-3.47-2.286-4.488-2.286-4.488C12.062.238 10.083.017 8.027 0h-.05C5.92.017 3.942.238 2.79.765c0 0-2.285 1.017-2.285 4.488l-.002.662c-.004.64-.007 1.35.011 2.091.083 3.394.626 6.74 3.78 7.57 1.454.383 2.703.463 3.709.408 1.823-.1 2.847-.647 2.847-.647l-.06-1.317s-1.303.41-2.767.36c-1.45-.05-2.98-.156-3.215-1.928a4 4 0 0 1-.033-.496s1.424.346 3.228.428c1.103.05 2.137-.064 3.188-.189zm1.613-2.47H11.13v-4.08c0-.859-.364-1.295-1.091-1.295-.804 0-1.207.517-1.207 1.541v2.233H7.168V5.89c0-1.024-.403-1.541-1.207-1.541-.727 0-1.091.436-1.091 1.296v4.079H3.197V5.522q0-1.288.66-2.046c.456-.505 1.052-.764 1.793-.764.856 0 1.504.328 1.933.983L8 4.39l.417-.695c.429-.655 1.077-.983 1.934-.983.74 0 1.336.259 1.791.764q.662.757.661 2.046z" />
|
<path d="M11.19 12.195c2.016-.24 3.77-1.475 3.99-2.603.348-1.778.32-4.339.32-4.339 0-3.47-2.286-4.488-2.286-4.488C12.062.238 10.083.017 8.027 0h-.05C5.92.017 3.942.238 2.79.765c0 0-2.285 1.017-2.285 4.488l-.002.662c-.004.64-.007 1.35.011 2.091.083 3.394.626 6.74 3.78 7.57 1.454.383 2.703.463 3.709.408 1.823-.1 2.847-.647 2.847-.647l-.06-1.317s-1.303.41-2.767.36c-1.45-.05-2.98-.156-3.215-1.928a4 4 0 0 1-.033-.496s1.424.346 3.228.428c1.103.05 2.137-.064 3.188-.189zm1.613-2.47H11.13v-4.08c0-.859-.364-1.295-1.091-1.295-.804 0-1.207.517-1.207 1.541v2.233H7.168V5.89c0-1.024-.403-1.541-1.207-1.541-.727 0-1.091.436-1.091 1.296v4.079H3.197V5.522q0-1.288.66-2.046c.456-.505 1.052-.764 1.793-.764.856 0 1.504.328 1.933.983L8 4.39l.417-.695c.429-.655 1.077-.983 1.934-.983.74 0 1.336.259 1.791.764q.662.757.661 2.046z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</div>
|
</div>
|
||||||
<:actions>
|
<:actions>
|
||||||
<.link patch={~p"/exams/new"}>
|
<.link patch={~p"/exams/new"}>
|
||||||
<.button>New Exam</.button>
|
<.button class="dark:bg-sky-300 text-white dark:text-black/80 dark:hover:bg-sky-400">New Exam</.button>
|
||||||
</.link>
|
</.link>
|
||||||
</:actions>
|
</:actions>
|
||||||
</.header>
|
</.header>
|
||||||
|
|
Loading…
Reference in a new issue