fix web build
This commit is contained in:
+113
-40
@@ -1,22 +1,33 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use gpui::*;
|
||||
use universal_time::{Instant, MonotonicClock, SystemTime, WallClock, define_time_provider};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
struct CustomTimeProvider;
|
||||
thread_local! {
|
||||
/// Dropping the handle releases the app, so the page's lifetime must own it.
|
||||
static APPLICATION: RefCell<Option<ApplicationHandle>> = const { RefCell::new(None) };
|
||||
}
|
||||
|
||||
impl WallClock for CustomTimeProvider {
|
||||
/// Serves `Date.now()` as the wall clock and `performance.now()` as the monotonic clock.
|
||||
struct BrowserTimeProvider;
|
||||
|
||||
impl WallClock for BrowserTimeProvider {
|
||||
fn system_time(&self) -> SystemTime {
|
||||
SystemTime::from_unix_duration(instant::Duration::from_secs(0))
|
||||
SystemTime::from_unix_duration(core::time::Duration::from_secs_f64(
|
||||
js_sys::Date::now() / 1000.0,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl MonotonicClock for CustomTimeProvider {
|
||||
impl MonotonicClock for BrowserTimeProvider {
|
||||
fn instant(&self) -> Instant {
|
||||
Instant::from_ticks(instant::Duration::from_secs(0))
|
||||
Instant::from_ticks(core::time::Duration::from_secs_f64(instant::now() / 1000.0))
|
||||
}
|
||||
}
|
||||
|
||||
define_time_provider!(CustomTimeProvider);
|
||||
define_time_provider!(BrowserTimeProvider);
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() -> Result<(), JsValue> {
|
||||
@@ -28,54 +39,116 @@ pub fn run() -> Result<(), JsValue> {
|
||||
// Also initialize tracing for WASM
|
||||
tracing_wasm::set_as_global_default();
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
// Sets the panic hook and GPUI's console logger
|
||||
gpui_platform::web_init();
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
let app = gpui_platform::application();
|
||||
// A single-threaded platform that draws emoji and CJK graphemes missing
|
||||
// from the bundled fonts with the browser's own fonts, plus a fetch-based
|
||||
// HTTP client so remote images and content work like on desktop
|
||||
let platform = std::rc::Rc::new(gpui_web::WebPlatform::new_with_backend_and_font_fallback(
|
||||
false,
|
||||
gpui_web::WebBackendPreference::Auto,
|
||||
gpui_web::CanvasFontFallback::EmojiAndCjk,
|
||||
));
|
||||
let http_client = std::sync::Arc::new(platform.fetch_http_client());
|
||||
let app = Application::with_platform(platform)
|
||||
.with_http_client(http_client)
|
||||
.with_assets(assets::CombinedAssets);
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
let app = {
|
||||
let app = gpui_platform::single_threaded_web();
|
||||
APPLICATION.with(|application| {
|
||||
*application.borrow_mut() = Some(app.run_embedded(|cx| {
|
||||
// Initialize the framework before anything renders
|
||||
gpui_kit::init(cx);
|
||||
|
||||
// Temporary fix: intentionally leak the `Rc<AppCell>` to keep the application alive
|
||||
struct WasmApplication(std::rc::Rc<AppCell>);
|
||||
let wasm_app = unsafe { std::mem::transmute::<Application, WasmApplication>(app) };
|
||||
std::mem::forget(wasm_app.0.clone());
|
||||
unsafe { std::mem::transmute::<WasmApplication, Application>(wasm_app) }
|
||||
};
|
||||
// The web text system starts with no fonts, and GPUI panics when
|
||||
// it lays out text in a family that does not exist. Inter is both
|
||||
// bundled and named on the theme (including both mode configs, so
|
||||
// theme reloads keep it) before any text is laid out
|
||||
load_embedded_fonts(cx);
|
||||
apply_web_fonts(cx);
|
||||
|
||||
app.run(|cx| {
|
||||
// Initialize the framework before anything renders
|
||||
gpui_kit::init(cx);
|
||||
// Initialize settings
|
||||
settings::init(cx);
|
||||
|
||||
// Initialize settings
|
||||
settings::init(cx);
|
||||
// There is no native theme on the web; apply the persisted
|
||||
// appearance directly, then the user's theme tuning
|
||||
apply_appearance(settings::persisted_appearance_mode(), cx);
|
||||
settings::AppSettings::apply_theme_style(cx);
|
||||
|
||||
// Initialize the nostr client
|
||||
state::init(cx, None);
|
||||
// Initialize the nostr client
|
||||
state::init(cx, None);
|
||||
|
||||
// Initialize person registry
|
||||
person::init(cx);
|
||||
// Initialize person registry
|
||||
person::init(cx);
|
||||
|
||||
// Initialize device signer
|
||||
//
|
||||
// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
||||
nip4e::init(cx);
|
||||
// Initialize device signer
|
||||
//
|
||||
// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
||||
nip4e::init(cx);
|
||||
|
||||
// Initialize app registry
|
||||
chat::init(cx);
|
||||
// Initialize app registry
|
||||
chat::init(cx);
|
||||
|
||||
// Initialize groups registry
|
||||
nip29::init(cx);
|
||||
// Initialize groups registry
|
||||
nip29::init(cx);
|
||||
|
||||
gpui_kit::open_window(WindowOptions::default(), cx, |window, cx| {
|
||||
workspace::init(window, cx)
|
||||
})
|
||||
.expect("Failed to open window. Please restart the application.");
|
||||
gpui_kit::open_window(WindowOptions::default(), cx, |window, cx| {
|
||||
workspace::init(window, cx)
|
||||
})
|
||||
.expect("Failed to open window. Please restart the application.");
|
||||
|
||||
cx.activate(true);
|
||||
cx.activate(true);
|
||||
}));
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Register every bundled font with the text system before any text is laid out
|
||||
fn load_embedded_fonts(cx: &mut App) {
|
||||
let font_paths = assets::Assets::iter()
|
||||
.filter(|path| path.starts_with("fonts/") && path.ends_with(".ttf"))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let fonts = font_paths
|
||||
.iter()
|
||||
.filter_map(|path| assets::Assets::get(path.as_ref()))
|
||||
.map(|font| font.data)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
cx.text_system()
|
||||
.add_fonts(fonts)
|
||||
.expect("Failed to load bundled fonts");
|
||||
}
|
||||
|
||||
/// Name Inter on the theme and both mode configs so every text run renders in
|
||||
/// it and theme reloads keep it. Without an explicit family the theme falls
|
||||
/// back to `.SystemUIFont`, which the web platform resolves to a family that
|
||||
/// is not bundled
|
||||
fn apply_web_fonts(cx: &mut App) {
|
||||
use gpui_kit::component::Theme;
|
||||
|
||||
const UI_FONT: &str = "Inter";
|
||||
|
||||
Theme::update(cx, |theme| {
|
||||
theme.font_family = UI_FONT.into();
|
||||
theme.mono_font_family = UI_FONT.into();
|
||||
|
||||
for config in [&mut theme.light_theme, &mut theme.dark_theme] {
|
||||
let config = Rc::make_mut(config);
|
||||
config.font_family = Some(UI_FONT.into());
|
||||
config.mono_font_family = Some(UI_FONT.into());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Honor the appearance mode against the default palettes
|
||||
fn apply_appearance(appearance: settings::AppearanceMode, cx: &mut App) {
|
||||
use gpui_kit::component::{Theme, ThemeMode};
|
||||
|
||||
match appearance {
|
||||
settings::AppearanceMode::System => Theme::sync_system_appearance(None, cx),
|
||||
settings::AppearanceMode::Light => Theme::change(ThemeMode::Light, None, cx),
|
||||
settings::AppearanceMode::Dark => Theme::change(ThemeMode::Dark, None, cx),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user