forked from rojo-rbx/rojo
Add abstraction for files to make iteration on UI easier
This commit is contained in:
@@ -12,6 +12,12 @@ exclude = [
|
||||
"/test-projects/**",
|
||||
]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
# Enable this feature to live-reload assets from the web UI.
|
||||
dev-live-assets = []
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"rojo-test",
|
||||
|
||||
@@ -22,11 +22,10 @@ body {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.main {
|
||||
.root {
|
||||
flex: 0 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
max-width: 50rem;
|
||||
@@ -38,19 +37,25 @@ body {
|
||||
.header {
|
||||
flex: 0 0;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
/*justify-content: space-around;*/
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
border-bottom: 1px solid #666;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.main-logo {
|
||||
flex: 0 0;
|
||||
width: 20rem;
|
||||
width: 10rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.stats {
|
||||
flex: 0 0 20rem;
|
||||
padding: 0 1rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.stat {
|
||||
@@ -65,12 +70,13 @@ body {
|
||||
.button-list {
|
||||
flex: 0 0;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
border: 1px solid #666;
|
||||
padding: 0.3em 1em;
|
||||
margin: 0 0.2rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
37
src/web/assets.rs
Normal file
37
src/web/assets.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
static LOGO: &[u8] = include_bytes!("../../assets/logo-512.png");
|
||||
static ICON: &[u8] = include_bytes!("../../assets/icon-32.png");
|
||||
static HOME_CSS: &str = include_str!("../../assets/index.css");
|
||||
|
||||
macro_rules! declare_asset {
|
||||
($name: ident, $path: expr) => {
|
||||
pub fn $name() -> &'static str {
|
||||
if cfg!(feature = "dev-live-assets") {
|
||||
let file_path = Path::new(file!());
|
||||
let asset_path = file_path.parent().unwrap().join($path);
|
||||
|
||||
println!("Reloading {}", asset_path.display());
|
||||
|
||||
let content = fs::read_to_string(asset_path)
|
||||
.expect("Couldn't read dev live asset")
|
||||
.into_boxed_str();
|
||||
|
||||
Box::leak(content)
|
||||
} else {
|
||||
static CONTENT: &str = include_str!($path);
|
||||
CONTENT
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
declare_asset!(css, "../../assets/index.css");
|
||||
|
||||
pub fn logo() -> &'static [u8] {
|
||||
LOGO
|
||||
}
|
||||
|
||||
pub fn icon() -> &'static [u8] {
|
||||
ICON
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
mod api;
|
||||
mod assets;
|
||||
pub mod interface;
|
||||
mod ui;
|
||||
mod util;
|
||||
|
||||
@@ -10,15 +10,12 @@ use crate::{
|
||||
imfs::ImfsFetcher,
|
||||
serve_session::ServeSession,
|
||||
web::{
|
||||
assets,
|
||||
interface::{ErrorResponse, SERVER_VERSION},
|
||||
util::json,
|
||||
},
|
||||
};
|
||||
|
||||
static LOGO: &[u8] = include_bytes!("../../assets/logo-512.png");
|
||||
static ICON: &[u8] = include_bytes!("../../assets/icon-32.png");
|
||||
static HOME_CSS: &str = include_str!("../../assets/index.css");
|
||||
|
||||
pub struct UiService<F> {
|
||||
serve_session: Arc<ServeSession<F>>,
|
||||
}
|
||||
@@ -56,46 +53,24 @@ impl<F: ImfsFetcher> UiService<F> {
|
||||
fn handle_logo(&self) -> Response<Body> {
|
||||
Response::builder()
|
||||
.header(header::CONTENT_TYPE, "image/png")
|
||||
.body(Body::from(LOGO))
|
||||
.body(Body::from(assets::logo()))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn handle_icon(&self) -> Response<Body> {
|
||||
Response::builder()
|
||||
.header(header::CONTENT_TYPE, "image/png")
|
||||
.body(Body::from(ICON))
|
||||
.body(Body::from(assets::icon()))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn handle_home(&self) -> Response<Body> {
|
||||
let project_name = self.serve_session.project_name().unwrap_or("<unnamed>");
|
||||
let uptime = {
|
||||
let elapsed = self.serve_session.start_time().elapsed();
|
||||
|
||||
// Round off all of our sub-second precision to make timestamps
|
||||
// nicer.
|
||||
let just_nanos = Duration::from_nanos(elapsed.subsec_nanos() as u64);
|
||||
let elapsed = elapsed - just_nanos;
|
||||
|
||||
humantime::format_duration(elapsed).to_string()
|
||||
};
|
||||
|
||||
let page = Self::page(html! {
|
||||
<main class="main">
|
||||
<header class="header">
|
||||
<img class="main-logo" src="/logo.png" />
|
||||
<div class="stats">
|
||||
{ Self::stat_item("Server Version", SERVER_VERSION) }
|
||||
{ Self::stat_item("Project", project_name) }
|
||||
{ Self::stat_item("Server Uptime", uptime) }
|
||||
</div>
|
||||
</header>
|
||||
<div class="button-list">
|
||||
{ Self::button("Rojo Documentation", "https://rojo.space/docs") }
|
||||
{ Self::button("View in-memory filesystem state", "/show-imfs") }
|
||||
{ Self::button("View instance tree state", "/show-instances") }
|
||||
</div>
|
||||
</main>
|
||||
let page = self.normal_page(html! {
|
||||
<div class="button-list">
|
||||
{ Self::button("Rojo Documentation", "https://rojo.space/docs") }
|
||||
{ Self::button("View in-memory filesystem state", "/show-imfs") }
|
||||
{ Self::button("View instance tree state", "/show-instances") }
|
||||
</div>
|
||||
});
|
||||
|
||||
Response::builder()
|
||||
@@ -133,14 +108,45 @@ impl<F: ImfsFetcher> UiService<F> {
|
||||
}
|
||||
}
|
||||
|
||||
fn normal_page<'a>(&'a self, body: HtmlContent<'a>) -> HtmlContent<'a> {
|
||||
let project_name = self.serve_session.project_name().unwrap_or("<unnamed>");
|
||||
let uptime = {
|
||||
let elapsed = self.serve_session.start_time().elapsed();
|
||||
|
||||
// Round off all of our sub-second precision to make timestamps
|
||||
// nicer.
|
||||
let just_nanos = Duration::from_nanos(elapsed.subsec_nanos() as u64);
|
||||
let elapsed = elapsed - just_nanos;
|
||||
|
||||
humantime::format_duration(elapsed).to_string()
|
||||
};
|
||||
|
||||
Self::page(html! {
|
||||
<div class="root">
|
||||
<header class="header">
|
||||
<img class="main-logo" src="/logo.png" />
|
||||
<div class="stats">
|
||||
{ Self::stat_item("Server Version", SERVER_VERSION) }
|
||||
{ Self::stat_item("Project", project_name) }
|
||||
{ Self::stat_item("Server Uptime", uptime) }
|
||||
</div>
|
||||
</header>
|
||||
<main class="main">
|
||||
{ body }
|
||||
</main>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
|
||||
fn page(body: HtmlContent<'_>) -> HtmlContent<'_> {
|
||||
html! {
|
||||
<html>
|
||||
<head>
|
||||
<title>"Rojo Live Server"</title>
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/icon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1" />
|
||||
<style>
|
||||
{ ritz::UnescapedText::new(HOME_CSS) }
|
||||
{ ritz::UnescapedText::new(assets::css()) }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user