mirror of
https://github.com/DioxusLabs/dioxus
synced 2025-02-16 21:58:25 +00:00
feat: allow customizing the index and head
This commit is contained in:
parent
ab4f75e4ea
commit
049976d23a
6 changed files with 107 additions and 12 deletions
37
examples/custom_html.rs
Normal file
37
examples/custom_html.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
//! This example shows how to use a custom index.html and custom <HEAD> extensions
|
||||
//! to add things like stylesheets, scripts, and third-party JS libraries.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
dioxus::desktop::launch_cfg(app, |c| {
|
||||
c.with_custom_head("<style>body { background-color: red; }</style>".into())
|
||||
});
|
||||
|
||||
dioxus::desktop::launch_cfg(app, |c| {
|
||||
c.with_custom_index(
|
||||
r#"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dioxus app</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<style>body { background-color: blue; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main"></div>
|
||||
</body>
|
||||
</html>
|
||||
"#
|
||||
.into(),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 {"hello world!"}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -21,6 +21,8 @@ pub struct DesktopConfig {
|
|||
pub(crate) event_handler: Option<Box<DynEventHandlerFn>>,
|
||||
pub(crate) disable_context_menu: bool,
|
||||
pub(crate) resource_dir: Option<PathBuf>,
|
||||
pub(crate) custom_head: Option<String>,
|
||||
pub(crate) custom_index: Option<String>,
|
||||
}
|
||||
|
||||
pub(crate) type WryProtocol = (
|
||||
|
@ -42,6 +44,8 @@ impl DesktopConfig {
|
|||
pre_rendered: None,
|
||||
disable_context_menu: !cfg!(debug_assertions),
|
||||
resource_dir: None,
|
||||
custom_head: None,
|
||||
custom_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,10 +104,32 @@ impl DesktopConfig {
|
|||
self
|
||||
}
|
||||
|
||||
|
||||
/// Add a custom icon for this application
|
||||
pub fn with_icon(&mut self, icon: Icon) -> &mut Self {
|
||||
self.window.window.window_icon = Some(icon);
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
/// Inject additional content into the document's HEAD.
|
||||
///
|
||||
/// This is useful for loading CSS libraries, JS libraries, etc.
|
||||
pub fn with_custom_head(&mut self, head: String) -> &mut Self {
|
||||
self.custom_head = Some(head);
|
||||
self
|
||||
}
|
||||
|
||||
/// Use a custom index.html instead of the default Dioxus one.
|
||||
///
|
||||
/// Make sure your index.html is valid HTML.
|
||||
///
|
||||
/// Dioxus injects some loader code into the closing body tag. Your document
|
||||
/// must include a body element!
|
||||
pub fn with_custom_index(&mut self, index: String) -> &mut Self {
|
||||
self.custom_index = Some(index);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl DesktopConfig {
|
||||
|
|
|
@ -201,7 +201,7 @@ pub(super) fn handler(
|
|||
|
||||
/// Get a closure that executes any JavaScript in the WebView context.
|
||||
pub fn use_eval<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) {
|
||||
let desktop = use_window(&cx).clone();
|
||||
let desktop = use_window(cx).clone();
|
||||
|
||||
cx.use_hook(|_| move |script| desktop.eval(script))
|
||||
}
|
||||
|
|
|
@ -3,13 +3,10 @@
|
|||
<head>
|
||||
<title>Dioxus app</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<!-- CUSTOM HEAD -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="main"></div>
|
||||
<script>
|
||||
import("./index.js").then(function (module) {
|
||||
module.main();
|
||||
});
|
||||
</script>
|
||||
<!-- MODULE LOADER -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -125,8 +125,9 @@ pub fn launch_with_props<P: 'static + Send>(
|
|||
let proxy = proxy.clone();
|
||||
|
||||
let file_handler = cfg.file_drop_handler.take();
|
||||
|
||||
let custom_head = cfg.custom_head.clone();
|
||||
let resource_dir = cfg.resource_dir.clone();
|
||||
let index_file = cfg.custom_index.clone();
|
||||
|
||||
let mut webview = WebViewBuilder::new(window)
|
||||
.unwrap()
|
||||
|
@ -164,7 +165,12 @@ pub fn launch_with_props<P: 'static + Send>(
|
|||
});
|
||||
})
|
||||
.with_custom_protocol(String::from("dioxus"), move |r| {
|
||||
protocol::desktop_handler(r, resource_dir.clone())
|
||||
protocol::desktop_handler(
|
||||
r,
|
||||
resource_dir.clone(),
|
||||
custom_head.clone(),
|
||||
index_file.clone(),
|
||||
)
|
||||
})
|
||||
.with_file_drop_handler(move |window, evet| {
|
||||
file_handler
|
||||
|
|
|
@ -4,7 +4,20 @@ use wry::{
|
|||
Result,
|
||||
};
|
||||
|
||||
pub(super) fn desktop_handler(request: &Request, asset_root: Option<PathBuf>) -> Result<Response> {
|
||||
const MODULE_LOADER: &str = r#"
|
||||
<script>
|
||||
import("./index.js").then(function (module) {
|
||||
module.main();
|
||||
});
|
||||
</script>
|
||||
"#;
|
||||
|
||||
pub(super) fn desktop_handler(
|
||||
request: &Request,
|
||||
asset_root: Option<PathBuf>,
|
||||
custom_head: Option<String>,
|
||||
custom_index: Option<String>,
|
||||
) -> Result<Response> {
|
||||
// Any content that uses the `dioxus://` scheme will be shuttled through this handler as a "special case".
|
||||
// For now, we only serve two pieces of content which get included as bytes into the final binary.
|
||||
let path = request.uri().replace("dioxus://", "");
|
||||
|
@ -13,9 +26,25 @@ pub(super) fn desktop_handler(request: &Request, asset_root: Option<PathBuf>) ->
|
|||
let trimmed = path.trim_start_matches("index.html/");
|
||||
|
||||
if trimmed.is_empty() {
|
||||
ResponseBuilder::new()
|
||||
.mimetype("text/html")
|
||||
.body(include_bytes!("./index.html").to_vec())
|
||||
// If a custom index is provided, just defer to that, expecting the user to know what they're doing.
|
||||
// we'll look for the closing </body> tag and insert our little module loader there.
|
||||
if let Some(custom_index) = custom_index {
|
||||
let rendered = custom_index
|
||||
.replace("</body>", &format!("{}</body>", MODULE_LOADER))
|
||||
.into_bytes();
|
||||
ResponseBuilder::new().mimetype("text/html").body(rendered)
|
||||
} else {
|
||||
// Otherwise, we'll serve the default index.html and apply a custom head if that's specified.
|
||||
let mut template = include_str!("./index.html").to_string();
|
||||
if let Some(custom_head) = custom_head {
|
||||
template = template.replace("<!-- CUSTOM HEAD -->", &custom_head);
|
||||
}
|
||||
template = template.replace("<!-- MODULE LOADER -->", MODULE_LOADER);
|
||||
|
||||
ResponseBuilder::new()
|
||||
.mimetype("text/html")
|
||||
.body(template.into_bytes())
|
||||
}
|
||||
} else if trimmed == "index.js" {
|
||||
ResponseBuilder::new()
|
||||
.mimetype("text/javascript")
|
||||
|
|
Loading…
Add table
Reference in a new issue