mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
CLI: Toasts & Tweaks (#2702)
* progress: cli toasts * forgot the html * progress: toasts * revision: don't open splash on desktop * fix: fmt, spellcheck
This commit is contained in:
parent
beeee0dda1
commit
bd58a92441
10 changed files with 363 additions and 31 deletions
|
@ -325,7 +325,6 @@
|
|||
ws.onmessage = (event) => {
|
||||
// Parse the message as json
|
||||
let data = JSON.parse(event.data);
|
||||
console.log(data);
|
||||
|
||||
// If the message is "Ready", reload the page
|
||||
if (data.type === "Ready") {
|
||||
|
@ -364,7 +363,6 @@
|
|||
let errorBlock = document.getElementById("error-block");
|
||||
errorBlock.innerHTML = formatting2;
|
||||
|
||||
console.log(data.data.error);
|
||||
} else if (data.type === "Building") {
|
||||
// Show correct view for message.
|
||||
let errorContainer = document.getElementById("error");
|
||||
|
|
206
packages/cli/assets/toast.html
Normal file
206
packages/cli/assets/toast.html
Normal file
|
@ -0,0 +1,206 @@
|
|||
<style>
|
||||
/* Inter Font */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');
|
||||
|
||||
#dx-toast-template {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.dx-toast {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 0;
|
||||
padding-right: 10px;
|
||||
user-select: none;
|
||||
transition: transform 0.2s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dx-toast .dx-toast-inner {
|
||||
transition: right 0.2s ease-out;
|
||||
position: relative;
|
||||
|
||||
background-color: #181B20;
|
||||
color: #ffffff;
|
||||
font-family: "Inter", sans-serif;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
min-width: 280px;
|
||||
min-height: 92px;
|
||||
width: min-content;
|
||||
border-radius: 5px;
|
||||
|
||||
}
|
||||
|
||||
.dx-toast:hover {
|
||||
cursor: pointer;
|
||||
transform: translateX(-5px);
|
||||
}
|
||||
|
||||
.dx-toast .dx-toast-level-bar-container {
|
||||
height: 100%;
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.dx-toast .dx-toast-level-bar-container .dx-toast-level-bar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 5px 0px 0px 5px;
|
||||
}
|
||||
|
||||
.dx-toast .dx-toast-content {
|
||||
padding: 13px;
|
||||
}
|
||||
|
||||
.dx-toast .dx-toast-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: start;
|
||||
align-items: end;
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
.dx-toast .dx-toast-header>svg {
|
||||
height: 22px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.dx-toast .dx-toast-header .dx-toast-header-text {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dx-toast .dx-toast-msg {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dx-toast-level-bar.info {
|
||||
background-color: #428EFF;
|
||||
}
|
||||
|
||||
.dx-toast-level-bar.success {
|
||||
background-color: #42FF65;
|
||||
}
|
||||
|
||||
.dx-toast-level-bar.error {
|
||||
background-color: #FF4242;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="dx-toast-template" class="dx-toast">
|
||||
<div class="dx-toast-inner" style="right:-300px;">
|
||||
<!-- Level/Color decor -->
|
||||
<div class="dx-toast-level-bar-container">
|
||||
<div class="dx-toast-level-bar info"></div>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="dx-toast-content">
|
||||
<!-- Header -->
|
||||
<div class="dx-toast-header">
|
||||
<!-- Dioxus Logo -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" preserveAspectRatio="none">
|
||||
<path
|
||||
d="M22.158 1.783c0 3.077-.851 5.482-2.215 7.377s-3.32 3.557-5.447 5.33-4.425 3.657-6.252 6.195-3.102 5.515-3.102 9.532h4.699c0-3.077.853-5.377 2.217-7.272s3.32-3.557 5.447-5.33 4.425-3.657 6.252-6.195 3.102-5.62 3.102-9.637z"
|
||||
fill="#e96020" />
|
||||
<path
|
||||
d="M9.531 25.927c-.635 0-1.021.515-1.02 1.15s.385 1.151 1.02 1.15H22.47a1.151 1.151 0 1 0 0-2.301zm1.361-4.076c-.608 0-.954.558-.953 1.166s.346 1.035.953 1.035h10.217a1.101 1.101 0 1 0 0-2.201zm0-13.594a1.101 1.101 0 1 0 0 2.201h10.217c.607 0 .953-.598.953-1.205s-.345-.996-.953-.996zM9.531 4.021A1.15 1.15 0 0 0 8.38 5.17a1.15 1.15 0 0 0 1.15 1.15h12.94c.635 0 1.021-.498 1.02-1.133s-.386-1.166-1.02-1.166z"
|
||||
fill="#2d323b" />
|
||||
<path
|
||||
d="M5.142 1.783c0 4.016 1.275 7.099 3.102 9.637s4.125 4.422 6.252 6.195 4.083 3.656 5.447 5.551 2.215 3.974 2.215 7.051h4.701c0-4.016-1.275-7.038-3.102-9.576s-4.125-4.422-6.252-6.195-4.083-3.435-5.447-5.33S9.841 4.86 9.841 1.783z"
|
||||
fill="#00a8d6" />
|
||||
</svg>
|
||||
<!-- Toast Title Text -->
|
||||
<h3 class="dx-toast-header-text">Your app is being rebuilt.</h3>
|
||||
</div>
|
||||
|
||||
<!-- Message -->
|
||||
<p class="dx-toast-msg">A non-hot-reloadable change occurred and we must rebuild.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const STORAGE_KEY = "SCHEDULED-DX-TOAST";
|
||||
let currentToast = null;
|
||||
let currentTimeout = null;
|
||||
|
||||
// Show a toast, removing the previous one.
|
||||
function showDXToast(headerText, message, progressLevel, durationMs) {
|
||||
// Close current toast if exists.
|
||||
closeDXToast();
|
||||
|
||||
// Clone template and add unique id.
|
||||
let toastTemplate = document.getElementById("dx-toast-template");
|
||||
let cloned = toastTemplate.cloneNode(true);
|
||||
let toastId = `dx-toast`;
|
||||
cloned.id = toastId;
|
||||
currentToast = cloned;
|
||||
|
||||
let innerElem = currentToast.querySelector(`#${toastId} .dx-toast-inner`);
|
||||
|
||||
// Set the progress level
|
||||
let progressBarElem = innerElem.querySelector(".dx-toast-inner .dx-toast-level-bar-container .dx-toast-level-bar");
|
||||
progressBarElem.className = `dx-toast-level-bar ${progressLevel}`;
|
||||
|
||||
// Set header text
|
||||
let headerTextElem = innerElem.querySelector(".dx-toast-inner .dx-toast-header .dx-toast-header-text");
|
||||
headerTextElem.innerText = headerText;
|
||||
|
||||
// Set message
|
||||
let messageElem = innerElem.querySelector(".dx-toast-inner .dx-toast-msg");
|
||||
messageElem.innerText = message;
|
||||
|
||||
document.body.appendChild(currentToast);
|
||||
|
||||
// Add listener to close toasts when clicked.
|
||||
// Safety: Calling `closeToast` removes the element and all event listeners with it.
|
||||
currentToast.addEventListener("click", closeDXToast);
|
||||
|
||||
// Wait a bit of time so animation plays correctly.
|
||||
setTimeout(() => {
|
||||
innerElem.style.right = "0";
|
||||
|
||||
currentTimeout = setTimeout(() => {
|
||||
closeDXToast();
|
||||
}, durationMs);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Schedule a toast to be displayed after reload.
|
||||
function scheduleDXToast(headerText, message, level, durationMs) {
|
||||
let data = {
|
||||
headerText,
|
||||
message,
|
||||
level,
|
||||
durationMs,
|
||||
};
|
||||
|
||||
let jsonData = JSON.stringify(data);
|
||||
sessionStorage.setItem(STORAGE_KEY, jsonData);
|
||||
}
|
||||
|
||||
// Close the current toast.
|
||||
function closeDXToast() {
|
||||
if (currentToast) {
|
||||
currentToast.remove();
|
||||
}
|
||||
clearTimeout(currentTimeout);
|
||||
}
|
||||
|
||||
// Handle any scheduled toasts after reload.
|
||||
let potentialData = sessionStorage.getItem(STORAGE_KEY);
|
||||
if (potentialData) {
|
||||
sessionStorage.removeItem(STORAGE_KEY);
|
||||
let data = JSON.parse(potentialData);
|
||||
showDXToast(data.headerText, data.message, data.level, data.durationMs);
|
||||
}
|
||||
|
||||
</script>
|
|
@ -10,6 +10,7 @@ use std::path::{Path, PathBuf};
|
|||
use tracing::Level;
|
||||
|
||||
const DEFAULT_HTML: &str = include_str!("../../assets/index.html");
|
||||
const TOAST_HTML: &str = include_str!("../../assets/toast.html");
|
||||
|
||||
impl BuildRequest {
|
||||
pub(crate) fn prepare_html(
|
||||
|
@ -110,9 +111,16 @@ impl BuildRequest {
|
|||
});
|
||||
}
|
||||
);
|
||||
</script></body"#,
|
||||
</script>
|
||||
{DX_TOAST_UTILITIES}
|
||||
</body"#,
|
||||
);
|
||||
|
||||
*html = match self.serve && !self.build_arguments.release {
|
||||
true => html.replace("{DX_TOAST_UTILITIES}", TOAST_HTML),
|
||||
false => html.replace("{DX_TOAST_UTILITIES}", ""),
|
||||
};
|
||||
|
||||
// And try to insert preload links for the wasm and js files
|
||||
*html = html.replace(
|
||||
"</head",
|
||||
|
|
|
@ -43,6 +43,7 @@ impl std::fmt::Display for Stage {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UpdateBuildProgress {
|
||||
pub stage: Stage,
|
||||
pub update: UpdateStage,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::builder::{Stage, UpdateBuildProgress, UpdateStage};
|
||||
use crate::cli::serve::Serve;
|
||||
use crate::dioxus_crate::DioxusCrate;
|
||||
use crate::Result;
|
||||
|
@ -106,9 +107,17 @@ pub async fn serve_all(serve: Serve, dioxus_crate: DioxusCrate) -> Result<()> {
|
|||
// We also can check the status of the builds here in case we have multiple ongoing builds
|
||||
match application {
|
||||
Ok(BuilderUpdate::Progress { platform, update }) => {
|
||||
let update_stage = update.stage;
|
||||
screen.new_build_logs(platform, update);
|
||||
server.update_build_status(screen.build_progress.progress(), update_stage.to_string()).await;
|
||||
let update_clone = update.clone();
|
||||
screen.new_build_logs(platform, update_clone);
|
||||
server.update_build_status(screen.build_progress.progress(), update.stage.to_string()).await;
|
||||
|
||||
match update {
|
||||
// Send rebuild start message.
|
||||
UpdateBuildProgress { stage: Stage::Compiling, update: UpdateStage::Start } => server.send_reload_start().await,
|
||||
// Send rebuild failed message.
|
||||
UpdateBuildProgress { stage: Stage::Finished, update: UpdateStage::Failed(_) } => server.send_reload_failed().await,
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
Ok(BuilderUpdate::Ready { results }) => {
|
||||
if !results.is_empty() {
|
||||
|
@ -130,7 +139,7 @@ pub async fn serve_all(serve: Serve, dioxus_crate: DioxusCrate) -> Result<()> {
|
|||
screen.new_ready_app(&mut builder, results);
|
||||
|
||||
// And then finally tell the server to reload
|
||||
server.send_reload().await;
|
||||
server.send_reload_command().await;
|
||||
},
|
||||
Err(err) => {
|
||||
server.send_build_error(err).await;
|
||||
|
|
|
@ -131,6 +131,7 @@ impl Server {
|
|||
// Actually just start the server, cloning in a few bits of config
|
||||
let web_config = cfg.dioxus_config.web.https.clone();
|
||||
let base_path = cfg.dioxus_config.web.app.base_path.clone();
|
||||
let platform = serve.platform();
|
||||
let _server_task = tokio::spawn(async move {
|
||||
let web_config = web_config.clone();
|
||||
// HTTPS
|
||||
|
@ -139,7 +140,7 @@ impl Server {
|
|||
let rustls: Option<RustlsConfig> = get_rustls(&web_config).await.unwrap();
|
||||
|
||||
// Open the browser
|
||||
if start_browser {
|
||||
if start_browser && platform != Platform::Desktop {
|
||||
open_browser(base_path, addr, rustls.is_some());
|
||||
}
|
||||
|
||||
|
@ -175,6 +176,7 @@ impl Server {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sends the current build status to all clients.
|
||||
async fn send_build_status(&mut self) {
|
||||
let mut i = 0;
|
||||
while i < self.build_status_sockets.len() {
|
||||
|
@ -190,6 +192,7 @@ impl Server {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sends a start build message to all clients.
|
||||
pub async fn start_build(&mut self) {
|
||||
self.build_status.set(Status::Building {
|
||||
progress: 0.0,
|
||||
|
@ -198,6 +201,7 @@ impl Server {
|
|||
self.send_build_status().await;
|
||||
}
|
||||
|
||||
/// Sends an updated build status to all clients.
|
||||
pub async fn update_build_status(&mut self, progress: f64, build_message: String) {
|
||||
if !matches!(self.build_status.get(), Status::Building { .. }) {
|
||||
return;
|
||||
|
@ -209,6 +213,7 @@ impl Server {
|
|||
self.send_build_status().await;
|
||||
}
|
||||
|
||||
/// Sends hot reloadable changes to all clients.
|
||||
pub async fn send_hotreload(&mut self, reload: HotReloadMsg) {
|
||||
let msg = DevserverMsg::HotReload(reload);
|
||||
let msg = serde_json::to_string(&msg).unwrap();
|
||||
|
@ -275,6 +280,7 @@ impl Server {
|
|||
None
|
||||
}
|
||||
|
||||
/// Converts a `cargo` error to HTML and sends it to clients.
|
||||
pub async fn send_build_error(&mut self, error: Error) {
|
||||
let error = error.to_string();
|
||||
self.build_status.set(Status::BuildError {
|
||||
|
@ -283,25 +289,36 @@ impl Server {
|
|||
self.send_build_status().await;
|
||||
}
|
||||
|
||||
pub async fn send_reload(&mut self) {
|
||||
self.build_status.set(Status::Ready);
|
||||
self.send_build_status().await;
|
||||
for socket in self.hot_reload_sockets.iter_mut() {
|
||||
_ = socket
|
||||
.send(Message::Text(
|
||||
serde_json::to_string(&DevserverMsg::FullReload).unwrap(),
|
||||
))
|
||||
/// Tells all clients that a full rebuild has started.
|
||||
pub async fn send_reload_start(&mut self) {
|
||||
self.send_devserver_message(DevserverMsg::FullReloadStart)
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Tells all clients that a full rebuild has failed.
|
||||
pub async fn send_reload_failed(&mut self) {
|
||||
self.send_devserver_message(DevserverMsg::FullReloadFailed)
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Send a shutdown message to all connected clients
|
||||
/// Tells all clients to reload if possible for new changes.
|
||||
pub async fn send_reload_command(&mut self) {
|
||||
self.build_status.set(Status::Ready);
|
||||
self.send_build_status().await;
|
||||
self.send_devserver_message(DevserverMsg::FullReloadCommand)
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Send a shutdown message to all connected clients.
|
||||
pub async fn send_shutdown(&mut self) {
|
||||
self.send_devserver_message(DevserverMsg::Shutdown).await;
|
||||
}
|
||||
|
||||
/// Sends a devserver message to all connected clients.
|
||||
async fn send_devserver_message(&mut self, msg: DevserverMsg) {
|
||||
for socket in self.hot_reload_sockets.iter_mut() {
|
||||
_ = socket
|
||||
.send(Message::Text(
|
||||
serde_json::to_string(&DevserverMsg::Shutdown).unwrap(),
|
||||
))
|
||||
.send(Message::Text(serde_json::to_string(&msg).unwrap()))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -330,8 +330,10 @@ impl App {
|
|||
not(target_os = "ios")
|
||||
))]
|
||||
pub fn handle_hot_reload_msg(&mut self, msg: dioxus_hot_reload::DevserverMsg) {
|
||||
use dioxus_hot_reload::DevserverMsg;
|
||||
|
||||
match msg {
|
||||
dioxus_hot_reload::DevserverMsg::HotReload(hr_msg) => {
|
||||
DevserverMsg::HotReload(hr_msg) => {
|
||||
for webview in self.webviews.values_mut() {
|
||||
dioxus_hot_reload::apply_changes(&mut webview.dom, &hr_msg);
|
||||
webview.poll_vdom();
|
||||
|
@ -343,11 +345,13 @@ impl App {
|
|||
}
|
||||
}
|
||||
}
|
||||
dioxus_hot_reload::DevserverMsg::FullReload => {
|
||||
DevserverMsg::FullReloadCommand
|
||||
| DevserverMsg::FullReloadStart
|
||||
| DevserverMsg::FullReloadFailed => {
|
||||
// usually only web gets this message - what are we supposed to do?
|
||||
// Maybe we could just binary patch ourselves in place without losing window state?
|
||||
}
|
||||
dioxus_hot_reload::DevserverMsg::Shutdown => {
|
||||
DevserverMsg::Shutdown => {
|
||||
self.control_flow = ControlFlow::Exit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,14 @@ pub enum DevserverMsg {
|
|||
/// This includes all the templates/literals/assets/binary patches that have changed in one shot
|
||||
HotReload(HotReloadMsg),
|
||||
|
||||
/// The devserver is starting a full rebuild.
|
||||
FullReloadStart,
|
||||
|
||||
/// The full reload failed.
|
||||
FullReloadFailed,
|
||||
|
||||
/// The app should reload completely if it can
|
||||
FullReload,
|
||||
FullReloadCommand,
|
||||
|
||||
/// The program is shutting down completely - maybe toss up a splash screen or something?
|
||||
Shutdown,
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
|||
LiveViewError,
|
||||
};
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_hot_reload::DevserverMsg;
|
||||
use dioxus_html::{EventData, HtmlEvent, PlatformEventData};
|
||||
use dioxus_interpreter_js::MutationState;
|
||||
use futures_util::{pin_mut, SinkExt, StreamExt};
|
||||
|
@ -213,16 +214,18 @@ pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), Li
|
|||
Some(msg) = hot_reload_wait => {
|
||||
#[cfg(all(feature = "hot-reload", debug_assertions))]
|
||||
match msg{
|
||||
dioxus_hot_reload::DevserverMsg::HotReload(msg)=> {
|
||||
DevserverMsg::HotReload(msg)=> {
|
||||
dioxus_hot_reload::apply_changes(&mut vdom, &msg);
|
||||
}
|
||||
dioxus_hot_reload::DevserverMsg::Shutdown => {
|
||||
DevserverMsg::Shutdown => {
|
||||
std::process::exit(0);
|
||||
},
|
||||
dioxus_hot_reload::DevserverMsg::FullReload => {
|
||||
DevserverMsg::FullReloadCommand
|
||||
| DevserverMsg::FullReloadStart
|
||||
| DevserverMsg::FullReloadFailed => {
|
||||
// usually only web gets this message - what are we supposed to do?
|
||||
// Maybe we could just binary patch ourselves in place without losing window state?
|
||||
}
|
||||
},
|
||||
}
|
||||
#[cfg(not(all(feature = "hot-reload", debug_assertions)))]
|
||||
let () = msg;
|
||||
|
|
|
@ -3,7 +3,12 @@
|
|||
//! This sets up a websocket connection to the devserver and handles messages from it.
|
||||
//! We also set up a little recursive timer that will attempt to reconnect if the connection is lost.
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::time::Duration;
|
||||
|
||||
use dioxus_core::ScopeId;
|
||||
use dioxus_hot_reload::{DevserverMsg, HotReloadMsg};
|
||||
use dioxus_html::prelude::eval;
|
||||
use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
|
||||
use js_sys::JsString;
|
||||
use wasm_bindgen::JsCast;
|
||||
|
@ -14,6 +19,9 @@ const POLL_INTERVAL_MIN: i32 = 250;
|
|||
const POLL_INTERVAL_MAX: i32 = 4000;
|
||||
const POLL_INTERVAL_SCALE_FACTOR: i32 = 2;
|
||||
|
||||
/// Amount of time that toats should be displayed.
|
||||
const TOAST_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
pub(crate) fn init() -> UnboundedReceiver<HotReloadMsg> {
|
||||
// Create the tx/rx pair that we'll use for the top-level future in the dioxus loop
|
||||
let (tx, rx) = unbounded();
|
||||
|
@ -62,8 +70,34 @@ fn make_ws(tx: UnboundedSender<HotReloadMsg>, poll_interval: i32, reload: bool)
|
|||
web_sys::console::error_1(&"Connection to the devserver was closed".into())
|
||||
}
|
||||
|
||||
// The devserver is telling us that it started a full rebuild. This does not mean that it is ready.
|
||||
Ok(DevserverMsg::FullReloadStart) => show_toast(
|
||||
"Your app is being rebuilt.",
|
||||
"A non-hot-reloadable change occurred and we must rebuild.",
|
||||
ToastLevel::Info,
|
||||
TOAST_TIMEOUT,
|
||||
false,
|
||||
),
|
||||
// The devserver is telling us that the full rebuild failed.
|
||||
Ok(DevserverMsg::FullReloadFailed) => show_toast(
|
||||
"Oops! The build failed.",
|
||||
"We tried to rebuild your app, but something went wrong.",
|
||||
ToastLevel::Error,
|
||||
TOAST_TIMEOUT,
|
||||
false,
|
||||
),
|
||||
|
||||
// The devserver is telling us to reload the whole page
|
||||
Ok(DevserverMsg::FullReload) => window().unwrap().location().reload().unwrap(),
|
||||
Ok(DevserverMsg::FullReloadCommand) => {
|
||||
show_toast(
|
||||
"Successfully rebuilt.",
|
||||
"Your app was rebuilt successfully and without error.",
|
||||
ToastLevel::Success,
|
||||
TOAST_TIMEOUT,
|
||||
true,
|
||||
);
|
||||
window().unwrap().location().reload().unwrap()
|
||||
}
|
||||
|
||||
Err(e) => web_sys::console::error_1(
|
||||
&format!("Error parsing devserver message: {}", e).into(),
|
||||
|
@ -133,6 +167,52 @@ fn make_ws(tx: UnboundedSender<HotReloadMsg>, poll_interval: i32, reload: bool)
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents what color the toast should have.
|
||||
enum ToastLevel {
|
||||
/// Green
|
||||
Success,
|
||||
/// Blue
|
||||
Info,
|
||||
/// Red
|
||||
Error,
|
||||
}
|
||||
|
||||
impl Display for ToastLevel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ToastLevel::Success => write!(f, "success"),
|
||||
ToastLevel::Info => write!(f, "info"),
|
||||
ToastLevel::Error => write!(f, "error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Displays a toast to the developer.
|
||||
fn show_toast(
|
||||
header_text: &str,
|
||||
message: &str,
|
||||
level: ToastLevel,
|
||||
duration: Duration,
|
||||
after_reload: bool,
|
||||
) {
|
||||
let as_ms = duration.as_millis();
|
||||
|
||||
let js_fn_name = match after_reload {
|
||||
true => "scheduleDXToast",
|
||||
false => "showDXToast",
|
||||
};
|
||||
|
||||
ScopeId::ROOT.in_runtime(|| {
|
||||
eval(&format!(
|
||||
r#"
|
||||
if (typeof {js_fn_name} !== "undefined") {{
|
||||
{js_fn_name}("{header_text}", "{message}", "{level}", {as_ms});
|
||||
}}
|
||||
"#,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/// Force a hotreload of the assets on this page by walking them and changing their URLs to include
|
||||
/// some extra entropy.
|
||||
///
|
||||
|
|
Loading…
Reference in a new issue