Show topbar loading indicator while scores are loading
This commit is contained in:
parent
d97de91978
commit
d5140267b1
8 changed files with 213 additions and 2 deletions
|
|
@ -105,4 +105,156 @@
|
|||
/* Make LiveView wrapper divs transparent for layout */
|
||||
[data-phx-session], [data-phx-teleported-src] { display: contents }
|
||||
|
||||
/* Markdown rendered content */
|
||||
.markdown-content {
|
||||
max-width: 64rem;
|
||||
margin: 2rem auto;
|
||||
padding: 0 1rem;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.markdown-content h1 {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
margin: 2rem 0 1rem;
|
||||
border-bottom: 1px solid oklch(80% 0 0);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.markdown-content h2 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
margin: 1.75rem 0 0.75rem;
|
||||
border-bottom: 1px solid oklch(85% 0 0);
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.markdown-content h3 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin: 1.5rem 0 0.5rem;
|
||||
}
|
||||
|
||||
.markdown-content h4 {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
margin: 1.25rem 0 0.5rem;
|
||||
}
|
||||
|
||||
.markdown-content p {
|
||||
margin: 0.75rem 0;
|
||||
}
|
||||
|
||||
.markdown-content ul, .markdown-content ol {
|
||||
margin: 0.75rem 0;
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.markdown-content ul { list-style-type: disc; }
|
||||
.markdown-content ol { list-style-type: decimal; }
|
||||
|
||||
.markdown-content li {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
.markdown-content code {
|
||||
font-family: ui-monospace, monospace;
|
||||
font-size: 0.875em;
|
||||
background: oklch(92% 0 0);
|
||||
padding: 0.15em 0.35em;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.markdown-content pre {
|
||||
margin: 1rem 0;
|
||||
padding: 1rem;
|
||||
background: oklch(20% 0.01 260);
|
||||
color: oklch(95% 0 0);
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.markdown-content pre code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
font-size: 0.85em;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.markdown-content table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 1rem 0;
|
||||
font-size: 0.9em;
|
||||
overflow-x: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.markdown-content th, .markdown-content td {
|
||||
border: 1px solid oklch(80% 0 0);
|
||||
padding: 0.5rem 0.75rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown-content th {
|
||||
background: oklch(94% 0 0);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-content tr:nth-child(even) {
|
||||
background: oklch(97% 0 0);
|
||||
}
|
||||
|
||||
.markdown-content hr {
|
||||
border: none;
|
||||
border-top: 2px solid oklch(85% 0 0);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.markdown-content strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown-content blockquote {
|
||||
border-left: 4px solid oklch(70% 0.15 260);
|
||||
margin: 1rem 0;
|
||||
padding: 0.5rem 1rem;
|
||||
background: oklch(96% 0.005 260);
|
||||
}
|
||||
|
||||
.markdown-content a {
|
||||
color: oklch(55% 0.2 260);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
:where([data-theme=dark]) .markdown-content code {
|
||||
background: oklch(30% 0.01 260);
|
||||
}
|
||||
|
||||
:where([data-theme=dark]) .markdown-content th {
|
||||
background: oklch(30% 0.01 260);
|
||||
}
|
||||
|
||||
:where([data-theme=dark]) .markdown-content tr:nth-child(even) {
|
||||
background: oklch(25% 0.01 260);
|
||||
}
|
||||
|
||||
:where([data-theme=dark]) .markdown-content th,
|
||||
:where([data-theme=dark]) .markdown-content td {
|
||||
border-color: oklch(40% 0 0);
|
||||
}
|
||||
|
||||
:where([data-theme=dark]) .markdown-content h1,
|
||||
:where([data-theme=dark]) .markdown-content h2 {
|
||||
border-color: oklch(40% 0 0);
|
||||
}
|
||||
|
||||
:where([data-theme=dark]) .markdown-content hr {
|
||||
border-color: oklch(40% 0 0);
|
||||
}
|
||||
|
||||
:where([data-theme=dark]) .markdown-content blockquote {
|
||||
background: oklch(25% 0.01 260);
|
||||
}
|
||||
|
||||
/* This file is for your main application CSS */
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import topbar from "../vendor/topbar"
|
||||
|
||||
export const PropagationMap = {
|
||||
mounted() {
|
||||
this.map = L.map(this.el, {
|
||||
|
|
@ -24,9 +26,13 @@ export const PropagationMap = {
|
|||
]
|
||||
|
||||
this.handleEvent("update_scores", ({ scores }) => {
|
||||
topbar.hide()
|
||||
this.renderScores(scores)
|
||||
})
|
||||
|
||||
// Show topbar whenever the server is processing a band change
|
||||
this.el.addEventListener("show-loading", () => topbar.show(300))
|
||||
|
||||
// Send bounds to server on load and on pan/zoom
|
||||
this.sendBounds()
|
||||
this.map.on("moveend", () => this.sendBounds())
|
||||
|
|
@ -168,6 +174,7 @@ export const PropagationMap = {
|
|||
},
|
||||
|
||||
sendBounds() {
|
||||
topbar.show(300)
|
||||
const b = this.map.getBounds()
|
||||
this.pushEvent("map_bounds", {
|
||||
south: b.getSouth(),
|
||||
|
|
|
|||
25
lib/microwaveprop_web/live/algo_live.ex
Normal file
25
lib/microwaveprop_web/live/algo_live.ex
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
defmodule MicrowavepropWeb.AlgoLive do
|
||||
@moduledoc false
|
||||
use MicrowavepropWeb, :live_view
|
||||
|
||||
@algo_path Path.join(:code.priv_dir(:microwaveprop), "../algo.md")
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
content =
|
||||
@algo_path
|
||||
|> File.read!()
|
||||
|> Earmark.as_html!()
|
||||
|
||||
{:ok, assign(socket, page_title: "Algorithm", content: content)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="markdown-content">
|
||||
{raw(@content)}
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
|
@ -117,7 +117,8 @@ defmodule MicrowavepropWeb.MapLive do
|
|||
<li :for={band <- @bands}>
|
||||
<button
|
||||
phx-click={
|
||||
JS.push("select_band", value: %{value: band.freq_mhz})
|
||||
JS.dispatch("show-loading", to: "#propagation-map")
|
||||
|> JS.push("select_band", value: %{value: band.freq_mhz})
|
||||
|> JS.dispatch("click", to: "#propagation-map")
|
||||
}
|
||||
class={[if(@selected_band == band.freq_mhz, do: "active")]}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ defmodule MicrowavepropWeb.Router do
|
|||
live "/map", MapLive
|
||||
live "/qsos", QsoLive.Index
|
||||
live "/qsos/:id", QsoLive.Show
|
||||
live "/algo", AlgoLive
|
||||
end
|
||||
|
||||
# Other scopes may use custom stacks.
|
||||
|
|
|
|||
3
mix.exs
3
mix.exs
|
|
@ -63,7 +63,8 @@ defmodule Microwaveprop.MixProject do
|
|||
{:bandit, "~> 1.5"},
|
||||
{:styler, "~> 1.11", only: [:dev, :test], runtime: false},
|
||||
{:oban, "~> 2.19"},
|
||||
{:credo, "~> 1.7", only: [:dev, :test], runtime: false}
|
||||
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
|
||||
{:earmark, "~> 1.4"}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
|||
1
mix.lock
1
mix.lock
|
|
@ -6,6 +6,7 @@
|
|||
"db_connection": {:hex, :db_connection, "2.9.0", "a6a97c5c958a2d7091a58a9be40caf41ab496b0701d21e1d1abff3fa27a7f371", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17d502eacaf61829db98facf6f20808ed33da6ccf495354a41e64fe42f9c509c"},
|
||||
"decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"},
|
||||
"dns_cluster": {:hex, :dns_cluster, "0.2.0", "aa8eb46e3bd0326bd67b84790c561733b25c5ba2fe3c7e36f28e88f384ebcb33", [:mix], [], "hexpm", "ba6f1893411c69c01b9e8e8f772062535a4cf70f3f35bcc964a324078d8c8240"},
|
||||
"earmark": {:hex, :earmark, "1.4.48", "5f41e579d85ef812351211842b6e005f6e0cef111216dea7d4b9d58af4608434", [:mix], [], "hexpm", "a461a0ddfdc5432381c876af1c86c411fd78a25790c75023c7a4c035fdc858f9"},
|
||||
"ecto": {:hex, :ecto, "3.13.5", "9d4a69700183f33bf97208294768e561f5c7f1ecf417e0fa1006e4a91713a834", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "df9efebf70cf94142739ba357499661ef5dbb559ef902b68ea1f3c1fabce36de"},
|
||||
"ecto_sql": {:hex, :ecto_sql, "3.13.5", "2f8282b2ad97bf0f0d3217ea0a6fff320ead9e2f8770f810141189d182dc304e", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aa36751f4e6a2b56ae79efb0e088042e010ff4935fc8684e74c23b1f49e25fdc"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"},
|
||||
|
|
|
|||
23
test/microwaveprop_web/live/algo_live_test.exs
Normal file
23
test/microwaveprop_web/live/algo_live_test.exs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
defmodule MicrowavepropWeb.AlgoLiveTest do
|
||||
use MicrowavepropWeb.ConnCase, async: true
|
||||
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
describe "mount" do
|
||||
test "renders algo page with markdown content as HTML", %{conn: conn} do
|
||||
{:ok, _lv, html} = live(conn, ~p"/algo")
|
||||
|
||||
# algo.md starts with this heading
|
||||
assert html =~ "Microwave Propagation Algorithm"
|
||||
# Earmark should convert ## headings to h2 tags
|
||||
assert html =~ "<h2>"
|
||||
# Should contain code blocks rendered as HTML
|
||||
assert html =~ "<code"
|
||||
end
|
||||
|
||||
test "sets page title", %{conn: conn} do
|
||||
{:ok, _lv, html} = live(conn, ~p"/algo")
|
||||
assert html =~ "Algorithm"
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue